| 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("status_file_parser"); | 5 #library("status_file_parser"); |
| 6 | 6 |
| 7 | 7 |
| 8 #import("status_expression.dart"); | 8 #import("status_expression.dart"); |
| 9 | 9 |
| 10 // Possible outcomes of running a test. | 10 // Possible outcomes of running a test. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 | 35 |
| 36 | 36 |
| 37 // Helper method to be able to run the test from the runtime | 37 // Helper method to be able to run the test from the runtime |
| 38 // directory, or the top directory. | 38 // directory, or the top directory. |
| 39 String getFilename(String path) => | 39 String getFilename(String path) => |
| 40 new File(path).existsSync() ? path : '../$path'; | 40 new File(path).existsSync() ? path : '../$path'; |
| 41 | 41 |
| 42 String getDirname(String path) => | 42 String getDirname(String path) => |
| 43 new Directory(path).existsSync() ? path : '../$path'; | 43 new Directory(path).existsSync() ? path : '../$path'; |
| 44 | 44 |
| 45 TestExpectationsMap ReadTestExpectations(String statusFilePath, environment) { | 45 void ReadTestExpectationsInto(TestExpectations expectations, |
| 46 String statusFilePath, |
| 47 environment) { |
| 46 List<Section> sections = new List<Section>(); | 48 List<Section> sections = new List<Section>(); |
| 47 ReadConfigurationInto(statusFilePath, sections); | 49 ReadConfigurationInto(statusFilePath, sections); |
| 48 | 50 |
| 49 TestExpectationsMap map = new TestExpectationsMap(); | |
| 50 for (Section section in sections) { | 51 for (Section section in sections) { |
| 51 if (section.isEnabled(environment)) { | 52 if (section.isEnabled(environment)) { |
| 52 for (var rule in section.testRules) { | 53 for (var rule in section.testRules) { |
| 53 map.addTest(rule, environment); | 54 expectations.addRule(rule, environment); |
| 54 } | 55 } |
| 55 } | 56 } |
| 56 } | 57 } |
| 57 return map; | |
| 58 } | 58 } |
| 59 | 59 |
| 60 void ReadConfigurationInto(path, sections) { | 60 void ReadConfigurationInto(path, sections) { |
| 61 File file = new File(getFilename(path)); | 61 File file = new File(getFilename(path)); |
| 62 if (!file.existsSync()) return; // TODO(whesse): Handle missing file. | 62 if (!file.existsSync()) return; // TODO(whesse): Handle missing file. |
| 63 FileInputStream file_stream = file.openInputStream(); | 63 FileInputStream file_stream = file.openInputStream(); |
| 64 StringInputStream lines = new StringInputStream(file_stream); | 64 StringInputStream lines = new StringInputStream(file_stream); |
| 65 | 65 |
| 66 Section current = new Section.always(); | 66 Section current = new Section.always(); |
| 67 sections.add(current); | 67 sections.add(current); |
| 68 String prefix = ""; | 68 String prefix = ""; |
| 69 | 69 |
| 70 String line; | 70 String line; |
| 71 while ((line = lines.readLine()) != null) { | 71 while ((line = lines.readLine()) != null) { |
| 72 Match match = StripComment.firstMatch(line); | 72 Match match = StripComment.firstMatch(line); |
| 73 line = (match == null) ? "" : match[0]; | 73 line = (match == null) ? "" : match[0]; |
| 74 line = line.trim(); | 74 line = line.trim(); |
| 75 if (line == "") continue; | 75 if (line.isEmpty()) continue; |
| 76 | 76 |
| 77 match = HeaderPattern.firstMatch(line); | 77 match = HeaderPattern.firstMatch(line); |
| 78 if (match != null) { | 78 if (match != null) { |
| 79 String condition_string = match[1].trim(); | 79 String condition_string = match[1].trim(); |
| 80 List<String> tokens = new Tokenizer(condition_string).tokenize(); | 80 List<String> tokens = new Tokenizer(condition_string).tokenize(); |
| 81 ExpressionParser parser = new ExpressionParser(new Scanner(tokens)); | 81 ExpressionParser parser = new ExpressionParser(new Scanner(tokens)); |
| 82 current = new Section(parser.parseBooleanExpression()); | 82 current = new Section(parser.parseBooleanExpression()); |
| 83 sections.add(current); | 83 sections.add(current); |
| 84 continue; | 84 continue; |
| 85 } | 85 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 110 | 110 |
| 111 | 111 |
| 112 class TestRule { | 112 class TestRule { |
| 113 String name; | 113 String name; |
| 114 SetExpression expression; | 114 SetExpression expression; |
| 115 | 115 |
| 116 TestRule(this.name, this.expression); | 116 TestRule(this.name, this.expression); |
| 117 } | 117 } |
| 118 | 118 |
| 119 | 119 |
| 120 class TestExpectationsMap { | 120 class TestExpectations { |
| 121 Map<String, Set<String>> map; | 121 bool _complexMatching; |
| 122 Map _map; |
| 123 bool _preprocessed = false; |
| 124 Map _regExpCache; |
| 125 Map _keyToRegExps; |
| 122 | 126 |
| 123 TestExpectationsMap() : map = new Map<String, Set<String>>(); | 127 /** |
| 128 * Create a TestExpectations object. Optionally specify |
| 129 * complexMatching behavior. See the [expectations] method |
| 130 * for an explanation of matching. |
| 131 */ |
| 132 TestExpectations([bool complexMatching = false]) |
| 133 : _complexMatching = complexMatching, |
| 134 _map = new Map(); |
| 124 | 135 |
| 125 void addTest(testRule, environment) { | 136 /** |
| 126 map[testRule.name] = testRule.expression.evaluate(environment); | 137 * Add a rule to the expectations. |
| 138 */ |
| 139 void addRule(testRule, environment) { |
| 140 // Once we have started using the expectations we cannot add more |
| 141 // rules. |
| 142 if (_preprocessed) { |
| 143 throw "TestExpectations.addRule: cannot add more rules"; |
| 144 } |
| 145 var values = testRule.expression.evaluate(environment); |
| 146 _map.putIfAbsent(testRule.name, () => new Set()).addAll(values); |
| 127 } | 147 } |
| 128 | 148 |
| 149 /** |
| 150 * Compute the expectations for a test based on the filename. |
| 151 * |
| 152 * For every (key, expectation) pair. Match the key with the file |
| 153 * name. Return the union of the expectations for all the keys |
| 154 * that match. |
| 155 * |
| 156 * Normal matching splits the key and the filename into path |
| 157 * components and checks that the anchored regular expression |
| 158 * "^$keyComponent\$" matches the corresponding filename component. |
| 159 * |
| 160 * If Complex matching is required the last filename component is |
| 161 * translated into multiple components. If the last filename |
| 162 * component starts with the second-to-last filename component that |
| 163 * part is removed from the last filename component. Then the last |
| 164 * component is split into more components at '_'s. |
| 165 * |
| 166 * Examples of complext filename component splits: |
| 167 * |
| 168 * a/b/c/d_e_f/d_e_f_A01_t01 -> ['a', 'b', 'c', 'd_e_f', 'A01', 't01'] |
| 169 * a/b/c/d_e_f_A01_t01 -> ['a', 'b', 'c', 'd', 'e', 'f', 'A01', 't01'] |
| 170 */ |
| 129 Set<String> expectations(String filename) { | 171 Set<String> expectations(String filename) { |
| 130 var result = map[filename]; | 172 var result = new Set(); |
| 131 return result != null ? result : new Set.from([PASS]); | 173 var splitFilename = filename.split(new Platform().pathSeparator()); |
| 174 |
| 175 // If complex matching is required split the last filename |
| 176 // component at '_'. Additionally, remove the prefix of the last |
| 177 // component if it is identical to the second-to-last component. |
| 178 if (_complexMatching && splitFilename.length >= 2) { |
| 179 var last = splitFilename.removeLast(); |
| 180 var secondToLast = splitFilename.last(); |
| 181 if (last.startsWith(secondToLast)) { |
| 182 last = last.substring(secondToLast.length); |
| 183 } |
| 184 last.split('_').forEach((component) { |
| 185 if (!component.isEmpty()) { |
| 186 splitFilename.add(component); |
| 187 } |
| 188 }); |
| 189 } |
| 190 |
| 191 // Create mapping from keys to list of RegExps once and for all. |
| 192 _preprocessForMatching(); |
| 193 |
| 194 _map.forEach((key, expectation) { |
| 195 List regExps = _keyToRegExps[key]; |
| 196 if (regExps.length > splitFilename.length) return; |
| 197 for (var i = 0; i < regExps.length; i++) { |
| 198 if (!regExps[i].hasMatch(splitFilename[i])) return; |
| 199 } |
| 200 // If all components of the status file key matches the filename |
| 201 // add the expectations to the result. |
| 202 result.addAll(expectation); |
| 203 }); |
| 204 |
| 205 // If no expectations were found the expectation is that the test |
| 206 // passes. |
| 207 if (result.isEmpty()) { |
| 208 result.add(PASS); |
| 209 } |
| 210 return result; |
| 211 } |
| 212 |
| 213 // Preprocess the expectations for matching against |
| 214 // filenames. Generate lists of regular expressions once and for all |
| 215 // for each key. |
| 216 void _preprocessForMatching() { |
| 217 if (_preprocessed) return; |
| 218 |
| 219 _keyToRegExps = new Map(); |
| 220 _regExpCache = new Map(); |
| 221 |
| 222 _map.forEach((key, expectations) { |
| 223 if (_keyToRegExps[key] != null) return; |
| 224 var splitKey = key.split('/'); |
| 225 var regExps = new List(splitKey.length); |
| 226 for (var i = 0; i < splitKey.length; i++) { |
| 227 var component = splitKey[i]; |
| 228 var regExp = _regExpCache[component]; |
| 229 if (regExp == null) { |
| 230 var pattern = "^${splitKey[i]}\$".replaceAll('*', '.*'); |
| 231 regExp = new RegExp(pattern); |
| 232 _regExpCache[component] = regExp; |
| 233 } |
| 234 regExps[i] = regExp; |
| 235 } |
| 236 _keyToRegExps[key] = regExps; |
| 237 }); |
| 238 |
| 239 _regExpCache = null; |
| 240 _preprocessed = true; |
| 132 } | 241 } |
| 133 } | 242 } |
| OLD | NEW |