545ee13cd4
Change-Id: I193e19581d29a9c4b343ae0a681d1ff530cfce1d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/281309 Commit-Queue: Nate Biggs <natebiggs@google.com> Reviewed-by: Mayank Patke <fishythefish@google.com>
433 lines
7.4 KiB
Dart
433 lines
7.4 KiB
Dart
// 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.
|
|
|
|
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 'package:compiler/src/util/memory_compiler.dart';
|
|
|
|
const List<Test> TESTS = const <Test>[
|
|
const SingleTest('Empty js-interop class.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
class A {}
|
|
|
|
main() => A();
|
|
''', warnings: const []),
|
|
const SingleTest('Js-interop class with external method.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
class A {
|
|
external method();
|
|
}
|
|
|
|
main() => A();
|
|
'''),
|
|
const SingleTest(
|
|
'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() => A();
|
|
'''),
|
|
const SingleTest(
|
|
'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() => A();
|
|
'''),
|
|
const SingleTest(
|
|
'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() => A();
|
|
'''),
|
|
const SingleTest('Js-interop class with static method.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
class A {
|
|
static method() {}
|
|
}
|
|
|
|
main() => A();
|
|
'''),
|
|
const SingleTest('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() => B();
|
|
'''),
|
|
const SingleTest(
|
|
'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() => B();
|
|
'''),
|
|
const MultiTest(
|
|
'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() => B();
|
|
''',
|
|
'other.dart': '''
|
|
@JS()
|
|
library other;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
abstract class A {
|
|
method();
|
|
}
|
|
'''
|
|
}),
|
|
const SingleTest('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() => B();
|
|
'''),
|
|
const SingleTest('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() => B();
|
|
'''),
|
|
const SingleTest('Js-interop class with generative constructor.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
class A {
|
|
external A();
|
|
}
|
|
|
|
main() => A();
|
|
'''),
|
|
const SingleTest('Js-interop class with factory constructor.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
class A {
|
|
factory A() => null;
|
|
}
|
|
|
|
main() => A();
|
|
'''),
|
|
const SingleTest('Empty anonymous js-interop class.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
@anonymous
|
|
class A {}
|
|
|
|
main() => A();
|
|
'''),
|
|
const SingleTest(
|
|
'Anonymous js-interop class with generative constructor.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
@anonymous
|
|
class A {
|
|
external A();
|
|
}
|
|
|
|
main() => A();
|
|
'''),
|
|
const SingleTest('Anonymous js-interop class with factory constructor.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
@anonymous
|
|
class A {
|
|
factory A() => null;
|
|
}
|
|
|
|
main() => A();
|
|
'''),
|
|
const SingleTest(
|
|
'Anonymous js-interop class with external factory constructor.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
@anonymous
|
|
class A {
|
|
external factory A();
|
|
}
|
|
|
|
main() => A();
|
|
'''),
|
|
const SingleTest('External factory constructor with named parameters.', '''
|
|
@JS()
|
|
library test;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS()
|
|
@anonymous
|
|
class A {
|
|
external factory A({a, b});
|
|
}
|
|
|
|
main() => A(a: 1);
|
|
'''),
|
|
const SingleTest(
|
|
'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() => A(a: 1);
|
|
'''),
|
|
const SingleTest('Function-typed return type', '''
|
|
@JS()
|
|
library lib;
|
|
|
|
import 'package:js/js.dart';
|
|
|
|
@JS('func')
|
|
external int Function() func();
|
|
|
|
main() {
|
|
func();
|
|
}
|
|
'''),
|
|
const SingleTest(
|
|
'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);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
abstract class Test {
|
|
final String name;
|
|
final List<MessageKind> errors;
|
|
final List<MessageKind> warnings;
|
|
|
|
const Test(this.name, {required this.errors, required this.warnings});
|
|
String get source;
|
|
Map<String, String> get sources;
|
|
}
|
|
|
|
class SingleTest extends Test {
|
|
@override
|
|
final String source;
|
|
|
|
const SingleTest(super.name, this.source,
|
|
{super.errors = const <MessageKind>[],
|
|
super.warnings = const <MessageKind>[]});
|
|
|
|
@override
|
|
Map<String, String> get sources => {'main.dart': source};
|
|
}
|
|
|
|
class MultiTest extends Test {
|
|
@override
|
|
final Map<String, String> sources;
|
|
|
|
const MultiTest(super.name, this.sources,
|
|
{super.errors = const <MessageKind>[],
|
|
super.warnings = const <MessageKind>[]});
|
|
|
|
@override
|
|
String get source => sources['main.dart']!;
|
|
}
|
|
|
|
runTest(Test test) async {
|
|
print('==${test.name}======================================================');
|
|
print(test.source);
|
|
await runTestInternal(test);
|
|
}
|
|
|
|
runTestInternal(Test test) async {
|
|
DiagnosticCollector collector = 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.');
|
|
}
|
|
}
|