Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Side by Side Diff: pkg/analyzer/test/reflective_tests.dart

Issue 2298913003: Pull in test_reflective_loader 0.0.4 and switch analyzer to it. (Closed)
Patch Set: Fixes for review comments. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 library analyzer.test.reflective_tests;
6
7 import 'dart:async';
8 @MirrorsUsed(metaTargets: 'ReflectiveTest')
9 import 'dart:mirrors';
10
11 import 'package:unittest/unittest.dart';
12
13 /**
14 * A marker annotation used to annotate overridden test methods (so we cannot
15 * rename them to `fail_`) which are expected to fail at `assert` in the
16 * checked mode.
17 */
18 const _AssertFailingTest assertFailingTest = const _AssertFailingTest();
19
20 /**
21 * A marker annotation used to annotate overridden test methods (so we cannot
22 * rename them to `fail_`) which are expected to fail.
23 */
24 const _FailingTest failingTest = const _FailingTest();
25
26 /**
27 * A marker annotation used to instruct dart2js to keep reflection information
28 * for the annotated classes.
29 */
30 const ReflectiveTest reflectiveTest = const ReflectiveTest();
31
32 /**
33 * Test classes annotated with this annotation are run using [solo_group].
34 */
35 const _SoloTest soloTest = const _SoloTest();
36
37 /**
38 * Is `true` the application is running in the checked mode.
39 */
40 final bool _isCheckedMode = () {
41 try {
42 assert(false);
43 return false;
44 } catch (_) {
45 return true;
46 }
47 }();
48
49 /**
50 * Runs test methods existing in the given [type].
51 *
52 * Methods with names starting with `test` are run using [test] function.
53 * Methods with names starting with `solo_test` are run using [solo_test] functi on.
54 *
55 * Each method is run with a new instance of [type].
56 * So, [type] should have a default constructor.
57 *
58 * If [type] declares method `setUp`, it methods will be invoked before any test
59 * method invocation.
60 *
61 * If [type] declares method `tearDown`, it will be invoked after any test
62 * method invocation. If method returns [Future] to test some asynchronous
63 * behavior, then `tearDown` will be invoked in `Future.complete`.
64 */
65 void runReflectiveTests(Type type) {
66 ClassMirror classMirror = reflectClass(type);
67 if (!classMirror.metadata.any((InstanceMirror annotation) =>
68 annotation.type.reflectedType == ReflectiveTest)) {
69 String name = MirrorSystem.getName(classMirror.qualifiedName);
70 throw new Exception('Class $name must have annotation "@reflectiveTest" '
71 'in order to be run by runReflectiveTests.');
72 }
73 void runMembers() {
74 classMirror.instanceMembers
75 .forEach((Symbol symbol, MethodMirror memberMirror) {
76 // we need only methods
77 if (memberMirror is! MethodMirror || !memberMirror.isRegularMethod) {
78 return;
79 }
80 String memberName = MirrorSystem.getName(symbol);
81 // test_
82 if (memberName.startsWith('test_')) {
83 test(memberName, () {
84 if (_hasFailingTestAnnotation(memberMirror) ||
85 _isCheckedMode && _hasAssertFailingTestAnnotation(memberMirror)) {
86 return _runFailingTest(classMirror, symbol);
87 } else {
88 return _runTest(classMirror, symbol);
89 }
90 });
91 return;
92 }
93 // solo_test_
94 if (memberName.startsWith('solo_test_')) {
95 solo_test(memberName, () {
96 return _runTest(classMirror, symbol);
97 });
98 }
99 // fail_test_
100 if (memberName.startsWith('fail_')) {
101 test(memberName, () {
102 return _runFailingTest(classMirror, symbol);
103 });
104 }
105 // solo_fail_test_
106 if (memberName.startsWith('solo_fail_')) {
107 solo_test(memberName, () {
108 return _runFailingTest(classMirror, symbol);
109 });
110 }
111 });
112 }
113 String className = MirrorSystem.getName(classMirror.simpleName);
114 if (_hasAnnotationInstance(classMirror, soloTest)) {
115 solo_group(className, runMembers);
116 } else {
117 group(className, runMembers);
118 }
119 }
120
121 bool _hasAnnotationInstance(DeclarationMirror declaration, instance) =>
122 declaration.metadata.any((InstanceMirror annotation) =>
123 identical(annotation.reflectee, instance));
124
125 bool _hasAssertFailingTestAnnotation(MethodMirror method) =>
126 _hasAnnotationInstance(method, assertFailingTest);
127
128 bool _hasFailingTestAnnotation(MethodMirror method) =>
129 _hasAnnotationInstance(method, failingTest);
130
131 Future _invokeSymbolIfExists(InstanceMirror instanceMirror, Symbol symbol) {
132 var invocationResult = null;
133 InstanceMirror closure;
134 try {
135 closure = instanceMirror.getField(symbol);
136 } on NoSuchMethodError {}
137
138 if (closure is ClosureMirror) {
139 invocationResult = closure.apply([]).reflectee;
140 }
141 return new Future.value(invocationResult);
142 }
143
144 /**
145 * Run a test that is expected to fail, and confirm that it fails.
146 *
147 * This properly handles the following cases:
148 * - The test fails by throwing an exception
149 * - The test returns a future which completes with an error.
150 *
151 * However, it does not handle the case where the test creates an asynchronous
152 * callback using expectAsync(), and that callback generates a failure.
153 */
154 Future _runFailingTest(ClassMirror classMirror, Symbol symbol) {
155 return new Future(() => _runTest(classMirror, symbol)).then((_) {
156 fail('Test passed - expected to fail.');
157 }, onError: (_) {});
158 }
159
160 _runTest(ClassMirror classMirror, Symbol symbol) {
161 InstanceMirror instanceMirror = classMirror.newInstance(new Symbol(''), []);
162 return _invokeSymbolIfExists(instanceMirror, #setUp)
163 .then((_) => instanceMirror.invoke(symbol, []).reflectee)
164 .whenComplete(() => _invokeSymbolIfExists(instanceMirror, #tearDown));
165 }
166
167 /**
168 * A marker annotation used to instruct dart2js to keep reflection information
169 * for the annotated classes.
170 */
171 class ReflectiveTest {
172 const ReflectiveTest();
173 }
174
175 /**
176 * A marker annotation used to annotate overridden test methods (so we cannot
177 * rename them to `fail_`) which are expected to fail at `assert` in the
178 * checked mode.
179 */
180 class _AssertFailingTest {
181 const _AssertFailingTest();
182 }
183
184 /**
185 * A marker annotation used to annotate overridden test methods (so we cannot
186 * rename them to `fail_`) which are expected to fail.
187 */
188 class _FailingTest {
189 const _FailingTest();
190 }
191
192 /**
193 * A marker annotation used to annotate a test class to run it using
194 * [solo_group].
195 */
196 class _SoloTest {
197 const _SoloTest();
198 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698