diff --git a/CHANGELOG.md b/CHANGELOG.md index fda7bd710d..54ed780380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +* fix: add `monorepo` flag for `check-unused-code` command. * fix: ignore a class usage inside `State` for `check-unused-code` command. * fix: correctly handle variables declaration for `check-unused-code` command. * feat: add static code diagnostics `avoid-dynamic`, `prefer-async-await`. diff --git a/lib/src/analyzers/unused_code_analyzer/unused_code_analyzer.dart b/lib/src/analyzers/unused_code_analyzer/unused_code_analyzer.dart index dcf4254edf..a8db66f276 100644 --- a/lib/src/analyzers/unused_code_analyzer/unused_code_analyzer.dart +++ b/lib/src/analyzers/unused_code_analyzer/unused_code_analyzer.dart @@ -6,7 +6,6 @@ import 'package:analyzer/dart/analysis/utilities.dart'; import 'package:analyzer/dart/element/element.dart'; // ignore: implementation_imports import 'package:analyzer/src/dart/element/element.dart'; -import 'package:glob/glob.dart'; import 'package:path/path.dart'; import 'package:source_span/source_span.dart'; @@ -14,7 +13,6 @@ import '../../config_builder/config_builder.dart'; import '../../config_builder/models/analysis_options.dart'; import '../../reporters/models/reporter.dart'; import '../../utils/analyzer_utils.dart'; -import '../../utils/file_utils.dart'; import 'models/file_elements_usage.dart'; import 'models/unused_code_file_report.dart'; import 'models/unused_code_issue.dart'; @@ -61,7 +59,7 @@ class UnusedCodeAnalyzer { final excludes = unusedCodeAnalysisConfig.globalExcludes .followedBy(unusedCodeAnalysisConfig.analyzerExcludedPatterns); - final filePaths = _getFilePaths(folders, context, rootFolder, excludes); + final filePaths = getFilePaths(folders, context, rootFolder, excludes); final analyzedFiles = filePaths.intersection(context.contextRoot.analyzedFiles().toSet()); @@ -111,22 +109,6 @@ class UnusedCodeAnalyzer { return ConfigBuilder.getUnusedCodeConfig(contextConfig, rootFolder); } - Set _getFilePaths( - Iterable folders, - AnalysisContext context, - String rootFolder, - Iterable excludes, - ) { - final contextFolders = folders.where((path) { - final newPath = normalize(join(rootFolder, path)); - - return newPath == context.contextRoot.root.path || - context.contextRoot.root.path.startsWith('$newPath/'); - }).toList(); - - return extractDartFilesFromFolders(contextFolders, rootFolder, excludes); - } - FileElementsUsage? _analyzeFileCodeUsages(SomeResolvedUnitResult unit) { if (unit is ResolvedUnitResult) { final visitor = UsedCodeVisitor(); diff --git a/lib/src/analyzers/unused_files_analyzer/unused_files_analyzer.dart b/lib/src/analyzers/unused_files_analyzer/unused_files_analyzer.dart index a1472da8cd..5b666bb118 100644 --- a/lib/src/analyzers/unused_files_analyzer/unused_files_analyzer.dart +++ b/lib/src/analyzers/unused_files_analyzer/unused_files_analyzer.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:analyzer/dart/analysis/analysis_context.dart'; import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/analysis/utilities.dart'; import 'package:path/path.dart'; @@ -8,10 +9,10 @@ import '../../config_builder/config_builder.dart'; import '../../config_builder/models/analysis_options.dart'; import '../../reporters/models/reporter.dart'; import '../../utils/analyzer_utils.dart'; -import '../../utils/file_utils.dart'; import 'models/unused_files_file_report.dart'; import 'reporters/reporter_factory.dart'; import 'reporters/unused_files_report_params.dart'; +import 'unused_files_analysis_config.dart'; import 'unused_files_config.dart'; import 'unused_files_visitor.dart'; @@ -45,22 +46,12 @@ class UnusedFilesAnalyzer { final unusedFiles = {}; for (final context in collection.contexts) { - final analysisOptions = await analysisOptionsFromContext(context) ?? - await analysisOptionsFromFilePath(rootFolder); - - final contextConfig = - ConfigBuilder.getUnusedFilesConfigFromOption(analysisOptions) - .merge(config); final unusedFilesAnalysisConfig = - ConfigBuilder.getUnusedFilesConfig(contextConfig, rootFolder); - - final contextFolders = folders - .where((path) => normalize(join(rootFolder, path)) - .startsWith(context.contextRoot.root.path)) - .toList(); + await _getAnalysisConfig(context, rootFolder, config); - final filePaths = extractDartFilesFromFolders( - contextFolders, + final filePaths = getFilePaths( + folders, + context, rootFolder, unusedFilesAnalysisConfig.globalExcludes, ); @@ -69,19 +60,18 @@ class UnusedFilesAnalyzer { final analyzedFiles = filePaths.intersection(context.contextRoot.analyzedFiles().toSet()); - for (final filePath in analyzedFiles) { final unit = await context.currentSession.getResolvedUnit(filePath); - unusedFiles.removeAll(_analyzeFile(filePath, unit)); + unusedFiles.removeAll(_analyzeFile(filePath, unit, config.isMonorepo)); } final notAnalyzedFiles = filePaths.difference(analyzedFiles); - for (final filePath in notAnalyzedFiles) { if (unusedFilesAnalysisConfig.analyzerExcludedPatterns .any((pattern) => pattern.matches(filePath))) { final unit = await resolveFile2(path: filePath); - unusedFiles.removeAll(_analyzeFile(filePath, unit)); + unusedFiles + .removeAll(_analyzeFile(filePath, unit, config.isMonorepo)); } } } @@ -102,9 +92,29 @@ class UnusedFilesAnalyzer { } } - Iterable _analyzeFile(String filePath, SomeResolvedUnitResult unit) { + Future _getAnalysisConfig( + AnalysisContext context, + String rootFolder, + UnusedFilesConfig config, + ) async { + final analysisOptions = await analysisOptionsFromContext(context) ?? + await analysisOptionsFromFilePath(rootFolder); + + final contextConfig = + ConfigBuilder.getUnusedFilesConfigFromOption(analysisOptions) + .merge(config); + + return ConfigBuilder.getUnusedFilesConfig(contextConfig, rootFolder); + } + + Iterable _analyzeFile( + String filePath, + SomeResolvedUnitResult unit, + bool ignoreExports, + ) { if (unit is ResolvedUnitResult) { - final visitor = UnusedFilesVisitor(filePath); + final visitor = + UnusedFilesVisitor(filePath, ignoreExports: ignoreExports); unit.unit.visitChildren(visitor); return visitor.paths; diff --git a/lib/src/analyzers/unused_files_analyzer/unused_files_config.dart b/lib/src/analyzers/unused_files_analyzer/unused_files_config.dart index cd993afa1f..a160cc9cb9 100644 --- a/lib/src/analyzers/unused_files_analyzer/unused_files_config.dart +++ b/lib/src/analyzers/unused_files_analyzer/unused_files_config.dart @@ -4,10 +4,12 @@ import '../../config_builder/models/analysis_options.dart'; class UnusedFilesConfig { final Iterable excludePatterns; final Iterable analyzerExcludePatterns; + final bool isMonorepo; const UnusedFilesConfig({ required this.excludePatterns, required this.analyzerExcludePatterns, + required this.isMonorepo, }); /// Creates the config from analysis [options]. @@ -16,13 +18,18 @@ class UnusedFilesConfig { excludePatterns: const [], analyzerExcludePatterns: options.readIterableOfString(['analyzer', 'exclude']), + isMonorepo: false, ); /// Creates the config from cli args. - factory UnusedFilesConfig.fromArgs(Iterable excludePatterns) => + factory UnusedFilesConfig.fromArgs( + Iterable excludePatterns, { + required bool isMonorepo, + }) => UnusedFilesConfig( excludePatterns: excludePatterns, analyzerExcludePatterns: const [], + isMonorepo: isMonorepo, ); /// Merges two configs into a single one. @@ -35,5 +42,6 @@ class UnusedFilesConfig { ...analyzerExcludePatterns, ...overrides.analyzerExcludePatterns, }, + isMonorepo: isMonorepo || overrides.isMonorepo, ); } diff --git a/lib/src/analyzers/unused_files_analyzer/unused_files_visitor.dart b/lib/src/analyzers/unused_files_analyzer/unused_files_visitor.dart index 0284ca7408..4ab6549194 100644 --- a/lib/src/analyzers/unused_files_analyzer/unused_files_visitor.dart +++ b/lib/src/analyzers/unused_files_analyzer/unused_files_visitor.dart @@ -6,13 +6,14 @@ import 'package:analyzer/dart/ast/visitor.dart'; import '../../utils/node_utils.dart'; class UnusedFilesVisitor extends GeneralizingAstVisitor { - final String _currentFilePath; + final String currentFilePath; + final bool ignoreExports; final _paths = []; Iterable get paths => _paths; - UnusedFilesVisitor(this._currentFilePath); + UnusedFilesVisitor(this.currentFilePath, {required this.ignoreExports}); @override void visitUriBasedDirective(UriBasedDirective node) { @@ -32,15 +33,17 @@ class UnusedFilesVisitor extends GeneralizingAstVisitor { } } - if (node is ExportDirective && !_paths.contains(_currentFilePath)) { - _paths.add(_currentFilePath); + if (!ignoreExports && + node is ExportDirective && + !_paths.contains(currentFilePath)) { + _paths.add(currentFilePath); } } @override void visitFunctionDeclaration(FunctionDeclaration node) { if (isEntrypoint(node.name.name, node.metadata)) { - _paths.add(_currentFilePath); + _paths.add(currentFilePath); } } } diff --git a/lib/src/cli/commands/check_unused_code_command.dart b/lib/src/cli/commands/check_unused_code_command.dart index 2c275a11ef..cceb684f15 100644 --- a/lib/src/cli/commands/check_unused_code_command.dart +++ b/lib/src/cli/commands/check_unused_code_command.dart @@ -100,7 +100,7 @@ class CheckUnusedCodeCommand extends BaseCommand { ..addSeparator('') ..addFlag( FlagNames.fatalOnUnused, - help: 'Treat find unused file as fatal.', + help: 'Treat find unused code as fatal.', // TODO(dkrutrkikh): activate on next major version // defaultsTo: true, ); diff --git a/lib/src/cli/commands/check_unused_files_command.dart b/lib/src/cli/commands/check_unused_files_command.dart index 1283239ca1..7171ef4dbb 100644 --- a/lib/src/cli/commands/check_unused_files_command.dart +++ b/lib/src/cli/commands/check_unused_files_command.dart @@ -31,11 +31,14 @@ class CheckUnusedFilesCommand extends BaseCommand { final folders = argResults.rest; final excludePath = argResults[FlagNames.exclude] as String; final reporterName = argResults[FlagNames.reporter] as String; - + final isMonorepo = argResults[FlagNames.isMonorepo] as bool; final noCongratulate = argResults[FlagNames.noCongratulate] as bool; final deleteFiles = argResults[FlagNames.deleteFiles] as bool; - final config = ConfigBuilder.getUnusedFilesConfigFromArgs([excludePath]); + final config = ConfigBuilder.getUnusedFilesConfigFromArgs( + [excludePath], + isMonorepo: isMonorepo, + ); final unusedFilesResult = await _analyzer.runCliAnalysis( folders, @@ -70,6 +73,7 @@ class CheckUnusedFilesCommand extends BaseCommand { void _addFlags() { _usesReporterOption(); addCommonFlags(); + _usesIsMonorepoOption(); _usesExitOption(); _usesDeleteUnusedFiles(); } @@ -90,6 +94,15 @@ class CheckUnusedFilesCommand extends BaseCommand { ); } + void _usesIsMonorepoOption() { + argParser + ..addSeparator('') + ..addFlag( + FlagNames.isMonorepo, + help: 'Treats all exported files as unused by default.', + ); + } + void _usesExitOption() { argParser ..addSeparator('') diff --git a/lib/src/config_builder/config_builder.dart b/lib/src/config_builder/config_builder.dart index 1f4899e067..4ad0638642 100644 --- a/lib/src/config_builder/config_builder.dart +++ b/lib/src/config_builder/config_builder.dart @@ -70,9 +70,10 @@ class ConfigBuilder { /// Creates a raw unused files config from given [excludePatterns]. static UnusedFilesConfig getUnusedFilesConfigFromArgs( - Iterable excludePatterns, - ) => - UnusedFilesConfig.fromArgs(excludePatterns); + Iterable excludePatterns, { + required bool isMonorepo, + }) => + UnusedFilesConfig.fromArgs(excludePatterns, isMonorepo: isMonorepo); /// Creates a raw unused files config from given [options]. static UnusedFilesConfig getUnusedFilesConfigFromOption( diff --git a/lib/src/utils/analyzer_utils.dart b/lib/src/utils/analyzer_utils.dart index 470ed37016..1716f9b453 100644 --- a/lib/src/utils/analyzer_utils.dart +++ b/lib/src/utils/analyzer_utils.dart @@ -1,11 +1,15 @@ // ignore_for_file: implementation_imports +import 'package:analyzer/dart/analysis/analysis_context.dart'; import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; import 'package:analyzer/file_system/physical_file_system.dart'; import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart'; import 'package:analyzer/src/dart/analysis/byte_store.dart'; import 'package:analyzer/src/dart/analysis/file_byte_store.dart'; +import 'package:glob/glob.dart'; import 'package:path/path.dart'; +import 'file_utils.dart'; + AnalysisContextCollection createAnalysisContextCollection( Iterable folders, String rootFolder, @@ -22,6 +26,22 @@ AnalysisContextCollection createAnalysisContextCollection( ); } +Set getFilePaths( + Iterable folders, + AnalysisContext context, + String rootFolder, + Iterable excludes, +) { + final contextFolders = folders.where((path) { + final newPath = normalize(join(rootFolder, path)); + + return newPath == context.contextRoot.root.path || + context.contextRoot.root.path.startsWith('$newPath/'); + }).toList(); + + return extractDartFilesFromFolders(contextFolders, rootFolder, excludes); +} + /// If the state location can be accessed, return the file byte store, /// otherwise return the memory byte store. ByteStore _createByteStore(PhysicalResourceProvider resourceProvider) { diff --git a/test/src/analyzers/lint_analyzer/lint_config_test.dart b/test/src/analyzers/lint_analyzer/lint_config_test.dart index b70fa66902..3923153464 100644 --- a/test/src/analyzers/lint_analyzer/lint_config_test.dart +++ b/test/src/analyzers/lint_analyzer/lint_config_test.dart @@ -193,6 +193,7 @@ void main() { ); expect(result.rules, equals(_defaults.rules)); }); + test('empty and overrides configs', () { final result = _empty.merge(_overrides); @@ -208,6 +209,7 @@ void main() { ); expect(result.rules, equals(_overrides.rules)); }); + test('defaults and overrides configs', () { final result = _defaults.merge(_overrides); diff --git a/test/src/analyzers/unused_code_analyzer/unused_code_config_test.dart b/test/src/analyzers/unused_code_analyzer/unused_code_config_test.dart new file mode 100644 index 0000000000..ebdb0afef7 --- /dev/null +++ b/test/src/analyzers/unused_code_analyzer/unused_code_config_test.dart @@ -0,0 +1,102 @@ +import 'package:dart_code_metrics/src/analyzers/unused_code_analyzer/unused_code_config.dart'; +import 'package:dart_code_metrics/src/config_builder/models/analysis_options.dart'; +import 'package:test/test.dart'; + +const _options = AnalysisOptions('path', { + 'analyzer': { + 'exclude': ['test/resources/**'], + 'plugins': ['dart_code_metrics'], + 'strong-mode': {'implicit-casts': false, 'implicit-dynamic': false}, + }, +}); + +const _defaults = UnusedCodeConfig( + excludePatterns: ['test/resources/**'], + analyzerExcludePatterns: ['test/**'], + isMonorepo: false, +); + +const _empty = UnusedCodeConfig( + excludePatterns: [], + analyzerExcludePatterns: [], + isMonorepo: false, +); + +const _merged = UnusedCodeConfig( + excludePatterns: ['test/resources/**'], + analyzerExcludePatterns: ['test/**', 'examples/**'], + isMonorepo: true, +); + +const _overrides = UnusedCodeConfig( + excludePatterns: [], + analyzerExcludePatterns: ['examples/**'], + isMonorepo: true, +); + +void main() { + group('UnusedCodeConfig', () { + group('fromAnalysisOptions constructs instance from passed', () { + test('empty options', () { + final config = UnusedCodeConfig.fromAnalysisOptions( + const AnalysisOptions(null, {}), + ); + + expect(config.excludePatterns, isEmpty); + expect(config.analyzerExcludePatterns, isEmpty); + expect(config.isMonorepo, false); + }); + + test('data', () { + final config = UnusedCodeConfig.fromAnalysisOptions(_options); + + expect(config.analyzerExcludePatterns, equals(['test/resources/**'])); + }); + }); + + group('fromArgs constructs instance from passed', () { + test('data', () { + final config = UnusedCodeConfig.fromArgs(['hello'], isMonorepo: true); + + expect(config.excludePatterns, equals(['hello'])); + expect(config.analyzerExcludePatterns, isEmpty); + expect(config.isMonorepo, true); + }); + }); + + group('merge constructs instance with data from', () { + test('defaults and empty configs', () { + final result = _defaults.merge(_empty); + + expect(result.excludePatterns, equals(_defaults.excludePatterns)); + expect( + result.analyzerExcludePatterns, + equals(_defaults.analyzerExcludePatterns), + ); + expect(result.isMonorepo, equals(_defaults.isMonorepo)); + }); + + test('empty and overrides configs', () { + final result = _empty.merge(_overrides); + + expect(result.excludePatterns, equals(_overrides.excludePatterns)); + expect( + result.analyzerExcludePatterns, + equals(_overrides.analyzerExcludePatterns), + ); + expect(result.isMonorepo, equals(_overrides.isMonorepo)); + }); + + test('defaults and overrides configs', () { + final result = _defaults.merge(_overrides); + + expect(result.excludePatterns, equals(_merged.excludePatterns)); + expect( + result.analyzerExcludePatterns, + equals(_merged.analyzerExcludePatterns), + ); + expect(result.isMonorepo, equals(_merged.isMonorepo)); + }); + }); + }); +} diff --git a/test/src/analyzers/unused_files_analyzer/unused_files_analyzer_test.dart b/test/src/analyzers/unused_files_analyzer/unused_files_analyzer_test.dart index c723b243aa..95f69bf714 100644 --- a/test/src/analyzers/unused_files_analyzer/unused_files_analyzer_test.dart +++ b/test/src/analyzers/unused_files_analyzer/unused_files_analyzer_test.dart @@ -51,4 +51,5 @@ UnusedFilesConfig _createConfig({ UnusedFilesConfig( excludePatterns: const [], analyzerExcludePatterns: analyzerExcludePatterns, + isMonorepo: false, ); diff --git a/test/src/analyzers/unused_files_analyzer/unused_files_config_test.dart b/test/src/analyzers/unused_files_analyzer/unused_files_config_test.dart new file mode 100644 index 0000000000..0bab3e1177 --- /dev/null +++ b/test/src/analyzers/unused_files_analyzer/unused_files_config_test.dart @@ -0,0 +1,102 @@ +import 'package:dart_code_metrics/src/analyzers/unused_files_analyzer/unused_files_config.dart'; +import 'package:dart_code_metrics/src/config_builder/models/analysis_options.dart'; +import 'package:test/test.dart'; + +const _options = AnalysisOptions('path', { + 'analyzer': { + 'exclude': ['test/resources/**'], + 'plugins': ['dart_code_metrics'], + 'strong-mode': {'implicit-casts': false, 'implicit-dynamic': false}, + }, +}); + +const _defaults = UnusedFilesConfig( + excludePatterns: ['test/resources/**'], + analyzerExcludePatterns: ['test/**'], + isMonorepo: false, +); + +const _empty = UnusedFilesConfig( + excludePatterns: [], + analyzerExcludePatterns: [], + isMonorepo: false, +); + +const _merged = UnusedFilesConfig( + excludePatterns: ['test/resources/**'], + analyzerExcludePatterns: ['test/**', 'examples/**'], + isMonorepo: true, +); + +const _overrides = UnusedFilesConfig( + excludePatterns: [], + analyzerExcludePatterns: ['examples/**'], + isMonorepo: true, +); + +void main() { + group('UnusedCodeConfig', () { + group('fromAnalysisOptions constructs instance from passed', () { + test('empty options', () { + final config = UnusedFilesConfig.fromAnalysisOptions( + const AnalysisOptions(null, {}), + ); + + expect(config.excludePatterns, isEmpty); + expect(config.analyzerExcludePatterns, isEmpty); + expect(config.isMonorepo, false); + }); + + test('data', () { + final config = UnusedFilesConfig.fromAnalysisOptions(_options); + + expect(config.analyzerExcludePatterns, equals(['test/resources/**'])); + }); + }); + + group('fromArgs constructs instance from passed', () { + test('data', () { + final config = UnusedFilesConfig.fromArgs(['hello'], isMonorepo: true); + + expect(config.excludePatterns, equals(['hello'])); + expect(config.analyzerExcludePatterns, isEmpty); + expect(config.isMonorepo, true); + }); + }); + + group('merge constructs instance with data from', () { + test('defaults and empty configs', () { + final result = _defaults.merge(_empty); + + expect(result.excludePatterns, equals(_defaults.excludePatterns)); + expect( + result.analyzerExcludePatterns, + equals(_defaults.analyzerExcludePatterns), + ); + expect(result.isMonorepo, equals(_defaults.isMonorepo)); + }); + + test('empty and overrides configs', () { + final result = _empty.merge(_overrides); + + expect(result.excludePatterns, equals(_overrides.excludePatterns)); + expect( + result.analyzerExcludePatterns, + equals(_overrides.analyzerExcludePatterns), + ); + expect(result.isMonorepo, equals(_overrides.isMonorepo)); + }); + + test('defaults and overrides configs', () { + final result = _defaults.merge(_overrides); + + expect(result.excludePatterns, equals(_merged.excludePatterns)); + expect( + result.analyzerExcludePatterns, + equals(_merged.analyzerExcludePatterns), + ); + expect(result.isMonorepo, equals(_merged.isMonorepo)); + }); + }); + }); +} diff --git a/test/src/analyzers/unused_l10n_analyzer/unused_l10n_config_test.dart b/test/src/analyzers/unused_l10n_analyzer/unused_l10n_config_test.dart new file mode 100644 index 0000000000..3b8ec6a43e --- /dev/null +++ b/test/src/analyzers/unused_l10n_analyzer/unused_l10n_config_test.dart @@ -0,0 +1,102 @@ +import 'package:dart_code_metrics/src/analyzers/unused_l10n_analyzer/unused_l10n_config.dart'; +import 'package:dart_code_metrics/src/config_builder/models/analysis_options.dart'; +import 'package:test/test.dart'; + +const _options = AnalysisOptions('path', { + 'analyzer': { + 'exclude': ['test/resources/**'], + 'plugins': ['dart_code_metrics'], + 'strong-mode': {'implicit-casts': false, 'implicit-dynamic': false}, + }, +}); + +const _defaults = UnusedL10nConfig( + excludePatterns: ['test/resources/**'], + analyzerExcludePatterns: ['test/**'], + classPattern: 'pattern1', +); + +const _empty = UnusedL10nConfig( + excludePatterns: [], + analyzerExcludePatterns: [], + classPattern: null, +); + +const _merged = UnusedL10nConfig( + excludePatterns: ['test/resources/**'], + analyzerExcludePatterns: ['test/**', 'examples/**'], + classPattern: 'pattern2', +); + +const _overrides = UnusedL10nConfig( + excludePatterns: [], + analyzerExcludePatterns: ['examples/**'], + classPattern: 'pattern2', +); + +void main() { + group('UnusedCodeConfig', () { + group('fromAnalysisOptions constructs instance from passed', () { + test('empty options', () { + final config = UnusedL10nConfig.fromAnalysisOptions( + const AnalysisOptions(null, {}), + ); + + expect(config.excludePatterns, isEmpty); + expect(config.analyzerExcludePatterns, isEmpty); + expect(config.classPattern, isNull); + }); + + test('data', () { + final config = UnusedL10nConfig.fromAnalysisOptions(_options); + + expect(config.analyzerExcludePatterns, equals(['test/resources/**'])); + }); + }); + + group('fromArgs constructs instance from passed', () { + test('data', () { + final config = UnusedL10nConfig.fromArgs(['hello'], 'pattern1'); + + expect(config.excludePatterns, equals(['hello'])); + expect(config.analyzerExcludePatterns, isEmpty); + expect(config.classPattern, equals('pattern1')); + }); + }); + + group('merge constructs instance with data from', () { + test('defaults and empty configs', () { + final result = _defaults.merge(_empty); + + expect(result.excludePatterns, equals(_defaults.excludePatterns)); + expect( + result.analyzerExcludePatterns, + equals(_defaults.analyzerExcludePatterns), + ); + expect(result.classPattern, equals(_defaults.classPattern)); + }); + + test('empty and overrides configs', () { + final result = _empty.merge(_overrides); + + expect(result.excludePatterns, equals(_overrides.excludePatterns)); + expect( + result.analyzerExcludePatterns, + equals(_overrides.analyzerExcludePatterns), + ); + expect(result.classPattern, equals(_overrides.classPattern)); + }); + + test('defaults and overrides configs', () { + final result = _defaults.merge(_overrides); + + expect(result.excludePatterns, equals(_merged.excludePatterns)); + expect( + result.analyzerExcludePatterns, + equals(_merged.analyzerExcludePatterns), + ); + expect(result.classPattern, equals(_merged.classPattern)); + }); + }); + }); +} diff --git a/test/src/cli/commands/check_unused_code_command_test.dart b/test/src/cli/commands/check_unused_code_command_test.dart index 7c0625203b..f1f73c6310 100644 --- a/test/src/cli/commands/check_unused_code_command_test.dart +++ b/test/src/cli/commands/check_unused_code_command_test.dart @@ -25,7 +25,7 @@ const _usage = 'Check unused code in *.dart files.\n' ' --[no-]monorepo Treats all exported code as unused by default.\n' '\n' '\n' - ' --[no-]fatal-unused Treat find unused file as fatal.\n' + ' --[no-]fatal-unused Treat find unused code as fatal.\n' '\n' 'Run "metrics help" to see global options.'; diff --git a/test/src/cli/commands/check_unused_files_command_test.dart b/test/src/cli/commands/check_unused_files_command_test.dart index 9ef16592a9..bd1f2becb7 100644 --- a/test/src/cli/commands/check_unused_files_command_test.dart +++ b/test/src/cli/commands/check_unused_files_command_test.dart @@ -22,6 +22,9 @@ const _usage = 'Check unused *.dart files.\n' " --no-congratulate Don't show output even when there are no issues.\n" '\n' '\n' + ' --[no-]monorepo Treats all exported files as unused by default.\n' + '\n' + '\n' ' --[no-]fatal-unused Treat find unused file as fatal.\n' '\n' '\n'