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 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 } | |
OLD | NEW |