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 |