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

Side by Side Diff: pkg/analyzer/test/src/task/strong/front_end_test_common.dart

Issue 3002893002: Begin writing tests of the runtime checks needed for Dart 2.0 soundness. (Closed)
Patch Set: Add more annotations to the "checks" category Created 3 years, 4 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 import 'dart:async';
6 import 'dart:convert';
7 import 'dart:io';
8
9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/element/element.dart';
11 import 'package:analyzer/dart/element/type.dart';
12 import 'package:analyzer/src/dart/analysis/driver.dart';
13 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
14 import 'package:analyzer/src/generated/parser.dart';
15 import 'package:analyzer/src/generated/resolver.dart';
16 import 'package:analyzer/src/generated/scanner.dart';
17 import 'package:analyzer/src/generated/source.dart';
18 import 'package:analyzer/src/generated/utilities_dart.dart';
19 import 'package:front_end/src/base/instrumentation.dart' as fasta;
20 import 'package:front_end/src/fasta/compiler_context.dart' as fasta;
21 import 'package:front_end/src/fasta/testing/validating_instrumentation.dart'
22 as fasta;
23 import 'package:front_end/src/fasta/util/relativize.dart' show relativizeUri;
24 import 'package:kernel/kernel.dart' as fasta;
25 import 'package:path/path.dart' as pathos;
26 import 'package:test/test.dart';
27
28 import '../../dart/analysis/base.dart';
29
30 /// Set this to `true` to cause expectation comments to be updated.
31 const bool fixProblems = false;
32
33 class ElementNamer {
34 final ConstructorElement currentFactoryConstructor;
35
36 ElementNamer(this.currentFactoryConstructor);
37
38 void appendElementName(StringBuffer buffer, Element element) {
39 // Synthetic FunctionElement(s) don't have a name or enclosing library.
40 if (element.isSynthetic && element is FunctionElement) {
41 return;
42 }
43
44 var enclosing = element.enclosingElement;
45 if (enclosing is CompilationUnitElement) {
46 enclosing = enclosing.enclosingElement;
47 } else if (enclosing is ClassElement &&
48 currentFactoryConstructor != null &&
49 identical(enclosing, currentFactoryConstructor.enclosingElement) &&
50 element is TypeParameterElement) {
51 enclosing = currentFactoryConstructor;
52 }
53 if (enclosing != null) {
54 if (enclosing is LibraryElement &&
55 (enclosing.name == 'dart.core' ||
56 enclosing.name == 'dart.async' ||
57 enclosing.name == 'test')) {
58 // For brevity, omit library name
59 } else {
60 appendElementName(buffer, enclosing);
61 buffer.write('::');
62 }
63 }
64
65 String name = element.name ?? '';
66 if (element is ConstructorElement && name == '') {
67 name = '•';
68 } else if (name.endsWith('=') &&
69 element is PropertyAccessorElement &&
70 element.isSetter) {
71 name = name.substring(0, name.length - 1);
72 }
73 buffer.write(name);
74 }
75 }
76
77 /// Instance of [InstrumentationValue] describing an [ExecutableElement].
78 class InstrumentationValueForExecutableElement
79 extends fasta.InstrumentationValue {
80 final ExecutableElement element;
81 final ElementNamer elementNamer;
82
83 InstrumentationValueForExecutableElement(this.element, this.elementNamer);
84
85 @override
86 String toString() {
87 StringBuffer buffer = new StringBuffer();
88 elementNamer.appendElementName(buffer, element);
89 return buffer.toString();
90 }
91 }
92
93 /**
94 * Instance of [InstrumentationValue] describing a [DartType].
95 */
96 class InstrumentationValueForType extends fasta.InstrumentationValue {
97 final DartType type;
98 final ElementNamer elementNamer;
99
100 InstrumentationValueForType(this.type, this.elementNamer);
101
102 @override
103 String toString() {
104 StringBuffer buffer = new StringBuffer();
105 _appendType(buffer, type);
106 return buffer.toString();
107 }
108
109 void _appendList<T>(StringBuffer buffer, String open, String close,
110 List<T> items, String separator, writeItem(T item),
111 {bool includeEmpty: false}) {
112 if (!includeEmpty && items.isEmpty) {
113 return;
114 }
115 buffer.write(open);
116 bool first = true;
117 for (T item in items) {
118 if (!first) {
119 buffer.write(separator);
120 }
121 writeItem(item);
122 first = false;
123 }
124 buffer.write(close);
125 }
126
127 void _appendParameters(
128 StringBuffer buffer, List<ParameterElement> parameters) {
129 buffer.write('(');
130 bool first = true;
131 ParameterKind lastKind = ParameterKind.REQUIRED;
132 for (var parameter in parameters) {
133 if (!first) {
134 buffer.write(', ');
135 }
136 if (lastKind != parameter.parameterKind) {
137 if (parameter.parameterKind == ParameterKind.POSITIONAL) {
138 buffer.write('[');
139 } else if (parameter.parameterKind == ParameterKind.NAMED) {
140 buffer.write('{');
141 }
142 }
143 if (parameter.parameterKind == ParameterKind.NAMED) {
144 buffer.write(parameter.name);
145 buffer.write(': ');
146 }
147 _appendType(buffer, parameter.type);
148 lastKind = parameter.parameterKind;
149 first = false;
150 }
151 if (lastKind == ParameterKind.POSITIONAL) {
152 buffer.write(']');
153 } else if (lastKind == ParameterKind.NAMED) {
154 buffer.write('}');
155 }
156 buffer.write(')');
157 }
158
159 void _appendType(StringBuffer buffer, DartType type) {
160 if (type is FunctionType) {
161 if (type.typeFormals.isNotEmpty) {
162 _appendTypeFormals(buffer, type.typeFormals);
163 }
164 _appendParameters(buffer, type.parameters);
165 buffer.write(' -> ');
166 _appendType(buffer, type.returnType);
167 } else if (type is InterfaceType) {
168 ClassElement element = type.element;
169 elementNamer.appendElementName(buffer, element);
170 _appendTypeArguments(buffer, type.typeArguments);
171 } else if (type.isBottom) {
172 buffer.write('<BottomType>');
173 } else if (type is TypeParameterType) {
174 elementNamer.appendElementName(buffer, type.element);
175 } else {
176 buffer.write(type.toString());
177 }
178 }
179
180 void _appendTypeArguments(StringBuffer buffer, List<DartType> typeArguments) {
181 _appendList<DartType>(buffer, '<', '>', typeArguments, ', ',
182 (type) => _appendType(buffer, type));
183 }
184
185 void _appendTypeFormals(
186 StringBuffer buffer, List<TypeParameterElement> typeFormals) {
187 _appendList<TypeParameterElement>(buffer, '<', '>', typeFormals, ', ',
188 (formal) {
189 buffer.write(formal.name);
190 buffer.write(' extends ');
191 if (formal.bound == null) {
192 buffer.write('Object');
193 } else {
194 _appendType(buffer, formal.bound);
195 }
196 });
197 }
198 }
199
200 /**
201 * Instance of [InstrumentationValue] describing a list of [DartType]s.
202 */
203 class InstrumentationValueForTypeArgs extends fasta.InstrumentationValue {
204 final List<DartType> types;
205 final ElementNamer elementNamer;
206
207 const InstrumentationValueForTypeArgs(this.types, this.elementNamer);
208
209 @override
210 String toString() => types
211 .map((type) =>
212 new InstrumentationValueForType(type, elementNamer).toString())
213 .join(', ');
214 }
215
216 class _FrontEndInferenceTest extends BaseAnalysisDriverTest {
217 final RunFrontEndTest _frontEndTestRunner;
218
219 _FrontEndInferenceTest(this._frontEndTestRunner);
220
221 @override
222 AnalysisOptionsImpl createAnalysisOptions() =>
223 super.createAnalysisOptions()..enableAssertInitializer = true;
224
225 Future<String> runTest(String path, String code) {
226 return fasta.CompilerContext.runWithDefaultOptions((_) async {
227 Uri uri = provider.pathContext.toUri(path);
228
229 List<int> lineStarts = new LineInfo.fromContent(code).lineStarts;
230 fasta.CompilerContext.current.uriToSource[relativizeUri(uri).toString()] =
231 new fasta.Source(lineStarts, UTF8.encode(code));
232
233 var validation = new fasta.ValidatingInstrumentation();
234 await validation.loadExpectations(uri);
235
236 _addFileAndImports(path, code);
237
238 AnalysisResult result = await driver.getResult(path);
239 _frontEndTestRunner.visitUnit(
240 result.typeProvider, result.unit, validation, uri);
241
242 validation.finish();
243
244 if (validation.hasProblems) {
245 if (fixProblems) {
246 validation.fixSource(uri, true);
247 return null;
248 } else {
249 return validation.problemsAsString;
250 }
251 } else {
252 return null;
253 }
254 });
255 }
256
257 void _addFileAndImports(String path, String code) {
258 provider.newFile(path, code);
259 var source = null;
260 var analysisErrorListener = null;
261 var scanner = new Scanner(
262 source, new CharSequenceReader(code), analysisErrorListener);
263 var token = scanner.tokenize();
264 var compilationUnit =
265 new Parser(source, analysisErrorListener).parseDirectives(token);
266 for (var directive in compilationUnit.directives) {
267 if (directive is UriBasedDirective) {
268 Uri uri = Uri.parse(directive.uri.stringValue);
269 if (uri.scheme == 'dart') {
270 // Ignore these--they should be in the mock SDK.
271 } else if (uri.scheme == '') {
272 var pathSegments = uri.pathSegments;
273 // For these tests we don't support any directory traversal; we just
274 // assume the URI is the name of a file in the same directory as all
275 // the other tests.
276 if (pathSegments.length != 1) fail('URI too complex: $uri');
277 var referencedPath =
278 pathos.join(pathos.dirname(path), pathSegments[0]);
279 if (!provider.getFile(referencedPath).exists) {
280 var referencedCode = new File(referencedPath).readAsStringSync();
281 _addFileAndImports(referencedPath, referencedCode);
282 }
283 }
284 }
285 }
286 }
287 }
288
289 abstract class RunFrontEndTest {
290 String get testSubdir;
291
292 test_run() async {
293 String pkgPath = _findPkgRoot();
294 String fePath = pathos.join(pkgPath, 'front_end', 'testcases', testSubdir);
295 List<File> dartFiles = new Directory(fePath)
296 .listSync()
297 .where((entry) => entry is File && entry.path.endsWith('.dart'))
298 .map((entry) => entry as File)
299 .toList();
300
301 var allProblems = new StringBuffer();
302 for (File file in dartFiles) {
303 var test = new _FrontEndInferenceTest(this);
304 await test.setUp();
305 try {
306 String code = file.readAsStringSync();
307 String problems = await test.runTest(file.path, code);
308 if (problems != null) {
309 allProblems.writeln(problems);
310 }
311 } finally {
312 await test.tearDown();
313 }
314 }
315 if (allProblems.isNotEmpty) {
316 fail(allProblems.toString());
317 }
318 }
319
320 /**
321 * Expects that the [Platform.script] is a test inside of `pkg/analyzer/test`
322 * folder, and return the absolute path of the `pkg` folder.
323 */
324 String _findPkgRoot() {
325 String scriptPath = pathos.fromUri(Platform.script);
326 List<String> parts = pathos.split(scriptPath);
327 for (int i = 0; i < parts.length - 2; i++) {
328 if (parts[i] == 'pkg' &&
329 parts[i + 1] == 'analyzer' &&
330 parts[i + 2] == 'test') {
331 return pathos.joinAll(parts.sublist(0, i + 1));
332 }
333 }
334 throw new StateError('Unable to find sdk/pkg/ in $scriptPath');
335 }
336
337 void visitUnit(TypeProvider typeProvider, CompilationUnit unit,
338 fasta.ValidatingInstrumentation validation, Uri uri);
339 }
OLDNEW
« no previous file with comments | « pkg/analyzer/test/src/task/strong/front_end_runtime_check_test.dart ('k') | pkg/analyzer/test/src/task/strong/test_all.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698