| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:io'; | 5 import 'dart:io'; |
| 6 | 6 |
| 7 import 'package:path/path.dart' as p; | 7 import 'package:path/path.dart' as p; |
| 8 | 8 |
| 9 import 'environment.dart'; | 9 import 'environment.dart'; |
| 10 import 'expectation.dart'; | 10 import 'expectation.dart'; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 } | 76 } |
| 77 source = source.trim(); | 77 source = source.trim(); |
| 78 | 78 |
| 79 // Ignore empty (or comment-only) lines. | 79 // Ignore empty (or comment-only) lines. |
| 80 if (source.isEmpty) continue; | 80 if (source.isEmpty) continue; |
| 81 | 81 |
| 82 // See if we are starting a new section. | 82 // See if we are starting a new section. |
| 83 var match = _sectionPattern.firstMatch(source); | 83 var match = _sectionPattern.firstMatch(source); |
| 84 if (match != null) { | 84 if (match != null) { |
| 85 try { | 85 try { |
| 86 section = new StatusSection(Expression.parse(match[1].trim())); | 86 var condition = Expression.parse(match[1].trim()); |
| 87 section = new StatusSection(condition, lineNumber); |
| 87 sections.add(section); | 88 sections.add(section); |
| 88 } on FormatException { | 89 } on FormatException { |
| 89 fail("Status expression syntax error"); | 90 fail("Status expression syntax error"); |
| 90 } | 91 } |
| 91 continue; | 92 continue; |
| 92 } | 93 } |
| 93 | 94 |
| 94 // Otherwise, it should be a new entry under the current section. | 95 // Otherwise, it should be a new entry under the current section. |
| 95 match = _entryPattern.firstMatch(source); | 96 match = _entryPattern.firstMatch(source); |
| 96 if (match != null) { | 97 if (match != null) { |
| 97 var path = match[1].trim(); | 98 var path = match[1].trim(); |
| 98 // TODO(whesse): Handle test names ending in a wildcard (*). | 99 // TODO(whesse): Handle test names ending in a wildcard (*). |
| 99 var expectations = <Expectation>[]; | 100 var expectations = <Expectation>[]; |
| 100 for (var name in match[2].split(",")) { | 101 for (var name in match[2].split(",")) { |
| 101 name = name.trim(); | 102 name = name.trim(); |
| 102 try { | 103 try { |
| 103 expectations.add(Expectation.find(name)); | 104 expectations.add(Expectation.find(name)); |
| 104 } on ArgumentError { | 105 } on ArgumentError { |
| 105 fail('Unrecognized test expectation "$name"'); | 106 fail('Unrecognized test expectation "$name"'); |
| 106 } | 107 } |
| 107 } | 108 } |
| 108 | 109 |
| 109 var issue = _issueNumber(comment); | 110 var issue = _issueNumber(comment); |
| 110 | 111 |
| 111 // If we haven't found a section header yet, create an implicit section | 112 // If we haven't found a section header yet, create an implicit section |
| 112 // that matches everything. | 113 // that matches everything. |
| 113 if (section == null) { | 114 if (section == null) { |
| 114 section = new StatusSection(null); | 115 section = new StatusSection(null, -1); |
| 115 sections.add(section); | 116 sections.add(section); |
| 116 } | 117 } |
| 117 | 118 |
| 118 section.entries.add(new StatusEntry(path, expectations, issue)); | 119 section.entries |
| 120 .add(new StatusEntry(path, lineNumber, expectations, issue)); |
| 119 continue; | 121 continue; |
| 120 } | 122 } |
| 121 | 123 |
| 122 fail("Unrecognized input"); | 124 fail("Unrecognized input"); |
| 123 } | 125 } |
| 124 } | 126 } |
| 125 | 127 |
| 126 bool get isEmpty => sections.isEmpty; | 128 bool get isEmpty => sections.isEmpty; |
| 127 | 129 |
| 128 /// Validates that the variables and values used in all of the section | 130 /// Validates that the variables and values used in all of the section |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 /// One section in a status file. | 183 /// One section in a status file. |
| 182 /// | 184 /// |
| 183 /// Contains the condition from the header that begins the section, then all of | 185 /// Contains the condition from the header that begins the section, then all of |
| 184 /// the entries within the section. | 186 /// the entries within the section. |
| 185 class StatusSection { | 187 class StatusSection { |
| 186 /// The expression that determines when this section is applied. | 188 /// The expression that determines when this section is applied. |
| 187 /// | 189 /// |
| 188 /// May be `null` for paths that appear before any section header in the file. | 190 /// May be `null` for paths that appear before any section header in the file. |
| 189 /// In that case, the section always applies. | 191 /// In that case, the section always applies. |
| 190 final Expression condition; | 192 final Expression condition; |
| 193 |
| 194 /// The one-based line number where the entry appears in the file. |
| 195 final int lineNumber; |
| 196 |
| 191 final List<StatusEntry> entries = []; | 197 final List<StatusEntry> entries = []; |
| 192 | 198 |
| 193 /// Returns true if this section should apply in the given [environment]. | 199 /// Returns true if this section should apply in the given [environment]. |
| 194 bool isEnabled(Environment environment) => | 200 bool isEnabled(Environment environment) => |
| 195 condition == null || condition.evaluate(environment); | 201 condition == null || condition.evaluate(environment); |
| 196 | 202 |
| 197 StatusSection(this.condition); | 203 StatusSection(this.condition, this.lineNumber); |
| 198 } | 204 } |
| 199 | 205 |
| 200 /// Describes the test status of the file or files at a given path. | 206 /// Describes the test status of the file or files at a given path. |
| 201 class StatusEntry { | 207 class StatusEntry { |
| 202 final String path; | 208 final String path; |
| 209 |
| 210 /// The one-based line number where the entry appears in the file. |
| 211 final int lineNumber; |
| 212 |
| 203 final List<Expectation> expectations; | 213 final List<Expectation> expectations; |
| 204 final int issue; | 214 final int issue; |
| 205 | 215 |
| 206 StatusEntry(this.path, this.expectations, this.issue); | 216 StatusEntry(this.path, this.lineNumber, this.expectations, this.issue); |
| 207 } | 217 } |
| 208 | 218 |
| 209 /// Error thrown when a parse or validation error occurs in a [StatusFile]. | 219 /// Error thrown when a parse or validation error occurs in a [StatusFile]. |
| 210 class SyntaxError implements Exception { | 220 class SyntaxError implements Exception { |
| 211 final String file; | 221 final String file; |
| 212 final int lineNumber; | 222 final int lineNumber; |
| 213 final String line; | 223 final String line; |
| 214 final String message; | 224 final String message; |
| 215 final List<String> errors; | 225 final List<String> errors; |
| 216 | 226 |
| 217 SyntaxError(this.file, this.lineNumber, this.line, this.message, this.errors); | 227 SyntaxError(this.file, this.lineNumber, this.line, this.message, this.errors); |
| 218 | 228 |
| 219 String toString() { | 229 String toString() { |
| 220 var buffer = new StringBuffer(); | 230 var buffer = new StringBuffer(); |
| 221 buffer.writeln('$message in "$file" line $lineNumber:'); | 231 buffer.writeln('$message in "$file" line $lineNumber:'); |
| 222 buffer.writeln(line); | 232 buffer.writeln(line); |
| 223 | 233 |
| 224 if (errors != null) { | 234 if (errors != null) { |
| 225 for (var error in errors) { | 235 for (var error in errors) { |
| 226 buffer.writeln("- ${error.replaceAll('\n', '\n ')}"); | 236 buffer.writeln("- ${error.replaceAll('\n', '\n ')}"); |
| 227 } | 237 } |
| 228 } | 238 } |
| 229 | 239 |
| 230 return buffer.toString().trimRight(); | 240 return buffer.toString().trimRight(); |
| 231 } | 241 } |
| 232 } | 242 } |
| OLD | NEW |