Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Unified Diff: test/codegen/lib/html/js_typed_interop_test.dart

Issue 1930043002: Add all dart:html tests from the sdk to test/codegen. (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: ptal Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test/codegen/lib/html/js_typed_interop_side_cast_test.dart ('k') | test/codegen/lib/html/json_helper.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/codegen/lib/html/js_typed_interop_test.dart
diff --git a/test/codegen/lib/html/js_typed_interop_test.dart b/test/codegen/lib/html/js_typed_interop_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..431d533037e10d83a3493fd049c0da557b007927
--- /dev/null
+++ b/test/codegen/lib/html/js_typed_interop_test.dart
@@ -0,0 +1,413 @@
+// 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.
+
+@JS()
+library js_typed_interop_test;
+
+import 'dart:html';
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'package:unittest/html_individual_config.dart';
+
+_injectJs() {
+ document.body.append(new ScriptElement()
+ ..type = 'text/javascript'
+ ..innerHtml = r"""
+ var Foo = {
+ multiplyDefault2: function(a, b) {
+ if (arguments.length >= 2) return a *b;
+ return a * 2;
+ }
+ };
+
+ var foo = {
+ x: 3,
+ z: 40, // Not specified in typed Dart API so should fail in checked mode.
+ multiplyByX: function(arg) { return arg * this.x; },
+ // This function can be torn off without having to bind this.
+ multiplyBy2: function(arg) { return arg * 2; },
+ multiplyDefault2Function: function(a, b) {
+ if (arguments.length >= 2) return a * b;
+ return a * 2;
+ },
+ callClosureWithArg1: function(closure, arg) {
+ return closure(arg);
+ },
+ callClosureWithArg2: function(closure, arg1, arg2) {
+ return closure(arg1, arg2);
+ },
+ callClosureWithArgAndThis: function(closure, arg) {
+ return closure.apply(this, [arg]);
+ },
+
+ getBar: function() {
+ return bar;
+ }
+ };
+
+ var foob = {
+ x: 8,
+ y: "why",
+ multiplyByX: function(arg) { return arg * this.x; }
+ };
+
+ var bar = {
+ x: "foo",
+ multiplyByX: true,
+ getFoo: function() {
+ return foo;
+ }
+ };
+
+ function ClassWithConstructor(a, b) {
+ this.a = a;
+ this.b = b;
+ };
+
+ ClassWithConstructor.prototype = {
+ getA: function() { return this.a;}
+ };
+
+ var selection = ["a", "b", "c", foo, bar];
+
+ function returnNumArgs() { return arguments.length; };
+ function returnLastArg() { return arguments[arguments.length-1]; };
+
+ function confuse(obj) { return obj; }
+
+ function StringWrapper(str) {
+ this.str = str;
+ }
+ StringWrapper.prototype = {
+ charCodeAt: function(index) {
+ return this.str.charCodeAt(index);
+ }
+ };
+ function getCanvasContext() {
+ return document.createElement('canvas').getContext('2d');
+ }
+ window.windowProperty = 42;
+ document.documentProperty = 45;
+""");
+}
+
+class RegularClass {
+ factory RegularClass(a) {
+ return new RegularClass.fooConstructor(a);
+ }
+ RegularClass.fooConstructor(this.a);
+ var a;
+}
+
+@JS()
+class ClassWithConstructor {
+ external ClassWithConstructor(aParam, bParam);
+ external getA();
+ external get a;
+ external get b;
+}
+
+typedef num MultiplyWithDefault(num a, [num b]);
+
+@JS()
+class Foo {
+ external int get x;
+ external set x(int v);
+ external num multiplyByX(num y);
+ external num multiplyBy2(num y);
+ external MultiplyWithDefault get multiplyDefault2Function;
+
+ external callClosureWithArgAndThis(Function closure, arg);
+ external callClosureWithArg1(Function closure, arg1);
+ external callClosureWithArg2(Function closure, arg1, arg2);
+ external Bar getBar();
+
+ external static num multiplyDefault2(num a, [num b]);
+}
+
+@anonymous
+@JS()
+class ExampleLiteral {
+ external factory ExampleLiteral({int x, String y, num z});
+
+ external int get x;
+ external String get y;
+ external num get z;
+}
+
+@anonymous
+@JS()
+class EmptyLiteral {
+ external factory EmptyLiteral();
+}
+
+@JS('Foob')
+class Foob extends Foo {
+ external String get y;
+}
+
+@JS('Bar')
+class Bar {
+ external String get x;
+ external bool get multiplyByX;
+ external Foo getFoo();
+}
+
+// No @JS is required for these external methods as the library is
+// annotated with Js.
+external Foo get foo;
+external Foob get foob;
+external Bar get bar;
+external Selection get selection;
+
+addWithDefault(a, [b = 100]) => a + b;
+
+external Function get returnNumArgs;
+external Function get returnLastArg;
+
+const STRINGIFY_LOCATION = "JSON.stringify";
+@JS(STRINGIFY_LOCATION)
+external String stringify(obj);
+
+@JS()
+class StringWrapper {
+ external StringWrapper(String str);
+ external int charCodeAt(int i);
+}
+
+// Defeat JS type inference by calling through JavaScript interop.
+@JS()
+external confuse(obj);
+
+@JS()
+external CanvasRenderingContext2D getCanvasContext();
+
+@JS('window.window.document.documentProperty')
+external num get propertyOnDocument;
+
+@JS('window.self.window.window.windowProperty')
+external num get propertyOnWindow;
+
+main() {
+ _injectJs();
+
+ useHtmlIndividualConfiguration();
+
+ group('object literal', () {
+ test('simple', () {
+ var l = new ExampleLiteral(x: 3, y: "foo");
+ expect(l.x, equals(3));
+ expect(l.y, equals("foo"));
+ expect(l.z, isNull);
+ expect(stringify(l), equals('{"x":3,"y":"foo"}'));
+ l = new ExampleLiteral(z: 100);
+ expect(l.x, isNull);
+ expect(l.y, isNull);
+ expect(l.z, equals(100));
+ expect(stringify(l), equals('{"z":100}'));
+ });
+
+ test('empty', () {
+ var l = new EmptyLiteral();
+ expect(stringify(l), equals('{}'));
+ });
+ });
+
+ group('constructor', () {
+ test('simple', () {
+ var o = new ClassWithConstructor("foo", "bar");
+ expect(o.a, equals("foo"));
+ expect(o.b, equals("bar"));
+ expect(o.getA(), equals("foo"));
+ });
+ });
+
+ group('property', () {
+ test('get', () {
+ expect(foo.x, equals(3));
+ expect(foob.x, equals(8));
+ expect(foob.y, equals("why"));
+
+ // Exists in JS but not in API.
+ expect(() => (foo as dynamic).zSomeInvalidName, throws);
+ expect(bar.multiplyByX, isTrue);
+ });
+ test('set', () {
+ foo.x = 42;
+ expect(foo.x, equals(42));
+ // Property tagged as read only in typed API.
+ expect(() => (foob as dynamic).y = "bla", throws);
+ expect(() => (foo as dynamic).unknownName = 42, throws);
+ });
+ });
+
+ group('method', () {
+ test('call', () {
+ foo.x = 100;
+ expect(foo.multiplyByX(4), equals(400));
+ foob.x = 10;
+ expect(foob.multiplyByX(4), equals(40));
+ });
+
+ test('tearoff', () {
+ foo.x = 10;
+ Function multiplyBy2 = foo.multiplyBy2;
+ expect(multiplyBy2(5), equals(10));
+ Function multiplyByX = foo.multiplyByX;
+ // Tearing off a JS closure doesn't bind this.
+ // You will need to use the new method tearoff syntax to bind this.
+ expect(multiplyByX(4), isNaN);
+
+ MultiplyWithDefault multiplyWithDefault = foo.multiplyDefault2Function;
+ expect(multiplyWithDefault(6, 6), equals(36));
+ expect(multiplyWithDefault(6), equals(12));
+ Function untypedFunction = foo.multiplyDefault2Function;
+ // Calling with extra bogus arguments has no impact for JavaScript
+ // methods.
+ expect(untypedFunction(6, 6, "ignored", "ignored"), equals(36));
+ expect(untypedFunction(6, 6, "ignored", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), equals(36));
+ // Calling a JavaScript method with too few arguments is also fine and
+ // defaults to JavaScript behavior of setting all unspecified arguments
+ // to undefined resulting in multiplying undefined by 2 == NAN.
+ expect(untypedFunction(), isNaN);
+
+ });
+ });
+
+ group('static_method_call', () {
+ test('call directly from dart', () {
+ expect(Foo.multiplyDefault2(6, 7), equals(42));
+ expect(Foo.multiplyDefault2(6), equals(12));
+ });
+ });
+
+ // Note: these extra groups are added to be able to mark each test
+ // individually in status files. This should be split as separate test files.
+ group('static_method_tearoff_1', () {
+ test('call tearoff from dart', () {
+ MultiplyWithDefault tearOffMethod = Foo.multiplyDefault2;
+ expect(tearOffMethod(6, 6), equals(36));
+ });
+ });
+
+ group('static_method_tearoff_2', () {
+ test('call tearoff from dart', () {
+ MultiplyWithDefault tearOffMethod = Foo.multiplyDefault2;
+ expect(tearOffMethod(6), equals(12));
+ });
+ });
+
+ group('closure', () {
+ test('call from js', () {
+ localClosure(x) => x * 10;
+ var wrappedLocalClosure = allowInterop(localClosure);
+ expect(
+ identical(allowInterop(localClosure), wrappedLocalClosure), isTrue);
+ expect(foo.callClosureWithArg1(wrappedLocalClosure, 10), equals(100));
+ expect(foo.callClosureWithArg1(wrappedLocalClosure, "a"),
+ equals("aaaaaaaaaa"));
+ expect(foo.callClosureWithArg1(allowInterop(addWithDefault), 10),
+ equals(110));
+ expect(foo.callClosureWithArg2(allowInterop(addWithDefault), 10, 20),
+ equals(30));
+ addThisXAndArg(Foo that, int arg) {
+ return foo.x + arg;
+ }
+
+ var wrappedCaptureThisClosure = allowInteropCaptureThis(addThisXAndArg);
+ foo.x = 20;
+ expect(foo.callClosureWithArgAndThis(wrappedCaptureThisClosure, 10),
+ equals(30));
+ foo.x = 50;
+ expect(foo.callClosureWithArgAndThis(wrappedCaptureThisClosure, 10),
+ equals(60));
+ expect(
+ identical(allowInteropCaptureThis(addThisXAndArg),
+ wrappedCaptureThisClosure),
+ isTrue);
+
+ ExampleLiteral addXValues(that, ExampleLiteral arg) {
+ return new ExampleLiteral(x: that.x + arg.x);
+ }
+
+ // Check to make sure returning a JavaScript value from a Dart closure
+ // works as expected.
+ expect(
+ foo
+ .callClosureWithArg2(allowInterop(addXValues),
+ new ExampleLiteral(x: 20), new ExampleLiteral(x: 10))
+ .x,
+ equals(30));
+
+ foo.x = 50;
+ expect(
+ foo
+ .callClosureWithArgAndThis(allowInteropCaptureThis(addXValues),
+ new ExampleLiteral(x: 10))
+ .x,
+ equals(60));
+ });
+
+ test('call from dart', () {
+ var returnNumArgsFn = returnNumArgs;
+ var returnLastArgFn = returnLastArg;
+ expect(returnNumArgsFn(), equals(0));
+ expect(returnNumArgsFn("a", "b", "c"), equals(3));
+ expect(returnNumArgsFn("a", "b", "c", null, null), equals(5));
+ expect(returnNumArgsFn(1, 2, 3, 4, 5, 6, null), equals(7));
+ expect(returnNumArgsFn(1, 2, 3, 4, 5, 6, 7, 8), equals(8));
+ expect(returnLastArgFn(1, 2, "foo"), equals("foo"));
+ expect(returnLastArgFn(1, 2, 3, 4, 5, 6, "foo"), equals("foo"));
+ });
+ });
+
+ group('chain calls', () {
+ test("method calls", () {
+ // In dart2js make sure we still use interceptors when making nested
+ // calls to objects.
+ var bar = foo.getBar().getFoo().getBar().getFoo().getBar();
+ expect(bar.x, equals("foo"));
+ });
+ });
+
+ group('avoid leaks on dart:core', () {
+ test('String', () {
+ var s = confuse('Hello');
+ var stringWrapper = confuse(new StringWrapper('Hello'));
+ // Make sure we don't allow calling JavaScript methods on String.
+ expect(() => s.charCodeAt(0), throws);
+ expect(stringWrapper.charCodeAt(0), equals(72));
+ });
+ });
+
+ group('type check', () {
+ test('js interfaces', () {
+ // Is checks return true for all JavaScript interfaces.
+ expect(foo is Bar, isTrue);
+ expect(foo is Foob, isTrue);
+
+ expect(selection is List, isTrue);
+
+ // We do know at runtime whether something is a JsArray or not.
+ expect(foo is List, isFalse);
+ });
+
+ test('dart interfaces', () {
+ expect(foo is Function, isFalse);
+ expect(selection is List, isTrue);
+ });
+ });
+ group('html', () {
+ test('return html type', () {
+ expect(getCanvasContext() is CanvasRenderingContext2D, isTrue);
+ });
+ test('js path contains html types', () {
+ expect(propertyOnWindow, equals(42));
+ expect(propertyOnDocument, equals(45));
+ });
+ });
+}
« no previous file with comments | « test/codegen/lib/html/js_typed_interop_side_cast_test.dart ('k') | test/codegen/lib/html/json_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698