| 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("multitest"); | 5 #library("multitest"); |
| 6 | 6 |
| 7 #import("dart:io"); | 7 #import("dart:io"); |
| 8 #import("test_suite.dart"); | |
| 9 | 8 |
| 10 // Multitests are Dart test scripts containing lines of the form | 9 // Multitests are Dart test scripts containing lines of the form |
| 11 // " [some dart code] /// [key]: [error type]" | 10 // " [some dart code] /// [key]: [error type]" |
| 12 // | 11 // |
| 13 // For each key in the file, a new test file is made containing all | 12 // For each key in the file, a new test file is made containing all |
| 14 // the normal lines of the file, and all of the multitest lines containing | 13 // the normal lines of the file, and all of the multitest lines containing |
| 15 // that key, in the same order as in the source file. The new test | 14 // that key, in the same order as in the source file. The new test |
| 16 // is expected to fail if there is a non-empty error type listed, of | 15 // is expected to fail if there is a non-empty error type listed, of |
| 17 // type 'compile-time error', 'runtime error', 'static type error', or | 16 // type 'compile-time error', 'runtime error', 'static type error', or |
| 18 // 'dynamic type error'. The type error tests fail only in checked mode. | 17 // 'dynamic type error'. The type error tests fail only in checked mode. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 Set<String> validMultitestOutcomes = new Set<String>.from( | 70 Set<String> validMultitestOutcomes = new Set<String>.from( |
| 72 ['compile-time error', 'runtime error', | 71 ['compile-time error', 'runtime error', |
| 73 'static type error', 'dynamic type error', '']); | 72 'static type error', 'dynamic type error', '']); |
| 74 | 73 |
| 75 List<String> testTemplate = new List<String>(); | 74 List<String> testTemplate = new List<String>(); |
| 76 testTemplate.add('// Test created from multitest named $filename.'); | 75 testTemplate.add('// Test created from multitest named $filename.'); |
| 77 // Create the set of multitests, which will have a new test added each | 76 // Create the set of multitests, which will have a new test added each |
| 78 // time we see a multitest line with a new key. | 77 // time we see a multitest line with a new key. |
| 79 Map<String, List<String>> testsAsLines = new Map<String, List<String>>(); | 78 Map<String, List<String>> testsAsLines = new Map<String, List<String>>(); |
| 80 | 79 |
| 80 // Matches #import( or #source( followed by " or ' followed by anything |
| 81 // except dart: or /, at the beginning of a line. |
| 82 RegExp relativeImportRegExp = |
| 83 const RegExp('^#(import|source)[(]["\'](?!(dart:|/))'); |
| 81 int lineCount = 0; | 84 int lineCount = 0; |
| 82 for (String line in lines) { | 85 for (String line in lines) { |
| 83 lineCount++; | 86 lineCount++; |
| 84 if (line.contains('///')) { | 87 if (line.contains('///')) { |
| 85 var parts = line.split('///')[1].split(':'); | 88 var parts = line.split('///')[1].split(':'); |
| 86 var key = parts[0].trim(); | 89 var key = parts[0].trim(); |
| 87 var rest = parts[1].trim(); | 90 var rest = parts[1].trim(); |
| 88 if (testsAsLines.containsKey(key)) { | 91 if (testsAsLines.containsKey(key)) { |
| 89 Expect.equals('continued', rest); | 92 Expect.equals('continued', rest); |
| 90 testsAsLines[key].add(line); | 93 testsAsLines[key].add(line); |
| 91 } else { | 94 } else { |
| 92 (testsAsLines[key] = new List<String>.from(testTemplate)).add(line); | 95 (testsAsLines[key] = new List<String>.from(testTemplate)).add(line); |
| 93 outcomes[key] = rest; | 96 outcomes[key] = rest; |
| 94 if (!validMultitestOutcomes.contains(rest)) { | 97 if (!validMultitestOutcomes.contains(rest)) { |
| 95 Expect.fail("Invalid test directive on line ${lineCount}: $rest "); | 98 Expect.fail("Invalid test directive on line ${lineCount}: $rest "); |
| 96 } | 99 } |
| 97 } | 100 } |
| 98 } else { | 101 } else { |
| 99 testTemplate.add(line); | 102 testTemplate.add(line); |
| 100 for (var test in testsAsLines.getValues()) test.add(line); | 103 for (var test in testsAsLines.getValues()) test.add(line); |
| 101 } | 104 } |
| 105 // Warn if any import or source tags have relative paths. |
| 106 if (relativeImportRegExp.hasMatch(line)) { |
| 107 print('Warning: Multitest cannot contain relative imports:'); |
| 108 print(' $filename: $line'); |
| 109 } |
| 102 } | 110 } |
| 103 // Add the template, with no multitest lines, as a test with key 'none'. | 111 // Add the template, with no multitest lines, as a test with key 'none'. |
| 104 testsAsLines['none'] = testTemplate; | 112 testsAsLines['none'] = testTemplate; |
| 105 outcomes['none'] = ''; | 113 outcomes['none'] = ''; |
| 106 | 114 |
| 107 // Copy all the tests into the output map tests, as multiline strings. | 115 // Copy all the tests into the output map tests, as multiline strings. |
| 108 for (String key in testsAsLines.getKeys()) { | 116 for (String key in testsAsLines.getKeys()) { |
| 109 tests[key] = | 117 tests[key] = |
| 110 Strings.join(testsAsLines[key], line_separator) + line_separator; | 118 Strings.join(testsAsLines[key], line_separator) + line_separator; |
| 111 } | 119 } |
| 112 } | 120 } |
| 113 | 121 |
| 114 // Find all relative imports and copy them into the dir that contains | |
| 115 // the generated tests. | |
| 116 Set<String> _findAllRelativeImports(String topLibrary) { | |
| 117 Set<String> toSearch = new Set<String>.from([topLibrary]); | |
| 118 Set<String> foundImports = new HashSet<String>(); | |
| 119 String pathSep = new Platform().pathSeparator(); | |
| 120 int end = topLibrary.lastIndexOf(pathSep); | |
| 121 String libraryDir = topLibrary.substring(0, end); | |
| 122 | |
| 123 // Matches #import( or #source( followed by " or ' followed by anything | |
| 124 // except dart: or /, at the beginning of a line. | |
| 125 RegExp relativeImportRegExp = | |
| 126 const RegExp('^#(import|source)[(]["\'](?!(dart:|/))([^"\']*)["\']'); | |
| 127 while (!toSearch.isEmpty()) { | |
| 128 var thisPass = toSearch; | |
| 129 toSearch = new HashSet<String>(); | |
| 130 for (String filename in thisPass) { | |
| 131 File f = new File(filename); | |
| 132 for (String line in f.readAsLinesSync()) { | |
| 133 Match match = relativeImportRegExp.firstMatch(line); | |
| 134 if (match != null) { | |
| 135 String relativePath = match.group(3); | |
| 136 if (foundImports.contains(relativePath)) { | |
| 137 continue; | |
| 138 } | |
| 139 if (relativePath.contains(@'\.\.')) { | |
| 140 // This is just for safety reasons, we don't want | |
| 141 // to unintentionally clobber files relative to the destination | |
| 142 // dir when copying them ove. | |
| 143 Expect.fail("relative paths containing .. are not allowed."); | |
| 144 } | |
| 145 foundImports.add(relativePath); | |
| 146 toSearch.add('$libraryDir/$relativePath'); | |
| 147 } | |
| 148 } | |
| 149 } | |
| 150 } | |
| 151 return foundImports; | |
| 152 } | |
| 153 | 122 |
| 154 void DoMultitest(String filename, | 123 void DoMultitest(String filename, |
| 155 String outputDir, | 124 String outputDir, |
| 156 String testDir, | 125 String testDir, |
| 157 Function doTest(String filename, | 126 Function doTest(String filename, |
| 158 bool isNegative, | 127 bool isNegative, |
| 159 [bool isNegativeIfChecked, | 128 [bool isNegativeIfChecked, |
| 160 bool hasFatalTypeErrors, | 129 bool hasFatalTypeErrors, |
| 161 bool hasRuntimeErrors]), | 130 bool hasRuntimeErrors]), |
| 162 Function multitestDone) { | 131 Function multitestDone) { |
| 163 // Each new test is a single String value in the Map tests. | 132 // Each new test is a single String value in the Map tests. |
| 164 Map<String, String> tests = new Map<String, String>(); | 133 Map<String, String> tests = new Map<String, String>(); |
| 165 Map<String, String> outcomes = new Map<String, String>(); | 134 Map<String, String> outcomes = new Map<String, String>(); |
| 166 ExtractTestsFromMultitest(filename, tests, outcomes); | 135 ExtractTestsFromMultitest(filename, tests, outcomes); |
| 167 | 136 |
| 168 String directory = CreateMultitestDirectory(outputDir, testDir); | 137 String directory = CreateMultitestDirectory(outputDir, testDir); |
| 169 Expect.isNotNull(directory); | 138 String pathSeparator = new Platform().pathSeparator(); |
| 170 String pathSep = new Platform().pathSeparator(); | 139 int start = filename.lastIndexOf(pathSeparator) + 1; |
| 171 int start = filename.lastIndexOf(pathSep) + 1; | |
| 172 int end = filename.indexOf('.dart', start); | 140 int end = filename.indexOf('.dart', start); |
| 173 String baseFilename = filename.substring(start, end); | 141 String baseFilename = filename.substring(start, end); |
| 174 String sourceDirectory = filename.substring(0, start - 1); | |
| 175 Set<String> importsToCopy = _findAllRelativeImports(filename); | |
| 176 Directory destDir = new Directory("directory"); | |
| 177 for (String import in importsToCopy) { | |
| 178 File source = new File('$sourceDirectory/$import'); | |
| 179 var dest = new File('$directory/$import'); | |
| 180 var basenameStart = import.lastIndexOf('/'); | |
| 181 if (basenameStart > 0) { | |
| 182 // make sure we have a dir for it | |
| 183 var importDir = import.substring(0, basenameStart); | |
| 184 TestUtils.mkdirRecursive(directory, importDir); | |
| 185 } | |
| 186 TestUtils.copyFile(source, dest); | |
| 187 } | |
| 188 for (String key in tests.getKeys()) { | 142 for (String key in tests.getKeys()) { |
| 189 final String filename = '$directory/${baseFilename}_$key.dart'; | 143 final String filename = '$directory/${baseFilename}_$key.dart'; |
| 190 final File file = new File(filename); | 144 final File file = new File(filename); |
| 191 | 145 |
| 192 file.createSync(); | 146 file.createSync(); |
| 193 RandomAccessFile openedFile = file.openSync(FileMode.WRITE); | 147 RandomAccessFile openedFile = file.openSync(FileMode.WRITE); |
| 194 var bytes = tests[key].charCodes(); | 148 var bytes = tests[key].charCodes(); |
| 195 openedFile.writeListSync(bytes, 0, bytes.length); | 149 openedFile.writeListSync(bytes, 0, bytes.length); |
| 196 openedFile.closeSync(); | 150 openedFile.closeSync(); |
| 197 var outcome = outcomes[key]; | 151 var outcome = outcomes[key]; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 222 var split = testDir.split('/'); | 176 var split = testDir.split('/'); |
| 223 var lastComponent = split.removeLast(); | 177 var lastComponent = split.removeLast(); |
| 224 Expect.isTrue(lastComponent == 'src'); | 178 Expect.isTrue(lastComponent == 'src'); |
| 225 String path = '${generatedTestDir.path}/${split.last()}'; | 179 String path = '${generatedTestDir.path}/${split.last()}'; |
| 226 Directory dir = new Directory(path); | 180 Directory dir = new Directory(path); |
| 227 if (!dir.existsSync()) { | 181 if (!dir.existsSync()) { |
| 228 dir.createSync(); | 182 dir.createSync(); |
| 229 } | 183 } |
| 230 return path; | 184 return path; |
| 231 } | 185 } |
| OLD | NEW |