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 ddc.src.testing; | 5 library ddc.src.testing; |
6 | 6 |
7 import 'package:analyzer/src/generated/ast.dart'; | 7 import 'package:analyzer/src/generated/ast.dart'; |
8 import 'package:analyzer/src/generated/element.dart'; | 8 import 'package:analyzer/src/generated/element.dart'; |
9 import 'package:analyzer/src/generated/engine.dart' show TimestampedData; | 9 import 'package:analyzer/src/generated/engine.dart' show TimestampedData; |
10 import 'package:analyzer/src/generated/source.dart'; | 10 import 'package:analyzer/src/generated/source.dart'; |
11 import 'package:logging/logging.dart'; | 11 import 'package:logging/logging.dart'; |
12 import 'package:path/path.dart' as path; | 12 import 'package:path/path.dart' as path; |
13 import 'package:source_span/source_span.dart'; | 13 import 'package:source_span/source_span.dart'; |
14 import 'package:unittest/unittest.dart'; | 14 import 'package:unittest/unittest.dart'; |
15 | 15 |
16 import 'package:dev_compiler/src/checker/dart_sdk.dart' | 16 import 'package:dev_compiler/src/checker/dart_sdk.dart' |
17 show mockSdkSources, dartSdkDirectory; | 17 show mockSdkSources, dartSdkDirectory; |
18 import 'package:dev_compiler/src/checker/resolver.dart' show TypeResolver; | 18 import 'package:dev_compiler/src/checker/resolver.dart' show TypeResolver; |
19 import 'package:dev_compiler/src/utils.dart'; | 19 import 'package:dev_compiler/src/utils.dart'; |
20 import 'package:dev_compiler/src/info.dart'; | 20 import 'package:dev_compiler/src/info.dart'; |
21 import 'package:dev_compiler/src/options.dart'; | 21 import 'package:dev_compiler/src/options.dart'; |
22 import 'package:dev_compiler/src/report.dart'; | 22 import 'package:dev_compiler/src/report.dart'; |
23 import 'package:dev_compiler/devc.dart' show compile; | 23 import 'package:dev_compiler/devc.dart' show Compiler; |
24 | 24 |
25 /// Run the checker on a program with files contents as indicated in | 25 /// Run the checker on a program with files contents as indicated in |
26 /// [testFiles]. | 26 /// [testFiles]. |
27 /// | 27 /// |
28 /// This function makes several assumptions to make it easier to describe error | 28 /// This function makes several assumptions to make it easier to describe error |
29 /// expectations: | 29 /// expectations: |
30 /// | 30 /// |
31 /// * a file named `/main.dart` exists in [testFiles]. | 31 /// * a file named `/main.dart` exists in [testFiles]. |
32 /// * all expected failures are listed in the source code using comments | 32 /// * all expected failures are listed in the source code using comments |
33 /// immediately in front of the AST node that should contain the error. | 33 /// immediately in front of the AST node that should contain the error. |
(...skipping 13 matching lines...) Expand all Loading... |
47 /// }); | 47 /// }); |
48 /// | 48 /// |
49 CheckerResults testChecker(Map<String, String> testFiles, | 49 CheckerResults testChecker(Map<String, String> testFiles, |
50 {bool allowConstCasts: true, String sdkDir, CheckerReporter reporter, | 50 {bool allowConstCasts: true, String sdkDir, CheckerReporter reporter, |
51 covariantGenerics: true, relaxedCasts: true, inferFromOverrides: true, | 51 covariantGenerics: true, relaxedCasts: true, inferFromOverrides: true, |
52 inferStaticsFromIdentifiers: false, inferInNonStableOrder: false}) { | 52 inferStaticsFromIdentifiers: false, inferInNonStableOrder: false}) { |
53 expect(testFiles.containsKey('/main.dart'), isTrue, | 53 expect(testFiles.containsKey('/main.dart'), isTrue, |
54 reason: '`/main.dart` is missing in testFiles'); | 54 reason: '`/main.dart` is missing in testFiles'); |
55 | 55 |
56 // Create a resolver that can load test files from memory. | 56 // Create a resolver that can load test files from memory. |
57 var testUriResolver = new _TestUriResolver(testFiles); | 57 var testUriResolver = new TestUriResolver(testFiles); |
58 var options = new CompilerOptions( | 58 var options = new CompilerOptions( |
59 allowConstCasts: allowConstCasts, | 59 allowConstCasts: allowConstCasts, |
60 covariantGenerics: covariantGenerics, | 60 covariantGenerics: covariantGenerics, |
61 relaxedCasts: relaxedCasts, | 61 relaxedCasts: relaxedCasts, |
62 inferFromOverrides: inferFromOverrides, | 62 inferFromOverrides: inferFromOverrides, |
63 inferStaticsFromIdentifiers: inferStaticsFromIdentifiers, | 63 inferStaticsFromIdentifiers: inferStaticsFromIdentifiers, |
64 inferInNonStableOrder: inferInNonStableOrder); | 64 inferInNonStableOrder: inferInNonStableOrder, |
| 65 useMockSdk: sdkDir == null, |
| 66 dartSdkPath: sdkDir, |
| 67 entryPointFile: '/main.dart'); |
65 var resolver = sdkDir == null | 68 var resolver = sdkDir == null |
66 ? new TypeResolver.fromMock(mockSdkSources, options, | 69 ? new TypeResolver.fromMock(mockSdkSources, options, |
67 otherResolvers: [testUriResolver]) | 70 otherResolvers: [testUriResolver]) |
68 : new TypeResolver.fromDir(sdkDir, options, | 71 : new TypeResolver.fromDir(sdkDir, options, |
69 otherResolvers: [testUriResolver]); | 72 otherResolvers: [testUriResolver]); |
70 | 73 |
71 // Run the checker on /main.dart. | 74 // Run the checker on /main.dart. |
72 var mainFile = new Uri.file('/main.dart'); | 75 var mainFile = new Uri.file('/main.dart'); |
73 var checkExpectations = reporter == null; | 76 var checkExpectations = reporter == null; |
74 if (reporter == null) reporter = new TestReporter(); | 77 if (reporter == null) reporter = new TestReporter(); |
75 var results = compile('/main.dart', resolver, options, reporter); | 78 var results = new Compiler(options, resolver, reporter).runOnce(); |
76 | 79 |
77 // Extract expectations from the comments in the test files. | 80 // Extract expectations from the comments in the test files. |
78 var expectedErrors = <AstNode, List<_ErrorExpectation>>{}; | 81 var expectedErrors = <AstNode, List<_ErrorExpectation>>{}; |
79 var visitor = new _ErrorMarkerVisitor(expectedErrors); | 82 var visitor = new _ErrorMarkerVisitor(expectedErrors); |
80 var initialLibrary = | 83 var initialLibrary = |
81 resolver.context.getLibraryElement(testUriResolver.files[mainFile]); | 84 resolver.context.getLibraryElement(testUriResolver.files[mainFile]); |
82 for (var lib in reachableLibraries(initialLibrary)) { | 85 for (var lib in reachableLibraries(initialLibrary)) { |
83 for (var unit in lib.units) { | 86 for (var unit in lib.units) { |
84 unit.unit.accept(visitor); | 87 unit.unit.accept(visitor); |
85 } | 88 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 } | 169 } |
167 | 170 |
168 String _messageWithSpan(StaticInfo info) { | 171 String _messageWithSpan(StaticInfo info) { |
169 var span = _spanFor(info.node); | 172 var span = _spanFor(info.node); |
170 var level = info.level.name.toLowerCase(); | 173 var level = info.level.name.toLowerCase(); |
171 return '$level: ${span.message(info.message, color: colorOf(level))}'; | 174 return '$level: ${span.message(info.message, color: colorOf(level))}'; |
172 } | 175 } |
173 | 176 |
174 SourceSpan _spanFor(AstNode node) { | 177 SourceSpan _spanFor(AstNode node) { |
175 var root = node.root as CompilationUnit; | 178 var root = node.root as CompilationUnit; |
176 _TestSource source = (root.element as CompilationUnitElementImpl).source; | 179 TestSource source = (root.element as CompilationUnitElementImpl).source; |
177 return source.spanFor(node); | 180 return source.spanFor(node); |
178 } | 181 } |
179 | 182 |
180 /// Visitor that extracts expected errors from comments. | 183 /// Visitor that extracts expected errors from comments. |
181 class _ErrorMarkerVisitor extends UnifyingAstVisitor { | 184 class _ErrorMarkerVisitor extends UnifyingAstVisitor { |
182 Map<AstNode, List<_ErrorExpectation>> expectedErrors; | 185 Map<AstNode, List<_ErrorExpectation>> expectedErrors; |
183 | 186 |
184 _ErrorMarkerVisitor(this.expectedErrors); | 187 _ErrorMarkerVisitor(this.expectedErrors); |
185 | 188 |
186 visitNode(AstNode node) { | 189 visitNode(AstNode node) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 if (tokens[0] == "pass") return null; | 252 if (tokens[0] == "pass") return null; |
250 // TODO(leafp) For now, we just use whatever the current expectation is, | 253 // TODO(leafp) For now, we just use whatever the current expectation is, |
251 // eventually we could do more automated reporting here. | 254 // eventually we could do more automated reporting here. |
252 return _parse(tokens[0]); | 255 return _parse(tokens[0]); |
253 } | 256 } |
254 | 257 |
255 String toString() => '$level $type'; | 258 String toString() => '$level $type'; |
256 } | 259 } |
257 | 260 |
258 /// Uri resolver that can load test files from memory. | 261 /// Uri resolver that can load test files from memory. |
259 class _TestUriResolver extends UriResolver { | 262 class TestUriResolver extends UriResolver { |
260 final Map<Uri, _TestSource> files = <Uri, _TestSource>{}; | 263 final Map<Uri, TestSource> files = <Uri, TestSource>{}; |
261 | 264 |
262 _TestUriResolver(Map<String, String> allFiles) { | 265 TestUriResolver(Map<String, String> allFiles) { |
263 allFiles.forEach((key, value) { | 266 allFiles.forEach((key, value) { |
264 var uri = key.startsWith('package:') ? Uri.parse(key) : new Uri.file(key); | 267 var uri = key.startsWith('package:') ? Uri.parse(key) : new Uri.file(key); |
265 files[uri] = new _TestSource(uri, value); | 268 files[uri] = new TestSource(uri, value); |
266 }); | 269 }); |
267 } | 270 } |
268 | 271 |
269 Source resolveAbsolute(Uri uri) { | 272 Source resolveAbsolute(Uri uri) { |
270 if (uri.scheme != 'file' && uri.scheme != 'package') return null; | 273 if (uri.scheme != 'file' && uri.scheme != 'package') return null; |
271 return files[uri]; | 274 return files.putIfAbsent(uri, () => new TestSource(uri, null)); |
272 } | 275 } |
273 } | 276 } |
274 | 277 |
| 278 class TestContents implements TimestampedData<String> { |
| 279 int modificationTime; |
| 280 String data; |
| 281 |
| 282 TestContents(this.modificationTime, this.data); |
| 283 } |
| 284 |
275 /// An in memory source file. | 285 /// An in memory source file. |
276 class _TestSource implements Source { | 286 class TestSource implements Source { |
277 final Uri uri; | 287 final Uri uri; |
278 final TimestampedData<String> contents; | 288 TestContents contents; |
279 final SourceFile _file; | 289 final SourceFile _file; |
280 final UriKind uriKind; | 290 final UriKind uriKind; |
| 291 bool _exists; |
281 | 292 |
282 _TestSource(uri, contents) | 293 TestSource(uri, contents) |
283 : uri = uri, | 294 : uri = uri, |
284 contents = new TimestampedData<String>(0, contents), | 295 _exists = contents != null, |
285 _file = new SourceFile(contents, url: uri), | 296 contents = new TestContents(1, contents), |
| 297 _file = contents != null ? new SourceFile(contents, url: uri) : null, |
286 uriKind = uri.scheme == 'file' ? UriKind.FILE_URI : UriKind.PACKAGE_URI; | 298 uriKind = uri.scheme == 'file' ? UriKind.FILE_URI : UriKind.PACKAGE_URI; |
287 | 299 |
288 bool exists() => true; | 300 bool exists() => _exists; |
289 | 301 |
290 Source get source => this; | 302 Source get source => this; |
291 | 303 |
292 String _encoding; | 304 String _encoding; |
293 String get encoding => _encoding != null ? _encoding : (_encoding = '$uri'); | 305 String get encoding => _encoding != null ? _encoding : (_encoding = '$uri'); |
294 | 306 |
295 String get fullName => uri.path; | 307 String get fullName => uri.path; |
296 | 308 |
297 int get modificationStamp => 0; | 309 int get modificationStamp => contents.modificationTime; |
298 String get shortName => path.basename(uri.path); | 310 String get shortName => path.basename(uri.path); |
299 | 311 |
300 operator ==(other) => other is _TestSource && uri == other.uri; | 312 operator ==(other) => other is TestSource && uri == other.uri; |
301 int get hashCode => uri.hashCode; | 313 int get hashCode => uri.hashCode; |
302 bool get isInSystemLibrary => false; | 314 bool get isInSystemLibrary => false; |
303 | 315 |
304 Uri resolveRelativeUri(Uri relativeUri) => uri.resolveUri(relativeUri); | 316 Uri resolveRelativeUri(Uri relativeUri) => uri.resolveUri(relativeUri); |
305 | 317 |
306 SourceSpan spanFor(AstNode node) { | 318 SourceSpan spanFor(AstNode node) { |
307 final begin = node is AnnotatedNode | 319 final begin = node is AnnotatedNode |
308 ? node.firstTokenAfterCommentAndMetadata.offset | 320 ? node.firstTokenAfterCommentAndMetadata.offset |
309 : node.offset; | 321 : node.offset; |
310 return _file.span(begin, node.end); | 322 return _file.span(begin, node.end); |
311 } | 323 } |
312 | 324 |
313 String toString() => '[$runtimeType: $uri]'; | 325 String toString() => '[$runtimeType: $uri]'; |
314 } | 326 } |
OLD | NEW |