| 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:io'; | 7 import 'dart:io'; |
| 8 | 8 |
| 9 import 'package:analyzer/plugin/options.dart'; | 9 import 'package:analyzer/plugin/options.dart'; |
| 10 import 'package:analyzer/source/analysis_options_provider.dart'; | 10 import 'package:analyzer/source/analysis_options_provider.dart'; |
| 11 import 'package:analyzer/src/generated/engine.dart'; | 11 import 'package:analyzer/src/generated/engine.dart'; |
| 12 import 'package:analyzer/src/generated/error.dart'; | 12 import 'package:analyzer/src/generated/error.dart'; |
| 13 import 'package:analyzer/src/generated/source.dart'; | 13 import 'package:analyzer/src/generated/source.dart'; |
| 14 import 'package:analyzer/src/plugin/plugin_configuration.dart'; | 14 import 'package:analyzer/src/plugin/plugin_configuration.dart'; |
| 15 import 'package:analyzer/src/services/lint.dart'; | 15 import 'package:analyzer/src/services/lint.dart'; |
| 16 import 'package:analyzer_cli/src/bootloader.dart'; | 16 import 'package:analyzer_cli/src/bootloader.dart'; |
| 17 import 'package:analyzer_cli/src/driver.dart'; | 17 import 'package:analyzer_cli/src/driver.dart'; |
| 18 import 'package:analyzer_cli/src/options.dart'; | 18 import 'package:analyzer_cli/src/options.dart'; |
| 19 import 'package:path/path.dart' as path; | 19 import 'package:path/path.dart' as path; |
| 20 import 'package:plugin/plugin.dart'; | 20 import 'package:plugin/plugin.dart'; |
| 21 import 'package:unittest/unittest.dart'; | 21 import 'package:unittest/unittest.dart'; |
| 22 import 'package:yaml/src/yaml_node.dart'; | 22 import 'package:yaml/src/yaml_node.dart'; |
| 23 | 23 |
| 24 import 'utils.dart'; | 24 // TODO(pq): fix tests to run safely on the bots |
| 25 // https://github.com/dart-lang/sdk/issues/25001 |
| 26 main() {} |
| 27 const emptyOptionsFile = 'test/data/empty_options.yaml'; |
| 25 | 28 |
| 26 main() { | 29 /// Start a driver for the given [source], optionally providing additional |
| 30 /// [args] and an [options] file path. The value of [options] defaults to |
| 31 /// an empty options file to avoid unwanted configuration from an otherwise |
| 32 /// discovered options file. |
| 33 void drive(String source, |
| 34 {String options: emptyOptionsFile, |
| 35 List<String> args: const <String>[]}) => |
| 36 new Driver().start(['--options', options, source]..addAll(args)); |
| 37 |
| 38 not_main() { |
| 27 group('Driver', () { | 39 group('Driver', () { |
| 40 StringSink savedOutSink, savedErrorSink; |
| 41 int savedExitCode; |
| 42 setUp(() { |
| 43 savedOutSink = outSink; |
| 44 savedErrorSink = errorSink; |
| 45 savedExitCode = exitCode; |
| 46 outSink = new StringBuffer(); |
| 47 errorSink = new StringBuffer(); |
| 48 }); |
| 49 tearDown(() { |
| 50 outSink = savedOutSink; |
| 51 errorSink = savedErrorSink; |
| 52 exitCode = savedExitCode; |
| 53 }); |
| 54 |
| 28 group('options', () { | 55 group('options', () { |
| 29 test('custom processor', () { | 56 test('custom processor', () { |
| 30 Driver driver = new Driver(); | 57 Driver driver = new Driver(); |
| 31 TestProcessor processor = new TestProcessor(); | 58 TestProcessor processor = new TestProcessor(); |
| 32 driver.userDefinedPlugins = [new TestPlugin(processor)]; | 59 driver.userDefinedPlugins = [new TestPlugin(processor)]; |
| 33 driver.start([ | 60 driver.start([ |
| 34 '--options', | 61 '--options', |
| 35 path.join(testDirectory, 'data/test_options.yaml'), | 62 'test/data/test_options.yaml', |
| 36 path.join(testDirectory, 'data/test_file.dart') | 63 'test/data/test_file.dart' |
| 37 ]); | 64 ]); |
| 38 expect(processor.options['test_plugin'], isNotNull); | 65 expect(processor.options['test_plugin'], isNotNull); |
| 39 expect(processor.exception, isNull); | 66 expect(processor.exception, isNull); |
| 40 }); | 67 }); |
| 41 }); | 68 }); |
| 42 | 69 |
| 43 //TODO(pq): refactor to NOT set actual error codes to play nice with bots | |
| 44 group('exit codes', () { | 70 group('exit codes', () { |
| 45 StringSink savedOutSink, savedErrorSink; | 71 StringSink savedOutSink, savedErrorSink; |
| 46 int savedExitCode; | 72 int savedExitCode; |
| 47 ExitHandler savedExitHandler; | 73 ExitHandler savedExitHandler; |
| 48 setUp(() { | 74 setUp(() { |
| 49 savedOutSink = outSink; | 75 savedOutSink = outSink; |
| 50 savedErrorSink = errorSink; | 76 savedErrorSink = errorSink; |
| 51 savedExitCode = exitCode; | 77 savedExitCode = exitCode; |
| 52 savedExitHandler = exitHandler; | 78 savedExitHandler = exitHandler; |
| 53 exitHandler = (code) => exitCode = code; | 79 exitHandler = (code) => exitCode = code; |
| 54 outSink = new StringBuffer(); | 80 outSink = new StringBuffer(); |
| 55 errorSink = new StringBuffer(); | 81 errorSink = new StringBuffer(); |
| 56 }); | 82 }); |
| 57 tearDown(() { | 83 tearDown(() { |
| 58 outSink = savedOutSink; | 84 outSink = savedOutSink; |
| 59 errorSink = savedErrorSink; | 85 errorSink = savedErrorSink; |
| 60 exitCode = savedExitCode; | 86 exitCode = savedExitCode; |
| 61 exitHandler = savedExitHandler; | 87 exitHandler = savedExitHandler; |
| 62 }); | 88 }); |
| 63 | 89 |
| 64 test('fatal hints', () { | 90 test('fatal hints', () { |
| 65 drive('data/file_with_hint.dart', args: ['--fatal-hints']); | 91 drive('test/data/file_with_hint.dart', args: ['--fatal-hints']); |
| 66 expect(exitCode, 3); | 92 expect(exitCode, 3); |
| 67 }); | 93 }); |
| 68 | 94 |
| 69 test('not fatal hints', () { | 95 test('not fatal hints', () { |
| 70 drive('data/file_with_hint.dart'); | 96 drive('test/data/file_with_hint.dart'); |
| 71 expect(exitCode, 0); | 97 expect(exitCode, 0); |
| 72 }); | 98 }); |
| 73 | 99 |
| 74 test('fatal errors', () { | 100 test('fatal errors', () { |
| 75 drive('data/file_with_error.dart'); | 101 drive('test/data/file_with_error.dart'); |
| 76 expect(exitCode, 3); | 102 expect(exitCode, 3); |
| 77 }); | 103 }); |
| 78 | 104 |
| 79 test('not fatal warnings', () { | 105 test('not fatal warnings', () { |
| 80 drive('data/file_with_warning.dart'); | 106 drive('test/data/file_with_warning.dart'); |
| 81 expect(exitCode, 0); | 107 expect(exitCode, 0); |
| 82 }); | 108 }); |
| 83 | 109 |
| 84 test('fatal warnings', () { | 110 test('fatal warnings', () { |
| 85 drive('data/file_with_warning.dart', args: ['--fatal-warnings']); | 111 drive('test/data/file_with_warning.dart', args: ['--fatal-warnings']); |
| 86 expect(exitCode, 3); | 112 expect(exitCode, 3); |
| 87 }); | 113 }); |
| 88 | 114 |
| 89 test('missing options file', () { | 115 test('missing options file', () { |
| 90 drive('data/test_file.dart', options: 'data/NO_OPTIONS_HERE'); | 116 drive('test/data/test_file.dart', options: 'test/data/NO_OPTIONS_HERE'); |
| 91 expect(exitCode, 3); | 117 expect(exitCode, 3); |
| 92 }); | 118 }); |
| 93 | 119 |
| 94 test('missing dart file', () { | 120 test('missing dart file', () { |
| 95 drive('data/NO_DART_FILE_HERE.dart'); | 121 drive('test/data/NO_DART_FILE_HERE.dart'); |
| 96 expect(exitCode, 3); | 122 expect(exitCode, 3); |
| 97 }); | 123 }); |
| 98 | 124 |
| 99 test('part file', () { | 125 test('part file', () { |
| 100 drive('data/library_and_parts/part2.dart'); | 126 drive('test/data/library_and_parts/part2.dart'); |
| 101 expect(exitCode, 3); | 127 expect(exitCode, 3); |
| 102 }); | 128 }); |
| 103 | 129 |
| 104 test('non-dangling part file', () { | 130 test('non-dangling part file', () { |
| 105 Driver driver = new Driver(); | 131 Driver driver = new Driver(); |
| 106 driver.start([ | 132 driver.start([ |
| 107 path.join(testDirectory, 'data/library_and_parts/lib.dart'), | 133 'test/data/library_and_parts/lib.dart', |
| 108 path.join(testDirectory, 'data/library_and_parts/part1.dart') | 134 'test/data/library_and_parts/part1.dart', |
| 109 ]); | 135 ]); |
| 110 expect(exitCode, 0); | 136 expect(exitCode, 0); |
| 111 }); | 137 }); |
| 112 | 138 |
| 113 test('extra part file', () { | 139 test('extra part file', () { |
| 114 Driver driver = new Driver(); | 140 Driver driver = new Driver(); |
| 115 driver.start([ | 141 driver.start([ |
| 116 path.join(testDirectory, 'data/library_and_parts/lib.dart'), | 142 'test/data/library_and_parts/lib.dart', |
| 117 path.join(testDirectory, 'data/library_and_parts/part1.dart'), | 143 'test/data/library_and_parts/part1.dart', |
| 118 path.join(testDirectory, 'data/library_and_parts/part2.dart') | 144 'test/data/library_and_parts/part2.dart', |
| 119 ]); | 145 ]); |
| 120 expect(exitCode, 3); | 146 expect(exitCode, 3); |
| 121 }); | 147 }); |
| 122 }); | 148 }); |
| 123 | 149 |
| 124 group('linter', () { | 150 group('linter', () { |
| 125 group('lints in options', () { | 151 group('lints in options', () { |
| 126 StringSink savedOutSink; | 152 StringSink savedOutSink; |
| 153 Driver driver; |
| 127 | 154 |
| 128 setUp(() { | 155 setUp(() { |
| 129 savedOutSink = outSink; | 156 savedOutSink = outSink; |
| 130 outSink = new StringBuffer(); | 157 outSink = new StringBuffer(); |
| 131 | 158 |
| 132 drive('data/linter_project/test_file.dart', | 159 driver = new Driver(); |
| 133 options: 'data/linter_project/.analysis_options', | 160 driver.start([ |
| 134 args: ['--lints']); | 161 '--options', |
| 162 'test/data/linter_project/.analysis_options', |
| 163 '--lints', |
| 164 'test/data/linter_project/test_file.dart' |
| 165 ]); |
| 135 }); | 166 }); |
| 136 | |
| 137 tearDown(() { | 167 tearDown(() { |
| 138 outSink = savedOutSink; | 168 outSink = savedOutSink; |
| 139 }); | 169 }); |
| 140 | 170 |
| 141 test('gets analysis options', () { | 171 test('gets analysis options', () { |
| 142 /// Lints should be enabled. | 172 /// Lints should be enabled. |
| 143 expect(driver.context.analysisOptions.lint, isTrue); | 173 expect(driver.context.analysisOptions.lint, isTrue); |
| 144 | 174 |
| 145 /// The .analysis_options file only specifies 'camel_case_types'. | 175 /// The .analysis_options file only specifies 'camel_case_types'. |
| 146 var lintNames = getLints(driver.context).map((r) => r.name); | 176 var lintNames = getLints(driver.context).map((r) => r.name); |
| 147 expect(lintNames, orderedEquals(['camel_case_types'])); | 177 expect(lintNames, orderedEquals(['camel_case_types'])); |
| 148 }); | 178 }); |
| 149 | 179 |
| 150 test('generates lints', () { | 180 test('generates lints', () { |
| 151 expect(outSink.toString(), | 181 expect(outSink.toString(), |
| 152 contains('[lint] Name types using UpperCamelCase.')); | 182 contains('[lint] Name types using UpperCamelCase.')); |
| 153 }); | 183 }); |
| 154 }); | 184 }); |
| 155 | 185 |
| 156 group('default lints', () { | 186 group('default lints', () { |
| 157 StringSink savedOutSink; | 187 StringSink savedOutSink; |
| 188 Driver driver; |
| 158 | 189 |
| 159 setUp(() { | 190 setUp(() { |
| 160 savedOutSink = outSink; | 191 savedOutSink = outSink; |
| 161 outSink = new StringBuffer(); | 192 outSink = new StringBuffer(); |
| 162 | 193 |
| 163 drive('data/linter_project/test_file.dart', | 194 driver = new Driver(); |
| 164 options: 'data/linter_project/.analysis_options', | 195 driver.start([ |
| 165 args: ['--lints']); | 196 '--lints', |
| 197 'test/data/linter_project/test_file.dart', |
| 198 '--options', |
| 199 'test/data/linter_project/.analysis_options' |
| 200 ]); |
| 166 }); | 201 }); |
| 167 tearDown(() { | 202 tearDown(() { |
| 168 outSink = savedOutSink; | 203 outSink = savedOutSink; |
| 169 }); | 204 }); |
| 170 | 205 |
| 171 test('gets default lints', () { | 206 test('gets default lints', () { |
| 172 /// Lints should be enabled. | 207 /// Lints should be enabled. |
| 173 expect(driver.context.analysisOptions.lint, isTrue); | 208 expect(driver.context.analysisOptions.lint, isTrue); |
| 174 | 209 |
| 175 /// Default list should include camel_case_types. | 210 /// Default list should include camel_case_types. |
| 176 var lintNames = getLints(driver.context).map((r) => r.name); | 211 var lintNames = getLints(driver.context).map((r) => r.name); |
| 177 expect(lintNames, contains('camel_case_types')); | 212 expect(lintNames, contains('camel_case_types')); |
| 178 }); | 213 }); |
| 179 | 214 |
| 180 test('generates lints', () { | 215 test('generates lints', () { |
| 181 expect(outSink.toString(), | 216 expect(outSink.toString(), |
| 182 contains('[lint] Name types using UpperCamelCase.')); | 217 contains('[lint] Name types using UpperCamelCase.')); |
| 183 }); | 218 }); |
| 184 }); | 219 }); |
| 185 | 220 |
| 186 group('no `--lints` flag (none in options)', () { | 221 group('no `--lints` flag (none in options)', () { |
| 187 StringSink savedOutSink; | 222 StringSink savedOutSink; |
| 223 Driver driver; |
| 188 | 224 |
| 189 setUp(() { | 225 setUp(() { |
| 190 savedOutSink = outSink; | 226 savedOutSink = outSink; |
| 191 outSink = new StringBuffer(); | 227 outSink = new StringBuffer(); |
| 192 | 228 |
| 193 drive('data/no_lints_project/test_file.dart', | 229 driver = new Driver(); |
| 194 options: 'data/no_lints_project/.analysis_options'); | 230 driver.start([ |
| 231 'test/data/no_lints_project/test_file.dart', |
| 232 '--options', |
| 233 'test/data/no_lints_project/.analysis_options' |
| 234 ]); |
| 195 }); | 235 }); |
| 196 tearDown(() { | 236 tearDown(() { |
| 197 outSink = savedOutSink; | 237 outSink = savedOutSink; |
| 198 }); | 238 }); |
| 199 | 239 |
| 200 test('lints disabled', () { | 240 test('lints disabled', () { |
| 201 expect(driver.context.analysisOptions.lint, isFalse); | 241 expect(driver.context.analysisOptions.lint, isFalse); |
| 202 }); | 242 }); |
| 203 | 243 |
| 204 test('no registered lints', () { | 244 test('no registered lints', () { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 232 linter: | 272 linter: |
| 233 # rules: | 273 # rules: |
| 234 # - foo | 274 # - foo |
| 235 '''); | 275 '''); |
| 236 expect(containsLintRuleEntry(options), false); | 276 expect(containsLintRuleEntry(options), false); |
| 237 }); | 277 }); |
| 238 | 278 |
| 239 group('options processing', () { | 279 group('options processing', () { |
| 240 group('error filters', () { | 280 group('error filters', () { |
| 241 StringSink savedOutSink; | 281 StringSink savedOutSink; |
| 282 Driver driver; |
| 242 | 283 |
| 243 setUp(() { | 284 setUp(() { |
| 244 savedOutSink = outSink; | 285 savedOutSink = outSink; |
| 245 outSink = new StringBuffer(); | 286 outSink = new StringBuffer(); |
| 246 | 287 |
| 247 drive('data/options_tests_project/test_file.dart', | 288 driver = new Driver(); |
| 248 options: 'data/options_tests_project/.analysis_options'); | 289 driver.start([ |
| 290 'test/data/options_tests_project/test_file.dart', |
| 291 '--options', |
| 292 'test/data/options_tests_project/.analysis_options' |
| 293 ]); |
| 249 }); | 294 }); |
| 250 tearDown(() { | 295 tearDown(() { |
| 251 outSink = savedOutSink; | 296 outSink = savedOutSink; |
| 252 }); | 297 }); |
| 253 | 298 |
| 254 test('filters', () { | 299 test('filters', () { |
| 255 var processors = | 300 var processors = |
| 256 driver.context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS); | 301 driver.context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS); |
| 257 expect(processors, hasLength(1)); | 302 expect(processors, hasLength(1)); |
| 258 | 303 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 savedErrorSink = errorSink; | 391 savedErrorSink = errorSink; |
| 347 errorSink = new StringBuffer(); | 392 errorSink = new StringBuffer(); |
| 348 }); | 393 }); |
| 349 tearDown(() { | 394 tearDown(() { |
| 350 errorSink = savedErrorSink; | 395 errorSink = savedErrorSink; |
| 351 }); | 396 }); |
| 352 test('bad format', () { | 397 test('bad format', () { |
| 353 BootLoader loader = new BootLoader(); | 398 BootLoader loader = new BootLoader(); |
| 354 loader.createImage([ | 399 loader.createImage([ |
| 355 '--options', | 400 '--options', |
| 356 path.join(testDirectory, 'data/bad_plugin_options.yaml'), | 401 'test/data/bad_plugin_options.yaml', |
| 357 path.join(testDirectory, 'data/test_file.dart') | 402 'test/data/test_file.dart' |
| 358 ]); | 403 ]); |
| 359 expect( | 404 expect( |
| 360 errorSink.toString(), | 405 errorSink.toString(), |
| 361 equals('Plugin configuration skipped: Unrecognized plugin config ' | 406 equals('Plugin configuration skipped: Unrecognized plugin config ' |
| 362 'format, expected `YamlMap`, got `YamlList` ' | 407 'format, expected `YamlMap`, got `YamlList` ' |
| 363 '(line 2, column 4)\n')); | 408 '(line 2, column 4)\n')); |
| 364 }); | 409 }); |
| 365 test('plugin config', () { | 410 test('plugin config', () { |
| 366 BootLoader loader = new BootLoader(); | 411 BootLoader loader = new BootLoader(); |
| 367 Image image = loader.createImage([ | 412 Image image = loader.createImage([ |
| 368 '--options', | 413 '--options', |
| 369 path.join(testDirectory, 'data/plugin_options.yaml'), | 414 'test/data/plugin_options.yaml', |
| 370 path.join(testDirectory, 'data/test_file.dart') | 415 'test/data/test_file.dart' |
| 371 ]); | 416 ]); |
| 372 var plugins = image.config.plugins; | 417 var plugins = image.config.plugins; |
| 373 expect(plugins, hasLength(1)); | 418 expect(plugins, hasLength(1)); |
| 374 expect(plugins.first.name, equals('my_plugin1')); | 419 expect(plugins.first.name, equals('my_plugin1')); |
| 375 }); | 420 }); |
| 376 group('plugin validation', () { | 421 group('plugin validation', () { |
| 377 test('requires class name', () { | 422 test('requires class name', () { |
| 378 expect( | 423 expect( |
| 379 validate(new PluginInfo( | 424 validate(new PluginInfo( |
| 380 name: 'test_plugin', libraryUri: 'my_package/foo.dart')), | 425 name: 'test_plugin', libraryUri: 'my_package/foo.dart')), |
| (...skipping 11 matching lines...) Expand all Loading... |
| 392 name: 'test_plugin', | 437 name: 'test_plugin', |
| 393 className: 'MyPlugin', | 438 className: 'MyPlugin', |
| 394 libraryUri: 'my_package/foo.dart')), | 439 libraryUri: 'my_package/foo.dart')), |
| 395 isNull); | 440 isNull); |
| 396 }); | 441 }); |
| 397 }); | 442 }); |
| 398 }); | 443 }); |
| 399 }); | 444 }); |
| 400 } | 445 } |
| 401 | 446 |
| 402 const emptyOptionsFile = 'data/empty_options.yaml'; | |
| 403 | |
| 404 /// Shared driver. | |
| 405 Driver driver; | |
| 406 | |
| 407 /// Start a driver for the given [source], optionally providing additional | |
| 408 /// [args] and an [options] file path. The value of [options] defaults to | |
| 409 /// an empty options file to avoid unwanted configuration from an otherwise | |
| 410 /// discovered options file. | |
| 411 void drive(String source, | |
| 412 {String options: emptyOptionsFile, List<String> args: const <String>[]}) { | |
| 413 driver = new Driver(); | |
| 414 var cmd = [ | |
| 415 '--options', | |
| 416 path.join(testDirectory, options), | |
| 417 path.join(testDirectory, source) | |
| 418 ]..addAll(args); | |
| 419 driver.start(cmd); | |
| 420 } | |
| 421 | |
| 422 Map<String, YamlNode> parseOptions(String src) => | 447 Map<String, YamlNode> parseOptions(String src) => |
| 423 new AnalysisOptionsProvider().getOptionsFromString(src); | 448 new AnalysisOptionsProvider().getOptionsFromString(src); |
| 424 | 449 |
| 425 class TestPlugin extends Plugin { | 450 class TestPlugin extends Plugin { |
| 426 TestProcessor processor; | 451 TestProcessor processor; |
| 427 TestPlugin(this.processor); | 452 TestPlugin(this.processor); |
| 428 | 453 |
| 429 @override | 454 @override |
| 430 String get uniqueIdentifier => 'test_plugin.core'; | 455 String get uniqueIdentifier => 'test_plugin.core'; |
| 431 | 456 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 455 this.options = options; | 480 this.options = options; |
| 456 } | 481 } |
| 457 } | 482 } |
| 458 | 483 |
| 459 class TestSource implements Source { | 484 class TestSource implements Source { |
| 460 TestSource(); | 485 TestSource(); |
| 461 | 486 |
| 462 @override | 487 @override |
| 463 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); | 488 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| 464 } | 489 } |
| OLD | NEW |