Index: tests/compiler/dart2js_native/error_safeToString_test.dart |
diff --git a/tests/compiler/dart2js_native/error_safeToString_test.dart b/tests/compiler/dart2js_native/error_safeToString_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3322560b0cc1935abe7149b9c05b9e4340bc4bc8 |
--- /dev/null |
+++ b/tests/compiler/dart2js_native/error_safeToString_test.dart |
@@ -0,0 +1,169 @@ |
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+import "package:expect/expect.dart"; |
+import 'dart:_foreign_helper' show JS_INTERCEPTOR_CONSTANT, JS; |
+import 'dart:_js_helper' show Native, Creates; |
+import 'dart:_interceptors' show |
+ Interceptor, |
+ JavaScriptObject, |
+ PlainJavaScriptObject, |
+ UnknownJavaScriptObject; |
+ |
+// Test for safe formatting of JavaScript objects by Error.safeToString. |
+ |
+@Native('PPPP') |
+class Purple {} |
+ |
+@Native('QQQQ') |
+class Q {} |
+ |
+@Native('RRRR') |
+class Rascal { |
+ toString() => 'RRRRRRRR'; |
+} |
+ |
+makeA() native; |
+makeB() native; |
+makeC() native; |
+makeD() native; |
+makeE() native; |
+makeP() native; |
+makeQ() native; |
+makeR() native; |
+ |
+void setup() native r""" |
+makeA = function(){return {hello: 123};}; |
+ |
+function BB(){} |
+makeB = function(){return new BB();}; |
+ |
+function CC(){} |
+makeC = function(){ |
+ var x = new CC(); |
+ x.constructor = null; // Foils constructor lookup. |
+ return x; |
+}; |
+ |
+function DD(){} |
+makeD = function(){ |
+ var x = new DD(); |
+ x.constructor = {name: 'DDxxx'}; // Foils constructor lookup. |
+ return x; |
+}; |
+ |
+function EE(){} |
+makeE = function(){ |
+ var x = new EE(); |
+ x.constructor = function Liar(){}; // Looks like a legitimate constructor. |
+ return x; |
+}; |
+ |
+function PPPP(){} |
+makeP = function(){return new PPPP();}; |
+ |
+function QQQQ(){} |
+makeQ = function(){return new QQQQ();}; |
+ |
+function RRRR(){} |
+makeR = function(){return new RRRR();}; |
+ |
+"""; |
+ |
+ |
+expectTypeName(expectedName, s) { |
+ var m = new RegExp(r"Instance of '(.*)'").firstMatch(s); |
+ Expect.isNotNull(m); |
+ var name = m.group(1); |
+ Expect.isTrue(expectedName == name || name.length <= 3, |
+ "Is '$expectedName' or minified: '$name'"); |
+} |
+ |
+final plainJsString = |
+ Error.safeToString(JS_INTERCEPTOR_CONSTANT(PlainJavaScriptObject)); |
+ |
+final unknownJsString = |
+ Error.safeToString(JS_INTERCEPTOR_CONSTANT(UnknownJavaScriptObject)); |
+ |
+final interceptorString = |
+ Error.safeToString(JS_INTERCEPTOR_CONSTANT(Interceptor)); |
+ |
+ |
+testDistinctInterceptors() { |
+ // Test invariants needed for the other tests. |
+ |
+ Expect.notEquals(plainJsString, unknownJsString); |
+ Expect.notEquals(plainJsString, interceptorString); |
+ Expect.notEquals(unknownJsString, interceptorString); |
+ |
+ expectTypeName('PlainJavaScriptObject', plainJsString); |
+ expectTypeName('UnknownJavaScriptObject', unknownJsString); |
+ expectTypeName('Interceptor', interceptorString); |
+ |
+ // Sometimes interceptor *objects* are used instead of the prototypes. Check |
+ // these work too. |
+ var plain2 = Error.safeToString(const PlainJavaScriptObject()); |
+ Expect.equals(plainJsString, plain2); |
+ |
+ var unk2 = Error.safeToString(const UnknownJavaScriptObject()); |
+ Expect.equals(unknownJsString, unk2); |
+} |
+ |
+ |
+testExternal() { |
+ var x = makeA(); |
+ Expect.equals(plainJsString, Error.safeToString(x)); |
+ |
+ x = makeB(); |
+ // Gets name from constructor, regardless of minification. |
+ Expect.equals("Instance of 'BB'", Error.safeToString(x)); |
+ |
+ x = makeC(); |
+ Expect.equals(unknownJsString, Error.safeToString(x)); |
+ |
+ x = makeD(); |
+ Expect.equals(unknownJsString, Error.safeToString(x)); |
+ |
+ x = makeE(); |
+ Expect.equals("Instance of 'Liar'", Error.safeToString(x)); |
+} |
+ |
+testNative() { |
+ var x = makeP(); |
+ Expect.isTrue(x is Purple); // This test forces Purple to be distinguished. |
+ Expect.notEquals(plainJsString, Error.safeToString(x)); |
+ Expect.notEquals(unknownJsString, Error.safeToString(x)); |
+ Expect.notEquals(interceptorString, Error.safeToString(x)); |
+ // And not the native class constructor. |
+ Expect.notEquals("Instance of 'PPPP'", Error.safeToString(x)); |
+ expectTypeName('Purple', Error.safeToString(x)); |
+ |
+ x = makeQ(); |
+ print('Q: $x ${Error.safeToString(x)}'); |
+ // We are going to get either the general interceptor or the JavaScript |
+ // constructor. |
+ Expect.isTrue( |
+ "Instance of 'QQQQ'" == Error.safeToString(x) || |
+ interceptorString == Error.safeToString(x)); |
+ |
+ x = makeR(); |
+ |
+ // Rascal overrides 'toString'. The toString() call causes Rascal to be |
+ // distinguished. |
+ x.toString(); |
+ Expect.notEquals(plainJsString, Error.safeToString(x)); |
+ Expect.notEquals(unknownJsString, Error.safeToString(x)); |
+ Expect.notEquals(interceptorString, Error.safeToString(x)); |
+ // And not the native class constructor. |
+ Expect.notEquals("Instance of 'RRRR'", Error.safeToString(x)); |
+ expectTypeName('Rascal', Error.safeToString(x)); |
+} |
+ |
+main() { |
+ setup(); |
+ |
+ testDistinctInterceptors(); |
+ testExternal(); |
+ testNative(); |
+} |