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

Side by Side Diff: tools/testing/dart/test_suite.dart

Issue 8872064: Cache the tests across configurations in the test scripts. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address review comments. Created 9 years 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 | Annotate | Revision Log
« no previous file with comments | « tools/testing/dart/test_runner.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 #library("test_suite"); 5 #library("test_suite");
6 6
7 #import("status_file_parser.dart"); 7 #import("status_file_parser.dart");
8 #import("test_runner.dart"); 8 #import("test_runner.dart");
9 #import("multitest.dart"); 9 #import("multitest.dart");
10 10
11 11
12 interface TestSuite { 12 interface TestSuite {
13 void forEachTest(Function onTest, [Function onDone]); 13 void forEachTest(Function onTest, Map testCache, [Function onDone]);
14 } 14 }
15 15
16 16
17 class CCTestListerIsolate extends Isolate { 17 class CCTestListerIsolate extends Isolate {
18 CCTestListerIsolate() : super.heavy(); 18 CCTestListerIsolate() : super.heavy();
19 19
20 void main() { 20 void main() {
21 port.receive((String runnerPath, SendPort replyTo) { 21 port.receive((String runnerPath, SendPort replyTo) {
22 var p = new Process(runnerPath, ["--list"]); 22 var p = new Process(runnerPath, ["--list"]);
23 StringInputStream stdoutStream = new StringInputStream(p.stdout); 23 StringInputStream stdoutStream = new StringInputStream(p.stdout);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
92 runnerPath, 92 runnerPath,
93 args, 93 args,
94 configuration, 94 configuration,
95 completeHandler, 95 completeHandler,
96 expectations)); 96 expectations));
97 97
98 receiveTestName.receive(testNameHandler); 98 receiveTestName.receive(testNameHandler);
99 } 99 }
100 } 100 }
101 101
102 void forEachTest(Function onTest, [Function onDone]) { 102 void forEachTest(Function onTest, Map testCache, [Function onDone]) {
103 doTest = onTest; 103 doTest = onTest;
104 doDone = (ignore) => (onDone != null) ? onDone() : null; 104 doDone = (ignore) => (onDone != null) ? onDone() : null;
105 105
106 testExpectations = 106 testExpectations =
107 new TestExpectations(complexMatching: complexStatusMatching()); 107 new TestExpectations(complexMatching: complexStatusMatching());
108 for (var statusFilePath in statusFilePaths) { 108 for (var statusFilePath in statusFilePaths) {
109 ReadTestExpectationsInto(testExpectations, 109 ReadTestExpectationsInto(testExpectations,
110 statusFilePath, 110 statusFilePath,
111 configuration); 111 configuration);
112 } 112 }
113 113
114 receiveTestName = new ReceivePort(); 114 receiveTestName = new ReceivePort();
115 new CCTestListerIsolate().spawn().then((port) { 115 new CCTestListerIsolate().spawn().then((port) {
116 port.send(runnerPath, receiveTestName.toSendPort()); 116 port.send(runnerPath, receiveTestName.toSendPort());
117 receiveTestName.receive(testNameHandler); 117 receiveTestName.receive(testNameHandler);
118 }); 118 });
119 } 119 }
120 120
121 void completeHandler(TestCase testCase) { 121 void completeHandler(TestCase testCase) {
122 } 122 }
123 } 123 }
124 124
125 125
126 class TestInformation {
127 String filename;
128 Map optionsFromFile;
129 bool isNegative;
130 bool isNegativeIfChecked;
131 bool hasFatalTypeErrors;
132
133 TestInformation(this.filename, this.optionsFromFile, this.isNegative,
134 this.isNegativeIfChecked, this.hasFatalTypeErrors);
135 }
136
137
126 class StandardTestSuite implements TestSuite { 138 class StandardTestSuite implements TestSuite {
127 Map configuration; 139 Map configuration;
128 String suiteName; 140 String suiteName;
129 String directoryPath; 141 String directoryPath;
130 List<String> statusFilePaths; 142 List<String> statusFilePaths;
131 Function doTest; 143 Function doTest;
132 Function doDone; 144 Function doDone;
133 int activeTestGenerators = 0; 145 int activeTestGenerators = 0;
134 bool listingDone = false; 146 bool listingDone = false;
135 TestExpectations testExpectations; 147 TestExpectations testExpectations;
148 List<TestInformation> cachedTests;
136 149
137 StandardTestSuite(Map this.configuration, 150 StandardTestSuite(Map this.configuration,
138 String this.suiteName, 151 String this.suiteName,
139 String this.directoryPath, 152 String this.directoryPath,
140 List<String> this.statusFilePaths); 153 List<String> this.statusFilePaths);
141 154
142 void isTestFile(String filename) => filename.endsWith("Test.dart"); 155 void isTestFile(String filename) => filename.endsWith("Test.dart");
143 156
144 void listRecursively() => false; 157 void listRecursively() => false;
145 158
146 void complexStatusMatching() => false; 159 void complexStatusMatching() => false;
147 160
148 String shellPath() => TestUtils.dartShellFileName(configuration); 161 String shellPath() => TestUtils.dartShellFileName(configuration);
149 162
150 List<String> additionalOptions() => []; 163 List<String> additionalOptions() => [];
151 164
152 void forEachTest(Function onTest, [Function onDone = null]) { 165 void forEachTest(Function onTest, Map testCache, [Function onDone = null]) {
153 doTest = onTest; 166 doTest = onTest;
154 doDone = (onDone != null) ? onDone : (() => null); 167 doDone = (onDone != null) ? onDone : (() => null);
155 168
156 // Read test expectations from status files. 169 // Read test expectations from status files.
157 testExpectations = 170 testExpectations =
158 new TestExpectations(complexMatching: complexStatusMatching()); 171 new TestExpectations(complexMatching: complexStatusMatching());
159 for (var statusFilePath in statusFilePaths) { 172 for (var statusFilePath in statusFilePaths) {
160 ReadTestExpectationsInto(testExpectations, 173 ReadTestExpectationsInto(testExpectations,
161 statusFilePath, 174 statusFilePath,
162 configuration); 175 configuration);
163 } 176 }
164 177
165 processDirectory(); 178 // Checked if we have already found and generated the tests for
179 // this suite.
180 if (!testCache.containsKey(suiteName)) {
181 cachedTests = testCache[suiteName] = [];
182 processDirectory();
183 } else {
184 // We rely on enqueueing completing asynchronously so use a
185 // timer to make it so.
186 void enqueueCachedTests(Timer ignore) {
187 for (var info in testCache[suiteName]) {
188 enqueueTestCaseFromTestInformation(info);
189 }
190 doDone();
191 }
192 new Timer(enqueueCachedTests, 0, false);
193 }
166 } 194 }
167 195
168 void processDirectory() { 196 void processDirectory() {
169 directoryPath = getDirname(directoryPath); 197 directoryPath = getDirname(directoryPath);
170 Directory dir = new Directory(directoryPath); 198 Directory dir = new Directory(directoryPath);
171 dir.errorHandler = (s) { 199 dir.errorHandler = (s) {
172 throw s; 200 throw s;
173 }; 201 };
174 dir.fileHandler = processFile; 202 dir.fileHandler = processFile;
175 dir.doneHandler = directoryListingDone; 203 dir.doneHandler = directoryListingDone;
176 dir.list(recursive: listRecursively()); 204 dir.list(recursive: listRecursively());
177 } 205 }
178 206
179 Function makeTestCaseCreator(Map optionsFromFile, Map configuration) { 207 void enqueueTestCaseFromTestInformation(TestInformation info) {
208 var filename = info.filename;
209 var optionsFromFile = info.optionsFromFile;
210 var isNegative = info.isNegative;
211
212 // Look up expectations in status files using a modified file path.
213 String pathSeparator = new Platform().pathSeparator();
214 String testName;
215 int start = filename.lastIndexOf('src' + pathSeparator);
216 if (start != -1) {
217 testName = filename.substring(start + 4, filename.length - 5);
218 } else if (optionsFromFile['isMultitest']) {
219 start = filename.lastIndexOf(pathSeparator);
220 int middle = filename.lastIndexOf('_');
221 testName = filename.substring(start + 1, middle) + pathSeparator +
222 filename.substring(middle + 1, filename.length - 5);
223 } else {
224 // This case is hit by the dartc client compilation
225 // tests. These tests are pretty broken compared to the
226 // rest. They use the .dart suffix in the status files. They
227 // find tests in weird ways (testing that they contain "#").
228 // They need to be redone.
229 start = filename.indexOf(directoryPath);
230 testName = filename.substring(start + directoryPath.length + 1,
231 filename.length);
232 }
233 Set<String> expectations = testExpectations.expectations(testName);
234 if (configuration["report"]) {
235 // Tests with multiple VMOptions are counted more than once.
236 for (var dummy in optionsFromFile["vmOptions"]) {
237 SummaryReport.add(expectations);
238 }
239 }
240 if (expectations.contains(SKIP)) return;
241
242 // Only dartc supports fatal type errors. Enable fatal type
243 // errors with a flag and treat tests that have fatal type
244 // errors as negative.
245 var enableFatalTypeErrors =
246 (info.hasFatalTypeErrors && configuration['component'] == 'dartc');
247 var argumentLists = argumentListsFromFile(filename,
248 optionsFromFile,
249 enableFatalTypeErrors);
250 isNegative = isNegative ||
251 (configuration['checked'] && info.isNegativeIfChecked) ||
252 enableFatalTypeErrors;
253
254 for (var args in argumentLists) {
255 doTest(new TestCase('$suiteName/$testName',
256 shellPath(),
257 args,
258 configuration,
259 completeHandler,
260 expectations,
261 isNegative));
262 }
263 }
264
265 Function makeTestCaseCreator(Map optionsFromFile) {
180 return (String filename, 266 return (String filename,
181 bool isNegative, 267 bool isNegative,
182 [bool isNegativeIfChecked = false, 268 [bool isNegativeIfChecked = false,
183 bool enableFatalTypeErrors = false]) { 269 bool hasFatalTypeErrors = false]) {
184 // Look up expectations in status files using a modified file path. 270 // Cache the test information for each test case.
185 String pathSeparator = new Platform().pathSeparator(); 271 var info = new TestInformation(filename,
186 String testName; 272 optionsFromFile,
187 int start = filename.lastIndexOf('src' + pathSeparator); 273 isNegative,
188 if (start != -1) { 274 isNegativeIfChecked,
189 testName = filename.substring(start + 4, filename.length - 5); 275 hasFatalTypeErrors);
190 } else if (optionsFromFile['isMultitest']) { 276 cachedTests.add(info);
191 start = filename.lastIndexOf(pathSeparator); 277 enqueueTestCaseFromTestInformation(info);
192 int middle = filename.lastIndexOf('_');
193 testName = filename.substring(start + 1, middle) + pathSeparator +
194 filename.substring(middle + 1, filename.length - 5);
195 } else {
196 // This case is hit by the dartc client compilation
197 // tests. These tests are pretty broken compared to the
198 // rest. They use the .dart suffix in the status files. They
199 // find tests in weird ways (testing that they contain "#").
200 // They need to be redone.
201 start = filename.indexOf(directoryPath);
202 testName = filename.substring(start + directoryPath.length + 1,
203 filename.length);
204 }
205 Set<String> expectations = testExpectations.expectations(testName);
206 if (configuration["report"]) {
207 // Tests with multiple VMOptions are counted more than once.
208 for (var dummy in optionsFromFile["vmOptions"]) {
209 SummaryReport.add(expectations);
210 }
211 }
212 if (expectations.contains(SKIP)) return;
213
214 isNegative = isNegative ||
215 (configuration['checked'] && isNegativeIfChecked);
216 var argumentLists = argumentListsFromFile(filename,
217 optionsFromFile,
218 enableFatalTypeErrors);
219 for (var args in argumentLists) {
220 doTest(new TestCase('$suiteName/$testName',
221 shellPath(),
222 args,
223 configuration,
224 completeHandler,
225 expectations,
226 isNegative));
227 }
228 }; 278 };
229 } 279 }
230 280
231 void processFile(String filename) { 281 void processFile(String filename) {
232 if (!isTestFile(filename)) return; 282 if (!isTestFile(filename)) return;
233 283
234 // Only run the tests that match the pattern. 284 // Only run the tests that match the pattern.
235 RegExp pattern = configuration['selectors'][suiteName]; 285 RegExp pattern = configuration['selectors'][suiteName];
236 if (!pattern.hasMatch(filename)) return; 286 if (!pattern.hasMatch(filename)) return;
237 287
238 var optionsFromFile = optionsFromFile(filename); 288 var optionsFromFile = optionsFromFile(filename);
239 Function createTestCase = 289 Function createTestCase = makeTestCaseCreator(optionsFromFile);
240 makeTestCaseCreator(optionsFromFile, configuration);
241 290
242 if (optionsFromFile['isMultitest']) { 291 if (optionsFromFile['isMultitest']) {
243 bool supportsFatalTypeErrors = (configuration['component'] == 'dartc');
244 testGeneratorStarted(); 292 testGeneratorStarted();
245 DoMultitest(filename, 293 DoMultitest(filename,
246 TestUtils.buildDir(configuration), 294 TestUtils.outputDir(configuration),
247 directoryPath, 295 directoryPath,
248 supportsFatalTypeErrors,
249 createTestCase, 296 createTestCase,
250 testGeneratorDone); 297 testGeneratorDone);
251 } else { 298 } else {
252 createTestCase(filename, optionsFromFile['isNegative']); 299 createTestCase(filename, optionsFromFile['isNegative']);
253 } 300 }
254 } 301 }
255 302
256 void testGeneratorStarted() { 303 void testGeneratorStarted() {
257 ++activeTestGenerators; 304 ++activeTestGenerators;
258 } 305 }
(...skipping 13 matching lines...) Expand all
272 } 319 }
273 320
274 void completeHandler(TestCase testCase) { 321 void completeHandler(TestCase testCase) {
275 } 322 }
276 323
277 List<List<String>> argumentListsFromFile(String filename, 324 List<List<String>> argumentListsFromFile(String filename,
278 Map optionsFromFile, 325 Map optionsFromFile,
279 bool enableFatalTypeErrors) { 326 bool enableFatalTypeErrors) {
280 List args = TestUtils.standardOptions(configuration); 327 List args = TestUtils.standardOptions(configuration);
281 args.addAll(additionalOptions()); 328 args.addAll(additionalOptions());
282 if (enableFatalTypeErrors) args.add('--fatal-type-errors'); 329 if (enableFatalTypeErrors && configuration['component'] == 'dartc') {
330 args.add('--fatal-type-errors');
331 }
283 332
284 bool isMultitest = optionsFromFile["isMultitest"]; 333 bool isMultitest = optionsFromFile["isMultitest"];
285 List<String> dartOptions = optionsFromFile["dartOptions"]; 334 List<String> dartOptions = optionsFromFile["dartOptions"];
286 List<List<String>> vmOptionsList = optionsFromFile["vmOptions"]; 335 List<List<String>> vmOptionsList = optionsFromFile["vmOptions"];
287 Expect.isTrue(!isMultitest || dartOptions == null); 336 Expect.isTrue(!isMultitest || dartOptions == null);
288 if (dartOptions == null) { 337 if (dartOptions == null) {
289 args.add(filename); 338 args.add(filename);
290 } else { 339 } else {
291 var filename = dartOptions[0]; 340 var filename = dartOptions[0];
292 // TODO(ager): Get rid of this hack when the runtime checkout goes away. 341 // TODO(ager): Get rid of this hack when the runtime checkout goes away.
293 var file = new File(filename); 342 var file = new File(filename);
294 if (!file.existsSync()) { 343 if (!file.existsSync()) {
295 filename = '../$filename'; 344 filename = '../$filename';
296 Expect.isTrue(new File(filename).existsSync()); 345 Expect.isTrue(new File(filename).existsSync());
297 dartOptions[0] = filename; 346 dartOptions[0] = filename;
298 } 347 }
299 args.addAll(dartOptions); 348 args.addAll(dartOptions);
300 } 349 }
301 350
302 var result = new List<List<String>>(); 351 var result = new List<List<String>>();
303 Expect.isFalse(vmOptionsList.isEmpty(), "empty vmOptionsList"); 352 Expect.isFalse(vmOptionsList.isEmpty(), "empty vmOptionsList");
304 for (var vmOptions in vmOptionsList) { 353 for (var vmOptions in vmOptionsList) {
305 if (isMultitest) { 354 var options = new List<String>.from(vmOptions);
306 // Make copy of vmOptions, since we will modify it at each iteration. 355 options.addAll(args);
307 vmOptions = new List<String>.from(vmOptions); 356 result.add(options);
308 }
309 vmOptions.addAll(args);
310 result.add(vmOptions);
311 } 357 }
312 358
313 return result; 359 return result;
314 } 360 }
315 361
316 Map optionsFromFile(String filename) { 362 Map optionsFromFile(String filename) {
317 RegExp testOptionsRegExp = const RegExp(@"// VMOptions=(.*)"); 363 RegExp testOptionsRegExp = const RegExp(@"// VMOptions=(.*)");
318 RegExp dartOptionsRegExp = const RegExp(@"// DartOptions=(.*)"); 364 RegExp dartOptionsRegExp = const RegExp(@"// DartOptions=(.*)");
319 RegExp multiTestRegExp = const RegExp(@"/// [0-9][0-9]:(.*)"); 365 RegExp multiTestRegExp = const RegExp(@"/// [0-9][0-9]:(.*)");
320 RegExp leadingHashRegExp = const RegExp(@"^#", multiLine: true); 366 RegExp leadingHashRegExp = const RegExp(@"^#", multiLine: true);
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 } 504 }
459 505
460 static String dartcCompilationShellPath(Map configuration) { 506 static String dartcCompilationShellPath(Map configuration) {
461 var name = buildDir(configuration) + 'compiler/bin/dartc'; 507 var name = buildDir(configuration) + 'compiler/bin/dartc';
462 if (!(new File(name)).existsSync()) { 508 if (!(new File(name)).existsSync()) {
463 throw "Executable '$name' does not exist"; 509 throw "Executable '$name' does not exist";
464 } 510 }
465 return name; 511 return name;
466 } 512 }
467 513
468 static String buildDir(Map configuration) { 514 static String outputDir(Map configuration) {
469 var buildDir = ''; 515 var outputDir = '';
470 var system = configuration['system']; 516 var system = configuration['system'];
471 if (system == 'linux') { 517 if (system == 'linux') {
472 buildDir = 'out/'; 518 outputDir = 'out/';
473 } else if (system == 'macos') { 519 } else if (system == 'macos') {
474 buildDir = 'xcodebuild/'; 520 outputDir = 'xcodebuild/';
475 } 521 }
522 return outputDir;
523 }
524
525 static String buildDir(Map configuration) {
526 var buildDir = outputDir(configuration);
476 buildDir += (configuration['mode'] == 'debug') ? 'Debug_' : 'Release_'; 527 buildDir += (configuration['mode'] == 'debug') ? 'Debug_' : 'Release_';
477 buildDir += configuration['arch'] + '/'; 528 buildDir += configuration['arch'] + '/';
478 return buildDir; 529 return buildDir;
479 } 530 }
480 531
481 static List<String> standardOptions(Map configuration) { 532 static List<String> standardOptions(Map configuration) {
482 List args = ["--ignore-unrecognized-flags"]; 533 List args = ["--ignore-unrecognized-flags"];
483 if (configuration["checked"]) { 534 if (configuration["checked"]) {
484 args.add('--enable_asserts'); 535 args.add('--enable_asserts');
485 args.add("--enable_type_checks"); 536 args.add("--enable_type_checks");
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 * $noCrash tests are expected to be flaky but not crash 592 * $noCrash tests are expected to be flaky but not crash
542 * $pass tests are expected to pass 593 * $pass tests are expected to pass
543 * $failOk tests are expected to fail that we won't fix 594 * $failOk tests are expected to fail that we won't fix
544 * $fail tests are expected to fail that we should fix 595 * $fail tests are expected to fail that we should fix
545 * $crash tests are expected to crash that we should fix 596 * $crash tests are expected to crash that we should fix
546 * $timeout tests are allowed to timeout\ 597 * $timeout tests are allowed to timeout\
547 """; 598 """;
548 print(report); 599 print(report);
549 } 600 }
550 } 601 }
OLDNEW
« no previous file with comments | « tools/testing/dart/test_runner.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698