blob: 39f5948fa1dadf5d6b0fab09dec5aa377019a5ba [file] [log] [blame]
// Copyright (c) 2012, 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 test program for checking implemention of MirrorSystem when
// inspecting the current isolate.
//
// VMOptions=--enable_type_checks
library isolate_mirror_local_test;
import "package:expect/expect.dart";
import 'dart:async';
import 'dart:isolate';
import 'dart:mirrors';
ReceivePort exit_port;
Set expectedTests;
void testDone(String test) {
if (!expectedTests.contains(test)) {
throw "Unexpected test name '$test'";
}
expectedTests.remove(test);
if (expectedTests.isEmpty) {
// All tests are done.
exit_port.close();
}
}
int global_var = 0;
final int final_global_var = 0;
// Top-level getter and setter.
int get myVar { return 5; }
void set myVar(x) {}
// This function will be invoked reflectively.
int function(int x) {
global_var = x;
return x + 1;
}
typedef void FuncType(String a);
FuncType myFunc = null;
_stringCompare(String a, String b) => a.compareTo(b);
sort(list) => list.sort(_stringCompare);
String buildMethodString(MethodMirror func) {
var result = '${MirrorSystem.getName(func.simpleName)} '
'return(${MirrorSystem.getName(func.returnType.simpleName)})';
if (func.isPrivate) {
result = '$result private';
}
if (func.isTopLevel) {
result = '$result toplevel';
}
if (func.isStatic) {
result = '$result static';
}
if (func.isAbstract) {
result = '$result abstract';
}
if (func.isRegularMethod) {
result = '$result method';
}
if (func.isGetter) {
result = '$result getter';
}
if (func.isSetter) {
result = '$result setter';
}
if (func.isConstructor) {
result = '$result constructor';
}
if (func.isConstConstructor) {
result = '$result const';
}
if (func.isGenerativeConstructor) {
result = '$result generative';
}
if (func.isRedirectingConstructor) {
result = '$result redirecting';
}
if (func.isFactoryConstructor) {
result = '$result factory';
}
return result;
}
String buildVariableString(VariableMirror variable) {
var result = '${MirrorSystem.getName(variable.simpleName)} '
'type(${MirrorSystem.getName(variable.type.simpleName)})';
if (variable.isPrivate) {
result = '$result private';
}
if (variable.isTopLevel) {
result = '$result toplevel';
}
if (variable.isStatic) {
result = '$result static';
}
if (variable.isFinal) {
result = '$result final';
}
return result;
}
void testRootLibraryMirror(LibraryMirror lib_mirror) {
Expect.equals(const Symbol('isolate_mirror_local_test'),
lib_mirror.simpleName);
Expect.equals(const Symbol('isolate_mirror_local_test'),
lib_mirror.qualifiedName);
Expect.equals(null, lib_mirror.owner);
Expect.isFalse(lib_mirror.isPrivate);
Expect.isTrue(lib_mirror.uri.path.contains('isolate_mirror_local_test.dart'));
// TODO(ahe): toString() test disabled for now as Symbols are 100% opaque.
// Expect.equals("LibraryMirror on 'isolate_mirror_local_test'",
// lib_mirror.toString());
// Test library invocation by calling function(123).
Expect.equals(0, global_var);
lib_mirror.invokeAsync(const Symbol('function'), [123]).then(
(InstanceMirror retval) {
Expect.equals(123, global_var);
Expect.equals(const Symbol('int'), retval.type.simpleName);
Expect.isTrue(retval.hasReflectee);
Expect.equals(124, retval.reflectee);
testDone('testRootLibraryMirror');
});
// Check that the members map is complete.
List keys = lib_mirror.members.keys.map(MirrorSystem.getName).toList();
sort(keys);
Expect.equals('['
'FuncType, '
'GenericClass, '
'MyClass, '
'MyException, '
'MyInterface, '
'MySuperClass, '
'_stringCompare, '
'buildMethodString, '
'buildVariableString, '
'exit_port, '
'expectedTests, '
'final_global_var, '
'function, '
'global_var, '
'main, '
'methodWithError, '
'methodWithException, '
'myFunc, '
'myVar, '
'myVar=, '
'sort, '
'testBoolInstanceMirror, '
'testCustomInstanceMirror, '
'testDone, '
'testIntegerInstanceMirror, '
'testLibrariesMap, '
'testMirrorErrors, '
'testMirrorSystem, '
'testNullInstanceMirror, '
'testRootLibraryMirror, '
'testStringInstanceMirror]',
'$keys');
// Check that the classes map is complete.
keys = lib_mirror.classes.keys.map(MirrorSystem.getName).toList();
sort(keys);
Expect.equals('['
'FuncType, '
'GenericClass, '
'MyClass, '
'MyException, '
'MyInterface, '
'MySuperClass]',
'$keys');
// Check that the functions map is complete.
keys = lib_mirror.functions.keys.map(MirrorSystem.getName).toList();
sort(keys);
Expect.equals('['
'_stringCompare, '
'buildMethodString, '
'buildVariableString, '
'function, '
'main, '
'methodWithError, '
'methodWithException, '
'myVar, '
'myVar=, '
'sort, '
'testBoolInstanceMirror, '
'testCustomInstanceMirror, '
'testDone, '
'testIntegerInstanceMirror, '
'testLibrariesMap, '
'testMirrorErrors, '
'testMirrorSystem, '
'testNullInstanceMirror, '
'testRootLibraryMirror, '
'testStringInstanceMirror]',
'$keys');
// Check that the getters map is complete.
keys = lib_mirror.getters.keys.map(MirrorSystem.getName).toList();
sort(keys);
Expect.equals('[myVar]', '$keys');
// Check that the setters map is complete.
keys = lib_mirror.setters.keys.map(MirrorSystem.getName).toList();
sort(keys);
Expect.equals('[myVar=]', '$keys');
// Check that the variables map is complete.
keys = lib_mirror.variables.keys.map(MirrorSystem.getName).toList();
sort(keys);
Expect.equals('['
'exit_port, '
'expectedTests, '
'final_global_var, '
'global_var, '
'myFunc]',
'$keys');
ClassMirror cls_mirror = lib_mirror.members[const Symbol('MyClass')];
ClassMirror generic_cls_mirror =
lib_mirror.members[const Symbol('GenericClass')];
// Test function mirrors.
MethodMirror func = lib_mirror.members[const Symbol('function')];
Expect.isTrue(func is MethodMirror);
Expect.equals('function return(int) toplevel static method',
buildMethodString(func));
func = lib_mirror.members[const Symbol('myVar')];
Expect.isTrue(func is MethodMirror);
Expect.equals('myVar return(int) toplevel static getter',
buildMethodString(func));
func = lib_mirror.members[const Symbol('myVar=')];
Expect.isTrue(func is MethodMirror);
Expect.equals('myVar= return(void) toplevel static setter',
buildMethodString(func));
func = cls_mirror.members[const Symbol('method')];
Expect.isTrue(func is MethodMirror);
Expect.equals('method return(int) method', buildMethodString(func));
func = cls_mirror.constructors[const Symbol('MyClass')];
Expect.isTrue(func is MethodMirror);
Expect.equals('MyClass return(MyClass) constructor', buildMethodString(func));
func = cls_mirror.constructors[const Symbol('MyClass.named')];
Expect.isTrue(func is MethodMirror);
Expect.equals('MyClass.named return(MyClass) constructor',
buildMethodString(func));
func = generic_cls_mirror.members[const Symbol('method')];
Expect.isTrue(func is MethodMirror);
Expect.equals('method return(T) method', buildMethodString(func));
// Test variable mirrors.
VariableMirror variable = lib_mirror.members[const Symbol('global_var')];
Expect.isTrue(variable is VariableMirror);
Expect.equals('global_var type(int) toplevel static',
buildVariableString(variable));
variable = lib_mirror.members[const Symbol('final_global_var')];
Expect.isTrue(variable is VariableMirror);
Expect.equals('final_global_var type(int) toplevel static final',
buildVariableString(variable));
variable = cls_mirror.members[const Symbol('value')];
Expect.isTrue(variable is VariableMirror);
Expect.equals('value type(dynamic) final', buildVariableString(variable));
// Test type variable mirrors.
var type_var = generic_cls_mirror.members[const Symbol('method')].returnType;
Expect.isTrue(type_var is TypeVariableMirror);
Expect.equals(const Symbol('GenericClass'), type_var.owner.simpleName);
Expect.equals(const Symbol('Object'), type_var.upperBound.simpleName);
// Test typedef mirrors.
var typedef_mirror = lib_mirror.members[const Symbol('myFunc')].type;
Expect.isTrue(typedef_mirror is TypedefMirror);
Expect.equals(const Symbol('isolate_mirror_local_test'),
typedef_mirror.owner.simpleName);
// Test function type mirrors.
var func_cls_mirror = typedef_mirror.referent;
Expect.isTrue(func_cls_mirror is FunctionTypeMirror);
// Expect.equals('void (dart.core.String)', func_cls_mirror.simpleName);
Expect.equals(const Symbol('void'), func_cls_mirror.returnType.simpleName);
}
void testLibrariesMap(Map libraries) {
// Just look for a couple of well-known libs.
LibraryMirror core_lib = libraries[Uri.parse('dart:core')];
Expect.isTrue(core_lib is LibraryMirror);
LibraryMirror mirror_lib = libraries[Uri.parse('dart:mirrors')];
Expect.isTrue(mirror_lib is LibraryMirror);
// Lookup an interface from a library and make sure it is sane.
ClassMirror list_intf = core_lib.members[const Symbol('List')];
Expect.isTrue(list_intf is ClassMirror);
Expect.equals(const Symbol('List'), list_intf.simpleName);
Expect.equals(const Symbol('dart.core.List'), list_intf.qualifiedName);
Expect.isFalse(list_intf.isPrivate);
Expect.equals(const Symbol('Object'), list_intf.superclass.simpleName);
Expect.equals(const Symbol('dart.core'), list_intf.owner.simpleName);
Expect.isTrue(list_intf.isClass);
Expect.equals(const Symbol('Iterable'),
list_intf.superinterfaces[0].simpleName);
// TODO(ahe): toString() test disabled for now as Symbols are 100% opaque.
// Expect.equals("ClassMirror on 'List'", list_intf.toString());
// Lookup a class from a library and make sure it is sane.
ClassMirror oom_cls = core_lib.members[const Symbol('OutOfMemoryError')];
Expect.isTrue(oom_cls is ClassMirror);
Expect.equals(const Symbol('OutOfMemoryError'), oom_cls.simpleName);
Expect.equals(const Symbol('dart.core.OutOfMemoryError'),
oom_cls.qualifiedName);
Expect.isFalse(oom_cls.isPrivate);
Expect.equals(const Symbol('Object'), oom_cls.superclass.simpleName);
Expect.isTrue(oom_cls.defaultFactory == null);
Expect.equals(const Symbol('dart.core'), oom_cls.owner.simpleName);
Expect.isTrue(oom_cls.isClass);
Expect.equals(const Symbol('Error'), oom_cls.superinterfaces[0].simpleName);
// TODO(ahe): toString() test disabled for now as Symbols are 100% opaque.
// Expect.equals("ClassMirror on 'OutOfMemoryError'",
// oom_cls.toString());
testDone('testLibrariesMap');
}
void testMirrorSystem(MirrorSystem mirrors) {
Expect.isTrue(mirrors.isolate.debugName.contains('main'));
testRootLibraryMirror(mirrors.isolate.rootLibrary);
testLibrariesMap(mirrors.libraries);
Expect.equals(const Symbol('void'), mirrors.voidType.simpleName);
Expect.equals(const Symbol('dynamic'), mirrors.dynamicType.simpleName);
testDone('testMirrorSystem');
}
void testIntegerInstanceMirror(InstanceMirror mirror) {
Expect.equals(const Symbol('int'), mirror.type.simpleName);
Expect.isTrue(mirror.hasReflectee);
Expect.equals(1001, mirror.reflectee);
Expect.equals("InstanceMirror on <1001>", mirror.toString());
// Invoke (mirror + mirror).
mirror.invokeAsync(const Symbol('+'), [ mirror ]).then(
(InstanceMirror retval) {
Expect.equals(const Symbol('int'), retval.type.simpleName);
Expect.isTrue(retval.hasReflectee);
Expect.equals(2002, retval.reflectee);
testDone('testIntegerInstanceMirror');
});
}
void testStringInstanceMirror(InstanceMirror mirror) {
Expect.equals(const Symbol('String'), mirror.type.simpleName);
Expect.isTrue(mirror.hasReflectee);
Expect.equals('This\nis\na\nString', mirror.reflectee);
Expect.equals("InstanceMirror on <'This\\nis\\na\\nString'>",
mirror.toString());
// Invoke mirror[0].
mirror.invokeAsync(const Symbol('[]'), [ 0 ]).then(
(InstanceMirror retval) {
Expect.equals(const Symbol('String'), retval.type.simpleName);
Expect.isTrue(retval.hasReflectee);
Expect.equals('T', retval.reflectee);
testDone('testStringInstanceMirror');
});
}
void testBoolInstanceMirror(InstanceMirror mirror) {
Expect.equals(const Symbol('bool'), mirror.type.simpleName);
Expect.isTrue(mirror.hasReflectee);
Expect.equals(true, mirror.reflectee);
Expect.equals("InstanceMirror on <true>", mirror.toString());
testDone('testBoolInstanceMirror');
}
void testNullInstanceMirror(InstanceMirror mirror) {
// TODO(turnidge): This is returning the wrong class. Fix it.
Expect.equals(const Symbol('Object'), mirror.type.simpleName);
Expect.isTrue(mirror.hasReflectee);
Expect.equals(null, mirror.reflectee);
Expect.equals("InstanceMirror on <null>", mirror.toString());
testDone('testNullInstanceMirror');
}
class MySuperClass {
}
class MyInterface {
}
class MyClass extends MySuperClass implements MyInterface {
MyClass(this.value) {}
MyClass.named() {}
final value;
int method(int arg) {
return arg + value;
}
}
class GenericClass<T> {
T method(int arg) {
return null;
}
}
void testCustomInstanceMirror(InstanceMirror mirror) {
Expect.isTrue(mirror.hasReflectee);
bool saw_exception = false;
try {
mirror.reflectee;
} on MirrorException catch (me) {
saw_exception = true;
}
Expect.isFalse(saw_exception);
// TODO(ahe): toString() test disabled for now as Symbols are 100% opaque.
// Expect.equals("InstanceMirror on instance of 'MyClass'",
// mirror.toString());
ClassMirror cls = mirror.type;
Expect.isTrue(cls is ClassMirror);
Expect.equals(const Symbol('MyClass'), cls.simpleName);
Expect.equals(const Symbol('MySuperClass'), cls.superclass.simpleName);
Expect.isTrue(cls.defaultFactory == null);
Expect.equals(const Symbol('isolate_mirror_local_test'), cls.owner.simpleName);
Expect.isTrue(cls.isClass);
Expect.equals(const Symbol('MyInterface'), cls.superinterfaces[0].simpleName);
// TODO(ahe): toString() test disabled for now as Symbols are 100% opaque.
// Expect.equals("ClassMirror on 'MyClass'", cls.toString());
// Invoke mirror.method(1000).
mirror.invokeAsync(const Symbol('method'), [ 1000 ]).then(
(InstanceMirror retval) {
Expect.equals(const Symbol('int'), retval.type.simpleName);
Expect.isTrue(retval.hasReflectee);
Expect.equals(1017, retval.reflectee);
testDone('testCustomInstanceMirror');
});
}
class MyException implements Exception {
MyException(this._message);
final String _message;
String toString() { return 'MyException: $_message'; }
}
void methodWithException() {
throw new MyException("from methodWithException");
}
void methodWithError() {
// We get a parse error when we try to run this function.
+++;
}
void testMirrorErrors(MirrorSystem mirrors) {
LibraryMirror lib_mirror = mirrors.isolate.rootLibrary;
lib_mirror.invokeAsync(const Symbol('methodWithException'), [])
.then((InstanceMirror retval) {
// Should not reach here.
Expect.isTrue(false);
})
.catchError((error) {
Expect.isTrue(error is MirroredUncaughtExceptionError);
Expect.equals(const Symbol('MyException'),
error.exception_mirror.type.simpleName);
Expect.equals('MyException: from methodWithException',
error.exception_string);
Expect.isTrue(error.stacktrace.toString().contains(
'isolate_mirror_local_test.dart'));
testDone('testMirrorErrors1');
});
lib_mirror.invokeAsync(const Symbol('methodWithError'), [])
.then((InstanceMirror retval) {
// Should not reach here.
Expect.isTrue(false);
})
.catchError((error) {
Expect.isTrue(error is MirroredCompilationError);
Expect.isTrue(error.message.contains('unexpected token'));
testDone('testMirrorErrors2');
});
// TODO(turnidge): When we call a method that doesn't exist, we
// should probably call noSuchMethod(). I'm adding this test to
// document the current behavior in the meantime.
lib_mirror.invokeAsync(const Symbol('methodNotFound'), [])
.then((InstanceMirror retval) {
// Should not reach here.
Expect.isTrue(false);
})
.catchError((error) {
Expect.isTrue(error is MirroredCompilationError);
Expect.isTrue(error.message.contains(
"did not find top-level function 'methodNotFound'"));
testDone('testMirrorErrors3');
});
}
void main() {
// When all of the expected tests complete, the exit_port is closed,
// allowing the program to terminate.
exit_port = new ReceivePort();
expectedTests = new Set<String>.from(['testRootLibraryMirror',
'testLibrariesMap',
'testMirrorSystem',
'testIntegerInstanceMirror',
'testStringInstanceMirror',
'testBoolInstanceMirror',
'testNullInstanceMirror',
'testCustomInstanceMirror',
'testMirrorErrors1',
'testMirrorErrors2',
'testMirrorErrors3']);
// Test that an isolate can reflect on itself.
mirrorSystemOf(exit_port.toSendPort()).then(testMirrorSystem);
testIntegerInstanceMirror(reflect(1001));
testStringInstanceMirror(reflect('This\nis\na\nString'));
testBoolInstanceMirror(reflect(true));
testNullInstanceMirror(reflect(null));
testCustomInstanceMirror(reflect(new MyClass(17)));
testMirrorErrors(currentMirrorSystem());
}