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