| OLD | NEW |
| 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 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 | 126 |
| 127 class StandardTestSuite implements TestSuite { | 127 class StandardTestSuite implements TestSuite { |
| 128 Map configuration; | 128 Map configuration; |
| 129 String suiteName; | 129 String suiteName; |
| 130 String directoryPath; | 130 String directoryPath; |
| 131 List<String> statusFilePaths; | 131 List<String> statusFilePaths; |
| 132 Function doTest; | 132 Function doTest; |
| 133 Function doDone; | 133 Function doDone; |
| 134 int activeMultitests = 0; | 134 int activeMultitests = 0; |
| 135 bool listingDone = false; | 135 bool listingDone = false; |
| 136 String shellPath; | |
| 137 TestExpectations testExpectations; | 136 TestExpectations testExpectations; |
| 138 | 137 |
| 139 StandardTestSuite(Map this.configuration, | 138 StandardTestSuite(Map this.configuration, |
| 140 String this.suiteName, | 139 String this.suiteName, |
| 141 String this.directoryPath, | 140 String this.directoryPath, |
| 142 List<String> this.statusFilePaths) { | 141 List<String> this.statusFilePaths); |
| 143 shellPath = TestUtils.dartShellFileName(configuration) ; | |
| 144 } | |
| 145 | |
| 146 | 142 |
| 147 void isTestFile(String filename) => filename.endsWith("Test.dart"); | 143 void isTestFile(String filename) => filename.endsWith("Test.dart"); |
| 148 | 144 |
| 149 void listRecursively() => false; | 145 void listRecursively() => false; |
| 150 | 146 |
| 151 void complexStatusMatching() => false; | 147 void complexStatusMatching() => false; |
| 152 | 148 |
| 149 String shellPath() => TestUtils.dartShellFileName(configuration); |
| 150 |
| 153 List<String> additionalOptions() => []; | 151 List<String> additionalOptions() => []; |
| 154 | 152 |
| 155 void forEachTest(Function onTest, [Function onDone = null]) { | 153 void forEachTest(Function onTest, [Function onDone = null]) { |
| 156 doTest = onTest; | 154 doTest = onTest; |
| 157 doDone = (onDone != null) ? onDone : (() => null); | 155 doDone = (onDone != null) ? onDone : (() => null); |
| 158 | 156 |
| 159 // Read test expectations from status files. | 157 // Read test expectations from status files. |
| 160 testExpectations = | 158 testExpectations = |
| 161 new TestExpectations(complexMatching: complexStatusMatching()); | 159 new TestExpectations(complexMatching: complexStatusMatching()); |
| 162 for (var statusFilePath in statusFilePaths) { | 160 for (var statusFilePath in statusFilePaths) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 192 Function createTestCase(String filename, | 190 Function createTestCase(String filename, |
| 193 bool isNegative, | 191 bool isNegative, |
| 194 [bool isNegativeIfChecked = false, | 192 [bool isNegativeIfChecked = false, |
| 195 bool enableFatalTypeErrors = false]) { | 193 bool enableFatalTypeErrors = false]) { |
| 196 // Look up expectations in status files using a modified file path. | 194 // Look up expectations in status files using a modified file path. |
| 197 String pathSeparator = new Platform().pathSeparator(); | 195 String pathSeparator = new Platform().pathSeparator(); |
| 198 String testName; | 196 String testName; |
| 199 int start = filename.lastIndexOf('src' + pathSeparator); | 197 int start = filename.lastIndexOf('src' + pathSeparator); |
| 200 if (start != -1) { | 198 if (start != -1) { |
| 201 testName = filename.substring(start + 4, filename.length - 5); | 199 testName = filename.substring(start + 4, filename.length - 5); |
| 202 } else { | 200 } else if (optionsFromFile['isMultitest']) { |
| 203 // Only multitests in a temporary directory should reach here. | |
| 204 start = filename.lastIndexOf(pathSeparator); | 201 start = filename.lastIndexOf(pathSeparator); |
| 205 int middle = filename.lastIndexOf('_'); | 202 int middle = filename.lastIndexOf('_'); |
| 206 testName = filename.substring(start + 1, middle) + pathSeparator + | 203 testName = filename.substring(start + 1, middle) + pathSeparator + |
| 207 filename.substring(middle + 1, filename.length - 5); | 204 filename.substring(middle + 1, filename.length - 5); |
| 205 } else { |
| 206 // This case is hit by the dartc client compilation |
| 207 // tests. These tests are pretty broken compared to the |
| 208 // rest. They use the .dart suffix in the status files. They |
| 209 // find tests in weird ways (testing that they contain "#"). |
| 210 // They need to be redone. |
| 211 start = filename.indexOf(directoryPath); |
| 212 testName = filename.substring(start + directoryPath.length + 1, |
| 213 filename.length); |
| 208 } | 214 } |
| 209 Set<String> expectations = testExpectations.expectations(testName); | 215 Set<String> expectations = testExpectations.expectations(testName); |
| 210 if (configuration["report"]) { | 216 if (configuration["report"]) { |
| 211 // Tests with multiple VMOptions are counted more than once. | 217 // Tests with multiple VMOptions are counted more than once. |
| 212 for (var dummy in optionsFromFile["vmOptions"]) { | 218 for (var dummy in optionsFromFile["vmOptions"]) { |
| 213 SummaryReport.add(expectations); | 219 SummaryReport.add(expectations); |
| 214 } | 220 } |
| 215 } | 221 } |
| 216 if (expectations.contains(SKIP)) return; | 222 if (expectations.contains(SKIP)) return; |
| 217 | 223 |
| 218 isNegative = isNegative || | 224 isNegative = isNegative || |
| 219 (configuration['checked'] && isNegativeIfChecked); | 225 (configuration['checked'] && isNegativeIfChecked); |
| 220 var argumentLists = argumentListsFromFile(filename, | 226 var argumentLists = argumentListsFromFile(filename, |
| 221 optionsFromFile, | 227 optionsFromFile, |
| 222 enableFatalTypeErrors); | 228 enableFatalTypeErrors); |
| 223 for (var args in argumentLists) { | 229 for (var args in argumentLists) { |
| 224 doTest(new TestCase(testName, | 230 doTest(new TestCase(testName, |
| 225 shellPath, | 231 shellPath(), |
| 226 args, | 232 args, |
| 227 timeout, | 233 timeout, |
| 228 completeHandler, | 234 completeHandler, |
| 229 expectations, | 235 expectations, |
| 230 isNegative)); | 236 isNegative)); |
| 231 } | 237 } |
| 232 } | 238 } |
| 233 | 239 |
| 234 if (optionsFromFile['isMultitest']) { | 240 if (optionsFromFile['isMultitest']) { |
| 235 bool supportsFatalTypeErrors = (configuration['component'] == 'dartc'); | 241 bool supportsFatalTypeErrors = (configuration['component'] == 'dartc'); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 vmOptions.addAll(args); | 303 vmOptions.addAll(args); |
| 298 result.add(vmOptions); | 304 result.add(vmOptions); |
| 299 } | 305 } |
| 300 | 306 |
| 301 return result; | 307 return result; |
| 302 } | 308 } |
| 303 | 309 |
| 304 Map optionsFromFile(String filename) { | 310 Map optionsFromFile(String filename) { |
| 305 RegExp testOptionsRegExp = const RegExp(@"// VMOptions=(.*)"); | 311 RegExp testOptionsRegExp = const RegExp(@"// VMOptions=(.*)"); |
| 306 RegExp dartOptionsRegExp = const RegExp(@"// DartOptions=(.*)"); | 312 RegExp dartOptionsRegExp = const RegExp(@"// DartOptions=(.*)"); |
| 313 RegExp multiTestRegExp = const RegExp(@"/// [0-9][0-9]:(.*)"); |
| 314 RegExp leadingHashRegExp = const RegExp(@"^#", multiLine: true); |
| 307 | 315 |
| 308 // Read the entire file into a byte buffer and transform it to a | 316 // Read the entire file into a byte buffer and transform it to a |
| 309 // String. This will treat the file as ascii but the only parts | 317 // String. This will treat the file as ascii but the only parts |
| 310 // we are interested in will be ascii in any case. | 318 // we are interested in will be ascii in any case. |
| 311 File file = new File(filename); | 319 File file = new File(filename); |
| 312 file.openSync(); | 320 file.openSync(); |
| 313 List chars = new List(file.lengthSync()); | 321 List chars = new List(file.lengthSync()); |
| 314 var offset = 0; | 322 var offset = 0; |
| 315 while (offset != chars.length) { | 323 while (offset != chars.length) { |
| 316 offset += file.readListSync(chars, offset, chars.length - offset); | 324 offset += file.readListSync(chars, offset, chars.length - offset); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 340 } | 348 } |
| 341 | 349 |
| 342 if (contents.contains("@compile-error") || | 350 if (contents.contains("@compile-error") || |
| 343 contents.contains("@runtime-error")) { | 351 contents.contains("@runtime-error")) { |
| 344 isNegative = true; | 352 isNegative = true; |
| 345 } else if (contents.contains("@dynamic-type-error") && | 353 } else if (contents.contains("@dynamic-type-error") && |
| 346 configuration['checked']) { | 354 configuration['checked']) { |
| 347 isNegative = true; | 355 isNegative = true; |
| 348 } | 356 } |
| 349 | 357 |
| 350 bool isMultitest = contents.contains("///"); | 358 bool isMultitest = multiTestRegExp.hasMatch(contents); |
| 359 bool containsLeadingHash = leadingHashRegExp.hasMatch(contents); |
| 351 | 360 |
| 352 return { "vmOptions": result, | 361 return { "vmOptions": result, |
| 353 "dartOptions": dartOptions, | 362 "dartOptions": dartOptions, |
| 354 "isNegative": isNegative, | 363 "isNegative": isNegative, |
| 355 "isMultitest": isMultitest}; | 364 "isMultitest": isMultitest, |
| 365 "containsLeadingHash" : containsLeadingHash }; |
| 356 } | 366 } |
| 357 } | 367 } |
| 358 | 368 |
| 369 |
| 370 class DartcCompilationTestSuite extends StandardTestSuite { |
| 371 List<String> _testDirs; |
| 372 int activityCount = 0; |
| 373 |
| 374 DartcCompilationTestSuite(Map configuration, |
| 375 String suiteName, |
| 376 String directoryPath, |
| 377 List<String> this._testDirs, |
| 378 List<String> expectations) |
| 379 : super(configuration, |
| 380 suiteName, |
| 381 directoryPath, |
| 382 expectations); |
| 383 |
| 384 void activityStarted() => ++activityCount; |
| 385 |
| 386 void activityCompleted() { |
| 387 if (--activityCount == 0) { |
| 388 directoryListingDone(true); |
| 389 } |
| 390 } |
| 391 |
| 392 String shellPath() => TestUtils.dartcCompilationShellPath(configuration); |
| 393 |
| 394 List<String> additionalOptions() { |
| 395 // TODO(ager): potentially register cleanup action to delete the temporary |
| 396 // directories? |
| 397 var tempDir = new Directory(''); |
| 398 tempDir.createTempSync(); |
| 399 return ['-check-only', '-fatal-type-errors', '-Werror', '-out', tempDir.path
]; |
| 400 } |
| 401 |
| 402 void processDirectory() { |
| 403 directoryPath = getDirname(directoryPath); |
| 404 // Enqueueing the directory listers is an activity. |
| 405 activityStarted(); |
| 406 for (String testDir in _testDirs) { |
| 407 Directory dir = new Directory("$directoryPath/$testDir"); |
| 408 if (dir.existsSync()) { |
| 409 activityStarted(); |
| 410 dir.errorHandler = (s) { |
| 411 throw s; |
| 412 }; |
| 413 dir.fileHandler = processFile; |
| 414 dir.doneHandler = (ignore) => activityCompleted(); |
| 415 dir.list(recursive: listRecursively()); |
| 416 } |
| 417 } |
| 418 // Completed the enqueueing of listers. |
| 419 activityCompleted(); |
| 420 } |
| 421 } |
| 422 |
| 359 | 423 |
| 360 class TestUtils { | 424 class TestUtils { |
| 361 static String executableName(Map configuration) { | 425 static String executableName(Map configuration) { |
| 362 String postfix = | 426 String postfix = |
| 363 (new Platform().operatingSystem() == 'windows') ? '.exe' : ''; | 427 (new Platform().operatingSystem() == 'windows') ? '.exe' : ''; |
| 364 switch (configuration['component']) { | 428 switch (configuration['component']) { |
| 365 case 'vm': | 429 case 'vm': |
| 366 return 'dart$postfix'; | 430 return 'dart$postfix'; |
| 367 case 'dartc': | 431 case 'dartc': |
| 368 return 'compiler/bin/dartc_test$postfix'; | 432 return 'compiler/bin/dartc_test$postfix'; |
| 369 case 'frog': | 433 case 'frog': |
| 370 case 'leg': | 434 case 'leg': |
| 371 return 'frog/bin/frog$postfix'; | 435 return 'frog/bin/frog$postfix'; |
| 372 case 'frogsh': | 436 case 'frogsh': |
| 373 return 'frog/bin/frogsh$postfix'; | 437 return 'frog/bin/frogsh$postfix'; |
| 374 default: | 438 default: |
| 375 throw "Unknown executable for: ${configuration['component']}"; | 439 throw "Unknown executable for: ${configuration['component']}"; |
| 376 } | 440 } |
| 377 } | 441 } |
| 378 | 442 |
| 379 | |
| 380 static String dartShellFileName(Map configuration) { | 443 static String dartShellFileName(Map configuration) { |
| 381 var name = buildDir(configuration) + executableName(configuration); | 444 var name = buildDir(configuration) + executableName(configuration); |
| 382 if (!(new File(name)).existsSync()) { | 445 if (!(new File(name)).existsSync()) { |
| 383 throw "Executable '$name' does not exist"; | 446 throw "Executable '$name' does not exist"; |
| 384 } | 447 } |
| 385 return name; | 448 return name; |
| 386 } | 449 } |
| 387 | 450 |
| 451 static String dartcCompilationShellPath(Map configuration) { |
| 452 var name = buildDir(configuration) + 'compiler/bin/dartc'; |
| 453 if (!(new File(name)).existsSync()) { |
| 454 throw "Executable '$name' does not exist"; |
| 455 } |
| 456 return name; |
| 457 } |
| 458 |
| 388 static String buildDir(Map configuration) { | 459 static String buildDir(Map configuration) { |
| 389 var buildDir = ''; | 460 var buildDir = ''; |
| 390 var system = configuration['system']; | 461 var system = configuration['system']; |
| 391 if (system == 'linux') { | 462 if (system == 'linux') { |
| 392 buildDir = 'out/'; | 463 buildDir = 'out/'; |
| 393 } else if (system == 'macos') { | 464 } else if (system == 'macos') { |
| 394 buildDir = 'xcodebuild/'; | 465 buildDir = 'xcodebuild/'; |
| 395 } | 466 } |
| 396 buildDir += (configuration['mode'] == 'debug') ? 'Debug_' : 'Release_'; | 467 buildDir += (configuration['mode'] == 'debug') ? 'Debug_' : 'Release_'; |
| 397 buildDir += configuration['architecture'] + '/'; | 468 buildDir += configuration['architecture'] + '/'; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 * $noCrash tests are expected to be flaky but not crash | 532 * $noCrash tests are expected to be flaky but not crash |
| 462 * $pass tests are expected to pass | 533 * $pass tests are expected to pass |
| 463 * $failOk tests are expected to fail that we won't fix | 534 * $failOk tests are expected to fail that we won't fix |
| 464 * $fail tests are expected to fail that we should fix | 535 * $fail tests are expected to fail that we should fix |
| 465 * $crash tests are expected to crash that we should fix | 536 * $crash tests are expected to crash that we should fix |
| 466 * $timeout tests are allowed to timeout\ | 537 * $timeout tests are allowed to timeout\ |
| 467 """; | 538 """; |
| 468 print(report); | 539 print(report); |
| 469 } | 540 } |
| 470 } | 541 } |
| OLD | NEW |