Index: tools/testing/dart/status_file_parser.dart |
diff --git a/tools/testing/dart/status_file_parser.dart b/tools/testing/dart/status_file_parser.dart |
deleted file mode 100644 |
index 49fdc9bf2420589b36a85d69b631d4bf38546e46..0000000000000000000000000000000000000000 |
--- a/tools/testing/dart/status_file_parser.dart |
+++ /dev/null |
@@ -1,368 +0,0 @@ |
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library status_file_parser; |
- |
-import "dart:async"; |
-import "dart:convert" show LineSplitter, UTF8; |
-import "dart:io"; |
- |
-import "path.dart"; |
-import "status_expression.dart"; |
- |
-typedef void Action(); |
- |
-class Expectation { |
- // Possible outcomes of running a test. |
- static Expectation PASS = byName('Pass'); |
- static Expectation CRASH = byName('Crash'); |
- static Expectation TIMEOUT = byName('Timeout'); |
- static Expectation FAIL = byName('Fail'); |
- |
- // Special 'FAIL' cases |
- static Expectation RUNTIME_ERROR = byName('RuntimeError'); |
- static Expectation COMPILETIME_ERROR = byName('CompileTimeError'); |
- static Expectation MISSING_RUNTIME_ERROR = byName('MissingRuntimeError'); |
- static Expectation MISSING_COMPILETIME_ERROR = |
- byName('MissingCompileTimeError'); |
- static Expectation STATIC_WARNING = byName('StaticWarning'); |
- static Expectation MISSING_STATIC_WARNING = byName('MissingStaticWarning'); |
- static Expectation PUB_GET_ERROR = byName('PubGetError'); |
- static Expectation NON_UTF8_ERROR = byName('NonUtf8Output'); |
- |
- // Special 'CRASH' cases |
- static Expectation DARTK_CRASH = byName('DartkCrash'); |
- |
- // Special 'TIMEOUT' cases |
- static Expectation DARTK_TIMEOUT = byName('DartkTimeout'); |
- |
- // Special 'COMPILETIME_ERROR' |
- static Expectation DARTK_COMPILETIME_ERROR = byName('DartkCompileTimeError'); |
- |
- // "meta expectations" |
- static Expectation OK = byName('Ok'); |
- static Expectation SLOW = byName('Slow'); |
- static Expectation SKIP = byName('Skip'); |
- static Expectation SKIP_SLOW = byName('SkipSlow'); |
- static Expectation SKIP_BY_DESIGN = byName('SkipByDesign'); |
- |
- // Can be returned by the test runner to say the result should be ignored, |
- // and assumed to meet the expectations, due to an infrastructure failure. |
- // Do not place in status files. |
- static Expectation IGNORE = byName('Ignore'); |
- |
- static Expectation byName(String name) { |
- _initialize(); |
- name = name.toLowerCase(); |
- if (!_AllExpectations.containsKey(name)) { |
- throw new Exception("Expectation.byName(name='$name'): Invalid name."); |
- } |
- return _AllExpectations[name]; |
- } |
- |
- // Keep a map of all possible Expectation objects, initialized lazily. |
- static Map<String, Expectation> _AllExpectations; |
- static void _initialize() { |
- if (_AllExpectations == null) { |
- _AllExpectations = new Map<String, Expectation>(); |
- |
- Expectation build(String prettyName, |
- {Expectation group, bool isMetaExpectation: false}) { |
- var expectation = new Expectation._(prettyName, |
- group: group, isMetaExpectation: isMetaExpectation); |
- assert(!_AllExpectations.containsKey(expectation.name)); |
- return _AllExpectations[expectation.name] = expectation; |
- } |
- |
- var fail = build("Fail"); |
- var crash = build("Crash"); |
- var timeout = build("Timeout"); |
- build("Pass"); |
- |
- var compileError = build("CompileTimeError", group: fail); |
- build("MissingCompileTimeError", group: fail); |
- build("MissingRuntimeError", group: fail); |
- build("RuntimeError", group: fail); |
- build("NonUtf8Output", group: fail); |
- |
- // Dartk sub expectations |
- build("DartkCrash", group: crash); |
- build("DartkTimeout", group: timeout); |
- build("DartkCompileTimeError", group: compileError); |
- |
- build("MissingStaticWarning", group: fail); |
- build("StaticWarning", group: fail); |
- |
- build("PubGetError", group: fail); |
- |
- var skip = build("Skip", isMetaExpectation: true); |
- build("SkipByDesign", isMetaExpectation: true); |
- build("SkipSlow", group: skip, isMetaExpectation: true); |
- build("Ok", isMetaExpectation: true); |
- build("Slow", isMetaExpectation: true); |
- build("Ignore"); |
- } |
- } |
- |
- final String prettyName; |
- final String name; |
- final Expectation group; |
- // Indicates whether this expectation cannot be a test outcome (i.e. it is a |
- // "meta marker"). |
- final bool isMetaExpectation; |
- |
- Expectation._(this.prettyName, |
- {Expectation this.group: null, bool this.isMetaExpectation: false}) |
- : name = prettyName.toLowerCase(); |
- |
- bool canBeOutcomeOf(Expectation expectation) { |
- Expectation outcome = this; |
- if (outcome == IGNORE) return true; |
- while (outcome != null) { |
- if (outcome == expectation) { |
- return true; |
- } |
- outcome = outcome.group; |
- } |
- return false; |
- } |
- |
- String toString() => prettyName; |
-} |
- |
-final RegExp SplitComment = new RegExp("^([^#]*)(#.*)?\$"); |
-final RegExp HeaderPattern = new RegExp(r"^\[([^\]]+)\]"); |
-final RegExp RulePattern = new RegExp(r"\s*([^: ]*)\s*:(.*)"); |
-final RegExp IssueNumberPattern = new RegExp("[Ii]ssue ([0-9]+)"); |
- |
-class StatusFile { |
- final Path location; |
- |
- StatusFile(this.location); |
-} |
- |
-// TODO(whesse): Implement configuration_info library that contains data |
-// structures for test configuration, including Section. |
-class Section { |
- final StatusFile statusFile; |
- |
- final BooleanExpression condition; |
- final List<TestRule> testRules; |
- final int lineNumber; |
- |
- Section.always(this.statusFile, this.lineNumber) |
- : condition = null, |
- testRules = new List<TestRule>(); |
- Section(this.statusFile, this.condition, this.lineNumber) |
- : testRules = new List<TestRule>(); |
- |
- bool isEnabled(environment) => |
- condition == null || condition.evaluate(environment); |
- |
- String toString() { |
- return "Section: $condition"; |
- } |
-} |
- |
-Future<TestExpectations> ReadTestExpectations( |
- List<String> statusFilePaths, Map<String, String> environment) { |
- var testExpectations = new TestExpectations(); |
- return Future.wait(statusFilePaths.map((String statusFile) { |
- return ReadTestExpectationsInto(testExpectations, statusFile, environment); |
- })).then((_) => testExpectations); |
-} |
- |
-Future ReadTestExpectationsInto(TestExpectations expectations, |
- String statusFilePath, Map<String, String> environment) { |
- var completer = new Completer<Null>(); |
- var sections = <Section>[]; |
- |
- void sectionsRead() { |
- for (Section section in sections) { |
- if (section.isEnabled(environment)) { |
- for (var rule in section.testRules) { |
- expectations.addRule(rule, environment); |
- } |
- } |
- } |
- completer.complete(); |
- } |
- |
- ReadConfigurationInto(new Path(statusFilePath), sections, sectionsRead); |
- return completer.future; |
-} |
- |
-void ReadConfigurationInto(Path path, List<Section> sections, Action onDone) { |
- StatusFile statusFile = new StatusFile(path); |
- File file = new File(path.toNativePath()); |
- if (!file.existsSync()) { |
- throw new Exception('Cannot find test status file $path'); |
- } |
- int lineNumber = 0; |
- Stream<String> lines = |
- file.openRead().transform(UTF8.decoder).transform(new LineSplitter()); |
- |
- Section currentSection = new Section.always(statusFile, -1); |
- sections.add(currentSection); |
- |
- lines.listen((String line) { |
- lineNumber++; |
- Match match = SplitComment.firstMatch(line); |
- line = (match == null) ? "" : match[1]; |
- line = line.trim(); |
- if (line.isEmpty) return; |
- |
- // Extract the comment to get the issue number if needed. |
- String comment = (match == null || match[2] == null) ? "" : match[2]; |
- |
- match = HeaderPattern.firstMatch(line); |
- if (match != null) { |
- String condition_string = match[1].trim(); |
- List<String> tokens = new Tokenizer(condition_string).tokenize(); |
- ExpressionParser parser = new ExpressionParser(new Scanner(tokens)); |
- currentSection = |
- new Section(statusFile, parser.parseBooleanExpression(), lineNumber); |
- sections.add(currentSection); |
- return; |
- } |
- |
- match = RulePattern.firstMatch(line); |
- if (match != null) { |
- String name = match[1].trim(); |
- // TODO(whesse): Handle test names ending in a wildcard (*). |
- String expression_string = match[2].trim(); |
- List<String> tokens = new Tokenizer(expression_string).tokenize(); |
- SetExpression expression = |
- new ExpressionParser(new Scanner(tokens)).parseSetExpression(); |
- |
- // Look for issue number in comment. |
- String issueString = null; |
- match = IssueNumberPattern.firstMatch(comment); |
- if (match != null) { |
- issueString = match[1]; |
- if (issueString == null) issueString = match[2]; |
- } |
- int issue = issueString != null ? int.parse(issueString) : null; |
- currentSection.testRules |
- .add(new TestRule(name, expression, issue, lineNumber)); |
- return; |
- } |
- |
- print("unmatched line: $line"); |
- }, onDone: onDone); |
-} |
- |
-class TestRule { |
- String name; |
- SetExpression expression; |
- int issue; |
- int lineNumber; |
- |
- TestRule(this.name, this.expression, this.issue, this.lineNumber); |
- |
- bool get hasIssue => issue != null; |
- |
- String toString() => 'TestRule($name, $expression, $issue)'; |
-} |
- |
-class TestExpectations { |
- // Only create one copy of each Set<Expectation>. |
- // We just use .toString as a key, so we may make a few |
- // sets that only differ in their toString element order. |
- static Map<String, Set<Expectation>> _cachedSets = {}; |
- |
- Map<String, Set<Expectation>> _map; |
- bool _preprocessed = false; |
- Map<String, RegExp> _regExpCache; |
- Map<String, List<RegExp>> _keyToRegExps; |
- |
- /** |
- * Create a TestExpectations object. See the [expectations] method |
- * for an explanation of matching. |
- */ |
- TestExpectations() : _map = {}; |
- |
- /** |
- * Add a rule to the expectations. |
- */ |
- void addRule(TestRule testRule, environment) { |
- // Once we have started using the expectations we cannot add more |
- // rules. |
- if (_preprocessed) { |
- throw "TestExpectations.addRule: cannot add more rules"; |
- } |
- var names = testRule.expression.evaluate(environment); |
- var expectations = names.map((name) => Expectation.byName(name)); |
- _map |
- .putIfAbsent(testRule.name, () => new Set<Expectation>()) |
- .addAll(expectations); |
- } |
- |
- /** |
- * Compute the expectations for a test based on the filename. |
- * |
- * For every (key, expectation) pair. Match the key with the file |
- * name. Return the union of the expectations for all the keys |
- * that match. |
- * |
- * Normal matching splits the key and the filename into path |
- * components and checks that the anchored regular expression |
- * "^$keyComponent\$" matches the corresponding filename component. |
- */ |
- Set<Expectation> expectations(String filename) { |
- var result = new Set<Expectation>(); |
- var splitFilename = filename.split('/'); |
- |
- // Create mapping from keys to list of RegExps once and for all. |
- _preprocessForMatching(); |
- |
- _map.forEach((key, Set<Expectation> expectations) { |
- List<RegExp> regExps = _keyToRegExps[key]; |
- if (regExps.length > splitFilename.length) return; |
- for (var i = 0; i < regExps.length; i++) { |
- if (!regExps[i].hasMatch(splitFilename[i])) return; |
- } |
- // If all components of the status file key matches the filename |
- // add the expectations to the result. |
- result.addAll(expectations); |
- }); |
- |
- // If no expectations were found the expectation is that the test |
- // passes. |
- if (result.isEmpty) { |
- result.add(Expectation.PASS); |
- } |
- return _cachedSets.putIfAbsent(result.toString(), () => result); |
- } |
- |
- // Preprocess the expectations for matching against |
- // filenames. Generate lists of regular expressions once and for all |
- // for each key. |
- void _preprocessForMatching() { |
- if (_preprocessed) return; |
- |
- _keyToRegExps = {}; |
- _regExpCache = {}; |
- |
- _map.forEach((key, expectations) { |
- if (_keyToRegExps[key] != null) return; |
- var splitKey = key.split('/'); |
- var regExps = new List<RegExp>(splitKey.length); |
- for (var i = 0; i < splitKey.length; i++) { |
- var component = splitKey[i]; |
- var regExp = _regExpCache[component]; |
- if (regExp == null) { |
- var pattern = "^${splitKey[i]}\$".replaceAll('*', '.*'); |
- regExp = new RegExp(pattern); |
- _regExpCache[component] = regExp; |
- } |
- regExps[i] = regExp; |
- } |
- _keyToRegExps[key] = regExps; |
- }); |
- |
- _regExpCache = null; |
- _preprocessed = true; |
- } |
-} |