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

Side by Side Diff: pkg/analyzer_cli/test/driver_test.dart

Issue 2976493002: Convert driver_test.dart to reflective tests. (Closed)
Patch Set: Created 3 years, 5 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 | « no previous file | 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 analyzer_cli.test.driver; 5 library analyzer_cli.test.driver;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:io'; 8 import 'dart:io';
9 9
10 import 'package:analyzer/error/error.dart'; 10 import 'package:analyzer/error/error.dart';
11 import 'package:analyzer/source/analysis_options_provider.dart'; 11 import 'package:analyzer/source/analysis_options_provider.dart';
12 import 'package:analyzer/source/error_processor.dart'; 12 import 'package:analyzer/source/error_processor.dart';
13 import 'package:analyzer/src/error/codes.dart'; 13 import 'package:analyzer/src/error/codes.dart';
14 import 'package:analyzer/src/generated/engine.dart'; 14 import 'package:analyzer/src/generated/engine.dart';
15 import 'package:analyzer/src/generated/source.dart'; 15 import 'package:analyzer/src/generated/source.dart';
16 import 'package:analyzer/src/services/lint.dart'; 16 import 'package:analyzer/src/services/lint.dart';
17 import 'package:analyzer/src/summary/idl.dart'; 17 import 'package:analyzer/src/summary/idl.dart';
18 import 'package:analyzer/src/util/sdk.dart'; 18 import 'package:analyzer/src/util/sdk.dart';
19 import 'package:analyzer_cli/src/ansi.dart' as ansi; 19 import 'package:analyzer_cli/src/ansi.dart' as ansi;
20 import 'package:analyzer_cli/src/driver.dart'; 20 import 'package:analyzer_cli/src/driver.dart';
21 import 'package:analyzer_cli/src/options.dart'; 21 import 'package:analyzer_cli/src/options.dart';
22 import 'package:path/path.dart' as path; 22 import 'package:path/path.dart' as path;
23 import 'package:test/test.dart'; 23 import 'package:test/test.dart';
24 import 'package:test_reflective_loader/test_reflective_loader.dart';
24 import 'package:yaml/src/yaml_node.dart'; 25 import 'package:yaml/src/yaml_node.dart';
25 26
26 import 'utils.dart'; 27 import 'utils.dart';
27 28
28 main() { 29 main() {
29 StringSink savedOutSink, savedErrorSink; 30 defineReflectiveSuite(() {
30 int savedExitCode; 31 defineReflectiveTests(BuildModeTest);
31 ExitHandler savedExitHandler; 32 defineReflectiveTests(ExitCodesTest);
32 33 defineReflectiveTests(LinterTest);
33 /// Base setup. 34 defineReflectiveTests(OptionsTest);
34 _setUp() { 35 }, name: 'Driver');
35 ansi.runningTests = true; 36 }
36 savedOutSink = outSink; 37
37 savedErrorSink = errorSink; 38 @reflectiveTest
38 savedExitHandler = exitHandler; 39 class BuildModeTest extends _BaseTest {
39 savedExitCode = exitCode; 40 test_buildLinked() async {
40 exitHandler = (code) => exitCode = code; 41 await withTempDirAsync((tempDir) async {
41 outSink = new StringBuffer(); 42 var outputPath = path.join(tempDir, 'test_file.dart.sum');
42 errorSink = new StringBuffer(); 43 await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [
43 } 44 '--build-summary-only',
44 45 '--build-summary-output=$outputPath'
45 /// Base teardown. 46 ]);
46 _tearDown() { 47 var output = new File(outputPath);
47 outSink = savedOutSink; 48 expect(output.existsSync(), isTrue);
48 errorSink = savedErrorSink; 49 PackageBundle bundle =
49 exitCode = savedExitCode; 50 new PackageBundle.fromBuffer(await output.readAsBytes());
50 exitHandler = savedExitHandler; 51 var testFileUri = 'file:///test_file.dart';
51 ansi.runningTests = false; 52 expect(bundle.unlinkedUnitUris, equals([testFileUri]));
52 } 53 expect(bundle.linkedLibraryUris, equals([testFileUri]));
53 54 expect(exitCode, 0);
54 setUp(() => _setUp());
55
56 tearDown(() => _tearDown());
57
58 group('Driver', () {
59 group('options', () {
60 test('todos', () async {
61 await drive('data/file_with_todo.dart');
62 expect(outSink.toString().contains('[info]'), isFalse);
63 });
64 }); 55 });
65 56 }
66 _test_exitCodes(); 57
67 _test_linter(); 58 test_buildSuppressExitCode_fail_whenFileNotFound() async {
68 _test_optionsProcessing(); 59 await _doDrive(path.join('data', 'non_existent_file.dart'),
69 _test_buildMode(); 60 additionalArgs: ['--build-suppress-exit-code']);
70 61 expect(exitCode, isNot(0));
71 //TODO(pq): fix to be bot-friendly (sdk#25258). 62 }
Brian Wilkerson 2017/07/07 16:25:30 Did we loose these tests?
scheglov 2017/07/07 16:37:53 Yes, we did. Comments is a good long-term code arc
72 // group('in temp directory', () { 63
73 // Directory savedCurrentDirectory; 64 test_buildSuppressExitCode_success_evenIfHasError() async {
74 // Directory tempDir; 65 await _doDrive(path.join('data', 'file_with_error.dart'),
75 // setUp(() { 66 additionalArgs: ['--build-suppress-exit-code']);
76 // // Call base setUp. 67 expect(exitCode, 0);
77 // _setUp(); 68 }
78 // savedCurrentDirectory = Directory.current; 69
79 // tempDir = Directory.systemTemp.createTempSync('analyzer_'); 70 test_buildUnlinked() async {
80 // }); 71 await withTempDirAsync((tempDir) async {
81 // tearDown(() { 72 var outputPath = path.join(tempDir, 'test_file.dart.sum');
82 // Directory.current = savedCurrentDirectory; 73 await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [
83 // tempDir.deleteSync(recursive: true); 74 '--build-summary-only',
84 // // Call base tearDown. 75 '--build-summary-only-unlinked',
85 // _tearDown(); 76 '--build-summary-output=$outputPath'
86 // }); 77 ]);
87 // 78 var output = new File(outputPath);
88 // test('packages folder', () { 79 expect(output.existsSync(), isTrue);
89 // Directory.current = tempDir; 80 PackageBundle bundle =
90 // new File(path.join(tempDir.path, 'test.dart')).writeAsStringSync(''' 81 new PackageBundle.fromBuffer(await output.readAsBytes());
91 //import 'package:foo/bar.dart'; 82 var testFileUri = 'file:///test_file.dart';
92 //main() { 83 expect(bundle.unlinkedUnits.length, 1);
93 // baz(); 84 expect(bundle.unlinkedUnitUris, equals([testFileUri]));
94 //} 85 expect(bundle.linkedLibraryUris, isEmpty);
95 // '''); 86 expect(exitCode, 0);
96 // Directory packagesDir = 87 });
97 // new Directory(path.join(tempDir.path, 'packages')); 88 }
98 // packagesDir.createSync(); 89
99 // Directory fooDir = new Directory(path.join(packagesDir.path, 'foo')); 90 test_consumeLinked() async {
100 // fooDir.createSync(); 91 await withTempDirAsync((tempDir) async {
101 // new File(path.join(fooDir.path, 'bar.dart')).writeAsStringSync(''' 92 var aDart = path.join(tempDir, 'a.dart');
102 //void baz() {} 93 var bDart = path.join(tempDir, 'b.dart');
103 // '''); 94 var cDart = path.join(tempDir, 'c.dart');
104 // new Driver().start(['test.dart']); 95
105 // expect(exitCode, 0); 96 var aUri = 'package:aaa/a.dart';
106 // }); 97 var bUri = 'package:bbb/b.dart';
107 // 98 var cUri = 'package:ccc/c.dart';
108 // test('no package resolution', () { 99
109 // Directory.current = tempDir; 100 var aSum = path.join(tempDir, 'a.sum');
110 // new File(path.join(tempDir.path, 'test.dart')).writeAsStringSync(''' 101 var bSum = path.join(tempDir, 'b.sum');
111 //import 'package:path/path.dart'; 102 var cSum = path.join(tempDir, 'c.sum');
112 //main() {} 103
113 // '''); 104 new File(aDart).writeAsStringSync('class A {}');
114 // new Driver().start(['test.dart']); 105 new File(bDart).writeAsStringSync('''
115 // expect(exitCode, 3);
116 // String stdout = outSink.toString();
117 // expect(stdout, contains('[error] Target of URI does not exist'));
118 // expect(stdout, contains('1 error found.'));
119 // expect(errorSink.toString(), '');
120 // });
121 //
122 // test('bad package root', () {
123 // new Driver().start(['--package-root', 'does/not/exist', 'test.dart']);
124 // String stdout = outSink.toString();
125 // expect(exitCode, 3);
126 // expect(
127 // stdout,
128 // contains(
129 // 'Package root directory (does/not/exist) does not exist.'));
130 // });
131 // });
132 });
133 }
134
135 const emptyOptionsFile = 'data/empty_options.yaml';
136
137 /// Shared driver.
138 Driver driver;
139
140 List<ErrorProcessor> get processors =>
141 driver.context.analysisOptions.errorProcessors;
142
143 /// Convert a file specification from a relative path to an absolute path.
144 /// Handles the case where the file specification is of the form "$uri|$path".
145 String adjustFileSpec(String fileSpec) {
146 int uriPrefixLength = fileSpec.indexOf('|') + 1;
147 String uriPrefix = fileSpec.substring(0, uriPrefixLength);
148 String relativePath = fileSpec.substring(uriPrefixLength);
149 return '$uriPrefix${path.join(testDirectory, relativePath)}';
150 }
151
152 /// Start a driver for the given [source], optionally providing additional
153 /// [args] and an [options] file path. The value of [options] defaults to
154 /// an empty options file to avoid unwanted configuration from an otherwise
155 /// discovered options file.
156 Future<Null> drive(String source,
157 {String options: emptyOptionsFile,
158 List<String> args: const <String>[]}) async {
159 driver = new Driver(isTesting: true);
160 var cmd = [
161 '--options',
162 path.join(testDirectory, options),
163 adjustFileSpec(source)
164 ]..addAll(args);
165 await driver.start(cmd);
166 }
167
168 /// Try to find a appropriate directory to pass to "--dart-sdk" that will
169 /// allow summaries to be found.
170 String findSdkDirForSummaries() {
171 Set<String> triedDirectories = new Set<String>();
172 bool isSuitable(String sdkDir) {
173 triedDirectories.add(sdkDir);
174 return new File(path.join(sdkDir, 'lib', '_internal', 'spec.sum'))
175 .existsSync();
176 }
177
178 // Usually the sdk directory is the parent of the parent of the "dart"
179 // executable.
180 Directory executableParent = new File(Platform.executable).parent;
181 Directory executableGrandparent = executableParent.parent;
182 if (isSuitable(executableGrandparent.path)) {
183 return executableGrandparent.path;
184 }
185 // During buildbot execution, the sdk directory is simply the parent of the
186 // "dart" executable.
187 if (isSuitable(executableParent.path)) {
188 return executableParent.path;
189 }
190 // If neither of those are suitable, assume we are running locally within the
191 // SDK project (e.g. within an IDE). Find the build output directory and
192 // search all built configurations.
193 Directory sdkRootDir =
194 new File(Platform.script.toFilePath()).parent.parent.parent.parent;
195 for (String outDirName in ['out', 'xcodebuild']) {
196 Directory outDir = new Directory(path.join(sdkRootDir.path, outDirName));
197 if (outDir.existsSync()) {
198 for (FileSystemEntity subdir in outDir.listSync()) {
199 if (subdir is Directory) {
200 String candidateSdkDir = path.join(subdir.path, 'dart-sdk');
201 if (isSuitable(candidateSdkDir)) {
202 return candidateSdkDir;
203 }
204 }
205 }
206 }
207 }
208 throw new Exception('Could not find an SDK directory containing summaries.'
209 ' Tried: ${triedDirectories.toList()}');
210 }
211
212 Map<String, YamlNode> parseOptions(String src) =>
213 new AnalysisOptionsProvider().getOptionsFromString(src);
214
215 ErrorProcessor processorFor(AnalysisError error) =>
216 processors.firstWhere((p) => p.appliesTo(error));
217
218 /// Normalize text with bullets.
219 String _bulletToDash(item) => '$item'.replaceAll('•', '-');
220
221 void _test_buildMode() {
222 void createTests(String designator, String optionsFileName) {
223 group('build-mode - $designator', () {
224 // Shared driver command.
225 Future<Null> doDrive(String path,
226 {String uri, List<String> additionalArgs: const []}) async {
227 uri ??= 'file:///test_file.dart';
228 await drive('$uri|$path',
229 args: [
230 '--dart-sdk',
231 findSdkDirForSummaries(),
232 '--build-mode',
233 '--format=machine'
234 ]..addAll(additionalArgs),
235 options: 'data/options_tests_project/$optionsFileName');
236 }
237
238 test('no stats', () async {
239 await doDrive(path.join('data', 'test_file.dart'));
240 // Should not print stat summary.
241 expect(outSink.toString(), isEmpty);
242 expect(errorSink.toString(), isEmpty);
243 expect(exitCode, 0);
244 });
245
246 test(
247 'Fails if file not found, even when --build-suppress-exit-code is give n',
248 () async {
249 await doDrive(path.join('data', 'non_existent_file.dart'),
250 additionalArgs: ['--build-suppress-exit-code']);
251 expect(exitCode, isNot(0));
252 });
253
254 test('Fails if there are errors', () async {
255 await doDrive(path.join('data', 'file_with_error.dart'));
256 expect(exitCode, isNot(0));
257 });
258
259 test(
260 'Succeeds if there are errors, when --build-suppress-exit-code is give n',
261 () async {
262 await doDrive(path.join('data', 'file_with_error.dart'),
263 additionalArgs: ['--build-suppress-exit-code']);
264 expect(exitCode, 0);
265 });
266
267 test('Consume summaries', () async {
268 await withTempDirAsync((tempDir) async {
269 var aDart = path.join(tempDir, 'a.dart');
270 var bDart = path.join(tempDir, 'b.dart');
271 var cDart = path.join(tempDir, 'c.dart');
272
273 var aUri = 'package:aaa/a.dart';
274 var bUri = 'package:bbb/b.dart';
275 var cUri = 'package:ccc/c.dart';
276
277 var aSum = path.join(tempDir, 'a.sum');
278 var bSum = path.join(tempDir, 'b.sum');
279 var cSum = path.join(tempDir, 'c.sum');
280
281 new File(aDart).writeAsStringSync('class A {}');
282 new File(bDart).writeAsStringSync('''
283 export 'package:aaa/a.dart'; 106 export 'package:aaa/a.dart';
284 class B {} 107 class B {}
285 '''); 108 ''');
286 new File(cDart).writeAsStringSync(''' 109 new File(cDart).writeAsStringSync('''
287 import 'package:bbb/b.dart'; 110 import 'package:bbb/b.dart';
288 var a = new A(); 111 var a = new A();
289 var b = new B(); 112 var b = new B();
290 '''); 113 ''');
291 114
292 // Analyze package:aaa/a.dart and compute summary. 115 // Analyze package:aaa/a.dart and compute summary.
293 { 116 {
294 await doDrive(aDart, 117 await _doDrive(aDart,
295 uri: aUri, additionalArgs: ['--build-summary-output=$aSum']); 118 uri: aUri, additionalArgs: ['--build-summary-output=$aSum']);
296 expect(exitCode, 0); 119 expect(exitCode, 0);
297 var bytes = new File(aSum).readAsBytesSync(); 120 var bytes = new File(aSum).readAsBytesSync();
298 var bundle = new PackageBundle.fromBuffer(bytes); 121 var bundle = new PackageBundle.fromBuffer(bytes);
299 expect(bundle.unlinkedUnitUris, equals([aUri])); 122 expect(bundle.unlinkedUnitUris, equals([aUri]));
300 expect(bundle.linkedLibraryUris, equals([aUri])); 123 expect(bundle.linkedLibraryUris, equals([aUri]));
124 }
125
126 // Analyze package:bbb/b.dart and compute summary.
127 {
128 await _doDrive(bDart, uri: bUri, additionalArgs: [
129 '--build-summary-input=$aSum',
130 '--build-summary-output=$bSum'
131 ]);
132 expect(exitCode, 0);
133 var bytes = new File(bSum).readAsBytesSync();
134 var bundle = new PackageBundle.fromBuffer(bytes);
135 expect(bundle.unlinkedUnitUris, equals([bUri]));
136 expect(bundle.linkedLibraryUris, equals([bUri]));
137 }
138
139 // Analyze package:ccc/c.dart and compute summary.
140 {
141 await _doDrive(cDart, uri: cUri, additionalArgs: [
142 '--build-summary-input=$aSum,$bSum',
143 '--build-summary-output=$cSum'
144 ]);
145 expect(exitCode, 0);
146 var bytes = new File(cSum).readAsBytesSync();
147 var bundle = new PackageBundle.fromBuffer(bytes);
148 expect(bundle.unlinkedUnitUris, equals([cUri]));
149 expect(bundle.linkedLibraryUris, equals([cUri]));
150 }
151 });
152 }
153
154 test_error_linkedAsUnlinked() async {
155 await withTempDirAsync((tempDir) async {
156 var aDart = path.join(tempDir, 'a.dart');
157 var bDart = path.join(tempDir, 'b.dart');
158
159 var aUri = 'package:aaa/a.dart';
160 var bUri = 'package:bbb/b.dart';
161
162 var aSum = path.join(tempDir, 'a.sum');
163 var bSum = path.join(tempDir, 'b.sum');
164
165 new File(aDart).writeAsStringSync('class A {}');
166
167 // Build linked a.sum
168 await _doDrive(aDart, uri: aUri, additionalArgs: [
169 '--build-summary-only',
170 '--build-summary-output=$aSum'
171 ]);
172 expect(new File(aSum).existsSync(), isTrue);
173
174 // Try to consume linked a.sum as unlinked.
175 try {
176 await _doDrive(bDart, uri: bUri, additionalArgs: [
177 '--build-summary-unlinked-input=$aSum',
178 '--build-summary-output=$bSum'
179 ]);
180 fail('ArgumentError expected.');
181 } on ArgumentError catch (e) {
182 expect(
183 e.message,
184 contains(
185 'Got a linked summary for --build-summary-input-unlinked'));
186 }
187 });
188 }
189
190 test_error_unlinkedAsLinked() async {
191 await withTempDirAsync((tempDir) async {
192 var aDart = path.join(tempDir, 'a.dart');
193 var bDart = path.join(tempDir, 'b.dart');
194
195 var aUri = 'package:aaa/a.dart';
196 var bUri = 'package:bbb/b.dart';
197
198 var aSum = path.join(tempDir, 'a.sum');
199 var bSum = path.join(tempDir, 'b.sum');
200
201 new File(aDart).writeAsStringSync('class A {}');
202
203 // Build unlinked a.sum
204 await _doDrive(aDart, uri: aUri, additionalArgs: [
205 '--build-summary-only',
206 '--build-summary-only-unlinked',
207 '--build-summary-output=$aSum'
208 ]);
209 expect(new File(aSum).existsSync(), isTrue);
210
211 // Try to consume unlinked a.sum as linked.
212 try {
213 await _doDrive(bDart, uri: bUri, additionalArgs: [
214 '--build-summary-input=$aSum',
215 '--build-summary-output=$bSum'
216 ]);
217 fail('ArgumentError expected.');
218 } on ArgumentError catch (e) {
219 expect(e.message,
220 contains('Got an unlinked summary for --build-summary-input'));
221 }
222 });
223 }
224
225 test_fail_whenHasError() async {
226 await _doDrive(path.join('data', 'file_with_error.dart'));
227 expect(exitCode, isNot(0));
228 }
229
230 test_noStatistics() async {
231 await _doDrive(path.join('data', 'test_file.dart'));
232 // Should not print statistics summary.
233 expect(outSink.toString(), isEmpty);
234 expect(errorSink.toString(), isEmpty);
235 expect(exitCode, 0);
236 }
237
238 Future<Null> _doDrive(String path,
239 {String uri, List<String> additionalArgs: const []}) async {
240 uri ??= 'file:///test_file.dart';
241 var optionsFileName = AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
242 await drive('$uri|$path',
243 args: [
244 '--dart-sdk',
245 _findSdkDirForSummaries(),
246 '--build-mode',
247 '--format=machine'
248 ]..addAll(additionalArgs),
249 options: 'data/options_tests_project/$optionsFileName');
250 }
251
252 /// Try to find a appropriate directory to pass to "--dart-sdk" that will
253 /// allow summaries to be found.
254 String _findSdkDirForSummaries() {
255 Set<String> triedDirectories = new Set<String>();
256 bool isSuitable(String sdkDir) {
257 triedDirectories.add(sdkDir);
258 return new File(path.join(sdkDir, 'lib', '_internal', 'spec.sum'))
259 .existsSync();
260 }
261
262 // Usually the sdk directory is the parent of the parent of the "dart"
263 // executable.
264 Directory executableParent = new File(Platform.executable).parent;
265 Directory executableGrandparent = executableParent.parent;
266 if (isSuitable(executableGrandparent.path)) {
267 return executableGrandparent.path;
268 }
269 // During build bot execution, the sdk directory is simply the parent of the
270 // "dart" executable.
271 if (isSuitable(executableParent.path)) {
272 return executableParent.path;
273 }
274 // If neither of those are suitable, assume we are running locally within th e
275 // SDK project (e.g. within an IDE). Find the build output directory and
276 // search all built configurations.
277 Directory sdkRootDir =
278 new File(Platform.script.toFilePath()).parent.parent.parent.parent;
279 for (String outDirName in ['out', 'xcodebuild']) {
280 Directory outDir = new Directory(path.join(sdkRootDir.path, outDirName));
281 if (outDir.existsSync()) {
282 for (FileSystemEntity subdir in outDir.listSync()) {
283 if (subdir is Directory) {
284 String candidateSdkDir = path.join(subdir.path, 'dart-sdk');
285 if (isSuitable(candidateSdkDir)) {
286 return candidateSdkDir;
287 }
301 } 288 }
302 289 }
303 // Analyze package:bbb/b.dart and compute summary. 290 }
304 { 291 }
305 await doDrive(bDart, uri: bUri, additionalArgs: [ 292 throw new Exception('Could not find an SDK directory containing summaries.'
306 '--build-summary-input=$aSum', 293 ' Tried: ${triedDirectories.toList()}');
307 '--build-summary-output=$bSum' 294 }
308 ]); 295 }
309 expect(exitCode, 0); 296
310 var bytes = new File(bSum).readAsBytesSync(); 297 @reflectiveTest
311 var bundle = new PackageBundle.fromBuffer(bytes); 298 class ExitCodesTest extends _BaseTest {
312 expect(bundle.unlinkedUnitUris, equals([bUri])); 299 test_bazelWorkspace_relativePath() async {
313 expect(bundle.linkedLibraryUris, equals([bUri])); 300 // Copy to temp dir so that existing analysis options
314 } 301 // in the test directory hierarchy do not interfere
315 302 await withTempDirAsync((String tempDirPath) async {
316 // Analyze package:ccc/c.dart and compute summary. 303 String dartSdkPath = path.absolute(getSdkPath());
317 { 304 await recursiveCopy(
318 await doDrive(cDart, uri: cUri, additionalArgs: [ 305 new Directory(path.join(testDirectory, 'data', 'bazel')),
319 '--build-summary-input=$aSum,$bSum', 306 tempDirPath);
320 '--build-summary-output=$cSum' 307 Directory origWorkingDir = Directory.current;
321 ]); 308 try {
322 expect(exitCode, 0); 309 Directory.current = path.join(tempDirPath, 'proj');
323 var bytes = new File(cSum).readAsBytesSync(); 310 Driver driver = new Driver(isTesting: true);
324 var bundle = new PackageBundle.fromBuffer(bytes); 311 try {
325 expect(bundle.unlinkedUnitUris, equals([cUri])); 312 await driver.start([
326 expect(bundle.linkedLibraryUris, equals([cUri])); 313 path.join('lib', 'file.dart'),
327 } 314 '--dart-sdk',
328 }); 315 dartSdkPath,
329 });
330
331 test('Error - unlinked summary as linked', () async {
332 await withTempDirAsync((tempDir) async {
333 var aDart = path.join(tempDir, 'a.dart');
334 var bDart = path.join(tempDir, 'b.dart');
335
336 var aUri = 'package:aaa/a.dart';
337 var bUri = 'package:bbb/b.dart';
338
339 var aSum = path.join(tempDir, 'a.sum');
340 var bSum = path.join(tempDir, 'b.sum');
341
342 new File(aDart).writeAsStringSync('class A {}');
343
344 // Build unlinked a.sum
345 await doDrive(aDart, uri: aUri, additionalArgs: [
346 '--build-summary-only',
347 '--build-summary-only-unlinked',
348 '--build-summary-output=$aSum'
349 ]); 316 ]);
350 expect(new File(aSum).existsSync(), isTrue); 317 } catch (e) {
351 318 print('=== debug info ===');
352 // Try to consume unlinked a.sum as linked. 319 print('dartSdkPath: $dartSdkPath');
353 try { 320 print('stderr:\n${errorSink.toString()}');
354 await doDrive(bDart, uri: bUri, additionalArgs: [ 321 rethrow;
355 '--build-summary-input=$aSum', 322 }
356 '--build-summary-output=$bSum' 323 expect(errorSink.toString(), isEmpty);
357 ]); 324 expect(outSink.toString(), contains('No issues found'));
358 fail('ArgumentError expected.'); 325 expect(exitCode, 0);
359 } on ArgumentError catch (e) { 326 } finally {
360 expect(e.message, 327 Directory.current = origWorkingDir;
361 contains('Got an unlinked summary for --build-summary-input')); 328 }
362 }
363 });
364 });
365
366 test('Error - linked summary as unlinked', () async {
367 await withTempDirAsync((tempDir) async {
368 var aDart = path.join(tempDir, 'a.dart');
369 var bDart = path.join(tempDir, 'b.dart');
370
371 var aUri = 'package:aaa/a.dart';
372 var bUri = 'package:bbb/b.dart';
373
374 var aSum = path.join(tempDir, 'a.sum');
375 var bSum = path.join(tempDir, 'b.sum');
376
377 new File(aDart).writeAsStringSync('class A {}');
378
379 // Build linked a.sum
380 await doDrive(aDart, uri: aUri, additionalArgs: [
381 '--build-summary-only',
382 '--build-summary-output=$aSum'
383 ]);
384 expect(new File(aSum).existsSync(), isTrue);
385
386 // Try to consume linked a.sum as unlinked.
387 try {
388 await doDrive(bDart, uri: bUri, additionalArgs: [
389 '--build-summary-unlinked-input=$aSum',
390 '--build-summary-output=$bSum'
391 ]);
392 fail('ArgumentError expected.');
393 } on ArgumentError catch (e) {
394 expect(
395 e.message,
396 contains(
397 'Got a linked summary for --build-summary-input-unlinked'));
398 }
399 });
400 });
401
402 test('Linked summary', () async {
403 await withTempDirAsync((tempDir) async {
404 var outputPath = path.join(tempDir, 'test_file.dart.sum');
405 await doDrive(path.join('data', 'test_file.dart'), additionalArgs: [
406 '--build-summary-only',
407 '--build-summary-output=$outputPath'
408 ]);
409 var output = new File(outputPath);
410 expect(output.existsSync(), isTrue);
411 PackageBundle bundle =
412 new PackageBundle.fromBuffer(await output.readAsBytes());
413 var testFileUri = 'file:///test_file.dart';
414 expect(bundle.unlinkedUnitUris, equals([testFileUri]));
415 expect(bundle.linkedLibraryUris, equals([testFileUri]));
416 expect(exitCode, 0);
417 });
418 });
419
420 test('Unlinked summary only', () async {
421 await withTempDirAsync((tempDir) async {
422 var outputPath = path.join(tempDir, 'test_file.dart.sum');
423 await doDrive(path.join('data', 'test_file.dart'), additionalArgs: [
424 '--build-summary-only',
425 '--build-summary-only-unlinked',
426 '--build-summary-output=$outputPath'
427 ]);
428 var output = new File(outputPath);
429 expect(output.existsSync(), isTrue);
430 PackageBundle bundle =
431 new PackageBundle.fromBuffer(await output.readAsBytes());
432 var testFileUri = 'file:///test_file.dart';
433 expect(bundle.unlinkedUnits.length, 1);
434 expect(bundle.unlinkedUnitUris, equals([testFileUri]));
435 expect(bundle.linkedLibraryUris, isEmpty);
436 expect(exitCode, 0);
437 });
438 });
439 }); 329 });
440 } 330 }
441 331
442 createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); 332 test_enableAssertInitializer() async {
443 createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); 333 await drive('data/file_with_assert_initializers.dart',
334 args: ['--enable-assert-initializers']);
335 expect(exitCode, 0);
336 }
337
338 test_fatalErrors() async {
339 await drive('data/file_with_error.dart');
340 expect(exitCode, 3);
341 }
342
343 test_fatalHints() async {
344 await drive('data/file_with_hint.dart', args: ['--fatal-hints']);
345 expect(exitCode, 1);
346 }
347
348 test_fatalWarnings() async {
349 await drive('data/file_with_warning.dart', args: ['--fatal-warnings']);
350 expect(exitCode, 2);
351 }
352
353 test_missingDartFile() async {
354 await drive('data/NO_DART_FILE_HERE.dart');
355 expect(exitCode, 3);
356 }
357
358 test_missingOptionsFile() async {
359 await drive('data/test_file.dart', options: 'data/NO_OPTIONS_HERE');
360 expect(exitCode, 3);
361 }
362
363 test_notFatalHints() async {
364 await drive('data/file_with_hint.dart');
365 expect(exitCode, 0);
366 }
367
368 test_notFatalWarnings() async {
369 await drive('data/file_with_warning.dart');
370 expect(exitCode, 0);
371 }
372
373 test_partFile() async {
374 Driver driver = new Driver(isTesting: true);
375 await driver.start([
376 path.join(testDirectory, 'data/library_and_parts/lib.dart'),
377 path.join(testDirectory, 'data/library_and_parts/part1.dart')
378 ]);
379 expect(exitCode, 0);
380 }
381
382 test_partFile_dangling() async {
383 await drive('data/library_and_parts/part2.dart');
384 expect(exitCode, 3);
385 }
386
387 test_partFile_extra() async {
388 Driver driver = new Driver(isTesting: true);
389 await driver.start([
390 path.join(testDirectory, 'data/library_and_parts/lib.dart'),
391 path.join(testDirectory, 'data/library_and_parts/part1.dart'),
392 path.join(testDirectory, 'data/library_and_parts/part2.dart')
393 ]);
394 expect(exitCode, 3);
395 }
444 } 396 }
445 397
446 void _test_exitCodes() { 398 @reflectiveTest
447 group('exit codes', () { 399 class LinterTest extends _BaseTest {
448 test('fatal hints', () async { 400 String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
449 await drive('data/file_with_hint.dart', args: ['--fatal-hints']); 401
450 expect(exitCode, 1); 402 test_containsLintRuleEntry() async {
451 });
452
453 test('not fatal hints', () async {
454 await drive('data/file_with_hint.dart');
455 expect(exitCode, 0);
456 });
457
458 test('fatal errors', () async {
459 await drive('data/file_with_error.dart');
460 expect(exitCode, 3);
461 });
462
463 test('not fatal warnings', () async {
464 await drive('data/file_with_warning.dart');
465 expect(exitCode, 0);
466 });
467
468 test('fatal warnings', () async {
469 await drive('data/file_with_warning.dart', args: ['--fatal-warnings']);
470 expect(exitCode, 2);
471 });
472
473 test('not parse enableAssertInitializer', () async {
474 await drive('data/file_with_assert_initializers.dart',
475 args: ['--enable-assert-initializers']);
476 expect(exitCode, 0);
477 });
478
479 test('missing options file', () async {
480 await drive('data/test_file.dart', options: 'data/NO_OPTIONS_HERE');
481 expect(exitCode, 3);
482 });
483
484 test('missing dart file', () async {
485 await drive('data/NO_DART_FILE_HERE.dart');
486 expect(exitCode, 3);
487 });
488
489 test('part file', () async {
490 await drive('data/library_and_parts/part2.dart');
491 expect(exitCode, 3);
492 });
493
494 test('non-dangling part file', () async {
495 Driver driver = new Driver(isTesting: true);
496 await driver.start([
497 path.join(testDirectory, 'data/library_and_parts/lib.dart'),
498 path.join(testDirectory, 'data/library_and_parts/part1.dart')
499 ]);
500 expect(exitCode, 0);
501 });
502
503 test('extra part file', () async {
504 Driver driver = new Driver(isTesting: true);
505 await driver.start([
506 path.join(testDirectory, 'data/library_and_parts/lib.dart'),
507 path.join(testDirectory, 'data/library_and_parts/part1.dart'),
508 path.join(testDirectory, 'data/library_and_parts/part2.dart')
509 ]);
510 expect(exitCode, 3);
511 });
512
513 test('bazel workspace relative path', () async {
514 // Copy to temp dir so that existing analysis options
515 // in the test directory hierarchy do not interfere
516 await withTempDirAsync((String tempDirPath) async {
517 String dartSdkPath = path.absolute(getSdkPath());
518 await recursiveCopy(
519 new Directory(path.join(testDirectory, 'data', 'bazel')),
520 tempDirPath);
521 Directory origWorkingDir = Directory.current;
522 try {
523 Directory.current = path.join(tempDirPath, 'proj');
524 Driver driver = new Driver(isTesting: true);
525 try {
526 await driver.start([
527 path.join('lib', 'file.dart'),
528 '--dart-sdk',
529 dartSdkPath,
530 ]);
531 } catch (e) {
532 print('=== debug info ===');
533 print('dartSdkPath: $dartSdkPath');
534 print('stderr:\n${errorSink.toString()}');
535 rethrow;
536 }
537 expect(errorSink.toString(), isEmpty);
538 expect(outSink.toString(), contains('No issues found'));
539 expect(exitCode, 0);
540 } finally {
541 Directory.current = origWorkingDir;
542 }
543 });
544 });
545 });
546 }
547
548 void _test_linter() {
549 test('containsLintRuleEntry', () {
550 Map<String, YamlNode> options; 403 Map<String, YamlNode> options;
551 options = parseOptions(''' 404 options = _parseOptions('''
552 linter: 405 linter:
553 rules: 406 rules:
554 - foo 407 - foo
555 '''); 408 ''');
556 expect(containsLintRuleEntry(options), true); 409 expect(containsLintRuleEntry(options), true);
557 options = parseOptions(''' 410 options = _parseOptions('''
558 '''); 411 ''');
559 expect(containsLintRuleEntry(options), false); 412 expect(containsLintRuleEntry(options), false);
560 options = parseOptions(''' 413 options = _parseOptions('''
561 linter: 414 linter:
562 rules: 415 rules:
563 # - foo 416 # - foo
564 '''); 417 ''');
565 expect(containsLintRuleEntry(options), true); 418 expect(containsLintRuleEntry(options), true);
566 options = parseOptions(''' 419 options = _parseOptions('''
567 linter: 420 linter:
568 # rules: 421 # rules:
569 # - foo 422 # - foo
570 '''); 423 ''');
571 expect(containsLintRuleEntry(options), false); 424 expect(containsLintRuleEntry(options), false);
572 }); 425 }
573 426
574 group('linter', () { 427 test_defaultLints_generatedLints() async {
575 void createTests(String designator, String optionsFileName) { 428 await _runLinter_defaultLints();
576 group('lints in options - $designator', () { 429 expect(_bulletToDash(outSink),
577 // Shared lint command. 430 contains('lint - Name types using UpperCamelCase'));
578 Future<Null> runLinter() async { 431 }
579 return await drive('data/linter_project/test_file.dart', 432
580 options: 'data/linter_project/$optionsFileName', 433 test_defaultLints_getsDefaultLints() async {
581 args: ['--lints']); 434 await _runLinter_defaultLints();
582 } 435
583 436 /// Lints should be enabled.
584 test('gets analysis options', () async { 437 expect(driver.context.analysisOptions.lint, isTrue);
585 await runLinter(); 438
586 439 /// Default list should include camel_case_types.
587 /// Lints should be enabled. 440 var lintNames = getLints(driver.context).map((r) => r.name);
588 expect(driver.context.analysisOptions.lint, isTrue); 441 expect(lintNames, contains('camel_case_types'));
589 442 }
590 /// The analysis options file only specifies 'camel_case_types'. 443
591 var lintNames = getLints(driver.context).map((r) => r.name); 444 test_lintsInOptions_generatedLints() async {
592 expect(lintNames, orderedEquals(['camel_case_types'])); 445 await _runLinter_lintsInOptions();
593 }); 446 expect(_bulletToDash(outSink),
594 447 contains('lint - Name types using UpperCamelCase'));
595 test('generates lints', () async { 448 }
596 await runLinter(); 449
597 expect(_bulletToDash(outSink), 450 test_lintsInOptions_getAnalysisOptions() async {
598 contains('lint - Name types using UpperCamelCase')); 451 await _runLinter_lintsInOptions();
599 }); 452
600 }); 453 /// Lints should be enabled.
601 454 expect(driver.context.analysisOptions.lint, isTrue);
602 group('default lints - $designator', () { 455
603 // Shared lint command. 456 /// The analysis options file only specifies 'camel_case_types'.
604 Future<Null> runLinter() async { 457 var lintNames = getLints(driver.context).map((r) => r.name);
605 return await drive('data/linter_project/test_file.dart', 458 expect(lintNames, orderedEquals(['camel_case_types']));
606 options: 'data/linter_project/$optionsFileName', 459 }
607 args: ['--lints']); 460
608 } 461 test_noLints_lintsDisabled() async {
609 462 await _runLinter_noLintsFlag();
610 test('gets default lints', () async { 463 expect(driver.context.analysisOptions.lint, isFalse);
611 await runLinter(); 464 }
612 465
613 /// Lints should be enabled. 466 test_noLints_noGeneratedWarnings() async {
614 expect(driver.context.analysisOptions.lint, isTrue); 467 await _runLinter_noLintsFlag();
615 468 expect(outSink.toString(), contains('No issues found'));
616 /// Default list should include camel_case_types. 469 }
617 var lintNames = getLints(driver.context).map((r) => r.name); 470
618 expect(lintNames, contains('camel_case_types')); 471 test_noLints_noRegisteredLints() async {
619 }); 472 await _runLinter_noLintsFlag();
620 473 expect(getLints(driver.context), isEmpty);
621 test('generates lints', () async { 474 }
622 await runLinter(); 475
623 expect(_bulletToDash(outSink), 476 Map<String, YamlNode> _parseOptions(String src) =>
624 contains('lint - Name types using UpperCamelCase')); 477 new AnalysisOptionsProvider().getOptionsFromString(src);
625 }); 478
626 }); 479 Future<Null> _runLinter_defaultLints() async {
627 480 await drive('data/linter_project/test_file.dart',
628 group('no `--lints` flag (none in options) - $designator', () { 481 options: 'data/linter_project/$optionsFileName', args: ['--lints']);
629 // Shared lint command. 482 }
630 Future<Null> runLinter() async { 483
631 return await drive('data/no_lints_project/test_file.dart', 484 Future<Null> _runLinter_lintsInOptions() async {
632 options: 'data/no_lints_project/$optionsFileName'); 485 await drive('data/linter_project/test_file.dart',
633 } 486 options: 'data/linter_project/$optionsFileName', args: ['--lints']);
634 487 }
635 test('lints disabled', () async { 488
636 await runLinter(); 489 Future<Null> _runLinter_noLintsFlag() async {
637 expect(driver.context.analysisOptions.lint, isFalse); 490 await drive('data/no_lints_project/test_file.dart',
638 }); 491 options: 'data/no_lints_project/$optionsFileName');
639 492 }
640 test('no registered lints', () async {
641 await runLinter();
642 expect(getLints(driver.context), isEmpty);
643 });
644
645 test('no generated warnings', () async {
646 await runLinter();
647 expect(outSink.toString(), contains('No issues found'));
648 });
649 });
650 }
651
652 createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE);
653 createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE);
654 });
655 } 493 }
656 494
657 void _test_optionsProcessing() { 495 @reflectiveTest
658 group('options processing', () { 496 class OptionsTest extends _BaseTest {
659 void createTests(String designator, String optionsFileName) { 497 String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
660 group('basic config - $designator', () { 498
661 // Shared driver command. 499 List<ErrorProcessor> get processors =>
662 Future<Null> doDrive() async { 500 driver.context.analysisOptions.errorProcessors;
663 await drive('data/options_tests_project/test_file.dart', 501
664 options: 'data/options_tests_project/$optionsFileName'); 502 ErrorProcessor processorFor(AnalysisError error) =>
665 } 503 processors.firstWhere((p) => p.appliesTo(error));
666 504
667 test('filters', () async { 505 test_basic_filters() async {
668 await doDrive(); 506 await _driveBasic();
669 expect(processors, hasLength(3)); 507 expect(processors, hasLength(3));
670 508
671 // unused_local_variable: ignore 509 // unused_local_variable: ignore
672 var unused_local_variable = new AnalysisError( 510 var unused_local_variable = new AnalysisError(
673 new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [ 511 new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
674 ['x'] 512 ['x']
675 ]); 513 ]);
676 expect(processorFor(unused_local_variable).severity, isNull); 514 expect(processorFor(unused_local_variable).severity, isNull);
677 515
678 // missing_return: error 516 // missing_return: error
679 var missing_return = new AnalysisError( 517 var missing_return =
680 new TestSource(), 0, 1, HintCode.MISSING_RETURN, [ 518 new AnalysisError(new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
681 ['x'] 519 ['x']
682 ]); 520 ]);
683 expect(processorFor(missing_return).severity, ErrorSeverity.ERROR); 521 expect(processorFor(missing_return).severity, ErrorSeverity.ERROR);
684 expect( 522 expect(_bulletToDash(outSink),
685 _bulletToDash(outSink), 523 contains("error - This function declares a return type of 'int'"));
686 contains( 524 expect(outSink.toString(), contains("1 error and 1 warning found."));
687 "error - This function declares a return type of 'int'")); 525 }
688 expect(outSink.toString(), contains("1 error and 1 warning found.")); 526
689 }); 527 test_basic_language() async {
690 528 await _driveBasic();
691 test('language', () async { 529 expect(driver.context.analysisOptions.enableSuperMixins, isTrue);
692 await doDrive(); 530 }
693 expect(driver.context.analysisOptions.enableSuperMixins, isTrue); 531
694 }); 532 test_basic_strongMode() async {
695 533 await _driveBasic();
696 test('strongMode', () async { 534 expect(driver.context.analysisOptions.strongMode, isTrue);
697 await doDrive(); 535 // https://github.com/dart-lang/sdk/issues/26129
698 expect(driver.context.analysisOptions.strongMode, isTrue); 536 AnalysisContext sdkContext = driver.context.sourceFactory.dartSdk.context;
699 //https://github.com/dart-lang/sdk/issues/26129 537 expect(sdkContext.analysisOptions.strongMode, isTrue);
700 AnalysisContext sdkContext = 538 }
701 driver.context.sourceFactory.dartSdk.context; 539
702 expect(sdkContext.analysisOptions.strongMode, isTrue); 540 test_includeDirective() async {
703 }); 541 String testDir = path.join(
704 }); 542 testDirectory, 'data', 'options_include_directive_tests_project');
705 543 await drive(
706 group('with flags - $designator', () { 544 path.join(testDir, 'lib', 'test_file.dart'),
707 // Shared driver command. 545 args: [
708 Future<Null> doDrive() async { 546 '--fatal-warnings',
709 await drive('data/options_tests_project/test_file.dart', 547 '--packages',
710 args: ['--fatal-warnings'], 548 path.join(testDir, '_packages'),
711 options: 'data/options_tests_project/$optionsFileName'); 549 ],
712 } 550 options: path.join(testDir, 'analysis_options.yaml'),
713 551 );
714 test('override fatal warning', () async { 552 expect(exitCode, 3);
715 await doDrive(); 553 expect(outSink.toString(),
716 // missing_return: error 554 contains('but doesn\'t end with a return statement'));
717 var undefined_function = new AnalysisError(new TestSource(), 0, 1, 555 expect(outSink.toString(), contains('isn\'t defined'));
718 StaticTypeWarningCode.UNDEFINED_FUNCTION, [ 556 expect(outSink.toString(), contains('Avoid empty else statements'));
719 ['x'] 557 }
720 ]); 558
721 expect( 559 test_strongSdk() async {
722 processorFor(undefined_function).severity, ErrorSeverity.WARNING); 560 String testDir = path.join(testDirectory, 'data', 'strong_sdk');
723 // Should not be made fatal by `--fatal-warnings`. 561 await drive(path.join(testDir, 'main.dart'), args: ['--strong']);
724 expect(_bulletToDash(outSink), 562 expect(driver.context.analysisOptions.strongMode, isTrue);
725 contains("warning - The function 'baz' isn't defined")); 563 expect(outSink.toString(), contains('No issues found'));
726 expect(outSink.toString(), contains("1 error and 1 warning found.")); 564 expect(exitCode, 0);
727 }); 565 }
728 }); 566
729 } 567 test_todo() async {
730 568 await drive('data/file_with_todo.dart');
731 createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); 569 expect(outSink.toString().contains('[info]'), isFalse);
732 createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); 570 }
733 571
734 test('include directive', () async { 572 test_withFlags_overrideFatalWarning() async {
735 String testDir = path.join( 573 await drive('data/options_tests_project/test_file.dart',
736 testDirectory, 'data', 'options_include_directive_tests_project'); 574 args: ['--fatal-warnings'],
737 await drive( 575 options: 'data/options_tests_project/$optionsFileName');
738 path.join(testDir, 'lib', 'test_file.dart'), 576
739 args: [ 577 // missing_return: error
740 '--fatal-warnings', 578 var undefined_function = new AnalysisError(
741 '--packages', 579 new TestSource(), 0, 1, StaticTypeWarningCode.UNDEFINED_FUNCTION, [
742 path.join(testDir, '_packages'), 580 ['x']
743 ], 581 ]);
744 options: path.join(testDir, 'analysis_options.yaml'), 582 expect(processorFor(undefined_function).severity, ErrorSeverity.WARNING);
745 ); 583 // Should not be made fatal by `--fatal-warnings`.
746 expect(exitCode, 3); 584 expect(_bulletToDash(outSink),
747 expect(outSink.toString(), 585 contains("warning - The function 'baz' isn't defined"));
748 contains('but doesn\'t end with a return statement')); 586 expect(outSink.toString(), contains("1 error and 1 warning found."));
749 expect(outSink.toString(), contains('isn\'t defined')); 587 }
750 expect(outSink.toString(), contains('Avoid empty else statements')); 588
751 }); 589 Future<Null> _driveBasic() async {
752 590 await drive('data/options_tests_project/test_file.dart',
753 test('test strong SDK', () async { 591 options: 'data/options_tests_project/$optionsFileName');
754 String testDir = path.join(testDirectory, 'data', 'strong_sdk'); 592 }
755 await drive(path.join(testDir, 'main.dart'), args: ['--strong']);
756 expect(driver.context.analysisOptions.strongMode, isTrue);
757 expect(outSink.toString(), contains('No issues found'));
758 expect(exitCode, 0);
759 });
760 });
761 } 593 }
762 594
763 class TestSource implements Source { 595 class TestSource implements Source {
764 TestSource(); 596 TestSource();
765 597
766 @override 598 @override
767 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); 599 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
768 } 600 }
601
602 class _BaseTest {
603 static const emptyOptionsFile = 'data/empty_options.yaml';
604
605 StringSink _savedOutSink, _savedErrorSink;
606 int _savedExitCode;
607 ExitHandler _savedExitHandler;
608
609 Driver driver;
610
611 /// Start a driver for the given [source], optionally providing additional
612 /// [args] and an [options] file path. The value of [options] defaults to
613 /// an empty options file to avoid unwanted configuration from an otherwise
614 /// discovered options file.
615 Future<Null> drive(String source,
616 {String options: emptyOptionsFile,
617 List<String> args: const <String>[]}) async {
618 driver = new Driver(isTesting: true);
619 var cmd = [
620 '--options',
621 path.join(testDirectory, options),
622 _adjustFileSpec(source)
623 ]..addAll(args);
624 await driver.start(cmd);
625 }
626
627 void setUp() {
628 ansi.runningTests = true;
629 _savedOutSink = outSink;
630 _savedErrorSink = errorSink;
631 _savedExitHandler = exitHandler;
632 _savedExitCode = exitCode;
633 exitHandler = (code) => exitCode = code;
634 outSink = new StringBuffer();
635 errorSink = new StringBuffer();
636 }
637
638 void tearDown() {
639 outSink = _savedOutSink;
640 errorSink = _savedErrorSink;
641 exitCode = _savedExitCode;
642 exitHandler = _savedExitHandler;
643 ansi.runningTests = false;
644 }
645
646 /// Convert a file specification from a relative path to an absolute path.
647 /// Handles the case where the file specification is of the form "$uri|$path".
648 String _adjustFileSpec(String fileSpec) {
649 int uriPrefixLength = fileSpec.indexOf('|') + 1;
650 String uriPrefix = fileSpec.substring(0, uriPrefixLength);
651 String relativePath = fileSpec.substring(uriPrefixLength);
652 return '$uriPrefix${path.join(testDirectory, relativePath)}';
653 }
654
655 /// Normalize text with bullets.
656 String _bulletToDash(item) => '$item'.replaceAll('•', '-');
657 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698