| 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 17 matching lines...) Expand all Loading... |
| 28 | 28 |
| 29 main() { | 29 main() { |
| 30 defineReflectiveSuite(() { | 30 defineReflectiveSuite(() { |
| 31 defineReflectiveTests(BuildModeTest); | 31 defineReflectiveTests(BuildModeTest); |
| 32 defineReflectiveTests(ExitCodesTest); | 32 defineReflectiveTests(ExitCodesTest); |
| 33 defineReflectiveTests(LinterTest); | 33 defineReflectiveTests(LinterTest); |
| 34 defineReflectiveTests(OptionsTest); | 34 defineReflectiveTests(OptionsTest); |
| 35 }, name: 'Driver'); | 35 }, name: 'Driver'); |
| 36 } | 36 } |
| 37 | 37 |
| 38 class BaseTest { |
| 39 static const emptyOptionsFile = 'data/empty_options.yaml'; |
| 40 |
| 41 StringSink _savedOutSink, _savedErrorSink; |
| 42 int _savedExitCode; |
| 43 ExitHandler _savedExitHandler; |
| 44 |
| 45 Driver driver; |
| 46 |
| 47 /// Normalize text with bullets. |
| 48 String bulletToDash(item) => '$item'.replaceAll('•', '-'); |
| 49 |
| 50 /// Start a driver for the given [source], optionally providing additional |
| 51 /// [args] and an [options] file path. The value of [options] defaults to |
| 52 /// an empty options file to avoid unwanted configuration from an otherwise |
| 53 /// discovered options file. |
| 54 Future<Null> drive(String source, |
| 55 {String options: emptyOptionsFile, |
| 56 List<String> args: const <String>[]}) async { |
| 57 driver = new Driver(isTesting: true); |
| 58 var cmd = [ |
| 59 '--options', |
| 60 path.join(testDirectory, options), |
| 61 _adjustFileSpec(source) |
| 62 ]..addAll(args); |
| 63 await driver.start(cmd); |
| 64 } |
| 65 |
| 66 void setUp() { |
| 67 ansi.runningTests = true; |
| 68 _savedOutSink = outSink; |
| 69 _savedErrorSink = errorSink; |
| 70 _savedExitHandler = exitHandler; |
| 71 _savedExitCode = exitCode; |
| 72 exitHandler = (code) => exitCode = code; |
| 73 outSink = new StringBuffer(); |
| 74 errorSink = new StringBuffer(); |
| 75 } |
| 76 |
| 77 void tearDown() { |
| 78 outSink = _savedOutSink; |
| 79 errorSink = _savedErrorSink; |
| 80 exitCode = _savedExitCode; |
| 81 exitHandler = _savedExitHandler; |
| 82 ansi.runningTests = false; |
| 83 } |
| 84 |
| 85 /// Convert a file specification from a relative path to an absolute path. |
| 86 /// Handles the case where the file specification is of the form "$uri|$path". |
| 87 String _adjustFileSpec(String fileSpec) { |
| 88 int uriPrefixLength = fileSpec.indexOf('|') + 1; |
| 89 String uriPrefix = fileSpec.substring(0, uriPrefixLength); |
| 90 String relativePath = fileSpec.substring(uriPrefixLength); |
| 91 return '$uriPrefix${path.join(testDirectory, relativePath)}'; |
| 92 } |
| 93 } |
| 94 |
| 38 @reflectiveTest | 95 @reflectiveTest |
| 39 class BuildModeTest extends _BaseTest { | 96 class BuildModeTest extends BaseTest { |
| 40 test_buildLinked() async { | 97 test_buildLinked() async { |
| 41 await withTempDirAsync((tempDir) async { | 98 await withTempDirAsync((tempDir) async { |
| 42 var outputPath = path.join(tempDir, 'test_file.dart.sum'); | 99 var outputPath = path.join(tempDir, 'test_file.dart.sum'); |
| 43 await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ | 100 await _doDrive(path.join('data', 'test_file.dart'), additionalArgs: [ |
| 44 '--build-summary-only', | 101 '--build-summary-only', |
| 45 '--build-summary-output=$outputPath' | 102 '--build-summary-output=$outputPath' |
| 46 ]); | 103 ]); |
| 47 var output = new File(outputPath); | 104 var output = new File(outputPath); |
| 48 expect(output.existsSync(), isTrue); | 105 expect(output.existsSync(), isTrue); |
| 49 PackageBundle bundle = | 106 PackageBundle bundle = |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 } | 345 } |
| 289 } | 346 } |
| 290 } | 347 } |
| 291 } | 348 } |
| 292 throw new Exception('Could not find an SDK directory containing summaries.' | 349 throw new Exception('Could not find an SDK directory containing summaries.' |
| 293 ' Tried: ${triedDirectories.toList()}'); | 350 ' Tried: ${triedDirectories.toList()}'); |
| 294 } | 351 } |
| 295 } | 352 } |
| 296 | 353 |
| 297 @reflectiveTest | 354 @reflectiveTest |
| 298 class ExitCodesTest extends _BaseTest { | 355 class ExitCodesTest extends BaseTest { |
| 299 test_bazelWorkspace_relativePath() async { | 356 test_bazelWorkspace_relativePath() async { |
| 300 // Copy to temp dir so that existing analysis options | 357 // Copy to temp dir so that existing analysis options |
| 301 // in the test directory hierarchy do not interfere | 358 // in the test directory hierarchy do not interfere |
| 302 await withTempDirAsync((String tempDirPath) async { | 359 await withTempDirAsync((String tempDirPath) async { |
| 303 String dartSdkPath = path.absolute(getSdkPath()); | 360 String dartSdkPath = path.absolute(getSdkPath()); |
| 304 await recursiveCopy( | 361 await recursiveCopy( |
| 305 new Directory(path.join(testDirectory, 'data', 'bazel')), | 362 new Directory(path.join(testDirectory, 'data', 'bazel')), |
| 306 tempDirPath); | 363 tempDirPath); |
| 307 Directory origWorkingDir = Directory.current; | 364 Directory origWorkingDir = Directory.current; |
| 308 try { | 365 try { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 await driver.start([ | 446 await driver.start([ |
| 390 path.join(testDirectory, 'data/library_and_parts/lib.dart'), | 447 path.join(testDirectory, 'data/library_and_parts/lib.dart'), |
| 391 path.join(testDirectory, 'data/library_and_parts/part1.dart'), | 448 path.join(testDirectory, 'data/library_and_parts/part1.dart'), |
| 392 path.join(testDirectory, 'data/library_and_parts/part2.dart') | 449 path.join(testDirectory, 'data/library_and_parts/part2.dart') |
| 393 ]); | 450 ]); |
| 394 expect(exitCode, 3); | 451 expect(exitCode, 3); |
| 395 } | 452 } |
| 396 } | 453 } |
| 397 | 454 |
| 398 @reflectiveTest | 455 @reflectiveTest |
| 399 class LinterTest extends _BaseTest { | 456 class LinterTest extends BaseTest { |
| 400 String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE; | 457 String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE; |
| 401 | 458 |
| 402 test_containsLintRuleEntry() async { | 459 test_containsLintRuleEntry() async { |
| 403 Map<String, YamlNode> options; | 460 Map<String, YamlNode> options; |
| 404 options = _parseOptions(''' | 461 options = _parseOptions(''' |
| 405 linter: | 462 linter: |
| 406 rules: | 463 rules: |
| 407 - foo | 464 - foo |
| 408 '''); | 465 '''); |
| 409 expect(containsLintRuleEntry(options), true); | 466 expect(containsLintRuleEntry(options), true); |
| 410 options = _parseOptions(''' | 467 options = _parseOptions(''' |
| 411 '''); | 468 '''); |
| 412 expect(containsLintRuleEntry(options), false); | 469 expect(containsLintRuleEntry(options), false); |
| 413 options = _parseOptions(''' | 470 options = _parseOptions(''' |
| 414 linter: | 471 linter: |
| 415 rules: | 472 rules: |
| 416 # - foo | 473 # - foo |
| 417 '''); | 474 '''); |
| 418 expect(containsLintRuleEntry(options), true); | 475 expect(containsLintRuleEntry(options), true); |
| 419 options = _parseOptions(''' | 476 options = _parseOptions(''' |
| 420 linter: | 477 linter: |
| 421 # rules: | 478 # rules: |
| 422 # - foo | 479 # - foo |
| 423 '''); | 480 '''); |
| 424 expect(containsLintRuleEntry(options), false); | 481 expect(containsLintRuleEntry(options), false); |
| 425 } | 482 } |
| 426 | 483 |
| 427 test_defaultLints_generatedLints() async { | 484 test_defaultLints_generatedLints() async { |
| 428 await _runLinter_defaultLints(); | 485 await _runLinter_defaultLints(); |
| 429 expect(_bulletToDash(outSink), | 486 expect(bulletToDash(outSink), |
| 430 contains('lint - Name types using UpperCamelCase')); | 487 contains('lint - Name types using UpperCamelCase')); |
| 431 } | 488 } |
| 432 | 489 |
| 433 test_defaultLints_getsDefaultLints() async { | 490 test_defaultLints_getsDefaultLints() async { |
| 434 await _runLinter_defaultLints(); | 491 await _runLinter_defaultLints(); |
| 435 | 492 |
| 436 /// Lints should be enabled. | 493 /// Lints should be enabled. |
| 437 expect(driver.context.analysisOptions.lint, isTrue); | 494 expect(driver.context.analysisOptions.lint, isTrue); |
| 438 | 495 |
| 439 /// Default list should include camel_case_types. | 496 /// Default list should include camel_case_types. |
| 440 var lintNames = getLints(driver.context).map((r) => r.name); | 497 var lintNames = getLints(driver.context).map((r) => r.name); |
| 441 expect(lintNames, contains('camel_case_types')); | 498 expect(lintNames, contains('camel_case_types')); |
| 442 } | 499 } |
| 443 | 500 |
| 444 test_lintsInOptions_generatedLints() async { | 501 test_lintsInOptions_generatedLints() async { |
| 445 await _runLinter_lintsInOptions(); | 502 await _runLinter_lintsInOptions(); |
| 446 expect(_bulletToDash(outSink), | 503 expect(bulletToDash(outSink), |
| 447 contains('lint - Name types using UpperCamelCase')); | 504 contains('lint - Name types using UpperCamelCase')); |
| 448 } | 505 } |
| 449 | 506 |
| 450 test_lintsInOptions_getAnalysisOptions() async { | 507 test_lintsInOptions_getAnalysisOptions() async { |
| 451 await _runLinter_lintsInOptions(); | 508 await _runLinter_lintsInOptions(); |
| 452 | 509 |
| 453 /// Lints should be enabled. | 510 /// Lints should be enabled. |
| 454 expect(driver.context.analysisOptions.lint, isTrue); | 511 expect(driver.context.analysisOptions.lint, isTrue); |
| 455 | 512 |
| 456 /// The analysis options file only specifies 'camel_case_types'. | 513 /// The analysis options file only specifies 'camel_case_types'. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 486 options: 'data/linter_project/$optionsFileName', args: ['--lints']); | 543 options: 'data/linter_project/$optionsFileName', args: ['--lints']); |
| 487 } | 544 } |
| 488 | 545 |
| 489 Future<Null> _runLinter_noLintsFlag() async { | 546 Future<Null> _runLinter_noLintsFlag() async { |
| 490 await drive('data/no_lints_project/test_file.dart', | 547 await drive('data/no_lints_project/test_file.dart', |
| 491 options: 'data/no_lints_project/$optionsFileName'); | 548 options: 'data/no_lints_project/$optionsFileName'); |
| 492 } | 549 } |
| 493 } | 550 } |
| 494 | 551 |
| 495 @reflectiveTest | 552 @reflectiveTest |
| 496 class OptionsTest extends _BaseTest { | 553 class OptionsTest extends BaseTest { |
| 497 String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE; | 554 String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE; |
| 498 | 555 |
| 499 List<ErrorProcessor> get processors => | 556 List<ErrorProcessor> get processors => |
| 500 driver.context.analysisOptions.errorProcessors; | 557 driver.context.analysisOptions.errorProcessors; |
| 501 | 558 |
| 502 ErrorProcessor processorFor(AnalysisError error) => | 559 ErrorProcessor processorFor(AnalysisError error) => |
| 503 processors.firstWhere((p) => p.appliesTo(error)); | 560 processors.firstWhere((p) => p.appliesTo(error)); |
| 504 | 561 |
| 505 test_basic_filters() async { | 562 test_basic_filters() async { |
| 506 await _driveBasic(); | 563 await _driveBasic(); |
| 507 expect(processors, hasLength(3)); | 564 expect(processors, hasLength(3)); |
| 508 | 565 |
| 509 // unused_local_variable: ignore | 566 // unused_local_variable: ignore |
| 510 var unused_local_variable = new AnalysisError( | 567 var unused_local_variable = new AnalysisError( |
| 511 new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [ | 568 new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [ |
| 512 ['x'] | 569 ['x'] |
| 513 ]); | 570 ]); |
| 514 expect(processorFor(unused_local_variable).severity, isNull); | 571 expect(processorFor(unused_local_variable).severity, isNull); |
| 515 | 572 |
| 516 // missing_return: error | 573 // missing_return: error |
| 517 var missing_return = | 574 var missing_return = |
| 518 new AnalysisError(new TestSource(), 0, 1, HintCode.MISSING_RETURN, [ | 575 new AnalysisError(new TestSource(), 0, 1, HintCode.MISSING_RETURN, [ |
| 519 ['x'] | 576 ['x'] |
| 520 ]); | 577 ]); |
| 521 expect(processorFor(missing_return).severity, ErrorSeverity.ERROR); | 578 expect(processorFor(missing_return).severity, ErrorSeverity.ERROR); |
| 522 expect(_bulletToDash(outSink), | 579 expect(bulletToDash(outSink), |
| 523 contains("error - This function declares a return type of 'int'")); | 580 contains("error - This function declares a return type of 'int'")); |
| 524 expect(outSink.toString(), contains("1 error and 1 warning found.")); | 581 expect(outSink.toString(), contains("1 error and 1 warning found.")); |
| 525 } | 582 } |
| 526 | 583 |
| 527 test_basic_language() async { | 584 test_basic_language() async { |
| 528 await _driveBasic(); | 585 await _driveBasic(); |
| 529 expect(driver.context.analysisOptions.enableSuperMixins, isTrue); | 586 expect(driver.context.analysisOptions.enableSuperMixins, isTrue); |
| 530 } | 587 } |
| 531 | 588 |
| 532 test_basic_strongMode() async { | 589 test_basic_strongMode() async { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 args: ['--fatal-warnings'], | 631 args: ['--fatal-warnings'], |
| 575 options: 'data/options_tests_project/$optionsFileName'); | 632 options: 'data/options_tests_project/$optionsFileName'); |
| 576 | 633 |
| 577 // missing_return: error | 634 // missing_return: error |
| 578 var undefined_function = new AnalysisError( | 635 var undefined_function = new AnalysisError( |
| 579 new TestSource(), 0, 1, StaticTypeWarningCode.UNDEFINED_FUNCTION, [ | 636 new TestSource(), 0, 1, StaticTypeWarningCode.UNDEFINED_FUNCTION, [ |
| 580 ['x'] | 637 ['x'] |
| 581 ]); | 638 ]); |
| 582 expect(processorFor(undefined_function).severity, ErrorSeverity.WARNING); | 639 expect(processorFor(undefined_function).severity, ErrorSeverity.WARNING); |
| 583 // Should not be made fatal by `--fatal-warnings`. | 640 // Should not be made fatal by `--fatal-warnings`. |
| 584 expect(_bulletToDash(outSink), | 641 expect(bulletToDash(outSink), |
| 585 contains("warning - The function 'baz' isn't defined")); | 642 contains("warning - The function 'baz' isn't defined")); |
| 586 expect(outSink.toString(), contains("1 error and 1 warning found.")); | 643 expect(outSink.toString(), contains("1 error and 1 warning found.")); |
| 587 } | 644 } |
| 588 | 645 |
| 589 Future<Null> _driveBasic() async { | 646 Future<Null> _driveBasic() async { |
| 590 await drive('data/options_tests_project/test_file.dart', | 647 await drive('data/options_tests_project/test_file.dart', |
| 591 options: 'data/options_tests_project/$optionsFileName'); | 648 options: 'data/options_tests_project/$optionsFileName'); |
| 592 } | 649 } |
| 593 } | 650 } |
| 594 | 651 |
| 595 class TestSource implements Source { | 652 class TestSource implements Source { |
| 596 TestSource(); | 653 TestSource(); |
| 597 | 654 |
| 598 @override | 655 @override |
| 599 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); | 656 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| 600 } | 657 } |
| 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 |