Index: tests/html/js_typed_interop_test.dart |
diff --git a/tests/html/js_typed_interop_test.dart b/tests/html/js_typed_interop_test.dart |
index 431d533037e10d83a3493fd049c0da557b007927..960c0ccf453521c4f8999ef37dfc3b4a07c722aa 100644 |
--- a/tests/html/js_typed_interop_test.dart |
+++ b/tests/html/js_typed_interop_test.dart |
@@ -71,6 +71,15 @@ _injectJs() { |
getA: function() { return this.a;} |
}; |
+ function _PrivateClass(a, b) { |
+ this._a = a; |
+ this._b = b; |
+ }; |
+ |
+ _PrivateClass.prototype = { |
+ _getA: function() { return this._a;} |
+ }; |
+ |
var selection = ["a", "b", "c", foo, bar]; |
function returnNumArgs() { return arguments.length; }; |
@@ -78,6 +87,23 @@ _injectJs() { |
function confuse(obj) { return obj; } |
+ window['class'] = function() { return 42; }; |
+ window['delete'] = 100; |
+ window['JS$hasJsInName'] = 'unicorn'; |
+ window['JS$hasJsInNameMethod'] = function(x) { return x*5; }; |
+ |
+ function JS$ClassWithJSInName(x) { |
+ this.x = x; |
+ this.JS$hasJsInName = 73; |
+ this.$JS$doesNotNeedEscape = 103; |
+ }; |
+ |
+ JS$ClassWithJSInName.prototype = { |
+ JS$getXwithJsInName: function() { return this.x;} |
+ }; |
+ |
+ JS$ClassWithJSInName.JS$staticMethod = function(x) { return x * 3; }; |
+ |
function StringWrapper(str) { |
this.str = str; |
} |
@@ -110,6 +136,49 @@ class ClassWithConstructor { |
external get b; |
} |
+@JS('ClassWithConstructor') |
+class _ClassWithConstructor { |
+ external _ClassWithConstructor(aParam, bParam); |
+ external getA(); |
+ external get a; |
+ external get b; |
+} |
+ |
+@JS() |
+class JS$_PrivateClass { |
+ external JS$_PrivateClass(aParam, bParam); |
+ external JS$_getA(); |
+ external get JS$_a; |
+ external get JS$_b; |
+ // Equivalent to JS$_a but only visible within |
+ // the class. |
+ external get _a; |
+} |
+ |
+@JS() |
+external String get JS$JS$hasJsInName; |
+ |
+@JS() |
+external int JS$JS$hasJsInNameMethod(int x); |
+ |
+// This is the prefered way to handle static or top level members that start |
+// with JS$. We verify that JS$JS$ works purely to prevent bugs. |
+@JS(r'JS$hasJsInName') |
+external String get JS$hasJsInName; |
+ |
+@JS(r'JS$hasJsInNameMethod') |
+external int JS$hasJsInNameMethod(int x); |
+ |
+@JS() |
+class JS$JS$ClassWithJSInName { |
+ external JS$JS$ClassWithJSInName(x); |
+ external int get x; |
+ external int get JS$JS$hasJsInName; |
+ external int get $JS$doesNotNeedEscape; |
+ external int JS$JS$getXwithJsInName(); |
+ external static int JS$JS$staticMethod(x); |
+} |
+ |
typedef num MultiplyWithDefault(num a, [num b]); |
@JS() |
@@ -118,6 +187,7 @@ class Foo { |
external set x(int v); |
external num multiplyByX(num y); |
external num multiplyBy2(num y); |
+ external num JS$multiplyBy2(num y); |
external MultiplyWithDefault get multiplyDefault2Function; |
external callClosureWithArgAndThis(Function closure, arg); |
@@ -126,14 +196,17 @@ class Foo { |
external Bar getBar(); |
external static num multiplyDefault2(num a, [num b]); |
+ // Should desugar to multiplyDefault2. |
+ external static num JS$multiplyDefault2(num a, [num b]); |
} |
@anonymous |
@JS() |
class ExampleLiteral { |
- external factory ExampleLiteral({int x, String y, num z}); |
+ external factory ExampleLiteral({int x, String y, num z, JS$class}); |
external int get x; |
+ external int get JS$class; |
external String get y; |
external num get z; |
} |
@@ -182,6 +255,13 @@ class StringWrapper { |
@JS() |
external confuse(obj); |
+/// Desugars to calling the js method named class. |
+@JS() |
+external JS$class(); |
+ |
+@JS() |
+external get JS$delete; |
+ |
@JS() |
external CanvasRenderingContext2D getCanvasContext(); |
@@ -191,6 +271,16 @@ external num get propertyOnDocument; |
@JS('window.self.window.window.windowProperty') |
external num get propertyOnWindow; |
+@JS() |
+@anonymous |
+class Simple |
+{ |
+ external List<int> get numbers; |
+ external set numbers(List<int> numbers); |
+ |
+ external factory Simple({ List<int> numbers }); |
+} |
+ |
main() { |
_injectJs(); |
@@ -210,6 +300,17 @@ main() { |
expect(stringify(l), equals('{"z":100}')); |
}); |
+ test('with array', () { |
+ // Repro for https://github.com/dart-lang/sdk/issues/26768 |
+ var simple = new Simple(numbers: [ 1, 2, 3 ]); |
+ expect(stringify(simple), equals('{"numbers":[1,2,3]}')); |
+ }); |
+ |
+ test(r'JS$ escaped name', () { |
+ var l = new ExampleLiteral(JS$class: 3, y: "foo"); |
+ expect(l.JS$class, equals(3)); |
+ }); |
+ |
test('empty', () { |
var l = new EmptyLiteral(); |
expect(stringify(l), equals('{}')); |
@@ -225,6 +326,25 @@ main() { |
}); |
}); |
+ group('private class', () { |
+ test('simple', () { |
+ var o = new _ClassWithConstructor("foo", "bar"); |
+ expect(o.a, equals("foo")); |
+ expect(o.b, equals("bar")); |
+ expect(o.getA(), equals("foo")); |
+ }); |
+ }); |
+ |
+ group('private class', () { |
+ test('simple', () { |
+ var o = new JS$_PrivateClass("foo", "bar"); |
+ expect(o.JS$_a, equals("foo")); |
+ expect(o.JS$_b, equals("bar")); |
+ expect(o._a, equals("foo")); |
+ expect(o.JS$_getA(), equals("foo")); |
+ }); |
+ }); |
+ |
group('property', () { |
test('get', () { |
expect(foo.x, equals(3)); |
@@ -276,6 +396,22 @@ main() { |
expect(untypedFunction(), isNaN); |
}); |
+ |
+ test(r'JS$ escaped name', () { |
+ foo.x = 10; |
+ expect(foo.JS$multiplyBy2(5), equals(10)); |
+ |
+ Function multiplyBy2 = foo.JS$multiplyBy2; |
+ expect(multiplyBy2(5), equals(10)); |
+ }); |
+ |
+ test(r'JS$ double escaped name', () { |
+ var obj = new JS$JS$ClassWithJSInName(42); |
+ expect(obj.x, equals(42)); |
+ expect(obj.JS$JS$getXwithJsInName(), equals(42)); |
+ expect(obj.JS$JS$hasJsInName, equals(73)); |
+ expect(obj.$JS$doesNotNeedEscape, equals(103)); |
+ }); |
}); |
group('static_method_call', () { |
@@ -283,6 +419,15 @@ main() { |
expect(Foo.multiplyDefault2(6, 7), equals(42)); |
expect(Foo.multiplyDefault2(6), equals(12)); |
}); |
+ |
+ test(r'JS$ escaped name', () { |
+ expect(Foo.JS$multiplyDefault2(6, 7), equals(42)); |
+ expect(Foo.JS$multiplyDefault2(6), equals(12)); |
+ }); |
+ |
+ test(r'JS$ double escaped name', () { |
+ expect(JS$JS$ClassWithJSInName.JS$JS$staticMethod(4), equals(12)); |
+ }); |
}); |
// Note: these extra groups are added to be able to mark each test |
@@ -384,6 +529,17 @@ main() { |
}); |
}); |
+ group(r'JS$ escaped', () { |
+ test('top level', () { |
+ expect(JS$class(), equals(42)); |
+ expect(JS$delete, equals(100)); |
+ }); |
+ test('top level double escaped', () { |
+ expect(JS$JS$hasJsInName, equals('unicorn')); |
+ expect(JS$JS$hasJsInNameMethod(4), equals(20)); |
+ }); |
+ }); |
+ |
group('type check', () { |
test('js interfaces', () { |
// Is checks return true for all JavaScript interfaces. |