OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 // This test reflectively enumerates all the methods in the system and tries to | |
6 // invoke them will all nulls. This may result in Dart exceptions or hangs, but | |
7 // should never result in crashes or JavaScript exceptions. | |
8 | |
9 library test.invoke_natives; | |
10 | |
11 import 'dart:mirrors'; | |
12 import 'dart:async'; | |
13 import 'package:expect/expect.dart'; | |
14 | |
15 // Methods to be skipped, by qualified name. | |
16 var blacklist = [ | |
17 // These prevent the test from exiting, typically by spawning another isolate. | |
18 'dart.async._scheduleAsyncCallback', | |
19 'dart.io._IOService.dispatch', | |
20 'dart.isolate.RawReceivePort.RawReceivePort', | |
21 'dart.isolate.ReceivePort.ReceivePort', | |
22 'dart.isolate.ReceivePort.ReceivePort.fromRawReceivePort', | |
23 'dart.isolate.ReceivePort.sendPort', | |
24 'dart.isolate.ReceivePort.close', | |
25 'dart.isolate.ReceivePort.listen', | |
26 'dart.isolate.RawReceivePort.sendPort', | |
27 'dart.isolate.RawReceivePort.close', | |
28 'dart.isolate.RawReceivePort.handler=', | |
29 | |
30 // These "crash" the VM (throw uncatchable API errors). | |
31 // TODO(15274): Fill in this list to make the test pass and provide coverage | |
32 // against addition of new natives. | |
33 ]; | |
34 | |
35 class Task { | |
36 var name; | |
37 var action; | |
38 } | |
39 var queue = new List(); | |
40 | |
41 checkMethod(MethodMirror m, ObjectMirror target, [origin]) { | |
42 if (blacklist.contains(MirrorSystem.getName(m.qualifiedName))) return; | |
43 | |
44 var task = new Task(); | |
45 task.name = '${MirrorSystem.getName(m.qualifiedName)} from $origin'; | |
46 | |
47 if (m.isRegularMethod) { | |
48 task.action = | |
49 () => target.invoke(m.simpleName, new List(m.parameters.length)); | |
50 } else if (m.isGetter) { | |
51 task.action = | |
52 () => target.getField(m.simpleName); | |
53 } else if (m.isSetter) { | |
54 task.action = | |
55 () => target.setField(m.simpleName, null); | |
56 } else if (m.isConstructor) { | |
57 return; | |
58 } else { | |
59 throw "Unexpected method kind"; | |
60 } | |
61 | |
62 queue.add(task); | |
63 } | |
64 | |
65 checkInstance(instanceMirror, origin) { | |
66 instanceMirror.type.declarations.values | |
67 .where((d) => d is MethodMirror) | |
68 .forEach((m) => checkMethod(m, instanceMirror, origin)); | |
69 } | |
70 | |
71 checkClass(classMirror) { | |
72 classMirror.declarations.values | |
73 .where((d) => d is MethodMirror) | |
74 .forEach((m) => checkMethod(m, classMirror)); | |
75 | |
76 classMirror.declarations.values | |
77 .where((d) => d is MethodMirror) | |
78 .forEach((m) { | |
79 if (blacklist.contains(MirrorSystem.getName(m.qualifiedName))) return; | |
80 if (!m.isConstructor) return; | |
81 var task = new Task(); | |
82 task.name = MirrorSystem.getName(m.qualifiedName); | |
83 | |
84 task.action = () { | |
85 var instance = classMirror.newInstance(m.constructorName, | |
86 new List(m.parameters.length)); | |
87 checkInstance(instance, task.name); | |
88 }; | |
89 queue.add(task); | |
90 }); | |
91 } | |
92 | |
93 checkLibrary(libraryMirror) { | |
94 // Don't recurse on this test. | |
95 if (libraryMirror.simpleName == #test.invoke_natives) return; | |
96 | |
97 libraryMirror.declarations.values | |
98 .where((d) => d is ClassMirror) | |
99 .forEach(checkClass); | |
100 | |
101 libraryMirror.declarations.values | |
102 .where((d) => d is MethodMirror) | |
103 .forEach((m) => checkMethod(m, libraryMirror)); | |
104 } | |
105 | |
106 var testZone; | |
107 var debug = true; | |
108 | |
109 doOneTask() { | |
110 if (queue.length == 0) { | |
111 if (debug) print('Done'); | |
112 return; | |
113 } | |
114 | |
115 var task = queue.removeLast(); | |
116 if (debug) print(task.name); | |
117 try { | |
118 task.action(); | |
119 } catch(e) {} | |
120 // Register the next task in a timer callback so as to yield to async code | |
121 // scheduled in the current task. This isn't necessary for the test itself, | |
122 // but is helpful when trying to figure out which function is responsible for | |
123 // a crash. | |
124 testZone.createTimer(Duration.ZERO, doOneTask); | |
125 } | |
126 | |
127 main() { | |
128 currentMirrorSystem().libraries.values.forEach(checkLibrary); | |
129 | |
130 uncaughtErrorHandler(self, parent, zone, error, stack) {}; | |
131 var zoneSpec = | |
132 new ZoneSpecification(handleUncaughtError: uncaughtErrorHandler); | |
133 testZone = Zone.current.fork(specification: zoneSpec); | |
134 testZone.createTimer(Duration.ZERO, doOneTask); | |
135 } | |
OLD | NEW |