// 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 TESTS = const [ 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 with abstract getter.', ''' @JS() library test; import 'package:js/js.dart'; @JS() class A { get foo; } main() => new A(); ''', warnings: const [MessageKind.ABSTRACT_GETTER], skipForKernel: true), 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 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 _sources; final List errors; final List warnings; final bool skipForKernel; const Test(this.name, this._source, {this.errors: const [], this.warnings: const [], this.skipForKernel: false}) : _sources = null; const Test.multi(this.name, this._sources, {this.errors: const [], this.warnings: const [], this.skipForKernel: false}) : _source = null; String get source => _source != null ? _source : _sources['main.dart']; Map get sources => _source != null ? {'main.dart': _source} : _sources; } runTest(Test test) async { print('==${test.name}======================================================'); print(test.source); if (!test.skipForKernel) { await runTestInternal(test); } } runTestInternal(Test test) async { DiagnosticCollector collector = new DiagnosticCollector(); List options = []; // 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.'); } }