| 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 library multitest; | 5 library multitest; |
| 6 | 6 |
| 7 import "dart:async"; | 7 import "dart:async"; |
| 8 import "dart:io"; | 8 import "dart:io"; |
| 9 | 9 |
| 10 import "path.dart"; | 10 import "path.dart"; |
| 11 import "test_suite.dart"; | 11 import "test_suite.dart"; |
| 12 import "utils.dart"; | 12 import "utils.dart"; |
| 13 | 13 |
| 14 // Multitests are Dart test scripts containing lines of the form | 14 // Multitests are Dart test scripts containing lines of the form |
| 15 // " [some dart code] //# [key]: [error type]" |
| 16 // |
| 17 // To support legacy multi tests we also handle lines of the form |
| 15 // " [some dart code] /// [key]: [error type]" | 18 // " [some dart code] /// [key]: [error type]" |
| 16 // | 19 // |
| 17 // For each key in the file, a new test file is made containing all | 20 // For each key in the file, a new test file is made containing all |
| 18 // the normal lines of the file, and all of the multitest lines containing | 21 // the normal lines of the file, and all of the multitest lines containing |
| 19 // that key, in the same order as in the source file. The new test is expected | 22 // that key, in the same order as in the source file. The new test is expected |
| 20 // to pass if the error type listed is 'ok', or to fail if there is an error | 23 // to pass if the error type listed is 'ok', or to fail if there is an error |
| 21 // type of type 'compile-time error', 'runtime error', 'static type warning', or | 24 // type of type 'compile-time error', 'runtime error', 'static type warning', or |
| 22 // 'dynamic type error'. The type error tests fail only in checked mode. | 25 // 'dynamic type error'. The type error tests fail only in checked mode. |
| 23 // There is also a test created from only the untagged lines of the file, | 26 // There is also a test created from only the untagged lines of the file, |
| 24 // with key "none", which is expected to pass. This library extracts these | 27 // with key "none", which is expected to pass. This library extracts these |
| 25 // tests, writes them into a temporary directory, and passes them to the test | 28 // tests, writes them into a temporary directory, and passes them to the test |
| 26 // runner. These tests may be referred to in the status files with the | 29 // runner. These tests may be referred to in the status files with the |
| 27 // pattern [test name]/[key]. | 30 // pattern [test name]/[key]. |
| 28 // | 31 // |
| 29 // For example: file I_am_a_multitest.dart | 32 // For example: file I_am_a_multitest.dart |
| 30 // aaa | 33 // aaa |
| 31 // bbb /// 02: runtime error | 34 // bbb //# 02: runtime error |
| 32 // ccc /// 02: continued | 35 // ccc //# 02: continued |
| 33 // ddd /// 07: static type warning | 36 // ddd //# 07: static type warning |
| 34 // eee /// 10: ok | 37 // eee //# 10: ok |
| 35 // fff | 38 // fff |
| 36 // | 39 // |
| 37 // should create four tests: | 40 // should create four tests: |
| 38 // I_am_a_multitest_none.dart | 41 // I_am_a_multitest_none.dart |
| 39 // aaa | 42 // aaa |
| 40 // fff | 43 // fff |
| 41 // | 44 // |
| 42 // I_am_a_multitest_02.dart | 45 // I_am_a_multitest_02.dart |
| 43 // aaa | 46 // aaa |
| 44 // bbb /// 02: runtime error | 47 // bbb //# 02: runtime error |
| 45 // ccc /// 02: continued | 48 // ccc //# 02: continued |
| 46 // fff | 49 // fff |
| 47 // | 50 // |
| 48 // I_am_a_multitest_07.dart | 51 // I_am_a_multitest_07.dart |
| 49 // aaa | 52 // aaa |
| 50 // ddd /// 07: static type warning | 53 // ddd //# 07: static type warning |
| 51 // fff | 54 // fff |
| 52 // | 55 // |
| 53 // and I_am_a_multitest_10.dart | 56 // and I_am_a_multitest_10.dart |
| 54 // aaa | 57 // aaa |
| 55 // eee /// 10: ok | 58 // eee //# 10: ok |
| 56 // fff | 59 // fff |
| 57 // | 60 // |
| 58 // Note that it is possible to indicate more than one acceptable outcome | 61 // Note that it is possible to indicate more than one acceptable outcome |
| 59 // in the case of dynamic and static type warnings | 62 // in the case of dynamic and static type warnings |
| 60 // aaa | 63 // aaa |
| 61 // ddd /// 07: static type warning, dynamic type error | 64 // ddd //# 07: static type warning, dynamic type error |
| 62 // fff | 65 // fff |
| 63 | 66 |
| 67 /// Until legacy multitests are ported we need to support both /// and //# |
| 68 final _multitestMarker = new RegExp(r"//[/#]"); |
| 69 |
| 64 void ExtractTestsFromMultitest(Path filePath, Map<String, String> tests, | 70 void ExtractTestsFromMultitest(Path filePath, Map<String, String> tests, |
| 65 Map<String, Set<String>> outcomes) { | 71 Map<String, Set<String>> outcomes) { |
| 66 // Read the entire file into a byte buffer and transform it to a | 72 // Read the entire file into a byte buffer and transform it to a |
| 67 // String. This will treat the file as ascii but the only parts | 73 // String. This will treat the file as ascii but the only parts |
| 68 // we are interested in will be ascii in any case. | 74 // we are interested in will be ascii in any case. |
| 69 List bytes = new File(filePath.toNativePath()).readAsBytesSync(); | 75 List bytes = new File(filePath.toNativePath()).readAsBytesSync(); |
| 70 String contents = decodeUtf8(bytes); | 76 String contents = decodeUtf8(bytes); |
| 71 int first_newline = contents.indexOf('\n'); | 77 int first_newline = contents.indexOf('\n'); |
| 72 final String line_separator = (first_newline == 0 || | 78 final String line_separator = |
| 73 contents[first_newline - 1] != '\r') ? '\n' : '\r\n'; | 79 (first_newline == 0 || contents[first_newline - 1] != '\r') |
| 80 ? '\n' |
| 81 : '\r\n'; |
| 74 List<String> lines = contents.split(line_separator); | 82 List<String> lines = contents.split(line_separator); |
| 75 if (lines.last == '') lines.removeLast(); | 83 if (lines.last == '') lines.removeLast(); |
| 76 bytes = null; | 84 bytes = null; |
| 77 contents = null; | 85 contents = null; |
| 78 Set<String> validMultitestOutcomes = new Set<String>.from([ | 86 Set<String> validMultitestOutcomes = new Set<String>.from([ |
| 79 'ok', | 87 'ok', |
| 80 'compile-time error', | 88 'compile-time error', |
| 81 'runtime error', | 89 'runtime error', |
| 82 'static type warning', | 90 'static type warning', |
| 83 'dynamic type error', | 91 'dynamic type error', |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 // If a key/multitest was marked for deletion, do the necessary cleanup. | 149 // If a key/multitest was marked for deletion, do the necessary cleanup. |
| 142 keysToDelete.forEach(outcomes.remove); | 150 keysToDelete.forEach(outcomes.remove); |
| 143 keysToDelete.forEach(testsAsLines.remove); | 151 keysToDelete.forEach(testsAsLines.remove); |
| 144 | 152 |
| 145 // Copy all the tests into the output map tests, as multiline strings. | 153 // Copy all the tests into the output map tests, as multiline strings. |
| 146 for (String key in testsAsLines.keys) { | 154 for (String key in testsAsLines.keys) { |
| 147 tests[key] = testsAsLines[key].join(line_separator); | 155 tests[key] = testsAsLines[key].join(line_separator); |
| 148 } | 156 } |
| 149 } | 157 } |
| 150 | 158 |
| 151 // Represents a mutlitest annotation in the special /// comment. | 159 // Represents a mutlitest annotation in the special //# comment. |
| 152 class _Annotation { | 160 class _Annotation { |
| 153 String key; | 161 String key; |
| 154 String rest; | 162 String rest; |
| 155 List<String> outcomesList; | 163 List<String> outcomesList; |
| 156 _Annotation() {} | 164 _Annotation() {} |
| 157 factory _Annotation.from(String line) { | 165 factory _Annotation.from(String line) { |
| 158 // Do an early return with "null" if this is not a valid multitest | 166 // Do an early return with "null" if this is not a valid multitest |
| 159 // annotation. | 167 // annotation. |
| 160 if (!line.contains('///')) { | 168 if (!line.contains(_multitestMarker)) { |
| 161 return null; | 169 return null; |
| 162 } | 170 } |
| 163 var parts = line | 171 var parts = line |
| 164 .split('///')[1] | 172 .split(_multitestMarker)[1] |
| 165 .split(':') | 173 .split(':') |
| 166 .map((s) => s.trim()) | 174 .map((s) => s.trim()) |
| 167 .where((s) => s.length > 0) | 175 .where((s) => s.length > 0) |
| 168 .toList(); | 176 .toList(); |
| 169 if (parts.length <= 1) { | 177 if (parts.length <= 1) { |
| 170 return null; | 178 return null; |
| 171 } | 179 } |
| 172 | 180 |
| 173 var annotation = new _Annotation(); | 181 var annotation = new _Annotation(); |
| 174 annotation.key = parts[0]; | 182 annotation.key = parts[0]; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 } | 221 } |
| 214 foundImports.add(relativePath.toString()); | 222 foundImports.add(relativePath.toString()); |
| 215 toSearch.add(libraryDir.join(relativePath)); | 223 toSearch.add(libraryDir.join(relativePath)); |
| 216 } | 224 } |
| 217 } | 225 } |
| 218 } | 226 } |
| 219 } | 227 } |
| 220 return foundImports; | 228 return foundImports; |
| 221 } | 229 } |
| 222 | 230 |
| 223 Future doMultitest( | 231 Future doMultitest(Path filePath, String outputDir, Path suiteDir, |
| 224 Path filePath, | 232 CreateTest doTest, bool hotReload) { |
| 225 String outputDir, | |
| 226 Path suiteDir, | |
| 227 CreateTest doTest, | |
| 228 bool hotReload) { | |
| 229 void writeFile(String filepath, String content) { | 233 void writeFile(String filepath, String content) { |
| 230 final File file = new File(filepath); | 234 final File file = new File(filepath); |
| 231 | 235 |
| 232 if (file.existsSync()) { | 236 if (file.existsSync()) { |
| 233 var oldContent = file.readAsStringSync(); | 237 var oldContent = file.readAsStringSync(); |
| 234 if (oldContent == content) { | 238 if (oldContent == content) { |
| 235 // Don't write to the file if the content is the same | 239 // Don't write to the file if the content is the same |
| 236 return; | 240 return; |
| 237 } | 241 } |
| 238 } | 242 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 var split = suiteDir.segments(); | 303 var split = suiteDir.segments(); |
| 300 // co19 test suite is at tests/co19/src. | 304 // co19 test suite is at tests/co19/src. |
| 301 if (split.last == 'src') { | 305 if (split.last == 'src') { |
| 302 split.removeLast(); | 306 split.removeLast(); |
| 303 } | 307 } |
| 304 return split.last; | 308 return split.last; |
| 305 } | 309 } |
| 306 | 310 |
| 307 Path createMultitestDirectory(String outputDir, Path suiteDir, Path sourceDir) { | 311 Path createMultitestDirectory(String outputDir, Path suiteDir, Path sourceDir) { |
| 308 Path relative = sourceDir.relativeTo(suiteDir); | 312 Path relative = sourceDir.relativeTo(suiteDir); |
| 309 Path path = new Path(outputDir).append('generated_tests') | 313 Path path = new Path(outputDir) |
| 310 .append(suiteNameFromPath(suiteDir)).join(relative); | 314 .append('generated_tests') |
| 315 .append(suiteNameFromPath(suiteDir)) |
| 316 .join(relative); |
| 311 TestUtils.mkdirRecursive(TestUtils.currentWorkingDirectory, path); | 317 TestUtils.mkdirRecursive(TestUtils.currentWorkingDirectory, path); |
| 312 return new Path(new File(path.toNativePath()).absolute.path); | 318 return new Path(new File(path.toNativePath()).absolute.path); |
| 313 } | 319 } |
| OLD | NEW |