blob: bed24f30b36b1288d6583e267e0ae31e0b3e011e [file] [log] [blame]
// 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.world_test;
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/common.dart';
import 'package:compiler/src/elements/elements.dart'
show ClassElement, PublicName;
import 'package:compiler/src/js_backend/js_backend.dart';
import 'package:compiler/src/universe/selector.dart';
import 'package:compiler/src/world.dart';
import '../type_test_helper.dart';
void main() {
asyncTest(() async {
await testClasses();
});
}
testClasses() async {
test(String mainSource,
{List<String> directlyInstantiated: const <String>[],
List<String> abstractlyInstantiated: const <String>[],
List<String> indirectlyInstantiated: const <String>[]}) async {
TypeEnvironment env = await TypeEnvironment.create(
r"""
@JS()
class A {
get foo;
external A(var foo);
}
@JS()
class B {
get foo;
external B(var foo);
}
@JS()
@anonymous
class C {
final foo;
external factory C({foo});
}
@JS()
@anonymous
class D {
final foo;
external factory D({foo});
}
class E {
final foo;
E(this.foo);
}
class F {
final foo;
F(this.foo);
}
newA() => new A(0);
newB() => new B(1);
newC() => new C(foo: 2);
newD() => new D(foo: 3);
newE() => new E(4);
newF() => new F(5);
""",
mainSource: """
import 'package:js/js.dart';
$mainSource
""",
useMockCompiler: false);
Map<String, ClassElement> classEnvironment = <String, ClassElement>{};
ClassElement registerClass(ClassElement cls) {
classEnvironment[cls.name] = cls;
return cls;
}
ClosedWorld world = env.closedWorld;
JavaScriptBackend backend = env.compiler.backend;
ClassElement Object_ =
registerClass(env.compiler.commonElements.objectClass);
ClassElement Interceptor =
registerClass(backend.helpers.jsInterceptorClass);
ClassElement JavaScriptObject =
registerClass(backend.helpers.jsJavaScriptObjectClass);
ClassElement A = registerClass(env.getElement('A'));
ClassElement B = registerClass(env.getElement('B'));
ClassElement C = registerClass(env.getElement('C'));
ClassElement D = registerClass(env.getElement('D'));
ClassElement E = registerClass(env.getElement('E'));
ClassElement F = registerClass(env.getElement('F'));
Selector nonExisting = new Selector.getter(const PublicName('nonExisting'));
Expect.equals(Interceptor.superclass, Object_);
Expect.equals(JavaScriptObject.superclass, Interceptor);
Expect.equals(A.superclass, JavaScriptObject);
Expect.equals(B.superclass, JavaScriptObject);
Expect.equals(C.superclass, JavaScriptObject);
Expect.equals(D.superclass, JavaScriptObject);
Expect.equals(E.superclass, Object_);
Expect.equals(F.superclass, Object_);
for (String name in classEnvironment.keys) {
ClassElement cls = classEnvironment[name];
bool isInstantiated = false;
if (directlyInstantiated.contains(name)) {
isInstantiated = true;
Expect.isTrue(
world.isDirectlyInstantiated(cls),
"Expected $name to be directly instantiated in `${mainSource}`:"
"\n${world.dump(cls)}");
}
if (abstractlyInstantiated.contains(name)) {
isInstantiated = true;
Expect.isTrue(
world.isAbstractlyInstantiated(cls),
"Expected $name to be abstractly instantiated in `${mainSource}`:"
"\n${world.dump(cls)}");
Expect.isTrue(
world.needsNoSuchMethod(cls, nonExisting, ClassQuery.EXACT),
"Expected $name to need noSuchMethod for $nonExisting.");
Expect.isTrue(
world.needsNoSuchMethod(cls, nonExisting, ClassQuery.SUBCLASS),
"Expected $name to need noSuchMethod for $nonExisting.");
Expect.isTrue(
world.needsNoSuchMethod(cls, nonExisting, ClassQuery.SUBTYPE),
"Expected $name to need noSuchMethod for $nonExisting.");
}
if (indirectlyInstantiated.contains(name)) {
isInstantiated = true;
Expect.isTrue(
world.isIndirectlyInstantiated(cls),
"Expected $name to be indirectly instantiated in `${mainSource}`:"
"\n${world.dump(cls)}");
}
if (!isInstantiated && (name != 'Object' && name != 'Interceptor')) {
Expect.isFalse(
world.isInstantiated(cls),
"Expected $name to be uninstantiated in `${mainSource}`:"
"\n${world.dump(cls)}");
}
}
}
await test('main() {}');
await test('main() => newA();',
abstractlyInstantiated: ['A', 'B', 'C', 'D'],
indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
await test('main() => newB();',
abstractlyInstantiated: ['A', 'B', 'C', 'D'],
indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
await test('main() => newC();',
abstractlyInstantiated: ['A', 'B', 'C', 'D'],
indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
await test('main() => newD();',
abstractlyInstantiated: ['A', 'B', 'C', 'D'],
indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
await test('main() => newE();', directlyInstantiated: ['E']);
await test('main() => newF();', directlyInstantiated: ['F']);
await test('main() => [newD(), newE()];',
directlyInstantiated: ['E'],
abstractlyInstantiated: ['A', 'B', 'C', 'D'],
indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
}