| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 status_clean; | 5 library status_clean; |
| 6 | 6 |
| 7 import "dart:async"; | 7 import "dart:async"; |
| 8 import "dart:convert" show JSON, UTF8; | 8 import "dart:convert" show JSON, UTF8; |
| 9 import "dart:io"; | 9 import "dart:io"; |
| 10 import "testing/dart/multitest.dart"; | 10 import "testing/dart/multitest.dart"; |
| 11 import "testing/dart/status_file_parser.dart"; | 11 import "testing/dart/status_file_parser.dart"; |
| 12 import "testing/dart/test_suite.dart" | 12 import "testing/dart/test_suite.dart" |
| 13 show multiHtmlTestGroupRegExp, multiTestRegExp, multiHtmlTestRegExp, | 13 show |
| 14 TestUtils; | 14 multiHtmlTestGroupRegExp, |
| 15 multiTestRegExp, |
| 16 multiHtmlTestRegExp, |
| 17 TestUtils; |
| 15 import "testing/dart/utils.dart" show Path; | 18 import "testing/dart/utils.dart" show Path; |
| 16 | 19 |
| 17 // [STATUS_TUPLES] is a list of (suite-name, directory, status-file)-tuples. | 20 // [STATUS_TUPLES] is a list of (suite-name, directory, status-file)-tuples. |
| 18 final STATUS_TUPLES = [ | 21 final STATUS_TUPLES = [ |
| 19 ["corelib", "tests/corelib", "tests/corelib/corelib.status"], | 22 ["corelib", "tests/corelib", "tests/corelib/corelib.status"], |
| 20 ["html", "tests/html", "tests/html/html.status"], | 23 ["html", "tests/html", "tests/html/html.status"], |
| 21 ["isolate", "tests/isolate", "tests/isolate/isolate.status"], | 24 ["isolate", "tests/isolate", "tests/isolate/isolate.status"], |
| 22 ["language", "tests/language", "tests/language/language.status"], | 25 ["language", "tests/language", "tests/language/language.status"], |
| 23 ["language", "tests/language", "tests/language/language_analyzer2.status"], | 26 ["language", "tests/language", "tests/language/language_analyzer2.status"], |
| 24 ["language","tests/language", "tests/language/language_analyzer.status"], | 27 ["language", "tests/language", "tests/language/language_analyzer.status"], |
| 25 ["language","tests/language", "tests/language/language_dart2js.status"], | 28 ["language", "tests/language", "tests/language/language_dart2js.status"], |
| 26 ["lib", "tests/lib", "tests/lib/lib.status"], | 29 ["lib", "tests/lib", "tests/lib/lib.status"], |
| 27 ["standalone", "tests/standalone", "tests/standalone/standalone.status"], | 30 ["standalone", "tests/standalone", "tests/standalone/standalone.status"], |
| 28 ["pkg", "pkg", "pkg/pkg.status"], | 31 ["pkg", "pkg", "pkg/pkg.status"], |
| 29 ["pkgbuild", ".", "pkg/pkgbuild.status"], | 32 ["pkgbuild", ".", "pkg/pkgbuild.status"], |
| 30 ["utils", "tests/utils", "tests/utils/utils.status"], | 33 ["utils", "tests/utils", "tests/utils/utils.status"], |
| 31 ["samples", "samples", "samples/samples.status"], | 34 ["samples", "samples", "samples/samples.status"], |
| 32 ["analyze_library", "sdk", "tests/lib/analyzer/analyze_library.status"], | 35 ["analyze_library", "sdk", "tests/lib/analyzer/analyze_library.status"], |
| 33 ["dart2js_extra", "tests/compiler/dart2js_extra", | 36 [ |
| 34 "tests/compiler/dart2js_extra/dart2js_extra.status"], | 37 "dart2js_extra", |
| 35 ["dart2js_native", "tests/compiler/dart2js_native", | 38 "tests/compiler/dart2js_extra", |
| 36 "tests/compiler/dart2js_native/dart2js_native.status"], | 39 "tests/compiler/dart2js_extra/dart2js_extra.status" |
| 37 ["dart2js", "tests/compiler/dart2js", | 40 ], |
| 38 "tests/compiler/dart2js/dart2js.status"], | 41 [ |
| 39 ["benchmark_smoke", "tests/benchmark_smoke", | 42 "dart2js_native", |
| 40 "tests/benchmark_smoke/benchmark_smoke.status"], | 43 "tests/compiler/dart2js_native", |
| 41 ["co19", "tests/co19/src", "tests/co19/co19-analyzer2.status"], | 44 "tests/compiler/dart2js_native/dart2js_native.status" |
| 42 ["co19", "tests/co19/src", "tests/co19/co19-analyzer.status"], | 45 ], |
| 43 ["co19", "tests/co19/src", "tests/co19/co19-dart2js.status"], | 46 [ |
| 44 ["co19", "tests/co19/src", "tests/co19/co19-co19.status"], | 47 "dart2js", |
| 45 ["co19", "tests/co19/src", "tests/co19/co19-dartium.status"], | 48 "tests/compiler/dart2js", |
| 46 ["co19", "tests/co19/src", "tests/co19/co19-runtime.status"], | 49 "tests/compiler/dart2js/dart2js.status" |
| 50 ], |
| 51 [ |
| 52 "benchmark_smoke", |
| 53 "tests/benchmark_smoke", |
| 54 "tests/benchmark_smoke/benchmark_smoke.status" |
| 55 ], |
| 56 ["co19", "tests/co19/src", "tests/co19/co19-analyzer2.status"], |
| 57 ["co19", "tests/co19/src", "tests/co19/co19-analyzer.status"], |
| 58 ["co19", "tests/co19/src", "tests/co19/co19-dart2js.status"], |
| 59 ["co19", "tests/co19/src", "tests/co19/co19-co19.status"], |
| 60 ["co19", "tests/co19/src", "tests/co19/co19-dartium.status"], |
| 61 ["co19", "tests/co19/src", "tests/co19/co19-runtime.status"], |
| 47 ]; | 62 ]; |
| 48 | 63 |
| 49 void main(List<String> args) { | 64 void main(List<String> args) { |
| 50 TestUtils.setDartDirUri(Platform.script.resolve('..')); | 65 TestUtils.setDartDirUri(Platform.script.resolve('..')); |
| 51 usage() { | 66 usage() { |
| 52 print("Usage: ${Platform.executable} <deflake|remove-nonexistent-tests>"); | 67 print("Usage: ${Platform.executable} <deflake|remove-nonexistent-tests>"); |
| 53 exit(1); | 68 exit(1); |
| 54 } | 69 } |
| 55 | 70 |
| 56 if (args.length == 0) usage(); | 71 if (args.length == 0) usage(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 Future run(String suiteName, String directory, String filePath) { | 115 Future run(String suiteName, String directory, String filePath) { |
| 101 return _readSections(filePath).then((List<Section> sections) { | 116 return _readSections(filePath).then((List<Section> sections) { |
| 102 Set<int> invalidLines = _analyzeStatusFile(directory, filePath, sections); | 117 Set<int> invalidLines = _analyzeStatusFile(directory, filePath, sections); |
| 103 if (invalidLines.length > 0) { | 118 if (invalidLines.length > 0) { |
| 104 return _writeFixedStatusFile(filePath, invalidLines); | 119 return _writeFixedStatusFile(filePath, invalidLines); |
| 105 } | 120 } |
| 106 return new Future.value(); | 121 return new Future.value(); |
| 107 }); | 122 }); |
| 108 } | 123 } |
| 109 | 124 |
| 110 bool _testExists(String filePath, | 125 bool _testExists(String filePath, List<String> testFiles, String directory, |
| 111 List<String> testFiles, | 126 TestRule rule) { |
| 112 String directory, | |
| 113 TestRule rule) { | |
| 114 // TODO: Unify this regular expression matching with status_file_parser.dart | 127 // TODO: Unify this regular expression matching with status_file_parser.dart |
| 115 List<RegExp> getRuleRegex(String name) { | 128 List<RegExp> getRuleRegex(String name) { |
| 116 return name.split("/") | 129 return name |
| 130 .split("/") |
| 117 .map((name) => new RegExp(name.replaceAll('*', '.*'))) | 131 .map((name) => new RegExp(name.replaceAll('*', '.*'))) |
| 118 .toList(); | 132 .toList(); |
| 119 } | 133 } |
| 134 |
| 120 bool matchRegexp(List<RegExp> patterns, String str) { | 135 bool matchRegexp(List<RegExp> patterns, String str) { |
| 121 var parts = str.split("/"); | 136 var parts = str.split("/"); |
| 122 if (patterns.length > parts.length) { | 137 if (patterns.length > parts.length) { |
| 123 return false; | 138 return false; |
| 124 } | 139 } |
| 125 // NOTE: patterns.length <= parts.length | 140 // NOTE: patterns.length <= parts.length |
| 126 for (var i = 0; i < patterns.length; i++) { | 141 for (var i = 0; i < patterns.length; i++) { |
| 127 if (!patterns[i].hasMatch(parts[i])) { | 142 if (!patterns[i].hasMatch(parts[i])) { |
| 128 return false; | 143 return false; |
| 129 } | 144 } |
| 130 } | 145 } |
| 131 return true; | 146 return true; |
| 132 } | 147 } |
| 133 | 148 |
| 134 var rulePattern = getRuleRegex(rule.name); | 149 var rulePattern = getRuleRegex(rule.name); |
| 135 return testFiles.any((String file) { | 150 return testFiles.any((String file) { |
| 136 // TODO: Use test_suite.dart's [buildTestCaseDisplayName] instead. | 151 // TODO: Use test_suite.dart's [buildTestCaseDisplayName] instead. |
| 137 var filePath = new Path(file).relativeTo(new Path(directory)); | 152 var filePath = new Path(file).relativeTo(new Path(directory)); |
| 138 String baseTestName = _concat("${filePath.directoryPath}", | 153 String baseTestName = _concat( |
| 139 "${filePath.filenameWithoutExtension}"); | 154 "${filePath.directoryPath}", "${filePath.filenameWithoutExtension}"); |
| 140 | 155 |
| 141 List<String> testNames = []; | 156 List<String> testNames = []; |
| 142 for (var name in multiTestDetector.getMultitestNames(file)) { | 157 for (var name in multiTestDetector.getMultitestNames(file)) { |
| 143 testNames.add(_concat(baseTestName, name)); | 158 testNames.add(_concat(baseTestName, name)); |
| 144 } | 159 } |
| 145 | 160 |
| 146 // If it is not a multitest the testname is [baseTestName] | 161 // If it is not a multitest the testname is [baseTestName] |
| 147 if (testNames.isEmpty) { | 162 if (testNames.isEmpty) { |
| 148 testNames.add(baseTestName); | 163 testNames.add(baseTestName); |
| 149 } | 164 } |
| 150 | 165 |
| 151 return testNames.any( | 166 return testNames |
| 152 (String testName) => matchRegexp(rulePattern, testName)); | 167 .any((String testName) => matchRegexp(rulePattern, testName)); |
| 153 }); | 168 }); |
| 154 } | 169 } |
| 155 | 170 |
| 156 Set<int> _analyzeStatusFile(String directory, | 171 Set<int> _analyzeStatusFile( |
| 157 String filePath, | 172 String directory, String filePath, List<Section> sections) { |
| 158 List<Section> sections) { | |
| 159 var invalidLines = new Set<int>(); | 173 var invalidLines = new Set<int>(); |
| 160 var dartFiles = testFileLister.listTestFiles(directory); | 174 var dartFiles = testFileLister.listTestFiles(directory); |
| 161 for (var section in sections) { | 175 for (var section in sections) { |
| 162 for (var rule in section.testRules) { | 176 for (var rule in section.testRules) { |
| 163 if (!_testExists(filePath, dartFiles, directory, rule)) { | 177 if (!_testExists(filePath, dartFiles, directory, rule)) { |
| 164 print("Invalid rule: ${rule.name} in file " | 178 print("Invalid rule: ${rule.name} in file " |
| 165 "$filePath:${rule.lineNumber}"); | 179 "$filePath:${rule.lineNumber}"); |
| 166 invalidLines.add(rule.lineNumber); | 180 invalidLines.add(rule.lineNumber); |
| 167 } | 181 } |
| 168 } | 182 } |
| 169 } | 183 } |
| 170 return invalidLines; | 184 return invalidLines; |
| 171 } | 185 } |
| 172 | 186 |
| 173 _writeFixedStatusFile(String statusFilePath, Set<int> invalidLines) { | 187 _writeFixedStatusFile(String statusFilePath, Set<int> invalidLines) { |
| 174 var lines = new File(statusFilePath).readAsLinesSync(); | 188 var lines = new File(statusFilePath).readAsLinesSync(); |
| 175 var outputLines = <String>[]; | 189 var outputLines = <String>[]; |
| 176 for (int i = 0; i < lines.length; i++) { | 190 for (int i = 0; i < lines.length; i++) { |
| 177 // The status file parser numbers lines starting with 1, not 0. | 191 // The status file parser numbers lines starting with 1, not 0. |
| 178 if (!invalidLines.contains(i + 1)) { | 192 if (!invalidLines.contains(i + 1)) { |
| 179 outputLines.add(lines[i]); | 193 outputLines.add(lines[i]); |
| 180 } | 194 } |
| 181 } | 195 } |
| 182 var outputFile = new File("$statusFilePath.fixed"); | 196 var outputFile = new File("$statusFilePath.fixed"); |
| 183 outputFile.writeAsStringSync(outputLines.join("\n")); | 197 outputFile.writeAsStringSync(outputLines.join("\n")); |
| 184 } | 198 } |
| 185 | 199 |
| 186 String _concat(String base, String part) { | 200 String _concat(String base, String part) { |
| 187 if (base == "") return part; | 201 if (base == "") return part; |
| 188 if (part == "") return base; | 202 if (part == "") return base; |
| 189 return "$base/$part"; | 203 return "$base/$part"; |
| 190 } | 204 } |
| 191 } | 205 } |
| 192 | 206 |
| 193 class StatusFileDeflaker extends StatusFileProcessor { | 207 class StatusFileDeflaker extends StatusFileProcessor { |
| 194 TestOutcomeFetcher _testOutcomeFetcher = new TestOutcomeFetcher(); | 208 TestOutcomeFetcher _testOutcomeFetcher = new TestOutcomeFetcher(); |
| 195 | 209 |
| 196 Future run(String suiteName, String directory, String filePath) { | 210 Future run(String suiteName, String directory, String filePath) { |
| 197 return _readSections(filePath).then((List<Section> sections) { | 211 return _readSections(filePath).then((List<Section> sections) { |
| 198 return _generatedDeflakedLines(suiteName, sections) | 212 return _generatedDeflakedLines(suiteName, sections) |
| 199 .then((Map<int, String> fixedLines) { | 213 .then((Map<int, String> fixedLines) { |
| 200 if (fixedLines.length > 0) { | 214 if (fixedLines.length > 0) { |
| 201 return _writeFixedStatusFile(filePath, fixedLines); | 215 return _writeFixedStatusFile(filePath, fixedLines); |
| 202 } | 216 } |
| 203 }); | 217 }); |
| 204 }); | 218 }); |
| 205 } | 219 } |
| 206 | 220 |
| 207 Future _generatedDeflakedLines(String suiteName, | 221 Future _generatedDeflakedLines(String suiteName, List<Section> sections) { |
| 208 List<Section> sections) { | |
| 209 var fixedLines = new Map<int, String>(); | 222 var fixedLines = new Map<int, String>(); |
| 210 return Future.forEach(sections, (Section section) { | 223 return Future.forEach(sections, (Section section) { |
| 211 return Future.forEach(section.testRules, (rule) { | 224 return Future.forEach(section.testRules, (rule) { |
| 212 return _maybeFixStatusfileLine(suiteName, section, rule, fixedLines); | 225 return _maybeFixStatusfileLine(suiteName, section, rule, fixedLines); |
| 213 }); | 226 }); |
| 214 }).then((_) => fixedLines); | 227 }).then((_) => fixedLines); |
| 215 } | 228 } |
| 216 | 229 |
| 217 Future _maybeFixStatusfileLine(String suiteName, | 230 Future _maybeFixStatusfileLine(String suiteName, Section section, |
| 218 Section section, | 231 TestRule rule, Map<int, String> fixedLines) { |
| 219 TestRule rule, | |
| 220 Map<int, String> fixedLines) { | |
| 221 print("Processing ${section.statusFile.location}: ${rule.lineNumber}"); | 232 print("Processing ${section.statusFile.location}: ${rule.lineNumber}"); |
| 222 // None of our status file lines have expressions, so we pass {} here. | 233 // None of our status file lines have expressions, so we pass {} here. |
| 223 var notedOutcomes = rule.expression | 234 var notedOutcomes = rule.expression |
| 224 .evaluate({}) | 235 .evaluate({}) |
| 225 .map((name) => Expectation.byName(name)) | 236 .map((name) => Expectation.byName(name)) |
| 226 .where((Expectation expectation) => !expectation.isMetaExpectation) | 237 .where((Expectation expectation) => !expectation.isMetaExpectation) |
| 227 .toSet(); | 238 .toSet(); |
| 228 | 239 |
| 229 if (notedOutcomes.isEmpty) return new Future.value(); | 240 if (notedOutcomes.isEmpty) return new Future.value(); |
| 230 | 241 |
| 231 // TODO: [rule.name] is actually a pattern not just a testname. We should | 242 // TODO: [rule.name] is actually a pattern not just a testname. We should |
| 232 // find all possible testnames this rule matches against and unify the | 243 // find all possible testnames this rule matches against and unify the |
| 233 // outcomes of these tests. | 244 // outcomes of these tests. |
| 234 return _testOutcomeFetcher.outcomesOf(suiteName, section, rule.name) | 245 return _testOutcomeFetcher |
| 235 .then((Set<Expectation> actualOutcomes) { | 246 .outcomesOf(suiteName, section, rule.name) |
| 236 | 247 .then((Set<Expectation> actualOutcomes) { |
| 237 var outcomesThatNeverHappened = new Set<Expectation>(); | 248 var outcomesThatNeverHappened = new Set<Expectation>(); |
| 238 for (Expectation notedOutcome in notedOutcomes) { | 249 for (Expectation notedOutcome in notedOutcomes) { |
| 239 bool found = false; | 250 bool found = false; |
| 240 for (Expectation actualOutcome in actualOutcomes) { | 251 for (Expectation actualOutcome in actualOutcomes) { |
| 241 if (actualOutcome.canBeOutcomeOf(notedOutcome)) { | 252 if (actualOutcome.canBeOutcomeOf(notedOutcome)) { |
| 242 found = true; | 253 found = true; |
| 243 break; | 254 break; |
| 244 } | 255 } |
| 245 } | 256 } |
| 246 if (!found) { | 257 if (!found) { |
| 247 outcomesThatNeverHappened.add(notedOutcome); | 258 outcomesThatNeverHappened.add(notedOutcome); |
| 248 } | 259 } |
| 249 } | 260 } |
| 250 | 261 |
| 251 if (outcomesThatNeverHappened.length > 0 && actualOutcomes.length > 0) { | 262 if (outcomesThatNeverHappened.length > 0 && actualOutcomes.length > 0) { |
| 252 // Print the change to stdout. | 263 // Print the change to stdout. |
| 253 print("${rule.name} " | 264 print("${rule.name} " |
| 254 "(${section.statusFile.location}:${rule.lineNumber}):"); | 265 "(${section.statusFile.location}:${rule.lineNumber}):"); |
| 255 print(" Actual outcomes: ${actualOutcomes.toList()}"); | 266 print(" Actual outcomes: ${actualOutcomes.toList()}"); |
| 256 print(" Outcomes in status file: ${notedOutcomes.toList()}"); | 267 print(" Outcomes in status file: ${notedOutcomes.toList()}"); |
| 257 print(" Outcomes in status file that never happened : " | 268 print(" Outcomes in status file that never happened : " |
| 258 "${outcomesThatNeverHappened.toList()}\n"); | 269 "${outcomesThatNeverHappened.toList()}\n"); |
| 259 | 270 |
| 260 // Build the fixed status file line. | 271 // Build the fixed status file line. |
| 261 fixedLines[rule.lineNumber] = | 272 fixedLines[rule.lineNumber] = |
| 262 '${rule.name}: ${actualOutcomes.join(', ')} ' | 273 '${rule.name}: ${actualOutcomes.join(', ')} ' |
| 263 '# before: ${notedOutcomes.join(', ')} / ' | 274 '# before: ${notedOutcomes.join(', ')} / ' |
| 264 'never happened: ${outcomesThatNeverHappened.join(', ')}'; | 275 'never happened: ${outcomesThatNeverHappened.join(', ')}'; |
| 265 } | 276 } |
| 266 }); | 277 }); |
| 267 } | 278 } |
| 268 | 279 |
| 269 _writeFixedStatusFile(String filePath, Map<int, String> fixedLines) { | 280 _writeFixedStatusFile(String filePath, Map<int, String> fixedLines) { |
| 270 var lines = new File(filePath).readAsLinesSync(); | 281 var lines = new File(filePath).readAsLinesSync(); |
| 271 var outputLines = <String>[]; | 282 var outputLines = <String>[]; |
| 272 for (int i = 0; i < lines.length; i++) { | 283 for (int i = 0; i < lines.length; i++) { |
| 273 if (fixedLines.containsKey(i + 1)) { | 284 if (fixedLines.containsKey(i + 1)) { |
| 274 outputLines.add(fixedLines[i + 1]); | 285 outputLines.add(fixedLines[i + 1]); |
| 275 } else { | 286 } else { |
| 276 outputLines.add(lines[i]); | 287 outputLines.add(lines[i]); |
| 277 } | 288 } |
| 278 } | 289 } |
| 279 var output = outputLines.join("\n"); | 290 var output = outputLines.join("\n"); |
| 280 var outputFile = new File("$filePath.deflaked"); | 291 var outputFile = new File("$filePath.deflaked"); |
| 281 outputFile.writeAsStringSync(output); | 292 outputFile.writeAsStringSync(output); |
| 282 } | 293 } |
| 283 } | 294 } |
| 284 | 295 |
| 285 class MultiTestDetector { | 296 class MultiTestDetector { |
| 286 final multiTestsCache = new Map<String,List<String>>(); | 297 final multiTestsCache = new Map<String, List<String>>(); |
| 287 final multiHtmlTestsCache = new Map<String,List<String>>(); | 298 final multiHtmlTestsCache = new Map<String, List<String>>(); |
| 288 | |
| 289 | 299 |
| 290 List<String> getMultitestNames(String file) { | 300 List<String> getMultitestNames(String file) { |
| 291 List<String> names = []; | 301 List<String> names = []; |
| 292 names.addAll(getStandardMultitestNames(file)); | 302 names.addAll(getStandardMultitestNames(file)); |
| 293 names.addAll(getHtmlMultitestNames(file)); | 303 names.addAll(getHtmlMultitestNames(file)); |
| 294 return names; | 304 return names; |
| 295 } | 305 } |
| 296 | 306 |
| 297 List<String> getStandardMultitestNames(String file) { | 307 List<String> getStandardMultitestNames(String file) { |
| 298 return multiTestsCache.putIfAbsent(file, () { | 308 return multiTestsCache.putIfAbsent(file, () { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 310 }); | 320 }); |
| 311 } | 321 } |
| 312 | 322 |
| 313 List<String> getHtmlMultitestNames(String file) { | 323 List<String> getHtmlMultitestNames(String file) { |
| 314 return multiHtmlTestsCache.putIfAbsent(file, () { | 324 return multiHtmlTestsCache.putIfAbsent(file, () { |
| 315 try { | 325 try { |
| 316 List<String> subtestNames = []; | 326 List<String> subtestNames = []; |
| 317 var content = new File(file).readAsStringSync(); | 327 var content = new File(file).readAsStringSync(); |
| 318 | 328 |
| 319 if (multiHtmlTestRegExp.hasMatch(content)) { | 329 if (multiHtmlTestRegExp.hasMatch(content)) { |
| 320 var matchesIter = multiHtmlTestGroupRegExp.allMatches(content).iterato
r; | 330 var matchesIter = |
| 321 while(matchesIter.moveNext()) { | 331 multiHtmlTestGroupRegExp.allMatches(content).iterator; |
| 332 while (matchesIter.moveNext()) { |
| 322 String fullMatch = matchesIter.current.group(0); | 333 String fullMatch = matchesIter.current.group(0); |
| 323 subtestNames.add(fullMatch.substring(fullMatch.indexOf("'") + 1)); | 334 subtestNames.add(fullMatch.substring(fullMatch.indexOf("'") + 1)); |
| 324 } | 335 } |
| 325 } | 336 } |
| 326 return subtestNames; | 337 return subtestNames; |
| 327 } catch (error) { | 338 } catch (error) { |
| 328 print("WARNING: Couldn't determine multitests in file ${file}: $error"); | 339 print("WARNING: Couldn't determine multitests in file ${file}: $error"); |
| 329 } | 340 } |
| 330 return []; | 341 return []; |
| 331 }); | 342 }); |
| 332 } | 343 } |
| 333 } | 344 } |
| 334 | 345 |
| 335 class TestFileLister { | 346 class TestFileLister { |
| 336 final Map<String, List<String>> _filesCache = {}; | 347 final Map<String, List<String>> _filesCache = {}; |
| 337 | 348 |
| 338 List<String> listTestFiles(String directory) { | 349 List<String> listTestFiles(String directory) { |
| 339 return _filesCache.putIfAbsent(directory, () { | 350 return _filesCache.putIfAbsent(directory, () { |
| 340 var dir = new Directory(directory); | 351 var dir = new Directory(directory); |
| 341 // Cannot test for _test.dart because co19 tests don't have that ending. | 352 // Cannot test for _test.dart because co19 tests don't have that ending. |
| 342 var dartFiles = dir.listSync(recursive: true) | 353 var dartFiles = dir |
| 354 .listSync(recursive: true) |
| 343 .where((fe) => fe is File) | 355 .where((fe) => fe is File) |
| 344 .where((file) => file.path.endsWith(".dart") || | 356 .where((file) => |
| 345 file.path.endsWith("_test.html")) | 357 file.path.endsWith(".dart") || file.path.endsWith("_test.html")) |
| 346 .map((file) => file.path) | 358 .map((file) => file.path) |
| 347 .toList(); | 359 .toList(); |
| 348 return dartFiles; | 360 return dartFiles; |
| 349 }); | 361 }); |
| 350 } | 362 } |
| 351 } | 363 } |
| 352 | 364 |
| 353 | |
| 354 /* | 365 /* |
| 355 * [TestOutcomeFetcher] will fetch test results from a server using a REST-like | 366 * [TestOutcomeFetcher] will fetch test results from a server using a REST-like |
| 356 * interface. | 367 * interface. |
| 357 */ | 368 */ |
| 358 class TestOutcomeFetcher { | 369 class TestOutcomeFetcher { |
| 359 static String SERVER = '108.170.219.8'; | 370 static String SERVER = '108.170.219.8'; |
| 360 static int PORT = 4540; | 371 static int PORT = 4540; |
| 361 | 372 |
| 362 HttpClient _client = new HttpClient(); | 373 HttpClient _client = new HttpClient(); |
| 363 | 374 |
| 364 Future<Set<Expectation>> outcomesOf( | 375 Future<Set<Expectation>> outcomesOf( |
| 365 String suiteName, Section section, String testName) { | 376 String suiteName, Section section, String testName) { |
| 366 var pathComponents = ['json', 'test-outcomes', 'outcomes', | 377 var pathComponents = [ |
| 367 Uri.encodeComponent("$suiteName/$testName")]; | 378 'json', |
| 379 'test-outcomes', |
| 380 'outcomes', |
| 381 Uri.encodeComponent("$suiteName/$testName") |
| 382 ]; |
| 368 var path = pathComponents.join('/') + '/'; | 383 var path = pathComponents.join('/') + '/'; |
| 369 var url = new Uri(scheme: 'http', host: SERVER, port: PORT, path: path); | 384 var url = new Uri(scheme: 'http', host: SERVER, port: PORT, path: path); |
| 370 | 385 |
| 371 return _client.getUrl(url) | 386 return _client |
| 372 .then((HttpClientRequest request) => request.close()) | 387 .getUrl(url) |
| 373 .then((HttpClientResponse response) { | 388 .then((HttpClientRequest request) => request.close()) |
| 374 return response.transform(UTF8.decoder).transform(JSON.decoder).first | 389 .then((HttpClientResponse response) { |
| 375 .then((List testResults) { | 390 return response |
| 376 var setOfActualOutcomes = new Set<Expectation>(); | 391 .transform(UTF8.decoder) |
| 392 .transform(JSON.decoder) |
| 393 .first |
| 394 .then((List testResults) { |
| 395 var setOfActualOutcomes = new Set<Expectation>(); |
| 377 | 396 |
| 378 try { | 397 try { |
| 379 for (var result in testResults) { | 398 for (var result in testResults) { |
| 380 var config = result['configuration']; | 399 var config = result['configuration']; |
| 381 var testResult = result['test_result']; | 400 var testResult = result['test_result']; |
| 382 var outcome = testResult['outcome']; | 401 var outcome = testResult['outcome']; |
| 383 | 402 |
| 384 // These variables are derived variables and will be set in | 403 // These variables are derived variables and will be set in |
| 385 // tools/testing/dart/test_options.dart. | 404 // tools/testing/dart/test_options.dart. |
| 386 // [Mostly due to the fact that we don't have an unary ! | 405 // [Mostly due to the fact that we don't have an unary ! |
| 387 // operator in status file expressions.] | 406 // operator in status file expressions.] |
| 388 config['unchecked'] = !config['checked']; | 407 config['unchecked'] = !config['checked']; |
| 389 config['unminified'] = !config['minified']; | 408 config['unminified'] = !config['minified']; |
| 390 config['nocsp'] = !config['csp']; | 409 config['nocsp'] = !config['csp']; |
| 391 config['browser'] = | 410 config['browser'] = TestUtils.isBrowserRuntime(config['runtime']); |
| 392 TestUtils.isBrowserRuntime(config['runtime']); | 411 config['analyzer'] = |
| 393 config['analyzer'] = | 412 TestUtils.isCommandLineAnalyzer(config['compiler']); |
| 394 TestUtils.isCommandLineAnalyzer(config['compiler']); | 413 config['jscl'] = |
| 395 config['jscl'] = | 414 TestUtils.isJsCommandLineRuntime(config['runtime']); |
| 396 TestUtils.isJsCommandLineRuntime(config['runtime']); | |
| 397 | 415 |
| 398 if (section.condition == null || | 416 if (section.condition == null || |
| 399 section.condition.evaluate(config)) { | 417 section.condition.evaluate(config)) { |
| 400 setOfActualOutcomes.add(Expectation.byName(outcome)); | 418 setOfActualOutcomes.add(Expectation.byName(outcome)); |
| 401 } | 419 } |
| 402 } | 420 } |
| 403 return setOfActualOutcomes; | 421 return setOfActualOutcomes; |
| 404 } catch (error) { | 422 } catch (error) { |
| 405 print("Warning: Error occured while processing testoutcomes" | 423 print("Warning: Error occured while processing testoutcomes" |
| 406 ": $error"); | 424 ": $error"); |
| 407 return []; | 425 return []; |
| 408 } | 426 } |
| 409 }).catchError((error) { | 427 }).catchError((error) { |
| 410 print("Warning: Error occured while fetching testoutcomes: $error"
); | 428 print("Warning: Error occured while fetching testoutcomes: $error"); |
| 411 return []; | 429 return []; |
| 412 }); | 430 }); |
| 413 }); | 431 }); |
| 414 } | 432 } |
| 415 } | 433 } |
| OLD | NEW |