| // Copyright (c) 2025, 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:cli_config/cli_config.dart'; |
| import 'package:path/path.dart' as path; |
| |
| class CoverageOptions { |
| const CoverageOptions({ |
| this.outputDirectory, |
| required this.scopeOutput, |
| required this.functionCoverage, |
| required this.branchCoverage, |
| required this.packageDirectory, |
| required this.testScript, |
| }); |
| |
| factory CoverageOptions.fromConfig( |
| Config options, |
| CoverageOptions defaultOptions, |
| String? optionsFilePath, |
| ) { |
| var outputDirectory = |
| options.optionalString('output_directory') ?? |
| defaultOptions.outputDirectory; |
| var packageDirectory = |
| options.optionalString('package_directory') ?? |
| defaultOptions.packageDirectory; |
| |
| if (optionsFilePath != null) { |
| if (outputDirectory != null && !path.isAbsolute(outputDirectory)) { |
| outputDirectory = path.normalize( |
| path.absolute(path.dirname(optionsFilePath), outputDirectory), |
| ); |
| } |
| if (!path.isAbsolute(packageDirectory)) { |
| packageDirectory = path.normalize( |
| path.absolute(path.dirname(optionsFilePath), packageDirectory), |
| ); |
| } |
| } |
| |
| return CoverageOptions( |
| outputDirectory: outputDirectory, |
| scopeOutput: |
| options.optionalStringList('scope_output') ?? |
| defaultOptions.scopeOutput, |
| functionCoverage: |
| options.optionalBool('function_coverage') ?? |
| defaultOptions.functionCoverage, |
| branchCoverage: |
| options.optionalBool('branch_coverage') ?? |
| defaultOptions.branchCoverage, |
| packageDirectory: packageDirectory, |
| testScript: |
| options.optionalString('test_script') ?? defaultOptions.testScript, |
| ); |
| } |
| |
| final String? outputDirectory; |
| final List<String> scopeOutput; |
| final bool functionCoverage; |
| final bool branchCoverage; |
| final String packageDirectory; |
| final String testScript; |
| } |
| |
| class CoverageOptionsProvider { |
| CoverageOptionsProvider({String? filePath}) { |
| final file = _getOptionsFile(filePath); |
| final fileContents = file?.readAsStringSync(); |
| |
| // Pass null to fileContents if the file is empty |
| final options = Config.fromConfigFileContents( |
| fileContents: fileContents, |
| fileSourceUri: file?.uri, |
| ); |
| |
| coverageOptions = CoverageOptions.fromConfig( |
| options, |
| defaultOptions, |
| optionsFilePath, |
| ); |
| } |
| |
| late final CoverageOptions coverageOptions; |
| late final String? optionsFilePath; |
| static const defaultFilePath = 'coverage_options.yaml'; |
| |
| File? _getOptionsFile(String? filePath) { |
| filePath ??= findOptionsFilePath(); |
| |
| optionsFilePath = filePath != null |
| ? path.normalize(path.absolute(filePath)) |
| : null; |
| |
| if (optionsFilePath == null) { |
| return null; |
| } |
| |
| final file = File(optionsFilePath!); |
| return file.existsSync() ? file : null; |
| } |
| |
| static String? findOptionsFilePath({Directory? directory}) { |
| var currentDir = directory ?? Directory.current; |
| |
| while (true) { |
| final pubSpecFilePath = path.join(currentDir.path, 'pubspec.yaml'); |
| if (File(pubSpecFilePath).existsSync()) { |
| final optionsFilePath = path.join(currentDir.path, defaultFilePath); |
| |
| if (File(optionsFilePath).existsSync()) { |
| return optionsFilePath; |
| } else { |
| return null; |
| } |
| } |
| final parentDir = currentDir.parent; |
| if (parentDir.path == currentDir.path) { |
| return null; |
| } |
| currentDir = parentDir; |
| } |
| } |
| |
| static const defaultOptions = CoverageOptions( |
| outputDirectory: null, |
| scopeOutput: [], |
| functionCoverage: false, |
| branchCoverage: false, |
| packageDirectory: '.', |
| testScript: 'test', |
| ); |
| } |