2ee771a4f6
I also cleaned up a bunch of places that referred to them. Change-Id: I45f68818c892f8620ea04257885ffa3763374bb5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/335863 Auto-Submit: Bob Nystrom <rnystrom@google.com> Commit-Queue: Bob Nystrom <rnystrom@google.com> Reviewed-by: Alexander Thomas <athom@google.com>
367 lines
13 KiB
Dart
367 lines
13 KiB
Dart
// Copyright (c) 2018, 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.
|
|
|
|
import 'dart:io';
|
|
import 'package:async_helper/async_helper.dart';
|
|
import 'package:compiler/src/common/elements.dart';
|
|
import 'package:compiler/src/elements/entities.dart';
|
|
import 'package:compiler/src/js_model/js_world.dart' show JClosedWorld;
|
|
import 'package:expect/expect.dart';
|
|
import 'package:compiler/src/util/memory_compiler.dart';
|
|
|
|
enum Kind {
|
|
regular,
|
|
native,
|
|
jsInterop,
|
|
}
|
|
|
|
main() {
|
|
asyncTest(() async {
|
|
await runTest('tests/web/jsinterop_test.dart', '', {
|
|
'Class': Kind.regular,
|
|
'JsInteropClass': Kind.jsInterop,
|
|
'flag': Kind.regular,
|
|
'topLevelField': Kind.regular,
|
|
'topLevelGetter': Kind.regular,
|
|
'topLevelSetter': Kind.regular,
|
|
'topLevelFunction': Kind.regular,
|
|
'externalTopLevelGetter': Kind.jsInterop,
|
|
'externalTopLevelSetter': Kind.jsInterop,
|
|
'externalTopLevelFunction': Kind.jsInterop,
|
|
'externalTopLevelJsInteropGetter': Kind.jsInterop,
|
|
'externalTopLevelJsInteropSetter': Kind.jsInterop,
|
|
'externalTopLevelJsInteropFunction': Kind.jsInterop,
|
|
'Class.generative': Kind.regular,
|
|
'Class.fact': Kind.regular,
|
|
'Class.instanceField': Kind.regular,
|
|
'Class.instanceGetter': Kind.regular,
|
|
'Class.instanceSetter': Kind.regular,
|
|
'Class.instanceMethod': Kind.regular,
|
|
'Class.staticField': Kind.regular,
|
|
'Class.staticGetter': Kind.regular,
|
|
'Class.staticSetter': Kind.regular,
|
|
'Class.staticMethod': Kind.regular,
|
|
'JsInteropClass.externalGenerative': Kind.jsInterop,
|
|
'JsInteropClass.externalFact': Kind.jsInterop,
|
|
'JsInteropClass.externalJsInteropGenerative': Kind.jsInterop,
|
|
'JsInteropClass.externalJsInteropFact': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceGetter': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceSetter': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceMethod': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticGetter': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticSetter': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticMethod': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceJsInteropGetter': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceJsInteropSetter': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceJsInteropMethod': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticJsInteropGetter': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticJsInteropSetter': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticJsInteropMethod': Kind.jsInterop,
|
|
}, skipList: [
|
|
// TODO(34174): Js-interop fields should not be allowed.
|
|
'01',
|
|
'02',
|
|
'03',
|
|
'04',
|
|
'38',
|
|
'42',
|
|
'46',
|
|
'51',
|
|
// TODO(33834): Non-external constructors should not be allowed.
|
|
'35',
|
|
'37',
|
|
// TODO(34345): Non-external static members should not be allowed.
|
|
'43',
|
|
'44',
|
|
'45',
|
|
'52',
|
|
'53',
|
|
'54',
|
|
]);
|
|
await runTest('tests/web/non_jsinterop_test.dart', '', {
|
|
'Class': Kind.regular,
|
|
'JsInteropClass': Kind.jsInterop,
|
|
'flag': Kind.regular,
|
|
'topLevelField': Kind.regular,
|
|
'topLevelGetter': Kind.regular,
|
|
'topLevelSetter': Kind.regular,
|
|
'topLevelFunction': Kind.regular,
|
|
'externalTopLevelJsInteropGetter': Kind.jsInterop,
|
|
'externalTopLevelJsInteropSetter': Kind.jsInterop,
|
|
'externalTopLevelJsInteropFunction': Kind.jsInterop,
|
|
'Class.generative': Kind.regular,
|
|
'Class.fact': Kind.regular,
|
|
'Class.instanceField': Kind.regular,
|
|
'Class.instanceGetter': Kind.regular,
|
|
'Class.instanceSetter': Kind.regular,
|
|
'Class.instanceMethod': Kind.regular,
|
|
'Class.staticField': Kind.regular,
|
|
'Class.staticGetter': Kind.regular,
|
|
'Class.staticSetter': Kind.regular,
|
|
'Class.staticMethod': Kind.regular,
|
|
'JsInteropClass.externalGenerative': Kind.jsInterop,
|
|
'JsInteropClass.externalFact': Kind.jsInterop,
|
|
'JsInteropClass.externalJsInteropGenerative': Kind.jsInterop,
|
|
'JsInteropClass.externalJsInteropFact': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceGetter': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceSetter': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceMethod': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticGetter': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticSetter': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticMethod': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceJsInteropGetter': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceJsInteropSetter': Kind.jsInterop,
|
|
'JsInteropClass.externalInstanceJsInteropMethod': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticJsInteropGetter': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticJsInteropSetter': Kind.jsInterop,
|
|
'JsInteropClass.externalStaticJsInteropMethod': Kind.jsInterop,
|
|
}, skipList: [
|
|
// TODO(34174): Js-interop fields should not be allowed.
|
|
'01',
|
|
'02',
|
|
'03',
|
|
'04',
|
|
'38',
|
|
'42',
|
|
'46',
|
|
'51',
|
|
// TODO(33834): Non-external constructors should not be allowed.
|
|
'35',
|
|
'37',
|
|
// TODO(34345): Non-external static members should not be allowed.
|
|
'43',
|
|
'44',
|
|
'45',
|
|
'52',
|
|
'53',
|
|
'54',
|
|
]);
|
|
|
|
await runTest(
|
|
'tests/web/native/native_test.dart', 'tests/web/native/', {
|
|
'Class': Kind.regular,
|
|
'NativeClass': Kind.native,
|
|
'topLevelField': Kind.regular,
|
|
'topLevelGetter': Kind.regular,
|
|
'topLevelSetter': Kind.regular,
|
|
'topLevelFunction': Kind.regular,
|
|
'nativeTopLevelGetter': Kind.native,
|
|
'nativeTopLevelSetter': Kind.native,
|
|
'nativeTopLevelFunction': Kind.native,
|
|
'Class.generative': Kind.regular,
|
|
'Class.fact': Kind.regular,
|
|
'Class.instanceField': Kind.regular,
|
|
'Class.instanceGetter': Kind.regular,
|
|
'Class.instanceSetter': Kind.regular,
|
|
'Class.instanceMethod': Kind.regular,
|
|
'Class.staticField': Kind.regular,
|
|
'Class.staticGetter': Kind.regular,
|
|
'Class.staticSetter': Kind.regular,
|
|
'Class.staticMethod': Kind.regular,
|
|
'Class.nativeInstanceGetter': Kind.native,
|
|
'Class.nativeInstanceSetter': Kind.native,
|
|
'Class.nativeInstanceMethod': Kind.native,
|
|
'NativeClass.generative': Kind.regular,
|
|
'NativeClass.fact': Kind.regular,
|
|
'NativeClass.nativeGenerative': Kind.native,
|
|
'NativeClass.nativeFact': Kind.native,
|
|
'NativeClass.instanceField': Kind.native,
|
|
'NativeClass.instanceNamedField': Kind.native,
|
|
'NativeClass.instanceGetter': Kind.regular,
|
|
'NativeClass.instanceSetter': Kind.regular,
|
|
'NativeClass.instanceMethod': Kind.regular,
|
|
'NativeClass.staticField': Kind.regular,
|
|
'NativeClass.staticGetter': Kind.regular,
|
|
'NativeClass.staticSetter': Kind.regular,
|
|
'NativeClass.staticMethod': Kind.regular,
|
|
'NativeClass.nativeInstanceGetter': Kind.native,
|
|
'NativeClass.nativeInstanceSetter': Kind.native,
|
|
'NativeClass.nativeInstanceMethod': Kind.native,
|
|
'NativeClass.nativeStaticGetter': Kind.native,
|
|
'NativeClass.nativeStaticSetter': Kind.native,
|
|
'NativeClass.nativeStaticMethod': Kind.native,
|
|
},
|
|
skipList: [
|
|
// External constructors in non-native class
|
|
//'08',
|
|
//'09',
|
|
// External instance members in non-native class
|
|
//'22',
|
|
//'23',
|
|
//'24',
|
|
// External static members in non-native class
|
|
//'25',
|
|
//'26',
|
|
//'27',
|
|
// External instance members in native class
|
|
//'36',
|
|
//'37',
|
|
//'38',
|
|
// External static members in native class
|
|
//'39',
|
|
//'40',
|
|
//'41',
|
|
]);
|
|
});
|
|
}
|
|
|
|
runTest(String fileName, String location, Map<String, Kind> expectations,
|
|
{List<String> skipList = const <String>[]}) async {
|
|
print('--------------------------------------------------------------------');
|
|
print('Testing $fileName');
|
|
print('--------------------------------------------------------------------');
|
|
String test = File(fileName).readAsStringSync();
|
|
|
|
List<String> commonLines = <String>[];
|
|
Map<String, SubTest> subTests = <String, SubTest>{};
|
|
|
|
int lineIndex = 0;
|
|
for (String line in test.split('\n')) {
|
|
int index = line.indexOf('//#');
|
|
if (index != -1) {
|
|
String prefix = line.substring(0, index);
|
|
String suffix = line.substring(index + 3);
|
|
String name = suffix.substring(0, suffix.indexOf((':'))).trim();
|
|
SubTest subTest = subTests.putIfAbsent(name, () => SubTest());
|
|
subTest.lines[lineIndex] = line;
|
|
int commentIndex = prefix.indexOf('// ');
|
|
if (commentIndex != -1) {
|
|
String combinedErrors = prefix.substring(commentIndex + 3);
|
|
for (String error in combinedErrors.split(',')) {
|
|
subTest.expectedErrors.add(error.trim());
|
|
}
|
|
}
|
|
commonLines.add('');
|
|
} else {
|
|
commonLines.add(line);
|
|
}
|
|
lineIndex++;
|
|
}
|
|
|
|
String path = '${location}main.dart';
|
|
Uri entryPoint = Uri.parse('memory:$path');
|
|
await runPositiveTest(
|
|
entryPoint, {path: commonLines.join('\n')}, expectations);
|
|
for (String name in subTests.keys) {
|
|
if (!skipList.contains(name)) {
|
|
SubTest subTest = subTests[name]!;
|
|
await runNegativeTest(
|
|
subTest, entryPoint, {path: subTest.generateCode(commonLines)});
|
|
}
|
|
}
|
|
}
|
|
|
|
runPositiveTest(Uri entryPoint, Map<String, String> sources,
|
|
Map<String, Kind> expectations) async {
|
|
CompilationResult result =
|
|
await runCompiler(entryPoint: entryPoint, memorySourceFiles: sources);
|
|
Expect.isTrue(result.isSuccess);
|
|
|
|
JClosedWorld closedWorld = result.compiler.backendClosedWorldForTesting;
|
|
ElementEnvironment elementEnvironment = closedWorld.elementEnvironment;
|
|
|
|
void checkClass(ClassEntity cls,
|
|
{bool isNative = false, bool isJsInterop = false}) {
|
|
if (isJsInterop) {
|
|
isNative = true;
|
|
}
|
|
Expect.equals(isJsInterop, closedWorld.nativeData.isJsInteropClass(cls),
|
|
"Unexpected js interop class result for $cls.");
|
|
Expect.equals(isNative, closedWorld.nativeData.isNativeClass(cls),
|
|
"Unexpected native class result for $cls.");
|
|
if (isJsInterop) {
|
|
Expect.isTrue(closedWorld.nativeData.isJsInteropLibrary(cls.library),
|
|
"Unexpected js interop library result for ${cls.library}.");
|
|
}
|
|
}
|
|
|
|
void checkMember(MemberEntity member,
|
|
{bool isNative = false, bool isJsInterop = false}) {
|
|
if (isJsInterop) {
|
|
isNative = true;
|
|
}
|
|
Expect.equals(isJsInterop, closedWorld.nativeData.isJsInteropMember(member),
|
|
"Unexpected js interop member result for $member.");
|
|
Expect.equals(isNative, closedWorld.nativeData.isNativeMember(member),
|
|
"Unexpected native member result for $member.");
|
|
if (isJsInterop) {
|
|
Expect.isTrue(closedWorld.nativeData.isJsInteropLibrary(member.library),
|
|
"Unexpected js interop library result for ${member.library}.");
|
|
}
|
|
}
|
|
|
|
elementEnvironment.forEachLibraryMember(elementEnvironment.mainLibrary!,
|
|
(MemberEntity member) {
|
|
if (member == elementEnvironment.mainFunction) return;
|
|
|
|
Kind? kind = expectations.remove(member.name);
|
|
Expect.isNotNull(kind, "No expectations for $member");
|
|
checkMember(member,
|
|
isNative: kind == Kind.native, isJsInterop: kind == Kind.jsInterop);
|
|
});
|
|
|
|
elementEnvironment.forEachClass(elementEnvironment.mainLibrary!,
|
|
(ClassEntity cls) {
|
|
Kind? kind = expectations.remove(cls.name);
|
|
Expect.isNotNull(kind, "No expectations for $cls");
|
|
checkClass(cls,
|
|
isNative: kind == Kind.native, isJsInterop: kind == Kind.jsInterop);
|
|
|
|
checkClassMember(MemberEntity member) {
|
|
Kind? kind = expectations.remove('${cls.name}.${member.name}');
|
|
Expect.isNotNull(kind, "No expectations for $member");
|
|
checkMember(member,
|
|
isNative: kind == Kind.native, isJsInterop: kind == Kind.jsInterop);
|
|
}
|
|
|
|
elementEnvironment.forEachConstructor(cls, checkClassMember);
|
|
elementEnvironment.forEachLocalClassMember(cls, checkClassMember);
|
|
});
|
|
|
|
Expect.isTrue(expectations.isEmpty, "Untested expectations: $expectations");
|
|
}
|
|
|
|
runNegativeTest(
|
|
SubTest subTest, Uri entryPoint, Map<String, String> sources) async {
|
|
DiagnosticCollector collector = DiagnosticCollector();
|
|
CompilationResult result = await runCompiler(
|
|
entryPoint: entryPoint,
|
|
memorySourceFiles: sources,
|
|
diagnosticHandler: collector);
|
|
Expect.isFalse(
|
|
result.isSuccess, "Expected compile time error(s) for\n$subTest");
|
|
List<String> expected =
|
|
subTest.expectedErrors.map((error) => 'MessageKind.' + error).toList();
|
|
List<String> actual =
|
|
collector.errors.map((error) => error.messageKind.toString()).toList();
|
|
expected.sort();
|
|
actual.sort();
|
|
Expect.listEquals(
|
|
expected, actual, "Unexpected compile time error(s) for\n$subTest");
|
|
}
|
|
|
|
class SubTest {
|
|
List<String> expectedErrors = [];
|
|
final Map<int, String> lines = <int, String>{};
|
|
|
|
String generateCode(List<String> commonLines) {
|
|
StringBuffer sb = StringBuffer();
|
|
int i = 0;
|
|
while (i < commonLines.length) {
|
|
if (lines.containsKey(i)) {
|
|
sb.writeln(lines[i]);
|
|
} else {
|
|
sb.writeln(commonLines[i]);
|
|
}
|
|
i++;
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
@override
|
|
String toString() {
|
|
return lines.values.join('\n');
|
|
}
|
|
}
|