OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, 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 part of test_controller; | |
6 | |
7 /** Path to DRT executable. */ | |
8 String drt; | |
9 | |
10 /** Whether to include elapsed time. */ | |
11 bool includeTime; | |
12 | |
13 /** Whether to regenerate layout test files. */ | |
14 bool regenerate; | |
15 | |
16 /** Whether to output test summary. */ | |
17 bool summarize; | |
18 | |
19 /** Whether to print results immediately as they come in. */ | |
20 bool immediate; | |
21 | |
22 /** Format strings to use for test result messages. */ | |
23 String listFormat, passFormat, failFormat, errorFormat; | |
24 | |
25 /** Path of the running test file. */ | |
26 String testfile; | |
27 | |
28 /** The filters must be set by the caller. */ | |
29 List includeFilters; | |
30 List excludeFilters; | |
31 | |
32 /** The print function to use. */ | |
33 Function tprint; | |
34 | |
35 /** A callback function to notify the caller we are done. */ | |
36 Function notifyDone; | |
37 | |
38 /** The action function to use. */ | |
39 Function action; | |
40 | |
41 /** | |
42 * A special marker string used to separate group names and | |
43 * identify non-debug output. | |
44 */ | |
45 final marker = '###'; | |
46 | |
47 class Macros { | |
48 static const String testTime = '<TIME>'; | |
49 static const String testfile = '<FILENAME>'; | |
50 static const String testGroup = '<GROUPNAME>'; | |
51 static const String testDescription = '<TESTNAME>'; | |
52 static const String testMessage = '<MESSAGE>'; | |
53 static const String testStacktrace = '<STACK>'; | |
54 } | |
55 | |
56 class TestRunnerConfiguration extends SimpleConfiguration { | |
57 get name => 'Minimal test runner configuration'; | |
58 get autoStart => false; | |
59 | |
60 void onInit() {} | |
61 | |
62 String formatMessage(filename, groupname, | |
63 [ testname = '', testTime = '', result = '', | |
64 message = '', stack = '' ]) { | |
65 var format = errorFormat; | |
66 if (result == 'pass') format = passFormat; | |
67 else if (result == 'fail') format = failFormat; | |
68 return format. | |
69 replaceAll(Macros.testTime, testTime). | |
70 replaceAll(Macros.testfile, filename). | |
71 replaceAll(Macros.testGroup, groupname). | |
72 replaceAll(Macros.testDescription, testname). | |
73 replaceAll(Macros.testMessage, message). | |
74 replaceAll(Macros.testStacktrace, stack); | |
75 } | |
76 | |
77 String elapsed(TestCase t) { | |
78 if (includeTime) { | |
79 double duration = t.runningTime.inMilliseconds.toDouble(); | |
80 duration /= 1000; | |
81 return '${duration.toStringAsFixed(3)}s '; | |
82 } else { | |
83 return ''; | |
84 } | |
85 } | |
86 | |
87 void dumpTestResult(source, TestCase t) { | |
88 var groupName = '', testName = ''; | |
89 var idx = t.description.lastIndexOf(marker); | |
90 if (idx >= 0) { | |
91 groupName = t.description.substring(0, idx).replaceAll(marker, ' '); | |
92 testName = t.description.substring(idx+3); | |
93 } else { | |
94 testName = t.description; | |
95 } | |
96 var stack = (t.stackTrace == null) ? '' : '${t.stackTrace} '; | |
97 var message = (t.message.length > 0) ? '${t.message} ' : ''; | |
98 var duration = elapsed(t); | |
99 tprint(formatMessage(source, '$groupName ', '$testName ', | |
100 duration, t.result, message, stack)); | |
101 } | |
102 | |
103 void onTestResult(TestCase testCase) { | |
104 if (immediate) { | |
105 dumpTestResult('$testfile ', testCase); | |
106 } | |
107 } | |
108 | |
109 void printSummary(int passed, int failed, int errors, | |
110 [String uncaughtError = '']) { | |
111 tprint(''); | |
112 if (passed == 0 && failed == 0 && errors == 0) { | |
113 tprint('$testfile: No tests found.'); | |
114 } else if (failed == 0 && errors == 0 && uncaughtError == null) { | |
115 tprint('$testfile: All $passed tests passed.'); | |
116 } else { | |
117 if (uncaughtError != null) { | |
118 tprint('$testfile: Top-level uncaught error: $uncaughtError'); | |
119 } | |
120 tprint('$testfile: $passed PASSED, $failed FAILED, $errors ERRORS'); | |
121 } | |
122 } | |
123 | |
124 void onSummary(int passed, int failed, int errors, | |
125 List<TestCase> results, String uncaughtError) { | |
126 if (!immediate) { | |
127 for (final testCase in results) { | |
128 dumpTestResult('$testfile ', testCase); | |
129 } | |
130 } | |
131 if (summarize) { | |
132 printSummary(passed, failed, errors, uncaughtError); | |
133 } | |
134 } | |
135 | |
136 void onDone(bool success) { | |
137 if (notifyDone != null) { | |
138 notifyDone(success ? 0 : -1); | |
139 } | |
140 } | |
141 } | |
142 | |
143 String formatListMessage(filename, groupname, [ testname = '']) { | |
144 return listFormat. | |
145 replaceAll(Macros.testfile, filename). | |
146 replaceAll(Macros.testGroup, groupname). | |
147 replaceAll(Macros.testDescription, testname); | |
148 } | |
149 | |
150 listGroups() { | |
151 List tests = testCases; | |
152 Map groups = {}; | |
153 for (var t in tests) { | |
154 var groupName, testName = ''; | |
155 var idx = t.description.lastIndexOf(marker); | |
156 if (idx >= 0) { | |
157 groupName = t.description.substring(0, idx).replaceAll(marker, ' '); | |
158 if (!groups.containsKey(groupName)) { | |
159 groups[groupName] = ''; | |
160 } | |
161 } | |
162 } | |
163 for (var g in groups.keys) { | |
164 var msg = formatListMessage('$testfile ', '$g '); | |
165 print('$marker$msg'); | |
166 } | |
167 if (notifyDone != null) { | |
168 notifyDone(0); | |
169 } | |
170 } | |
171 | |
172 listTests() { | |
173 List tests = testCases; | |
174 for (var t in tests) { | |
175 var groupName, testName = ''; | |
176 var idx = t.description.lastIndexOf(marker); | |
177 if (idx >= 0) { | |
178 groupName = t.description.substring(0, idx).replaceAll(marker, ' '); | |
179 testName = t.description.substring(idx+3); | |
180 } else { | |
181 groupName = ''; | |
182 testName = t.description; | |
183 } | |
184 var msg = formatListMessage('$testfile ', '$groupName ', '$testName '); | |
185 print('$marker$msg'); | |
186 } | |
187 if (notifyDone != null) { | |
188 notifyDone(0); | |
189 } | |
190 } | |
191 | |
192 // Support for running in isolates. | |
193 | |
194 class TestRunnerChildConfiguration extends SimpleConfiguration { | |
195 get name => 'Test runner child configuration'; | |
196 get autoStart => false; | |
197 | |
198 void onSummary(int passed, int failed, int errors, | |
199 List<TestCase> results, String uncaughtError) { | |
200 TestCase test = results[0]; | |
201 parentPort.send([test.result, test.runningTime.inMilliseconds, | |
202 test.message, test.stackTrace.toString()]); | |
203 } | |
204 } | |
205 | |
206 var parentPort; | |
207 runChildTest(message) { | |
208 var testName = message[0]; | |
209 parentPort = message[1]; | |
210 unittestConfiguration = new TestRunnerChildConfiguration(); | |
211 groupSep = marker; | |
212 group('', test.main); | |
213 filterTests(testName); | |
214 runTests(); | |
215 } | |
216 | |
217 isolatedTestParentWrapper(testCase) => () { | |
218 ReceivePort response = new ReceivePort(); | |
219 return Isolate.spawn(runChildTest, [testCase.description, response.sendPort]) | |
220 .then((_) => response.first) | |
221 .then((results) { | |
222 var result = results[0]; | |
223 var duration = new Duration(milliseconds: results[1]); | |
224 var message = results[2]; | |
225 var stack = results[3]; | |
226 if (result == 'fail') { | |
227 testCase.fail(message, stack); | |
228 } else if (result == 'error') { | |
229 testCase.error(message, stack); | |
230 } | |
231 }); | |
232 }; | |
233 | |
234 runIsolateTests() { | |
235 // Replace each test with a wrapped version first. | |
236 for (var i = 0; i < testCases.length; i++) { | |
237 testCases[i].testFunction = isolatedTestParentWrapper(testCases[i]); | |
238 } | |
239 runTests(); | |
240 } | |
241 | |
242 // Main | |
243 | |
244 filterTest(t) { | |
245 var name = t.description.replaceAll(marker, " "); | |
246 if (includeFilters.length > 0) { | |
247 for (var f in includeFilters) { | |
248 if (name.indexOf(f) >= 0) return true; | |
249 } | |
250 return false; | |
251 } else if (excludeFilters.length > 0) { | |
252 for (var f in excludeFilters) { | |
253 if (name.indexOf(f) >= 0) return false; | |
254 } | |
255 return true; | |
256 } else { | |
257 return true; | |
258 } | |
259 } | |
260 | |
261 process(testMain, action) { | |
262 groupSep = marker; | |
263 unittestConfiguration = new TestRunnerConfiguration(); | |
264 group('', testMain); | |
265 // Do any user-specified test filtering. | |
266 filterTests(filterTest); | |
267 action(); | |
268 } | |
OLD | NEW |