| 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'; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 tearDown(() => _tearDown()); | 56 tearDown(() => _tearDown()); |
| 57 | 57 |
| 58 group('Driver', () { | 58 group('Driver', () { |
| 59 group('options', () { | 59 group('options', () { |
| 60 test('todos', () async { | 60 test('todos', () async { |
| 61 await drive('data/file_with_todo.dart'); | 61 await drive('data/file_with_todo.dart'); |
| 62 expect(outSink.toString().contains('[info]'), isFalse); | 62 expect(outSink.toString().contains('[info]'), isFalse); |
| 63 }); | 63 }); |
| 64 }); | 64 }); |
| 65 | 65 |
| 66 group('exit codes', () { | 66 _test_exitCodes(); |
| 67 test('fatal hints', () async { | 67 _test_linter(); |
| 68 await drive('data/file_with_hint.dart', args: ['--fatal-hints']); | 68 _test_optionsProcessing(); |
| 69 expect(exitCode, 1); | 69 _test_buildMode(); |
| 70 }); | |
| 71 | |
| 72 test('not fatal hints', () async { | |
| 73 await drive('data/file_with_hint.dart'); | |
| 74 expect(exitCode, 0); | |
| 75 }); | |
| 76 | |
| 77 test('fatal errors', () async { | |
| 78 await drive('data/file_with_error.dart'); | |
| 79 expect(exitCode, 3); | |
| 80 }); | |
| 81 | |
| 82 test('not fatal warnings', () async { | |
| 83 await drive('data/file_with_warning.dart'); | |
| 84 expect(exitCode, 0); | |
| 85 }); | |
| 86 | |
| 87 test('fatal warnings', () async { | |
| 88 await drive('data/file_with_warning.dart', args: ['--fatal-warnings']); | |
| 89 expect(exitCode, 2); | |
| 90 }); | |
| 91 | |
| 92 test('not parse enableAssertInitializer', () async { | |
| 93 await drive('data/file_with_assert_initializers.dart', | |
| 94 args: ['--enable-assert-initializers']); | |
| 95 expect(exitCode, 0); | |
| 96 }); | |
| 97 | |
| 98 test('missing options file', () async { | |
| 99 await drive('data/test_file.dart', options: 'data/NO_OPTIONS_HERE'); | |
| 100 expect(exitCode, 3); | |
| 101 }); | |
| 102 | |
| 103 test('missing dart file', () async { | |
| 104 await drive('data/NO_DART_FILE_HERE.dart'); | |
| 105 expect(exitCode, 3); | |
| 106 }); | |
| 107 | |
| 108 test('part file', () async { | |
| 109 await drive('data/library_and_parts/part2.dart'); | |
| 110 expect(exitCode, 3); | |
| 111 }); | |
| 112 | |
| 113 test('non-dangling part file', () async { | |
| 114 Driver driver = new Driver(isTesting: true); | |
| 115 await driver.start([ | |
| 116 path.join(testDirectory, 'data/library_and_parts/lib.dart'), | |
| 117 path.join(testDirectory, 'data/library_and_parts/part1.dart') | |
| 118 ]); | |
| 119 expect(exitCode, 0); | |
| 120 }); | |
| 121 | |
| 122 test('extra part file', () async { | |
| 123 Driver driver = new Driver(isTesting: true); | |
| 124 await driver.start([ | |
| 125 path.join(testDirectory, 'data/library_and_parts/lib.dart'), | |
| 126 path.join(testDirectory, 'data/library_and_parts/part1.dart'), | |
| 127 path.join(testDirectory, 'data/library_and_parts/part2.dart') | |
| 128 ]); | |
| 129 expect(exitCode, 3); | |
| 130 }); | |
| 131 | |
| 132 test('bazel workspace relative path', () async { | |
| 133 // Copy to temp dir so that existing analysis options | |
| 134 // in the test directory hierarchy do not interfere | |
| 135 await withTempDirAsync((String tempDirPath) async { | |
| 136 String dartSdkPath = path.absolute(getSdkPath()); | |
| 137 await recursiveCopy( | |
| 138 new Directory(path.join(testDirectory, 'data', 'bazel')), | |
| 139 tempDirPath); | |
| 140 Directory origWorkingDir = Directory.current; | |
| 141 try { | |
| 142 Directory.current = path.join(tempDirPath, 'proj'); | |
| 143 Driver driver = new Driver(isTesting: true); | |
| 144 try { | |
| 145 await driver.start([ | |
| 146 path.join('lib', 'file.dart'), | |
| 147 '--dart-sdk', | |
| 148 dartSdkPath, | |
| 149 ]); | |
| 150 } catch (e) { | |
| 151 print('=== debug info ==='); | |
| 152 print('dartSdkPath: $dartSdkPath'); | |
| 153 print('stderr:\n${errorSink.toString()}'); | |
| 154 rethrow; | |
| 155 } | |
| 156 expect(errorSink.toString(), isEmpty); | |
| 157 expect(outSink.toString(), contains('No issues found')); | |
| 158 expect(exitCode, 0); | |
| 159 } finally { | |
| 160 Directory.current = origWorkingDir; | |
| 161 } | |
| 162 }); | |
| 163 }); | |
| 164 }); | |
| 165 | |
| 166 group('linter', () { | |
| 167 void createTests(String designator, String optionsFileName) { | |
| 168 group('lints in options - $designator', () { | |
| 169 // Shared lint command. | |
| 170 Future<Null> runLinter() async { | |
| 171 return await drive('data/linter_project/test_file.dart', | |
| 172 options: 'data/linter_project/$optionsFileName', | |
| 173 args: ['--lints']); | |
| 174 } | |
| 175 | |
| 176 test('gets analysis options', () async { | |
| 177 await runLinter(); | |
| 178 | |
| 179 /// Lints should be enabled. | |
| 180 expect(driver.context.analysisOptions.lint, isTrue); | |
| 181 | |
| 182 /// The analysis options file only specifies 'camel_case_types'. | |
| 183 var lintNames = getLints(driver.context).map((r) => r.name); | |
| 184 expect(lintNames, orderedEquals(['camel_case_types'])); | |
| 185 }); | |
| 186 | |
| 187 test('generates lints', () async { | |
| 188 await runLinter(); | |
| 189 expect(_bulletToDash(outSink), | |
| 190 contains('lint - Name types using UpperCamelCase')); | |
| 191 }); | |
| 192 }); | |
| 193 | |
| 194 group('default lints - $designator', () { | |
| 195 // Shared lint command. | |
| 196 Future<Null> runLinter() async { | |
| 197 return await drive('data/linter_project/test_file.dart', | |
| 198 options: 'data/linter_project/$optionsFileName', | |
| 199 args: ['--lints']); | |
| 200 } | |
| 201 | |
| 202 test('gets default lints', () async { | |
| 203 await runLinter(); | |
| 204 | |
| 205 /// Lints should be enabled. | |
| 206 expect(driver.context.analysisOptions.lint, isTrue); | |
| 207 | |
| 208 /// Default list should include camel_case_types. | |
| 209 var lintNames = getLints(driver.context).map((r) => r.name); | |
| 210 expect(lintNames, contains('camel_case_types')); | |
| 211 }); | |
| 212 | |
| 213 test('generates lints', () async { | |
| 214 await runLinter(); | |
| 215 expect(_bulletToDash(outSink), | |
| 216 contains('lint - Name types using UpperCamelCase')); | |
| 217 }); | |
| 218 }); | |
| 219 | |
| 220 group('no `--lints` flag (none in options) - $designator', () { | |
| 221 // Shared lint command. | |
| 222 Future<Null> runLinter() async { | |
| 223 return await drive('data/no_lints_project/test_file.dart', | |
| 224 options: 'data/no_lints_project/$optionsFileName'); | |
| 225 } | |
| 226 | |
| 227 test('lints disabled', () async { | |
| 228 await runLinter(); | |
| 229 expect(driver.context.analysisOptions.lint, isFalse); | |
| 230 }); | |
| 231 | |
| 232 test('no registered lints', () async { | |
| 233 await runLinter(); | |
| 234 expect(getLints(driver.context), isEmpty); | |
| 235 }); | |
| 236 | |
| 237 test('no generated warnings', () async { | |
| 238 await runLinter(); | |
| 239 expect(outSink.toString(), contains('No issues found')); | |
| 240 }); | |
| 241 }); | |
| 242 } | |
| 243 | |
| 244 createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); | |
| 245 createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); | |
| 246 }); | |
| 247 | |
| 248 test('containsLintRuleEntry', () { | |
| 249 Map<String, YamlNode> options; | |
| 250 options = parseOptions(''' | |
| 251 linter: | |
| 252 rules: | |
| 253 - foo | |
| 254 '''); | |
| 255 expect(containsLintRuleEntry(options), true); | |
| 256 options = parseOptions(''' | |
| 257 '''); | |
| 258 expect(containsLintRuleEntry(options), false); | |
| 259 options = parseOptions(''' | |
| 260 linter: | |
| 261 rules: | |
| 262 # - foo | |
| 263 '''); | |
| 264 expect(containsLintRuleEntry(options), true); | |
| 265 options = parseOptions(''' | |
| 266 linter: | |
| 267 # rules: | |
| 268 # - foo | |
| 269 '''); | |
| 270 expect(containsLintRuleEntry(options), false); | |
| 271 }); | |
| 272 | |
| 273 group('options processing', () { | |
| 274 void createTests(String designator, String optionsFileName) { | |
| 275 group('basic config - $designator', () { | |
| 276 // Shared driver command. | |
| 277 Future<Null> doDrive() async { | |
| 278 await drive('data/options_tests_project/test_file.dart', | |
| 279 options: 'data/options_tests_project/$optionsFileName'); | |
| 280 } | |
| 281 | |
| 282 test('filters', () async { | |
| 283 await doDrive(); | |
| 284 expect(processors, hasLength(3)); | |
| 285 | |
| 286 // unused_local_variable: ignore | |
| 287 var unused_local_variable = new AnalysisError( | |
| 288 new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [ | |
| 289 ['x'] | |
| 290 ]); | |
| 291 expect(processorFor(unused_local_variable).severity, isNull); | |
| 292 | |
| 293 // missing_return: error | |
| 294 var missing_return = new AnalysisError( | |
| 295 new TestSource(), 0, 1, HintCode.MISSING_RETURN, [ | |
| 296 ['x'] | |
| 297 ]); | |
| 298 expect(processorFor(missing_return).severity, ErrorSeverity.ERROR); | |
| 299 expect( | |
| 300 _bulletToDash(outSink), | |
| 301 contains( | |
| 302 "error - This function declares a return type of 'int'")); | |
| 303 expect( | |
| 304 outSink.toString(), contains("1 error and 1 warning found.")); | |
| 305 }); | |
| 306 | |
| 307 test('language', () async { | |
| 308 await doDrive(); | |
| 309 expect(driver.context.analysisOptions.enableSuperMixins, isTrue); | |
| 310 }); | |
| 311 | |
| 312 test('strongMode', () async { | |
| 313 await doDrive(); | |
| 314 expect(driver.context.analysisOptions.strongMode, isTrue); | |
| 315 //https://github.com/dart-lang/sdk/issues/26129 | |
| 316 AnalysisContext sdkContext = | |
| 317 driver.context.sourceFactory.dartSdk.context; | |
| 318 expect(sdkContext.analysisOptions.strongMode, isTrue); | |
| 319 }); | |
| 320 }); | |
| 321 | |
| 322 group('with flags - $designator', () { | |
| 323 // Shared driver command. | |
| 324 Future<Null> doDrive() async { | |
| 325 await drive('data/options_tests_project/test_file.dart', | |
| 326 args: ['--fatal-warnings'], | |
| 327 options: 'data/options_tests_project/$optionsFileName'); | |
| 328 } | |
| 329 | |
| 330 test('override fatal warning', () async { | |
| 331 await doDrive(); | |
| 332 // missing_return: error | |
| 333 var undefined_function = new AnalysisError(new TestSource(), 0, 1, | |
| 334 StaticTypeWarningCode.UNDEFINED_FUNCTION, [ | |
| 335 ['x'] | |
| 336 ]); | |
| 337 expect(processorFor(undefined_function).severity, | |
| 338 ErrorSeverity.WARNING); | |
| 339 // Should not be made fatal by `--fatal-warnings`. | |
| 340 expect(_bulletToDash(outSink), | |
| 341 contains("warning - The function 'baz' isn't defined")); | |
| 342 expect( | |
| 343 outSink.toString(), contains("1 error and 1 warning found.")); | |
| 344 }); | |
| 345 }); | |
| 346 } | |
| 347 | |
| 348 createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); | |
| 349 createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); | |
| 350 | |
| 351 test('include directive', () async { | |
| 352 String testDir = path.join( | |
| 353 testDirectory, 'data', 'options_include_directive_tests_project'); | |
| 354 await drive( | |
| 355 path.join(testDir, 'lib', 'test_file.dart'), | |
| 356 args: [ | |
| 357 '--fatal-warnings', | |
| 358 '--packages', | |
| 359 path.join(testDir, '_packages'), | |
| 360 ], | |
| 361 options: path.join(testDir, 'analysis_options.yaml'), | |
| 362 ); | |
| 363 expect(exitCode, 3); | |
| 364 expect(outSink.toString(), | |
| 365 contains('but doesn\'t end with a return statement')); | |
| 366 expect(outSink.toString(), contains('isn\'t defined')); | |
| 367 expect(outSink.toString(), contains('Avoid empty else statements')); | |
| 368 }); | |
| 369 | |
| 370 test('test strong SDK', () async { | |
| 371 String testDir = path.join(testDirectory, 'data', 'strong_sdk'); | |
| 372 await drive(path.join(testDir, 'main.dart'), args: ['--strong']); | |
| 373 expect(driver.context.analysisOptions.strongMode, isTrue); | |
| 374 expect(outSink.toString(), contains('No issues found')); | |
| 375 expect(exitCode, 0); | |
| 376 }); | |
| 377 }); | |
| 378 | |
| 379 void createTests(String designator, String optionsFileName) { | |
| 380 group('build-mode - $designator', () { | |
| 381 // Shared driver command. | |
| 382 Future<Null> doDrive(String filePath, | |
| 383 {List<String> additionalArgs: const []}) async { | |
| 384 await drive('file:///test_file.dart|$filePath', | |
| 385 args: [ | |
| 386 '--dart-sdk', | |
| 387 findSdkDirForSummaries(), | |
| 388 '--build-mode', | |
| 389 '--format=machine' | |
| 390 ]..addAll(additionalArgs), | |
| 391 options: 'data/options_tests_project/$optionsFileName'); | |
| 392 } | |
| 393 | |
| 394 test('no stats', () async { | |
| 395 await doDrive(path.join('data', 'test_file.dart')); | |
| 396 // Should not print stat summary. | |
| 397 expect(outSink.toString(), isEmpty); | |
| 398 expect(errorSink.toString(), isEmpty); | |
| 399 expect(exitCode, 0); | |
| 400 }); | |
| 401 | |
| 402 test( | |
| 403 'Fails if file not found, even when --build-suppress-exit-code is gi
ven', | |
| 404 () async { | |
| 405 await doDrive(path.join('data', 'non_existent_file.dart'), | |
| 406 additionalArgs: ['--build-suppress-exit-code']); | |
| 407 expect(exitCode, isNot(0)); | |
| 408 }); | |
| 409 | |
| 410 test('Fails if there are errors', () async { | |
| 411 await doDrive(path.join('data', 'file_with_error.dart')); | |
| 412 expect(exitCode, isNot(0)); | |
| 413 }); | |
| 414 | |
| 415 test( | |
| 416 'Succeeds if there are errors, when --build-suppress-exit-code is gi
ven', | |
| 417 () async { | |
| 418 await doDrive(path.join('data', 'file_with_error.dart'), | |
| 419 additionalArgs: ['--build-suppress-exit-code']); | |
| 420 expect(exitCode, 0); | |
| 421 }); | |
| 422 | |
| 423 test('Linked summary', () async { | |
| 424 await withTempDirAsync((tempDir) async { | |
| 425 var outputPath = path.join(tempDir, 'test_file.dart.sum'); | |
| 426 await doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ | |
| 427 '--build-summary-only', | |
| 428 '--build-summary-output=$outputPath' | |
| 429 ]); | |
| 430 var output = new File(outputPath); | |
| 431 expect(output.existsSync(), isTrue); | |
| 432 PackageBundle bundle = | |
| 433 new PackageBundle.fromBuffer(await output.readAsBytes()); | |
| 434 var testFileUri = 'file:///test_file.dart'; | |
| 435 expect(bundle.unlinkedUnitUris, equals([testFileUri])); | |
| 436 expect(bundle.linkedLibraryUris, equals([testFileUri])); | |
| 437 expect(exitCode, 0); | |
| 438 }); | |
| 439 }); | |
| 440 | |
| 441 test('Unlinked summary only', () async { | |
| 442 await withTempDirAsync((tempDir) async { | |
| 443 var outputPath = path.join(tempDir, 'test_file.dart.sum'); | |
| 444 await doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ | |
| 445 '--build-summary-only', | |
| 446 '--build-summary-only-unlinked', | |
| 447 '--build-summary-output=$outputPath' | |
| 448 ]); | |
| 449 var output = new File(outputPath); | |
| 450 expect(output.existsSync(), isTrue); | |
| 451 PackageBundle bundle = | |
| 452 new PackageBundle.fromBuffer(await output.readAsBytes()); | |
| 453 var testFileUri = 'file:///test_file.dart'; | |
| 454 expect(bundle.unlinkedUnits.length, 1); | |
| 455 expect(bundle.unlinkedUnitUris, equals([testFileUri])); | |
| 456 expect(bundle.linkedLibraryUris, isEmpty); | |
| 457 expect(exitCode, 0); | |
| 458 }); | |
| 459 }); | |
| 460 }); | |
| 461 } | |
| 462 | |
| 463 createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); | |
| 464 createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); | |
| 465 | 70 |
| 466 //TODO(pq): fix to be bot-friendly (sdk#25258). | 71 //TODO(pq): fix to be bot-friendly (sdk#25258). |
| 467 // group('in temp directory', () { | 72 // group('in temp directory', () { |
| 468 // Directory savedCurrentDirectory; | 73 // Directory savedCurrentDirectory; |
| 469 // Directory tempDir; | 74 // Directory tempDir; |
| 470 // setUp(() { | 75 // setUp(() { |
| 471 // // Call base setUp. | 76 // // Call base setUp. |
| 472 // _setUp(); | 77 // _setUp(); |
| 473 // savedCurrentDirectory = Directory.current; | 78 // savedCurrentDirectory = Directory.current; |
| 474 // tempDir = Directory.systemTemp.createTempSync('analyzer_'); | 79 // tempDir = Directory.systemTemp.createTempSync('analyzer_'); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 606 | 211 |
| 607 Map<String, YamlNode> parseOptions(String src) => | 212 Map<String, YamlNode> parseOptions(String src) => |
| 608 new AnalysisOptionsProvider().getOptionsFromString(src); | 213 new AnalysisOptionsProvider().getOptionsFromString(src); |
| 609 | 214 |
| 610 ErrorProcessor processorFor(AnalysisError error) => | 215 ErrorProcessor processorFor(AnalysisError error) => |
| 611 processors.firstWhere((p) => p.appliesTo(error)); | 216 processors.firstWhere((p) => p.appliesTo(error)); |
| 612 | 217 |
| 613 /// Normalize text with bullets. | 218 /// Normalize text with bullets. |
| 614 String _bulletToDash(item) => '$item'.replaceAll('•', '-'); | 219 String _bulletToDash(item) => '$item'.replaceAll('•', '-'); |
| 615 | 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 filePath, |
| 226 {List<String> additionalArgs: const []}) async { |
| 227 await drive('file:///test_file.dart|$filePath', |
| 228 args: [ |
| 229 '--dart-sdk', |
| 230 findSdkDirForSummaries(), |
| 231 '--build-mode', |
| 232 '--format=machine' |
| 233 ]..addAll(additionalArgs), |
| 234 options: 'data/options_tests_project/$optionsFileName'); |
| 235 } |
| 236 |
| 237 test('no stats', () async { |
| 238 await doDrive(path.join('data', 'test_file.dart')); |
| 239 // Should not print stat summary. |
| 240 expect(outSink.toString(), isEmpty); |
| 241 expect(errorSink.toString(), isEmpty); |
| 242 expect(exitCode, 0); |
| 243 }); |
| 244 |
| 245 test( |
| 246 'Fails if file not found, even when --build-suppress-exit-code is give
n', |
| 247 () async { |
| 248 await doDrive(path.join('data', 'non_existent_file.dart'), |
| 249 additionalArgs: ['--build-suppress-exit-code']); |
| 250 expect(exitCode, isNot(0)); |
| 251 }); |
| 252 |
| 253 test('Fails if there are errors', () async { |
| 254 await doDrive(path.join('data', 'file_with_error.dart')); |
| 255 expect(exitCode, isNot(0)); |
| 256 }); |
| 257 |
| 258 test( |
| 259 'Succeeds if there are errors, when --build-suppress-exit-code is give
n', |
| 260 () async { |
| 261 await doDrive(path.join('data', 'file_with_error.dart'), |
| 262 additionalArgs: ['--build-suppress-exit-code']); |
| 263 expect(exitCode, 0); |
| 264 }); |
| 265 |
| 266 test('Linked summary', () async { |
| 267 await withTempDirAsync((tempDir) async { |
| 268 var outputPath = path.join(tempDir, 'test_file.dart.sum'); |
| 269 await doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ |
| 270 '--build-summary-only', |
| 271 '--build-summary-output=$outputPath' |
| 272 ]); |
| 273 var output = new File(outputPath); |
| 274 expect(output.existsSync(), isTrue); |
| 275 PackageBundle bundle = |
| 276 new PackageBundle.fromBuffer(await output.readAsBytes()); |
| 277 var testFileUri = 'file:///test_file.dart'; |
| 278 expect(bundle.unlinkedUnitUris, equals([testFileUri])); |
| 279 expect(bundle.linkedLibraryUris, equals([testFileUri])); |
| 280 expect(exitCode, 0); |
| 281 }); |
| 282 }); |
| 283 |
| 284 test('Unlinked summary only', () async { |
| 285 await withTempDirAsync((tempDir) async { |
| 286 var outputPath = path.join(tempDir, 'test_file.dart.sum'); |
| 287 await doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ |
| 288 '--build-summary-only', |
| 289 '--build-summary-only-unlinked', |
| 290 '--build-summary-output=$outputPath' |
| 291 ]); |
| 292 var output = new File(outputPath); |
| 293 expect(output.existsSync(), isTrue); |
| 294 PackageBundle bundle = |
| 295 new PackageBundle.fromBuffer(await output.readAsBytes()); |
| 296 var testFileUri = 'file:///test_file.dart'; |
| 297 expect(bundle.unlinkedUnits.length, 1); |
| 298 expect(bundle.unlinkedUnitUris, equals([testFileUri])); |
| 299 expect(bundle.linkedLibraryUris, isEmpty); |
| 300 expect(exitCode, 0); |
| 301 }); |
| 302 }); |
| 303 }); |
| 304 } |
| 305 |
| 306 createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); |
| 307 createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); |
| 308 } |
| 309 |
| 310 void _test_exitCodes() { |
| 311 group('exit codes', () { |
| 312 test('fatal hints', () async { |
| 313 await drive('data/file_with_hint.dart', args: ['--fatal-hints']); |
| 314 expect(exitCode, 1); |
| 315 }); |
| 316 |
| 317 test('not fatal hints', () async { |
| 318 await drive('data/file_with_hint.dart'); |
| 319 expect(exitCode, 0); |
| 320 }); |
| 321 |
| 322 test('fatal errors', () async { |
| 323 await drive('data/file_with_error.dart'); |
| 324 expect(exitCode, 3); |
| 325 }); |
| 326 |
| 327 test('not fatal warnings', () async { |
| 328 await drive('data/file_with_warning.dart'); |
| 329 expect(exitCode, 0); |
| 330 }); |
| 331 |
| 332 test('fatal warnings', () async { |
| 333 await drive('data/file_with_warning.dart', args: ['--fatal-warnings']); |
| 334 expect(exitCode, 2); |
| 335 }); |
| 336 |
| 337 test('not parse enableAssertInitializer', () async { |
| 338 await drive('data/file_with_assert_initializers.dart', |
| 339 args: ['--enable-assert-initializers']); |
| 340 expect(exitCode, 0); |
| 341 }); |
| 342 |
| 343 test('missing options file', () async { |
| 344 await drive('data/test_file.dart', options: 'data/NO_OPTIONS_HERE'); |
| 345 expect(exitCode, 3); |
| 346 }); |
| 347 |
| 348 test('missing dart file', () async { |
| 349 await drive('data/NO_DART_FILE_HERE.dart'); |
| 350 expect(exitCode, 3); |
| 351 }); |
| 352 |
| 353 test('part file', () async { |
| 354 await drive('data/library_and_parts/part2.dart'); |
| 355 expect(exitCode, 3); |
| 356 }); |
| 357 |
| 358 test('non-dangling part file', () async { |
| 359 Driver driver = new Driver(isTesting: true); |
| 360 await driver.start([ |
| 361 path.join(testDirectory, 'data/library_and_parts/lib.dart'), |
| 362 path.join(testDirectory, 'data/library_and_parts/part1.dart') |
| 363 ]); |
| 364 expect(exitCode, 0); |
| 365 }); |
| 366 |
| 367 test('extra part file', () async { |
| 368 Driver driver = new Driver(isTesting: true); |
| 369 await driver.start([ |
| 370 path.join(testDirectory, 'data/library_and_parts/lib.dart'), |
| 371 path.join(testDirectory, 'data/library_and_parts/part1.dart'), |
| 372 path.join(testDirectory, 'data/library_and_parts/part2.dart') |
| 373 ]); |
| 374 expect(exitCode, 3); |
| 375 }); |
| 376 |
| 377 test('bazel workspace relative path', () async { |
| 378 // Copy to temp dir so that existing analysis options |
| 379 // in the test directory hierarchy do not interfere |
| 380 await withTempDirAsync((String tempDirPath) async { |
| 381 String dartSdkPath = path.absolute(getSdkPath()); |
| 382 await recursiveCopy( |
| 383 new Directory(path.join(testDirectory, 'data', 'bazel')), |
| 384 tempDirPath); |
| 385 Directory origWorkingDir = Directory.current; |
| 386 try { |
| 387 Directory.current = path.join(tempDirPath, 'proj'); |
| 388 Driver driver = new Driver(isTesting: true); |
| 389 try { |
| 390 await driver.start([ |
| 391 path.join('lib', 'file.dart'), |
| 392 '--dart-sdk', |
| 393 dartSdkPath, |
| 394 ]); |
| 395 } catch (e) { |
| 396 print('=== debug info ==='); |
| 397 print('dartSdkPath: $dartSdkPath'); |
| 398 print('stderr:\n${errorSink.toString()}'); |
| 399 rethrow; |
| 400 } |
| 401 expect(errorSink.toString(), isEmpty); |
| 402 expect(outSink.toString(), contains('No issues found')); |
| 403 expect(exitCode, 0); |
| 404 } finally { |
| 405 Directory.current = origWorkingDir; |
| 406 } |
| 407 }); |
| 408 }); |
| 409 }); |
| 410 } |
| 411 |
| 412 void _test_linter() { |
| 413 test('containsLintRuleEntry', () { |
| 414 Map<String, YamlNode> options; |
| 415 options = parseOptions(''' |
| 416 linter: |
| 417 rules: |
| 418 - foo |
| 419 '''); |
| 420 expect(containsLintRuleEntry(options), true); |
| 421 options = parseOptions(''' |
| 422 '''); |
| 423 expect(containsLintRuleEntry(options), false); |
| 424 options = parseOptions(''' |
| 425 linter: |
| 426 rules: |
| 427 # - foo |
| 428 '''); |
| 429 expect(containsLintRuleEntry(options), true); |
| 430 options = parseOptions(''' |
| 431 linter: |
| 432 # rules: |
| 433 # - foo |
| 434 '''); |
| 435 expect(containsLintRuleEntry(options), false); |
| 436 }); |
| 437 |
| 438 group('linter', () { |
| 439 void createTests(String designator, String optionsFileName) { |
| 440 group('lints in options - $designator', () { |
| 441 // Shared lint command. |
| 442 Future<Null> runLinter() async { |
| 443 return await drive('data/linter_project/test_file.dart', |
| 444 options: 'data/linter_project/$optionsFileName', |
| 445 args: ['--lints']); |
| 446 } |
| 447 |
| 448 test('gets analysis options', () async { |
| 449 await runLinter(); |
| 450 |
| 451 /// Lints should be enabled. |
| 452 expect(driver.context.analysisOptions.lint, isTrue); |
| 453 |
| 454 /// The analysis options file only specifies 'camel_case_types'. |
| 455 var lintNames = getLints(driver.context).map((r) => r.name); |
| 456 expect(lintNames, orderedEquals(['camel_case_types'])); |
| 457 }); |
| 458 |
| 459 test('generates lints', () async { |
| 460 await runLinter(); |
| 461 expect(_bulletToDash(outSink), |
| 462 contains('lint - Name types using UpperCamelCase')); |
| 463 }); |
| 464 }); |
| 465 |
| 466 group('default lints - $designator', () { |
| 467 // Shared lint command. |
| 468 Future<Null> runLinter() async { |
| 469 return await drive('data/linter_project/test_file.dart', |
| 470 options: 'data/linter_project/$optionsFileName', |
| 471 args: ['--lints']); |
| 472 } |
| 473 |
| 474 test('gets default lints', () async { |
| 475 await runLinter(); |
| 476 |
| 477 /// Lints should be enabled. |
| 478 expect(driver.context.analysisOptions.lint, isTrue); |
| 479 |
| 480 /// Default list should include camel_case_types. |
| 481 var lintNames = getLints(driver.context).map((r) => r.name); |
| 482 expect(lintNames, contains('camel_case_types')); |
| 483 }); |
| 484 |
| 485 test('generates lints', () async { |
| 486 await runLinter(); |
| 487 expect(_bulletToDash(outSink), |
| 488 contains('lint - Name types using UpperCamelCase')); |
| 489 }); |
| 490 }); |
| 491 |
| 492 group('no `--lints` flag (none in options) - $designator', () { |
| 493 // Shared lint command. |
| 494 Future<Null> runLinter() async { |
| 495 return await drive('data/no_lints_project/test_file.dart', |
| 496 options: 'data/no_lints_project/$optionsFileName'); |
| 497 } |
| 498 |
| 499 test('lints disabled', () async { |
| 500 await runLinter(); |
| 501 expect(driver.context.analysisOptions.lint, isFalse); |
| 502 }); |
| 503 |
| 504 test('no registered lints', () async { |
| 505 await runLinter(); |
| 506 expect(getLints(driver.context), isEmpty); |
| 507 }); |
| 508 |
| 509 test('no generated warnings', () async { |
| 510 await runLinter(); |
| 511 expect(outSink.toString(), contains('No issues found')); |
| 512 }); |
| 513 }); |
| 514 } |
| 515 |
| 516 createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); |
| 517 createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); |
| 518 }); |
| 519 } |
| 520 |
| 521 void _test_optionsProcessing() { |
| 522 group('options processing', () { |
| 523 void createTests(String designator, String optionsFileName) { |
| 524 group('basic config - $designator', () { |
| 525 // Shared driver command. |
| 526 Future<Null> doDrive() async { |
| 527 await drive('data/options_tests_project/test_file.dart', |
| 528 options: 'data/options_tests_project/$optionsFileName'); |
| 529 } |
| 530 |
| 531 test('filters', () async { |
| 532 await doDrive(); |
| 533 expect(processors, hasLength(3)); |
| 534 |
| 535 // unused_local_variable: ignore |
| 536 var unused_local_variable = new AnalysisError( |
| 537 new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [ |
| 538 ['x'] |
| 539 ]); |
| 540 expect(processorFor(unused_local_variable).severity, isNull); |
| 541 |
| 542 // missing_return: error |
| 543 var missing_return = new AnalysisError( |
| 544 new TestSource(), 0, 1, HintCode.MISSING_RETURN, [ |
| 545 ['x'] |
| 546 ]); |
| 547 expect(processorFor(missing_return).severity, ErrorSeverity.ERROR); |
| 548 expect( |
| 549 _bulletToDash(outSink), |
| 550 contains( |
| 551 "error - This function declares a return type of 'int'")); |
| 552 expect(outSink.toString(), contains("1 error and 1 warning found.")); |
| 553 }); |
| 554 |
| 555 test('language', () async { |
| 556 await doDrive(); |
| 557 expect(driver.context.analysisOptions.enableSuperMixins, isTrue); |
| 558 }); |
| 559 |
| 560 test('strongMode', () async { |
| 561 await doDrive(); |
| 562 expect(driver.context.analysisOptions.strongMode, isTrue); |
| 563 //https://github.com/dart-lang/sdk/issues/26129 |
| 564 AnalysisContext sdkContext = |
| 565 driver.context.sourceFactory.dartSdk.context; |
| 566 expect(sdkContext.analysisOptions.strongMode, isTrue); |
| 567 }); |
| 568 }); |
| 569 |
| 570 group('with flags - $designator', () { |
| 571 // Shared driver command. |
| 572 Future<Null> doDrive() async { |
| 573 await drive('data/options_tests_project/test_file.dart', |
| 574 args: ['--fatal-warnings'], |
| 575 options: 'data/options_tests_project/$optionsFileName'); |
| 576 } |
| 577 |
| 578 test('override fatal warning', () async { |
| 579 await doDrive(); |
| 580 // missing_return: error |
| 581 var undefined_function = new AnalysisError(new TestSource(), 0, 1, |
| 582 StaticTypeWarningCode.UNDEFINED_FUNCTION, [ |
| 583 ['x'] |
| 584 ]); |
| 585 expect( |
| 586 processorFor(undefined_function).severity, ErrorSeverity.WARNING); |
| 587 // Should not be made fatal by `--fatal-warnings`. |
| 588 expect(_bulletToDash(outSink), |
| 589 contains("warning - The function 'baz' isn't defined")); |
| 590 expect(outSink.toString(), contains("1 error and 1 warning found.")); |
| 591 }); |
| 592 }); |
| 593 } |
| 594 |
| 595 createTests('old', AnalysisEngine.ANALYSIS_OPTIONS_FILE); |
| 596 createTests('new', AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE); |
| 597 |
| 598 test('include directive', () async { |
| 599 String testDir = path.join( |
| 600 testDirectory, 'data', 'options_include_directive_tests_project'); |
| 601 await drive( |
| 602 path.join(testDir, 'lib', 'test_file.dart'), |
| 603 args: [ |
| 604 '--fatal-warnings', |
| 605 '--packages', |
| 606 path.join(testDir, '_packages'), |
| 607 ], |
| 608 options: path.join(testDir, 'analysis_options.yaml'), |
| 609 ); |
| 610 expect(exitCode, 3); |
| 611 expect(outSink.toString(), |
| 612 contains('but doesn\'t end with a return statement')); |
| 613 expect(outSink.toString(), contains('isn\'t defined')); |
| 614 expect(outSink.toString(), contains('Avoid empty else statements')); |
| 615 }); |
| 616 |
| 617 test('test strong SDK', () async { |
| 618 String testDir = path.join(testDirectory, 'data', 'strong_sdk'); |
| 619 await drive(path.join(testDir, 'main.dart'), args: ['--strong']); |
| 620 expect(driver.context.analysisOptions.strongMode, isTrue); |
| 621 expect(outSink.toString(), contains('No issues found')); |
| 622 expect(exitCode, 0); |
| 623 }); |
| 624 }); |
| 625 } |
| 626 |
| 616 class TestSource implements Source { | 627 class TestSource implements Source { |
| 617 TestSource(); | 628 TestSource(); |
| 618 | 629 |
| 619 @override | 630 @override |
| 620 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); | 631 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| 621 } | 632 } |
| OLD | NEW |