| 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, |
| 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); |
| 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)); |
| 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. |
| 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(""); |
| 129 dir.errorHandler = |
| 130 (error) { Expect.fail("Error creating temp directory: $error"); }; |
| 131 |
| 132 dir.createTempHandler = () { |
| 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'); |
| 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 |