| // Copyright (c) 2016, 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. |
| |
| // @dart = 2.7 |
| |
| library jsinterop.abstract_test; |
| |
| import 'package:expect/expect.dart'; |
| import 'package:async_helper/async_helper.dart'; |
| import 'package:compiler/src/common.dart'; |
| import 'package:compiler/src/commandline_options.dart'; |
| import '../helpers/memory_compiler.dart'; |
| |
| const List<Test> TESTS = const <Test>[ |
| const Test('Empty js-interop class.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| class A {} |
| |
| main() => new A(); |
| ''', warnings: const []), |
| const Test('Js-interop class with external method.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| class A { |
| external method(); |
| } |
| |
| main() => new A(); |
| '''), |
| const Test( |
| 'Js-interop class with external method with required parameters.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| class A { |
| external method(a, b); |
| } |
| |
| main() => new A(); |
| '''), |
| const Test( |
| 'Js-interop class with external method with optional parameters.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| class A { |
| external method([a, b]); |
| } |
| |
| main() => new A(); |
| '''), |
| const Test( |
| 'Js-interop class with external method with optional parameters ' |
| 'with default values.', |
| ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| class A { |
| external method([a = 1, b = 2]); |
| } |
| |
| main() => new A(); |
| '''), |
| const Test('Js-interop class with static method.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| class A { |
| static method() {} |
| } |
| |
| main() => new A(); |
| '''), |
| const Test('Js-interop class that extends a js-interop class.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| abstract class A { |
| method(); |
| } |
| |
| @JS() |
| class B extends A { |
| external method(); |
| } |
| |
| main() => new B(); |
| '''), |
| const Test( |
| 'Js-interop class that extends a js-interop class, ' |
| 'reversed declaration order.', |
| ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| class B extends A { |
| external method(); |
| } |
| |
| @JS() |
| abstract class A { |
| method(); |
| } |
| |
| main() => new B(); |
| '''), |
| const Test.multi( |
| 'Js-interop class that extends a js-interop class from a different ' |
| 'library.', |
| const { |
| 'main.dart': ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| import 'other.dart'; |
| |
| @JS() |
| class B extends A { |
| external method(); |
| } |
| |
| main() => new B(); |
| ''', |
| 'other.dart': ''' |
| @JS() |
| library other; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| abstract class A { |
| method(); |
| } |
| ''' |
| }), |
| const Test('Js-interop class that implements a regular class.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| abstract class A { |
| method(); |
| } |
| |
| @JS() |
| class B implements A { |
| external method(); |
| } |
| |
| main() => new B(); |
| '''), |
| const Test('Js-interop class that implements a js-interop class.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| abstract class A { |
| method(); |
| } |
| |
| @JS() |
| class B implements A { |
| external method(); |
| } |
| |
| main() => new B(); |
| '''), |
| const Test('Js-interop class with generative constructor.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| class A { |
| external A(); |
| } |
| |
| main() => new A(); |
| '''), |
| const Test('Js-interop class with factory constructor.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| class A { |
| factory A() => null; |
| } |
| |
| main() => new A(); |
| '''), |
| const Test('Empty anonymous js-interop class.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| @anonymous |
| class A {} |
| |
| main() => new A(); |
| '''), |
| const Test('Anonymous js-interop class with generative constructor.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| @anonymous |
| class A { |
| external A(); |
| } |
| |
| main() => new A(); |
| '''), |
| const Test('Anonymous js-interop class with factory constructor.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| @anonymous |
| class A { |
| factory A() => null; |
| } |
| |
| main() => new A(); |
| '''), |
| const Test( |
| 'Anonymous js-interop class with external factory constructor.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| @anonymous |
| class A { |
| external factory A(); |
| } |
| |
| main() => new A(); |
| '''), |
| const Test('External factory constructor with named parameters.', ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| @anonymous |
| class A { |
| external factory A({a, b}); |
| } |
| |
| main() => new A(a: 1); |
| '''), |
| const Test( |
| 'External factory constructor with named parameters ' |
| 'with default parameters.', |
| ''' |
| @JS() |
| library test; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| @anonymous |
| class A { |
| external factory A({a: 1, b: 2}); |
| } |
| |
| main() => new A(a: 1); |
| '''), |
| const Test('Function-typed return type', ''' |
| @JS() |
| library lib; |
| |
| import 'package:js/js.dart'; |
| |
| @JS('func') |
| external int Function() func(); |
| |
| main() { |
| func(); |
| } |
| '''), |
| const Test( |
| 'Non-external field.', |
| ''' |
| @JS() |
| library lib; |
| |
| import 'package:js/js.dart'; |
| |
| @JS() |
| @anonymous |
| class B { |
| int Function() callback; |
| } |
| |
| @JS('makeB') |
| external B makeB(); |
| |
| main() { |
| makeB().callback(); |
| } |
| ''', |
| // TODO(34174): Disallow js-interop fields. |
| /*errors: const [MessageKind.IMPLICIT_JS_INTEROP_FIELD_NOT_SUPPORTED]*/ |
| ), |
| ]; |
| |
| void main(List<String> args) { |
| asyncTest(() async { |
| for (Test test in TESTS) { |
| bool run = true; |
| if (args.isNotEmpty) { |
| run = false; |
| for (String arg in args) { |
| if (test.name.contains(arg)) { |
| run = true; |
| break; |
| } |
| } |
| } |
| if (run) { |
| await runTest(test); |
| } |
| } |
| }); |
| } |
| |
| class Test { |
| final String name; |
| final String _source; |
| final Map<String, String> _sources; |
| final List<MessageKind> errors; |
| final List<MessageKind> warnings; |
| |
| const Test(this.name, this._source, |
| {this.errors: const <MessageKind>[], |
| this.warnings: const <MessageKind>[]}) |
| : _sources = null; |
| |
| const Test.multi(this.name, this._sources, |
| {this.errors: const <MessageKind>[], |
| this.warnings: const <MessageKind>[]}) |
| : _source = null; |
| |
| String get source => _source ?? _sources['main.dart']; |
| |
| Map<String, String> get sources => |
| _source != null ? {'main.dart': _source} : _sources; |
| } |
| |
| runTest(Test test) async { |
| print('==${test.name}======================================================'); |
| print(test.source); |
| await runTestInternal(test); |
| } |
| |
| runTestInternal(Test test) async { |
| DiagnosticCollector collector = new DiagnosticCollector(); |
| List<String> options = <String>[]; |
| // TODO(redemption): Enable inlining. |
| options.add(Flags.disableInlining); |
| await runCompiler( |
| diagnosticHandler: collector, |
| options: options, |
| memorySourceFiles: test.sources); |
| Expect.equals( |
| test.errors.length, collector.errors.length, 'Unexpected error count.'); |
| Expect.equals(test.warnings.length, collector.warnings.length, |
| 'Unexpected warning count.'); |
| for (int index = 0; index < test.errors.length; index++) { |
| Expect.equals(test.errors[index], |
| collector.errors.elementAt(index).messageKind, 'Unexpected error.'); |
| } |
| for (int index = 0; index < test.warnings.length; index++) { |
| Expect.equals(test.warnings[index], |
| collector.warnings.elementAt(index).messageKind, 'Unexpected warning.'); |
| } |
| } |