Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: test/testing.dart

Issue 1406983003: Remove the checker and corresponding dead code (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « test/report_test.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 dev_compiler.src.testing; 5 library dev_compiler.src.testing;
6 6
7 import 'dart:mirrors'; 7 import 'dart:mirrors';
8 import 'package:analyzer/file_system/file_system.dart'; 8 import 'package:analyzer/file_system/file_system.dart';
9 import 'package:analyzer/file_system/memory_file_system.dart'; 9 import 'package:analyzer/file_system/memory_file_system.dart';
10 import 'package:analyzer/src/generated/ast.dart';
11 import 'package:analyzer/src/generated/engine.dart' 10 import 'package:analyzer/src/generated/engine.dart'
12 show AnalysisContext, AnalysisEngine, AnalysisOptionsImpl; 11 show AnalysisContext, AnalysisEngine, AnalysisOptionsImpl;
13 import 'package:analyzer/src/generated/error.dart';
14 import 'package:analyzer/src/generated/source.dart'; 12 import 'package:analyzer/src/generated/source.dart';
15 import 'package:cli_util/cli_util.dart' show getSdkDir; 13 import 'package:cli_util/cli_util.dart' show getSdkDir;
16 import 'package:logging/logging.dart';
17 import 'package:path/path.dart' as path; 14 import 'package:path/path.dart' as path;
18 import 'package:source_span/source_span.dart';
19 import 'package:test/test.dart';
20 15
21 import 'package:dev_compiler/strong_mode.dart';
22 import 'package:dev_compiler/src/analysis_context.dart'; 16 import 'package:dev_compiler/src/analysis_context.dart';
23 17
24 import 'package:dev_compiler/src/server/dependency_graph.dart' 18 import 'package:dev_compiler/src/server/dependency_graph.dart'
25 show runtimeFilesForServerMode; 19 show runtimeFilesForServerMode;
26 import 'package:dev_compiler/src/info.dart';
27 import 'package:dev_compiler/src/options.dart'; 20 import 'package:dev_compiler/src/options.dart';
28 import 'package:dev_compiler/src/utils.dart';
29 21
30 /// Shared analysis context used for compilation. 22 /// Shared analysis context used for compilation.
31 final AnalysisContext realSdkContext = () { 23 final AnalysisContext realSdkContext = () {
32 var context = createAnalysisContextWithSources( 24 var context = createAnalysisContextWithSources(new SourceResolverOptions(
33 new StrongModeOptions(), 25 dartSdkPath: getSdkDir().path,
34 new SourceResolverOptions( 26 customUrlMappings: {
35 dartSdkPath: getSdkDir().path, 27 'package:expect/expect.dart': _testCodegenPath('expect.dart'),
36 customUrlMappings: { 28 'package:async_helper/async_helper.dart':
37 'package:expect/expect.dart': _testCodegenPath('expect.dart'), 29 _testCodegenPath('async_helper.dart'),
38 'package:async_helper/async_helper.dart': 30 'package:unittest/unittest.dart': _testCodegenPath('unittest.dart'),
39 _testCodegenPath('async_helper.dart'), 31 'package:dom/dom.dart': _testCodegenPath('sunflower', 'dom.dart')
40 'package:unittest/unittest.dart': _testCodegenPath('unittest.dart'), 32 }));
41 'package:dom/dom.dart': _testCodegenPath('sunflower', 'dom.dart')
42 }));
43 (context.analysisOptions as AnalysisOptionsImpl).cacheSize = 512; 33 (context.analysisOptions as AnalysisOptionsImpl).cacheSize = 512;
44 return context; 34 return context;
45 }(); 35 }();
46 36
47 String _testCodegenPath(String p1, [String p2]) => 37 String _testCodegenPath(String p1, [String p2]) =>
48 path.join(testDirectory, 'codegen', p1, p2); 38 path.join(testDirectory, 'codegen', p1, p2);
49 39
50 final String testDirectory = 40 final String testDirectory =
51 path.dirname((reflectClass(_TestUtils).owner as LibraryMirror).uri.path); 41 path.dirname((reflectClass(_TestUtils).owner as LibraryMirror).uri.path);
52 42
53 class _TestUtils {} 43 class _TestUtils {}
54 44
55 /// Run the checker on a program with files contents as indicated in
56 /// [testFiles].
57 ///
58 /// This function makes several assumptions to make it easier to describe error
59 /// expectations:
60 ///
61 /// * a file named `/main.dart` exists in [testFiles].
62 /// * all expected failures are listed in the source code using comments
63 /// immediately in front of the AST node that should contain the error.
64 /// * errors are formatted as a token `level:Type`, where `level` is the
65 /// logging level were the error would be reported at, and `Type` is the
66 /// concrete subclass of [StaticInfo] that denotes the error.
67 ///
68 /// For example, to check that an assignment produces a warning about a boxing
69 /// conversion, you can describe the test as follows:
70 ///
71 /// testChecker({
72 /// '/main.dart': '''
73 /// testMethod() {
74 /// dynamic x = /*warning:Box*/3;
75 /// }
76 /// '''
77 /// });
78 ///
79 void testChecker(String name, Map<String, String> testFiles,
80 {String sdkDir, customUrlMappings: const {}}) {
81 test(name, () {
82 expect(testFiles.containsKey('/main.dart'), isTrue,
83 reason: '`/main.dart` is missing in testFiles');
84
85 var provider = createTestResourceProvider(testFiles);
86 var uriResolver = new TestUriResolver(provider);
87 // Enable task model strong mode
88 AnalysisEngine.instance.useTaskModel = true;
89 var context = AnalysisEngine.instance.createAnalysisContext();
90 context.analysisOptions.strongMode = true;
91 context.sourceFactory = createSourceFactory(
92 new SourceResolverOptions(
93 customUrlMappings: customUrlMappings,
94 useMockSdk: sdkDir == null,
95 dartSdkPath: sdkDir),
96 fileResolvers: [uriResolver]);
97
98 var checker =
99 new StrongChecker(context, new StrongModeOptions(hints: true));
100
101 // Run the checker on /main.dart.
102 var mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart'));
103 var initialLibrary =
104 context.resolveCompilationUnit2(mainSource, mainSource);
105
106 // Extract expectations from the comments in the test files, and
107 // check that all errors we emit are included in the expected map.
108 var allLibraries = reachableLibraries(initialLibrary.element.library);
109 for (var lib in allLibraries) {
110 for (var unit in lib.units) {
111 if (unit.source.uri.scheme == 'dart') continue;
112
113 var errorInfo = checker.computeErrors(unit.source);
114 new _ExpectedErrorVisitor(errorInfo.errors).validate(unit.unit);
115 }
116 }
117 });
118 }
119
120 /// Creates a [MemoryResourceProvider] with test data 45 /// Creates a [MemoryResourceProvider] with test data
121 MemoryResourceProvider createTestResourceProvider( 46 MemoryResourceProvider createTestResourceProvider(
122 Map<String, String> testFiles) { 47 Map<String, String> testFiles) {
123 var provider = new MemoryResourceProvider(); 48 var provider = new MemoryResourceProvider();
124 runtimeFilesForServerMode.forEach((filepath) { 49 runtimeFilesForServerMode.forEach((filepath) {
125 testFiles['/dev_compiler_runtime/$filepath'] = 50 testFiles['/dev_compiler_runtime/$filepath'] =
126 '/* test contents of $filepath */'; 51 '/* test contents of $filepath */';
127 }); 52 });
128 testFiles.forEach((key, value) { 53 testFiles.forEach((key, value) {
129 var scheme = 'package:'; 54 var scheme = 'package:';
(...skipping 13 matching lines...) Expand all
143 68
144 @override 69 @override
145 Source resolveAbsolute(Uri uri, [Uri actualUri]) { 70 Source resolveAbsolute(Uri uri, [Uri actualUri]) {
146 if (uri.scheme == 'package') { 71 if (uri.scheme == 'package') {
147 return (provider.getResource('/packages/' + uri.path) as File) 72 return (provider.getResource('/packages/' + uri.path) as File)
148 .createSource(uri); 73 .createSource(uri);
149 } 74 }
150 return super.resolveAbsolute(uri, actualUri); 75 return super.resolveAbsolute(uri, actualUri);
151 } 76 }
152 } 77 }
153
154 class _ExpectedErrorVisitor extends UnifyingAstVisitor {
155 final Set<AnalysisError> _actualErrors;
156 CompilationUnit _unit;
157 String _unitSourceCode;
158
159 _ExpectedErrorVisitor(List<AnalysisError> actualErrors)
160 : _actualErrors = new Set.from(actualErrors);
161
162 validate(CompilationUnit unit) {
163 _unit = unit;
164 // This reads the file. Only safe because tests use MemoryFileSystem.
165 _unitSourceCode = unit.element.source.contents.data;
166
167 // Visit the compilation unit.
168 unit.accept(this);
169
170 if (_actualErrors.isNotEmpty) {
171 var actualMsgs = _actualErrors.map(_formatActualError).join('\n');
172 fail('Unexpected errors reported by checker:\n\n$actualMsgs');
173 }
174 }
175
176 visitNode(AstNode node) {
177 var token = node.beginToken;
178 var comment = token.precedingComments;
179 // Use error marker found in an immediately preceding comment,
180 // and attach it to the outermost expression that starts at that token.
181 if (comment != null) {
182 while (comment.next != null) {
183 comment = comment.next;
184 }
185 if (comment.end == token.offset && node.parent.beginToken != token) {
186 var commentText = '$comment';
187 var start = commentText.lastIndexOf('/*');
188 var end = commentText.lastIndexOf('*/');
189 if (start != -1 && end != -1) {
190 expect(start, lessThan(end));
191 var errors = commentText.substring(start + 2, end).split(',');
192 var expectations =
193 errors.map(_ErrorExpectation.parse).where((x) => x != null);
194
195 for (var e in expectations) _expectError(node, e);
196 }
197 }
198 }
199 return super.visitNode(node);
200 }
201
202 void _expectError(AstNode node, _ErrorExpectation expected) {
203 // See if we can find the expected error in our actual errors
204 for (var actual in _actualErrors) {
205 if (actual.offset == node.offset && actual.length == node.length) {
206 var actualMsg = _formatActualError(actual);
207 expect(_actualErrorLevel(actual), expected.level,
208 reason: 'expected different error code at:\n\n$actualMsg');
209 expect(errorCodeName(actual.errorCode), expected.typeName,
210 reason: 'expected different error type at:\n\n$actualMsg');
211
212 // We found it. Stop the search.
213 _actualErrors.remove(actual);
214 return;
215 }
216 }
217
218 var span = _createSpan(node.offset, node.length);
219 var levelName = expected.level.name.toLowerCase();
220 var msg = span.message(expected.typeName, color: colorOf(levelName));
221 fail('expected error was not reported at:\n\n$levelName: $msg');
222 }
223
224 Level _actualErrorLevel(AnalysisError actual) {
225 return const <ErrorSeverity, Level>{
226 ErrorSeverity.ERROR: Level.SEVERE,
227 ErrorSeverity.WARNING: Level.WARNING,
228 ErrorSeverity.INFO: Level.INFO
229 }[actual.errorCode.errorSeverity];
230 }
231
232 String _formatActualError(AnalysisError actual) {
233 var span = _createSpan(actual.offset, actual.length);
234 var levelName = _actualErrorLevel(actual).name.toLowerCase();
235 var msg = span.message(actual.message, color: colorOf(levelName));
236 return '$levelName: [${errorCodeName(actual.errorCode)}] $msg';
237 }
238
239 SourceSpan _createSpan(int offset, int len) {
240 return createSpanHelper(_unit.lineInfo, offset, offset + len,
241 _unit.element.source, _unitSourceCode);
242 }
243 }
244
245 /// Describes an expected message that should be produced by the checker.
246 class _ErrorExpectation {
247 final Level level;
248 final String typeName;
249 _ErrorExpectation(this.level, this.typeName);
250
251 static _ErrorExpectation _parse(String descriptor) {
252 var tokens = descriptor.split(':');
253 expect(tokens.length, 2, reason: 'invalid error descriptor');
254 var name = tokens[0].toUpperCase();
255 var typeName = tokens[1];
256
257 var level =
258 Level.LEVELS.firstWhere((l) => l.name == name, orElse: () => null);
259 expect(level, isNotNull,
260 reason: 'invalid level in error descriptor: `${tokens[0]}`');
261 expect(typeName, isNotNull,
262 reason: 'invalid type in error descriptor: ${tokens[1]}');
263 return new _ErrorExpectation(level, typeName);
264 }
265
266 static _ErrorExpectation parse(String descriptor) {
267 descriptor = descriptor.trim();
268 var tokens = descriptor.split(' ');
269 if (tokens.length == 1) return _parse(tokens[0]);
270 expect(tokens.length, 4, reason: 'invalid error descriptor');
271 expect(tokens[1], "should", reason: 'invalid error descriptor');
272 expect(tokens[2], "be", reason: 'invalid error descriptor');
273 if (tokens[0] == "pass") return null;
274 // TODO(leafp) For now, we just use whatever the current expectation is,
275 // eventually we could do more automated reporting here.
276 return _parse(tokens[0]);
277 }
278
279 String toString() => '$level $typeName';
280 }
OLDNEW
« no previous file with comments | « test/report_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698