Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 #library("multitest"); | |
| 6 | |
| 7 // Multitests are Dart test scripts containing lines of the form | |
| 8 // " [some dart code] /// [key]: [error type]" | |
| 9 // | |
| 10 // For each key in the file, a new test file is made containing all | |
| 11 // the normal lines of the file, and all of the multitest lines containing | |
| 12 // that key, in the same order as in the source file. The new test | |
| 13 // is expected to fail if there is a non-empty error type listed, of | |
| 14 // type 'compile-time error', 'runtime error', 'static type error', or | |
| 15 // 'dynamic type error'. The type error tests fail only in checked mode. | |
| 16 // There is also a test created from only the untagged lines of the file, | |
| 17 // with key "none", which is expected to pass. This library extracts these | |
| 18 // tests, writes them into a temporary directory, and passes them to the test | |
| 19 // runner. These tests may be referred to in the status files with the | |
| 20 // pattern [test name]/[key]. | |
| 21 // | |
| 22 // For example: file I_am_a_multitest.dart | |
| 23 // aaa | |
| 24 // bbb /// 02: runtime error | |
| 25 // ccc /// 02: continued | |
| 26 // ddd /// 07: static type error | |
| 27 // eee | |
| 28 // | |
| 29 // should create three tests: | |
| 30 // I_am_a_multitest_none.dart | |
| 31 // aaa | |
| 32 // eee | |
| 33 // | |
| 34 // I_am_a_multitest_02.dart | |
| 35 // aaa | |
| 36 // bbb /// 02: runtime error | |
| 37 // ccc /// 02: continued | |
| 38 // eee | |
| 39 // | |
| 40 // and I_am_a_multitest_07.dart | |
| 41 // aaa | |
| 42 // ddd /// 07: static type error | |
| 43 // eee | |
| 44 | |
| 45 void ExtractTestsFromMultitest(String filename, | |
| 46 Map<String, String> tests, | |
|
Mads Ager (google)
2011/11/30 09:11:23
Identation.
Bill Hesse
2011/11/30 10:01:39
Done.
| |
| 47 Map<String, String> outcomes) { | |
| 48 // Read the entire file into a byte buffer and transform it to a | |
| 49 // String. This will treat the file as ascii but the only parts | |
| 50 // we are interested in will be ascii in any case. | |
| 51 File file = new File(filename); | |
| 52 file.openSync(); | |
| 53 List chars = new List(file.lengthSync()); | |
| 54 int offset = 0; | |
| 55 while (offset != chars.length) { | |
| 56 offset += file.readListSync(chars, offset, chars.length - offset); | |
| 57 } | |
| 58 file.closeSync(); | |
| 59 String contents = new String.fromCharCodes(chars); | |
| 60 chars = null; | |
| 61 int first_newline = contents.indexOf('\n'); | |
| 62 final String line_separator = | |
| 63 (first_newline == 0 || contents[first_newline - 1] != '\r') | |
| 64 ? '\n' | |
| 65 : '\r\n'; | |
| 66 List<String> lines = contents.split(line_separator); | |
| 67 if (lines.last() == '') lines.removeLast(); | |
| 68 contents = null; | |
| 69 Set<String> validMultitestOutcomes = new Set<String>.from( | |
| 70 ['compile-time error', 'runtime error', | |
| 71 'static type error', 'dynamic type error', '']); | |
| 72 | |
| 73 List<String> testTemplate = new List<String>(); | |
| 74 testTemplate.add('// Test created from multitest named $filename.'); | |
| 75 // Create the set of multitests, which will have a new test added each | |
| 76 // time we see a multitest line with a new key. | |
| 77 Map<String, List<String>> testsAsLines = new Map<String, List<String>>(); | |
| 78 | |
| 79 for (String line in lines) { | |
| 80 if (line.contains('///')) { | |
| 81 var parts = line.split('///')[1].split(':'); | |
| 82 var key = parts[0].trim(); | |
| 83 var rest = parts[1].trim(); | |
| 84 if (testsAsLines.containsKey(key)) { | |
| 85 Expect.equals('continued', rest); | |
|
Mads Ager (google)
2011/11/30 09:11:23
Should we always throw an exception here? Users wi
Bill Hesse
2011/11/30 10:01:39
I was under the impression that Expect always chec
| |
| 86 testsAsLines[key].add(line); | |
| 87 } else { | |
| 88 (testsAsLines[key] = new List<String>.from(testTemplate)).add(line); | |
| 89 outcomes[key] = rest; | |
| 90 Expect.isTrue(validMultitestOutcomes.contains(rest)); | |
|
Mads Ager (google)
2011/11/30 09:11:23
Ditto.
| |
| 91 } | |
| 92 } else { | |
| 93 if ((line.startsWith('#import(') || line.startsWith('#source(')) && | |
| 94 !line.contains("dart:")) { | |
| 95 // TODO(whesse): Rewrite relative paths to reflect temporary directory. | |
|
Mads Ager (google)
2011/11/30 09:11:23
Why does this work if we don't do this? Where are
Bill Hesse
2011/11/30 10:01:39
Only one multitest has an #import, and so only tha
| |
| 96 tests = []; | |
| 97 outcomes = []; | |
| 98 return; | |
| 99 } | |
| 100 testTemplate.add(line); | |
| 101 for (var test in testsAsLines.getValues()) test.add(line); | |
| 102 } | |
| 103 } | |
| 104 // Add the template, with no multitest lines, as a test with key 'none'. | |
| 105 testsAsLines['none'] = testTemplate; | |
| 106 outcomes['none'] = ''; | |
| 107 | |
| 108 // Copy all the tests into the output map tests, as multiline strings. | |
| 109 for (String key in testsAsLines.getKeys()) { | |
| 110 tests[key] = | |
| 111 Strings.join(testsAsLines[key], line_separator) + line_separator; | |
| 112 } | |
| 113 } | |
| 114 | |
| 115 | |
| 116 void DoMultitest(String filename, | |
| 117 Function doTest(List<String> args, | |
| 118 bool isNegative, | |
| 119 bool isNegativeIfChecked)) { | |
| 120 // Each new test is a single String value in the Map tests. | |
| 121 Map<String, String> tests = new Map<String, String>(); | |
| 122 Map<String, String> outcomes = new Map<String, String>(); | |
| 123 ExtractTestsFromMultitest(filename, tests, outcomes); | |
| 124 String pathSeparator = new Platform().pathSeparator(); | |
| 125 int start = filename.lastIndexOf(pathSeparator) + 1; | |
| 126 int end = filename.indexOf('.dart', start); | |
| 127 String baseFilename = filename.substring(start, end); | |
| 128 Directory dir = new Directory(""); | |
|
Mads Ager (google)
2011/11/30 09:11:23
Could you add a TODO here. We should make sure to
Bill Hesse
2011/11/30 10:01:39
OK, I didn't think of using the build directory.
| |
| 129 dir.errorHandler = | |
| 130 (error) { Expect.fail("Error creating temp directory: $error"); }; | |
|
Mads Ager (google)
2011/11/30 09:11:23
Maybe just throw exception?
| |
| 131 | |
| 132 dir.createTempHandler = (){ | |
|
Mads Ager (google)
2011/11/30 09:11:23
space between '()' and '{'
Also multiple occurren
| |
| 133 String path = dir.path + new Platform().pathSeparator(); | |
| 134 Iterator currentKey = tests.getKeys().iterator(); | |
| 135 WriteMultitestToFileAndQueueIt(tests, outcomes, currentKey, | |
| 136 '$path$baseFilename', doTest); | |
| 137 }; | |
| 138 | |
| 139 dir.createTemp(); | |
| 140 } | |
| 141 | |
| 142 | |
| 143 // Write multiple tests to files, using tail recursion in a callback | |
| 144 // to serialize the file operations, rather than opening all files at once. | |
| 145 WriteMultitestToFileAndQueueIt(Map<String, String> tests, | |
| 146 Map<String, String> outcomes, | |
| 147 Iterator currentKey, | |
| 148 String basePath, | |
| 149 Function doTest) { | |
| 150 if (!currentKey.hasNext()) return; | |
| 151 final String key = currentKey.next(); | |
| 152 final String filename = '${basePath}_$key.dart'; | |
| 153 final File file = new File(filename); | |
| 154 file.errorHandler = (error) { | |
| 155 Expect.fail("Error creating temp file: $error"); | |
| 156 }; | |
| 157 file.createHandler = (){ | |
| 158 file.open(writable: true); | |
| 159 }; | |
| 160 file.openHandler = (){ | |
| 161 var bytes = tests[key].charCodes(); | |
| 162 file.writeList(bytes, 0, bytes.length); | |
| 163 }; | |
| 164 file.noPendingWriteHandler =(){ | |
| 165 file.close(); | |
| 166 }; | |
| 167 file.closeHandler = (){ | |
| 168 var outcome = outcomes[key]; | |
| 169 bool isNegative = outcome.contains('compile-time error') || | |
| 170 outcome.contains('runtime error'); | |
|
Mads Ager (google)
2011/11/30 09:11:23
Indentation.
| |
| 171 bool isNegativeIfChecked = outcome.contains('type error'); | |
| 172 doTest(filename, isNegative, isNegativeIfChecked); | |
| 173 // TODO(whesse): Register files and directories to be deleted. | |
| 174 // They should be registered in a persistent list, so they can | |
| 175 // be deleted later even if the test script is interrupted. | |
| 176 WriteMultitestToFileAndQueueIt(tests, outcomes, currentKey, | |
| 177 basePath, doTest); | |
| 178 }; | |
| 179 file.create(); | |
| 180 } | |
| OLD | NEW |