| // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'dart:io'; |
| |
| import 'package:analyzer/dart/analysis/features.dart'; |
| import 'package:analyzer/file_system/physical_file_system.dart'; |
| import 'package:analyzer/src/dart/analysis/analysis_options.dart'; |
| import 'package:analyzer/src/dart/analysis/experiments.dart'; |
| import 'package:analyzer/src/dart/analysis/experiments_impl.dart' |
| show overrideKnownFeatures; |
| import 'package:analyzer_cli/src/driver.dart'; |
| import 'package:analyzer_cli/src/options.dart'; |
| import 'package:analyzer_testing/resource_provider_mixin.dart'; |
| import 'package:args/args.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| void main() { |
| group('CommandLineOptions', () { |
| group('parse', () { |
| var outStringBuffer = StringBuffer(); |
| var errorStringBuffer = StringBuffer(); |
| |
| late StringSink savedOutSink, savedErrorSink; |
| late int savedExitCode; |
| late ExitHandler savedExitHandler; |
| |
| CommandLineOptions? parse( |
| List<String> args, { |
| void Function(String msg) printAndFail = printAndFail, |
| }) { |
| var resourceProvider = PhysicalResourceProvider.INSTANCE; |
| return CommandLineOptions.parse( |
| resourceProvider, |
| args, |
| printAndFail: printAndFail, |
| ); |
| } |
| |
| setUp(() { |
| savedOutSink = outSink; |
| savedErrorSink = errorSink; |
| savedExitHandler = exitHandler; |
| savedExitCode = exitCode; |
| exitHandler = (int code) {}; |
| outSink = outStringBuffer; |
| errorSink = errorStringBuffer; |
| }); |
| |
| tearDown(() { |
| outSink = savedOutSink; |
| errorSink = savedErrorSink; |
| exitCode = savedExitCode; |
| exitHandler = savedExitHandler; |
| }); |
| |
| test('defaults', () { |
| var options = parse(['--dart-sdk', '.', 'foo.dart'])!; |
| expect(options, isNotNull); |
| expect(options.dartSdkPath, isNotNull); |
| expect(options.disableCacheFlushing, isFalse); |
| expect(options.enabledExperiments, isEmpty); |
| expect(options.displayVersion, isFalse); |
| expect(options.ignoreUnrecognizedFlags, isFalse); |
| expect(options.log, isFalse); |
| expect(options.jsonFormat, isFalse); |
| expect(options.machineFormat, isFalse); |
| expect(options.batchMode, isFalse); |
| expect(options.sourceFiles, equals(['foo.dart'])); |
| expect(options.trainSnapshot, isFalse); |
| }); |
| |
| test('batch', () { |
| var options = parse(['--dart-sdk', '.', '--batch'])!; |
| expect(options.batchMode, isTrue); |
| }); |
| |
| test('defined variables', () { |
| var options = parse(['--dart-sdk', '.', '-Dfoo=bar', 'foo.dart'])!; |
| expect(options.declaredVariables['foo'], equals('bar')); |
| expect(options.declaredVariables['bar'], isNull); |
| }); |
| |
| test('disable cache flushing', () { |
| var options = parse([ |
| '--dart-sdk', |
| '.', |
| '--disable-cache-flushing', |
| 'foo.dart', |
| ])!; |
| expect(options.disableCacheFlushing, isTrue); |
| }); |
| |
| group('enable experiment', () { |
| var knownFeatures = { |
| 'a': ExperimentalFeature( |
| index: 0, |
| enableString: 'a', |
| isEnabledByDefault: false, |
| isExpired: false, |
| documentation: 'a', |
| experimentalReleaseVersion: null, |
| releaseVersion: null, |
| ), |
| 'b': ExperimentalFeature( |
| index: 1, |
| enableString: 'b', |
| isEnabledByDefault: false, |
| isExpired: false, |
| documentation: 'b', |
| experimentalReleaseVersion: null, |
| releaseVersion: null, |
| ), |
| 'c': ExperimentalFeature( |
| index: 2, |
| enableString: 'c', |
| isEnabledByDefault: false, |
| isExpired: false, |
| documentation: 'c', |
| experimentalReleaseVersion: null, |
| releaseVersion: null, |
| ), |
| }; |
| |
| test('no values', () { |
| var options = overrideKnownFeatures( |
| knownFeatures, |
| () => parse(['foo.dart'])!, |
| ); |
| expect(options.enabledExperiments, isEmpty); |
| }); |
| |
| test('single value', () { |
| var options = overrideKnownFeatures( |
| knownFeatures, |
| () => parse(['--enable-experiment', 'a', 'foo.dart'])!, |
| ); |
| expect(options.enabledExperiments, ['a']); |
| }); |
| |
| group('multiple values', () { |
| test('single flag', () { |
| var options = overrideKnownFeatures( |
| knownFeatures, |
| () => parse(['--enable-experiment', 'a,b', 'foo.dart'])!, |
| ); |
| expect(options.enabledExperiments, ['a', 'b']); |
| }); |
| |
| test('mixed single and multiple flags', () { |
| var options = overrideKnownFeatures( |
| knownFeatures, |
| () => parse([ |
| '--enable-experiment', |
| 'a,b', |
| '--enable-experiment', |
| 'c', |
| 'foo.dart', |
| ])!, |
| ); |
| expect(options.enabledExperiments, ['a', 'b', 'c']); |
| }); |
| |
| test('multiple flags', () { |
| var options = overrideKnownFeatures( |
| knownFeatures, |
| () => parse([ |
| '--enable-experiment', |
| 'a', |
| '--enable-experiment', |
| 'b', |
| 'foo.dart', |
| ])!, |
| ); |
| expect(options.enabledExperiments, ['a', 'b']); |
| }); |
| }); |
| }); |
| |
| test('log', () { |
| var options = parse(['--dart-sdk', '.', '--log', 'foo.dart'])!; |
| expect(options.log, isTrue); |
| }); |
| |
| group('format', () { |
| test('json', () { |
| var options = parse([ |
| '--dart-sdk', |
| '.', |
| '--format=json', |
| 'foo.dart', |
| ])!; |
| expect(options.jsonFormat, isTrue); |
| expect(options.machineFormat, isFalse); |
| }); |
| |
| test('machine', () { |
| var options = parse([ |
| '--dart-sdk', |
| '.', |
| '--format=machine', |
| 'foo.dart', |
| ])!; |
| expect(options.jsonFormat, isFalse); |
| expect(options.machineFormat, isTrue); |
| }); |
| }); |
| |
| test('options', () { |
| var options = parse([ |
| '--dart-sdk', |
| '.', |
| '--options', |
| 'options.yaml', |
| 'foo.dart', |
| ])!; |
| expect(options.defaultAnalysisOptionsPath, endsWith('options.yaml')); |
| }); |
| |
| test('sourceFiles', () { |
| var options = parse([ |
| '--dart-sdk', |
| '.', |
| '--log', |
| 'foo.dart', |
| 'foo2.dart', |
| 'foo3.dart', |
| ])!; |
| expect( |
| options.sourceFiles, |
| equals(['foo.dart', 'foo2.dart', 'foo3.dart']), |
| ); |
| }); |
| |
| test('ignore unrecognized flags', () { |
| var options = parse([ |
| '--ignore-unrecognized-flags', |
| '--bar', |
| '--baz', |
| '--dart-sdk', |
| '.', |
| 'foo.dart', |
| ])!; |
| expect(options, isNotNull); |
| expect(options.sourceFiles, equals(['foo.dart'])); |
| }); |
| |
| test('bad SDK dir', () { |
| String? failureMessage; |
| parse([ |
| '--dart-sdk', |
| '&&&&&', |
| 'foo.dart', |
| ], printAndFail: (msg) => failureMessage = msg); |
| expect(failureMessage, equals('Invalid Dart SDK path: &&&&&')); |
| }); |
| |
| test('--train-snapshot', () { |
| var options = parse(['--train-snapshot', 'foo.dart'])!; |
| expect(options.trainSnapshot, isTrue); |
| }); |
| }); |
| }); |
| defineReflectiveTests(ArgumentsTest); |
| } |
| |
| @reflectiveTest |
| class ArgumentsTest with ResourceProviderMixin { |
| CommandLineOptions? commandLineOptions; |
| String? failureMessage; |
| |
| void test_declaredVariables() { |
| _parse(['-Da=0', '-Db=', 'a.dart']); |
| |
| var definedVariables = commandLineOptions!.declaredVariables; |
| |
| expect(definedVariables['a'], '0'); |
| expect(definedVariables['b'], ''); |
| expect(definedVariables['c'], isNull); |
| } |
| |
| void test_defaultAnalysisOptionsFilePath() { |
| var expected = 'my_options.yaml'; |
| _parse(['--options=$expected', 'a.dart']); |
| |
| expect(commandLineOptions!.defaultAnalysisOptionsPath, endsWith(expected)); |
| } |
| |
| void test_defaultPackageFilePath() { |
| var expected = 'my_package_config.json'; |
| _parse(['--packages=$expected', 'a.dart']); |
| |
| expect(commandLineOptions!.defaultPackagesPath, endsWith(expected)); |
| } |
| |
| void test_defaults() { |
| _parse(['a.dart']); |
| expect(commandLineOptions!.declaredVariables, isEmpty); |
| expect(commandLineOptions!.defaultAnalysisOptionsPath, isNull); |
| expect(commandLineOptions!.defaultPackagesPath, isNull); |
| } |
| |
| void test_filterUnknownArguments() { |
| var args = ['--a', '--b', '--c=0', '--d=1', '-Da=b', '-e=2', '-f', 'bar']; |
| var parser = ArgParser(); |
| parser.addFlag('a'); |
| parser.addOption('c'); |
| parser.addOption('ee', abbr: 'e'); |
| parser.addFlag('ff', abbr: 'f'); |
| var result = CommandLineOptions.filterUnknownArguments(args, parser); |
| expect( |
| result, |
| orderedEquals(['--a', '--c=0', '-Da=b', '-e=2', '-f', 'bar']), |
| ); |
| } |
| |
| void test_updateAnalysisOptions_enableExperiment() { |
| var feature_a = ExperimentalFeature( |
| index: 0, |
| enableString: 'a', |
| isEnabledByDefault: false, |
| isExpired: false, |
| documentation: 'a', |
| experimentalReleaseVersion: null, |
| releaseVersion: null, |
| ); |
| |
| var feature_b = ExperimentalFeature( |
| index: 1, |
| enableString: 'a', |
| isEnabledByDefault: false, |
| isExpired: false, |
| documentation: 'a', |
| experimentalReleaseVersion: null, |
| releaseVersion: null, |
| ); |
| |
| ExperimentStatus featuresWithExperiments(List<String> experiments) { |
| return FeatureSet.fromEnableFlags2( |
| sdkLanguageVersion: ExperimentStatus.currentVersion, |
| flags: experiments, |
| ) |
| as ExperimentStatus; |
| } |
| |
| overrideKnownFeatures({'a': feature_a, 'b': feature_b}, () { |
| // Replace. |
| _applyAnalysisOptions( |
| ['--enable-experiment=b', 'a.dart'], |
| (optionsBuilder) => |
| optionsBuilder.contextFeatures = featuresWithExperiments(['a']), |
| (analysisOptions) { |
| var featureSet = analysisOptions.contextFeatures; |
| expect(featureSet.isEnabled(feature_a), isFalse); |
| expect(featureSet.isEnabled(feature_b), isTrue); |
| }, |
| ); |
| |
| // Don't change if not provided. |
| _applyAnalysisOptions( |
| ['a.dart'], |
| (optionsBuilder) => |
| optionsBuilder.contextFeatures = featuresWithExperiments(['a']), |
| (analysisOptions) { |
| var featureSet = analysisOptions.contextFeatures; |
| expect(featureSet.isEnabled(feature_a), isTrue); |
| expect(featureSet.isEnabled(feature_b), isFalse); |
| }, |
| ); |
| }); |
| } |
| |
| void _applyAnalysisOptions( |
| List<String> args, |
| void Function(AnalysisOptionsBuilder) configureInitial, |
| void Function(AnalysisOptionsImpl) checkApplied, |
| ) { |
| _parse(args); |
| expect(commandLineOptions, isNotNull); |
| |
| var optionsBuilder = AnalysisOptionsBuilder(); |
| configureInitial(optionsBuilder); |
| |
| var analysisOptions = optionsBuilder.build(); |
| |
| commandLineOptions!.updateAnalysisOptions(analysisOptions); |
| checkApplied(analysisOptions); |
| } |
| |
| void _parse(List<String> args, {bool ignoreUnrecognized = true}) { |
| var resourceProvider = PhysicalResourceProvider.INSTANCE; |
| commandLineOptions = CommandLineOptions.parse( |
| resourceProvider, |
| [if (ignoreUnrecognized) '--ignore-unrecognized-flags', ...args], |
| printAndFail: (msg) { |
| failureMessage = msg; |
| }, |
| ); |
| } |
| } |