OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 test.runner.parse_metadata; | 5 library test.runner.parse_metadata; |
6 | 6 |
7 import 'dart:io'; | 7 import 'dart:io'; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart'; | 9 import 'package:analyzer/analyzer.dart'; |
10 import 'package:analyzer/src/generated/ast.dart'; | 10 import 'package:analyzer/src/generated/ast.dart'; |
(...skipping 14 matching lines...) Expand all Loading... | |
25 "microseconds" | 25 "microseconds" |
26 ]; | 26 ]; |
27 | 27 |
28 /// Parse the test metadata for the test file at [path]. | 28 /// Parse the test metadata for the test file at [path]. |
29 /// | 29 /// |
30 /// Throws an [AnalysisError] if parsing fails or a [FormatException] if the | 30 /// Throws an [AnalysisError] if parsing fails or a [FormatException] if the |
31 /// test annotations are incorrect. | 31 /// test annotations are incorrect. |
32 Metadata parseMetadata(String path) { | 32 Metadata parseMetadata(String path) { |
33 var timeout; | 33 var timeout; |
34 var testOn; | 34 var testOn; |
35 var skip; | |
35 | 36 |
36 var contents = new File(path).readAsStringSync(); | 37 var contents = new File(path).readAsStringSync(); |
37 var directives = parseDirectives(contents, name: path).directives; | 38 var directives = parseDirectives(contents, name: path).directives; |
38 var annotations = directives.isEmpty ? [] : directives.first.metadata; | 39 var annotations = directives.isEmpty ? [] : directives.first.metadata; |
39 | 40 |
40 // We explicitly *don't* just look for "package:test" imports here, | 41 // We explicitly *don't* just look for "package:test" imports here, |
41 // because it could be re-exported from another library. | 42 // because it could be re-exported from another library. |
42 var prefixes = directives.map((directive) { | 43 var prefixes = directives.map((directive) { |
43 if (directive is! ImportDirective) return null; | 44 if (directive is! ImportDirective) return null; |
44 if (directive.prefix == null) return null; | 45 if (directive.prefix == null) return null; |
(...skipping 30 matching lines...) Expand all Loading... | |
75 _spanFor(annotation, path)); | 76 _spanFor(annotation, path)); |
76 } | 77 } |
77 testOn = _parseTestOn(annotation, constructorName, path); | 78 testOn = _parseTestOn(annotation, constructorName, path); |
78 } else if (name == 'Timeout') { | 79 } else if (name == 'Timeout') { |
79 if (timeout != null) { | 80 if (timeout != null) { |
80 throw new SourceSpanFormatException( | 81 throw new SourceSpanFormatException( |
81 "Only a single Timeout annotation may be used for a given test file. ", | 82 "Only a single Timeout annotation may be used for a given test file. ", |
82 _spanFor(annotation, path)); | 83 _spanFor(annotation, path)); |
83 } | 84 } |
84 timeout = _parseTimeout(annotation, constructorName, path); | 85 timeout = _parseTimeout(annotation, constructorName, path); |
86 } else if (name == 'Skip') { | |
87 if (skip != null) { | |
88 throw new SourceSpanFormatException( | |
89 "Only a single Skip annotation may be used for a given test file.", | |
90 _spanFor(annotation, path)); | |
91 } | |
92 skip = _parseSkip(annotation, constructorName, path); | |
85 } | 93 } |
86 } | 94 } |
87 | 95 |
88 try { | 96 try { |
89 return new Metadata.parse( | 97 return new Metadata.parse( |
90 testOn: testOn == null ? null : testOn.stringValue, | 98 testOn: testOn == null ? null : testOn.stringValue, |
91 timeout: timeout); | 99 timeout: timeout, |
100 skip: skip); | |
92 } on SourceSpanFormatException catch (error) { | 101 } on SourceSpanFormatException catch (error) { |
93 var file = new SourceFile(new File(path).readAsStringSync(), | 102 var file = new SourceFile(new File(path).readAsStringSync(), |
94 url: p.toUri(path)); | 103 url: p.toUri(path)); |
95 var span = contextualizeSpan(error.span, testOn, file); | 104 var span = contextualizeSpan(error.span, testOn, file); |
96 if (span == null) rethrow; | 105 if (span == null) rethrow; |
97 throw new SourceSpanFormatException(error.message, span); | 106 throw new SourceSpanFormatException(error.message, span); |
98 } | 107 } |
99 } | 108 } |
100 | 109 |
101 /// Parses a `@TestOn` annotation. | 110 /// Parses a `@TestOn` annotation. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
181 _spanFor(annotation.arguments, path)); | 190 _spanFor(annotation.arguments, path)); |
182 } | 191 } |
183 | 192 |
184 if (constructorName == null) { | 193 if (constructorName == null) { |
185 return new Timeout(_parseDuration(args.first, path)); | 194 return new Timeout(_parseDuration(args.first, path)); |
186 } else { | 195 } else { |
187 return new Timeout.factor(_parseNum(args.first, path)); | 196 return new Timeout.factor(_parseNum(args.first, path)); |
188 } | 197 } |
189 } | 198 } |
190 | 199 |
200 /// Parses a `@Skip` annotation. | |
201 /// | |
202 /// [annotation] is the annotation. [constructorName] is the name of the named | |
203 /// constructor for the annotation, if any. [path] is the path to the file from | |
204 /// which the annotation was parsed. | |
205 _parseSkip(Annotation annotation, String constructorName, String path) { | |
kevmoo
2015/04/17 23:56:29
Is this a String? Define (and document) return val
nweiz
2015/04/18 00:07:39
Done.
| |
206 if (constructorName != null) { | |
207 throw new SourceSpanFormatException( | |
208 'Skip doesn\'t have a constructor named "$constructorName".', | |
209 _spanFor(annotation, path)); | |
210 } | |
211 | |
212 if (annotation.arguments == null) { | |
213 throw new SourceSpanFormatException( | |
214 'Skip must have parentheses.', _spanFor(annotation, path)); | |
215 } | |
216 | |
217 var args = annotation.arguments.arguments; | |
218 if (args.length > 1) { | |
219 throw new SourceSpanFormatException( | |
220 'Skip takes zero arguments or one argument.', | |
221 _spanFor(annotation.arguments, path)); | |
222 } | |
223 | |
224 if (args.isEmpty) return true; | |
225 | |
226 if (args.first is NamedExpression) { | |
227 throw new SourceSpanFormatException( | |
228 "Skip doesn't take named parameters.", _spanFor(args.first, path)); | |
229 } | |
230 | |
231 if (args.first is! StringLiteral) { | |
232 throw new SourceSpanFormatException( | |
233 "Skip takes a String.", _spanFor(args.first, path)); | |
234 } | |
235 | |
236 return args.first.stringValue; | |
237 } | |
238 | |
191 /// Parses a `const Duration` expression. | 239 /// Parses a `const Duration` expression. |
192 Duration _parseDuration(Expression expression, String path) { | 240 Duration _parseDuration(Expression expression, String path) { |
193 if (expression is! InstanceCreationExpression) { | 241 if (expression is! InstanceCreationExpression) { |
194 throw new SourceSpanFormatException( | 242 throw new SourceSpanFormatException( |
195 "Expected a Duration.", | 243 "Expected a Duration.", |
196 _spanFor(expression, path)); | 244 _spanFor(expression, path)); |
197 } | 245 } |
198 | 246 |
199 var constructor = expression as InstanceCreationExpression; | 247 var constructor = expression as InstanceCreationExpression; |
200 if (constructor.constructorName.type.name.name != 'Duration') { | 248 if (constructor.constructorName.type.name.name != 'Duration') { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
265 throw new SourceSpanFormatException( | 313 throw new SourceSpanFormatException( |
266 "Expected an integer.", _spanFor(expression, path)); | 314 "Expected an integer.", _spanFor(expression, path)); |
267 } | 315 } |
268 | 316 |
269 /// Creates a [SourceSpan] for [node]. | 317 /// Creates a [SourceSpan] for [node]. |
270 SourceSpan _spanFor(AstNode node, String path) => | 318 SourceSpan _spanFor(AstNode node, String path) => |
271 // Load a SourceFile from scratch here since we're only ever going to emit | 319 // Load a SourceFile from scratch here since we're only ever going to emit |
272 // one error per file anyway. | 320 // one error per file anyway. |
273 new SourceFile(new File(path).readAsStringSync(), url: p.toUri(path)) | 321 new SourceFile(new File(path).readAsStringSync(), url: p.toUri(path)) |
274 .span(node.offset, node.end); | 322 .span(node.offset, node.end); |
OLD | NEW |