Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ doc/api/
# Files generated during tests
.test_coverage.dart
coverage/
# The coverage library and its tests are sources, not reports.
!lib/src/coverage/
!test/src/coverage/
.test_optimizer.dart
!bricks/test_optimizer/__brick__/test/.test_optimizer.dart
*.vm.json
Expand Down
5 changes: 3 additions & 2 deletions lib/src/cli/cli.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,24 @@ import 'dart:async';
import 'dart:math';

import 'package:collection/collection.dart';
import 'package:coverage/coverage.dart' as coverage;
import 'package:glob/glob.dart';
import 'package:lcov_parser/lcov_parser.dart';
import 'package:mason/mason.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as p;
import 'package:pubspec_parse/pubspec_parse.dart';
import 'package:universal_io/io.dart';
import 'package:very_good_cli/src/coverage/coverage.dart';
import 'package:very_good_cli/src/test_optimizer/test_optimizer.dart';
import 'package:very_good_test_runner/very_good_test_runner.dart';

export 'package:very_good_cli/src/coverage/coverage.dart';
export 'package:very_good_cli/src/test_optimizer/test_optimizer.dart';

part 'dart_cli.dart';
part 'flutter_cli.dart';
part 'git_cli.dart';
part 'test_cli_runner.dart';
part 'test_event_reporter.dart';

const R Function<R>(
R Function(), {
Expand Down
128 changes: 0 additions & 128 deletions lib/src/cli/flutter_cli.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,84 +56,6 @@ class _ProcessSignalOverridesScope extends ProcessSignalOverrides {
/// Thrown when `flutter pub get` is executed without a `pubspec.yaml`.
class PubspecNotFound implements Exception;

/// {@template coverage_metrics}
/// Aggregated coverage metrics computed from a list of LCOV records.
/// {@endtemplate}
class CoverageMetrics {
/// {@macro coverage_metrics}
@visibleForTesting
const new({
this.totalHits = 0,
this.totalFound = 0,
this.uncoveredLines = const {},
});

/// Generate coverage metrics from a list of lcov records.
factory fromLcovRecords(List<Record> records, {String? excludeFromCoverage}) {
final globs = <Glob>[];

if (excludeFromCoverage != null && excludeFromCoverage.isNotEmpty) {
for (final glob in excludeFromCoverage.trim().split(' ')) {
if (glob.isNotEmpty) globs.add(Glob(glob));
}
}

return records.fold<CoverageMetrics>(const CoverageMetrics(), (
current,
record,
) {
final found = record.lines?.found ?? 0;
final hit = record.lines?.hit ?? 0;
if (globs.isNotEmpty && record.file != null) {
for (final glob in globs) {
if (glob.matches(record.file!)) return current;
}
}

final file = record.file;
final details = record.lines?.details;
final uncoveredLines = Map<String, List<int>>.from(
current.uncoveredLines,
);

if (file != null && details != null) {
for (final line in details) {
if ((line.hit ?? 1) == 0 && line.line != null) {
uncoveredLines.update(
file,
(lines) => [...lines, line.line!],
ifAbsent: () => [line.line!],
);
}
}
}

return CoverageMetrics(
totalFound: current.totalFound + found,
totalHits: current.totalHits + hit,
uncoveredLines: uncoveredLines,
);
});
}

/// Total number of lines hit (covered) across all included files.
final int totalHits;

/// Total number of instrumented lines found across all included files.
final int totalFound;

/// Lines not covered.
/// Keyed by file path, values are sorted line numbers.
final Map<String, List<int>> uncoveredLines;

/// Coverage percentage: [totalHits] / [totalFound] * 100.
///
/// Returns `0` when [totalFound] is less than 1.
double get percentage {
return totalFound < 1 ? 0 : (totalHits / totalFound * 100);
}
}

/// Flutter CLI
class Flutter {
/// Determine whether flutter is installed.
Expand Down Expand Up @@ -307,53 +229,3 @@ Future<List<T>> _runCommand<T>({
}
return results;
}

// The extension is intended to be unnamed, but it's not possible due to
// an issue with Dart SDK 2.18.0.
//
// Once the min Dart SDK is bumped, this extension can be unnamed again.
extension _TestEvent on TestEvent {
bool shouldCancelTimer() {
final event = this;
if (event is MessageTestEvent) return true;
if (event is ErrorTestEvent) return true;
if (event is DoneTestEvent) return true;
if (event is TestDoneEvent) return !event.hidden;
return false;
}
}

extension on Duration {
String formatted() {
String twoDigits(int n) => n.toString().padLeft(2, '0');
final twoDigitMinutes = twoDigits(inMinutes.remainder(60));
final twoDigitSeconds = twoDigits(inSeconds.remainder(60));
return darkGray.wrap('$twoDigitMinutes:$twoDigitSeconds')!;
}
}

extension on int {
String formatSuccess() {
return this > 0 ? lightGreen.wrap('+$this')! : '';
}

String formatFailure() {
return this > 0 ? lightRed.wrap('-$this')! : '';
}

String formatSkipped() {
return this > 0 ? lightYellow.wrap('~$this')! : '';
}
}

extension on String {
String truncated(int maxLength) {
if (length <= maxLength) return this;
final truncated = substring(length - maxLength, length).trim();
return '...$truncated';
}

String toSingleLine() {
return replaceAll('\n', '').replaceAll(RegExp(r'\s\s+'), ' ');
}
}
Loading
Loading