Skip to content

Commit 43d72be

Browse files
feat(test): add check-ignore and run-skipped (#1517)
* feat(test): add check-ignore and run-skipped * test(mcp): cover run_skipped and check_ignore in _parseTest * chore: check-ignore true by default * fix: failing test * fix: revert bad merge regressions in dart_cli and dart_test_test
1 parent 08868d1 commit 43d72be

7 files changed

Lines changed: 141 additions & 12 deletions

File tree

lib/src/cli/dart_cli.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,12 @@ class Dart {
9999
required Logger logger,
100100
String cwd = '.',
101101
bool recursive = false,
102+
bool checkIgnore = true,
103+
bool showUncovered = false,
102104
bool collectCoverage = false,
103105
bool optimizePerformance = false,
104106
Set<String> ignore = const {},
105107
double? minCoverage,
106-
bool showUncovered = false,
107108
String? excludeFromCoverage,
108109
CoverageCollectionMode collectCoverageFrom = CoverageCollectionMode.imports,
109110
String? randomSeed,
@@ -119,11 +120,12 @@ class Dart {
119120
testType: TestRunType.dart,
120121
cwd: cwd,
121122
recursive: recursive,
123+
checkIgnore: checkIgnore,
124+
showUncovered: showUncovered,
122125
collectCoverage: collectCoverage,
123126
optimizePerformance: optimizePerformance,
124127
ignore: ignore,
125128
minCoverage: minCoverage,
126-
showUncovered: showUncovered,
127129
excludeFromCoverage: excludeFromCoverage,
128130
collectCoverageFrom: collectCoverageFrom,
129131
randomSeed: randomSeed,

lib/src/cli/test_cli_runner.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class TestCLIRunner {
104104
void Function(String)? stderr,
105105
GeneratorBuilder buildGenerator = MasonGenerator.fromBundle,
106106
String? reportOn,
107+
bool checkIgnore = false,
107108
@visibleForTesting VeryGoodTestRunner? overrideTestRunner,
108109
}) async {
109110
final initialCwd = cwd;
@@ -206,6 +207,7 @@ class TestCLIRunner {
206207
final hitmap = await coverage.HitMap.parseFiles(
207208
files,
208209
packagePath: packagesPath,
210+
checkIgnoredLines: checkIgnore,
209211
);
210212

211213
final resolver = await coverage.Resolver.create(

lib/src/commands/dart/commands/dart_test_command.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class DartTestOptions {
2626
required this.platform,
2727
required this.rest,
2828
required this.reportOn,
29+
required this.runSkipped,
30+
required this.checkIgnore,
2931
});
3032

3133
/// Parses [ArgResults] into a [DartTestOptions] instance.
@@ -54,6 +56,8 @@ class DartTestOptions {
5456
final forceAnsi = argResults['force-ansi'] as bool?;
5557
final platform = argResults['platform'] as String?;
5658
final reportOn = argResults['report-on'] as String?;
59+
final runSkipped = argResults['run-skipped'] as bool;
60+
final checkIgnore = argResults['check-ignore'] as bool;
5761
final rest = argResults.rest;
5862

5963
return DartTestOptions._(
@@ -71,6 +75,8 @@ class DartTestOptions {
7175
forceAnsi: forceAnsi,
7276
platform: platform,
7377
reportOn: reportOn,
78+
runSkipped: runSkipped,
79+
checkIgnore: checkIgnore,
7480
rest: rest,
7581
);
7682
}
@@ -118,6 +124,12 @@ class DartTestOptions {
118124
/// An optional file path to report coverage information to.
119125
final String? reportOn;
120126

127+
/// Whether to run skipped tests instead of skipping them.
128+
final bool runSkipped;
129+
130+
/// Whether to check for and respect coverage ignore comments.
131+
final bool checkIgnore;
132+
121133
/// The remaining arguments passed to the `dart test` command.
122134
final List<String> rest;
123135
}
@@ -143,6 +155,7 @@ typedef DartTestCommandCall =
143155
void Function(String)? stdout,
144156
void Function(String)? stderr,
145157
String? reportOn,
158+
bool checkIgnore,
146159
});
147160

148161
/// {@template dart_test_command}
@@ -253,6 +266,18 @@ class DartTestCommand extends Command<int> {
253266
'platform',
254267
help: 'The platform to run tests on. ',
255268
valueHelp: 'chrome|vm',
269+
)
270+
..addFlag(
271+
'run-skipped',
272+
help: 'Run skipped tests instead of skipping them.',
273+
negatable: false,
274+
)
275+
..addFlag(
276+
'check-ignore',
277+
defaultsTo: true,
278+
help:
279+
'Whether to check for and respect coverage ignore comments '
280+
'(e.g. // coverage:ignore-line).',
256281
);
257282
}
258283

@@ -316,11 +341,13 @@ This command should be run from the root of your Dart project.''');
316341
if (options.excludeTags != null) ...['-x', options.excludeTags!],
317342
if (options.tags != null) ...['-t', options.tags!],
318343
if (options.failFast) '--fail-fast',
344+
if (options.runSkipped) '--run-skipped',
319345
if (options.platform != null) ...['--platform', options.platform!],
320346
if (options.platform == null) ...['-j', options.concurrency],
321347
...options.rest,
322348
],
323349
reportOn: options.reportOn,
350+
checkIgnore: options.checkIgnore,
324351
);
325352
if (results.any((code) => code != ExitCode.success.code)) {
326353
return ExitCode.unavailable.code;

lib/src/mcp/mcp_server.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,17 @@ The available values are: chrome, vm, android, ios.
205205
Only one value can be selected.
206206
''',
207207
),
208+
'run_skipped': BooleanSchema(
209+
description:
210+
'Run skipped tests instead of skipping them. '
211+
'Only applies to Dart tests (dart: true).',
212+
),
213+
'check_ignore': BooleanSchema(
214+
description:
215+
'Whether to check for and respect coverage ignore comments '
216+
'(e.g. // coverage:ignore-line). '
217+
'Only applies to Dart tests (dart: true).',
218+
),
208219
},
209220
),
210221
),
@@ -359,6 +370,12 @@ Only one value can be selected.
359370
if (args['platform'] != null) {
360371
cliArgs.addAll(['--platform', args['platform']! as String]);
361372
}
373+
if (args['run_skipped'] == true) {
374+
cliArgs.add('--run-skipped');
375+
}
376+
if (args['check_ignore'] == true) {
377+
cliArgs.add('--check-ignore');
378+
}
362379

363380
return cliArgs;
364381
}

test/src/cli/test_cli_runner_test.dart

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -780,12 +780,10 @@ void main() {
780780
stdout: stdoutLogs.add,
781781
stderr: stderrLogs.add,
782782
overrideTestRunner: testRunner(
783-
Stream.fromIterable(
784-
[
785-
const DoneTestEvent(success: true, time: 0),
786-
const ExitTestEvent(exitCode: 0, time: 0),
787-
],
788-
),
783+
Stream.fromIterable([
784+
const DoneTestEvent(success: true, time: 0),
785+
const ExitTestEvent(exitCode: 0, time: 0),
786+
]),
789787
onStart: () {
790788
expect(lcovFile.existsSync(), isFalse);
791789
lcovFile.createSync(recursive: true);
@@ -805,6 +803,42 @@ void main() {
805803
expect(testRunnerArgs, equals(['--coverage=coverage']));
806804
});
807805

806+
test('runs dart tests w/coverage and checkIgnore', () async {
807+
final tempDirectory = Directory.systemTemp.createTempSync();
808+
addTearDown(() => tempDirectory.deleteSync(recursive: true));
809+
810+
final lcovFile = File(
811+
p.join(tempDirectory.path, 'coverage', 'lcov.info'),
812+
);
813+
File(p.join(tempDirectory.path, 'pubspec.yaml')).createSync();
814+
Directory(p.join(tempDirectory.path, 'test')).createSync();
815+
lcovFile.createSync(recursive: true);
816+
817+
await expectLater(
818+
TestCLIRunner.test(
819+
testType: TestRunType.dart,
820+
cwd: tempDirectory.path,
821+
logger: logger,
822+
checkIgnore: true,
823+
collectCoverage: true,
824+
stdout: stdoutLogs.add,
825+
stderr: stderrLogs.add,
826+
overrideTestRunner: testRunner(
827+
Stream.fromIterable([
828+
const DoneTestEvent(success: true, time: 0),
829+
const ExitTestEvent(exitCode: 0, time: 0),
830+
]),
831+
onStart: () {
832+
expect(lcovFile.existsSync(), isFalse);
833+
lcovFile.createSync(recursive: true);
834+
},
835+
),
836+
),
837+
completion(equals([ExitCode.success.code])),
838+
);
839+
expect(testRunnerArgs, equals(['--coverage=coverage']));
840+
});
841+
808842
test('runs tests w/coverage + min-coverage 100 (pass)', () async {
809843
final tempDirectory = Directory.systemTemp.createTempSync();
810844
addTearDown(() => tempDirectory.deleteSync(recursive: true));
@@ -816,8 +850,9 @@ void main() {
816850
TestCLIRunner.test(
817851
testType: TestRunType.flutter,
818852
cwd: tempDirectory.path,
819-
collectCoverage: true,
853+
logger: logger,
820854
minCoverage: 100,
855+
collectCoverage: true,
821856
stdout: stdoutLogs.add,
822857
stderr: stderrLogs.add,
823858
overrideTestRunner: testRunner(
@@ -833,7 +868,6 @@ void main() {
833868
..writeAsStringSync(lcov100);
834869
},
835870
),
836-
logger: logger,
837871
),
838872
completion(equals([ExitCode.success.code])),
839873
);

test/src/commands/dart/commands/dart_test_test.dart

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ const expectedTestUsage = [
4545
' --force-ansi Whether to force ansi output. If not specified, it will maintain the default behavior based on stdout and stderr.\n'
4646
' --report-on=<lib/> An optional file path to report coverage information to. This should be a path relative to the current working directory.\n'
4747
' --platform=<chrome|vm> The platform to run tests on. \n'
48+
' --run-skipped Run skipped tests instead of skipping them.\n'
49+
' --[no-]check-ignore Whether to check for and respect coverage ignore comments (e.g. // coverage:ignore-line).\n'
50+
' (defaults to on)\n'
4851
'\n'
4952
'Run "very_good help" to see global options.',
5053
];
@@ -56,10 +59,11 @@ abstract class DartTestCommandCall {
5659
Future<List<int>> call({
5760
String cwd = '.',
5861
bool recursive = false,
62+
bool checkIgnore = true,
63+
bool showUncovered = false,
5964
bool collectCoverage = false,
6065
bool optimizePerformance = false,
6166
double? minCoverage,
62-
bool showUncovered = false,
6367
String? excludeFromCoverage,
6468
CoverageCollectionMode collectCoverageFrom = CoverageCollectionMode.imports,
6569
String? randomSeed,
@@ -102,10 +106,11 @@ void main() {
102106
() => dartTest(
103107
cwd: any(named: 'cwd'),
104108
recursive: any(named: 'recursive'),
109+
checkIgnore: any(named: 'checkIgnore'),
110+
showUncovered: any(named: 'showUncovered'),
105111
collectCoverage: any(named: 'collectCoverage'),
106112
optimizePerformance: any(named: 'optimizePerformance'),
107113
minCoverage: any(named: 'minCoverage'),
108-
showUncovered: any(named: 'showUncovered'),
109114
excludeFromCoverage: any(named: 'excludeFromCoverage'),
110115
collectCoverageFrom: any(named: 'collectCoverageFrom'),
111116
randomSeed: any(named: 'randomSeed'),
@@ -120,8 +125,10 @@ void main() {
120125
when<dynamic>(() => argResults['concurrency']).thenReturn(concurrency);
121126
when<dynamic>(() => argResults['recursive']).thenReturn(false);
122127
when<dynamic>(() => argResults['coverage']).thenReturn(false);
128+
when<dynamic>(() => argResults['check-ignore']).thenReturn(true);
123129
when<dynamic>(() => argResults['show-uncovered']).thenReturn(false);
124130
when<dynamic>(() => argResults['fail-fast']).thenReturn(false);
131+
when<dynamic>(() => argResults['run-skipped']).thenReturn(false);
125132
when<dynamic>(() => argResults['optimization']).thenReturn(true);
126133
when<dynamic>(() => argResults['platform']).thenReturn(null);
127134
when<dynamic>(
@@ -222,6 +229,7 @@ void main() {
222229
logger: any(named: 'logger'),
223230
stdout: any(named: 'stdout'),
224231
stderr: any(named: 'stderr'),
232+
checkIgnore: any(named: 'checkIgnore'),
225233
),
226234
).thenAnswer(
227235
(_) async => [ExitCode.success.code, ExitCode.unavailable.code],
@@ -495,6 +503,7 @@ void main() {
495503
logger: any(named: 'logger'),
496504
stdout: any(named: 'stdout'),
497505
stderr: any(named: 'stderr'),
506+
checkIgnore: any(named: 'checkIgnore'),
498507
),
499508
).thenThrow(exception);
500509
final result = await testCommand.run();
@@ -540,6 +549,7 @@ void main() {
540549
logger: any(named: 'logger'),
541550
stdout: any(named: 'stdout'),
542551
stderr: any(named: 'stderr'),
552+
checkIgnore: any(named: 'checkIgnore'),
543553
),
544554
).thenThrow(exception);
545555
final result = await testCommand.run();
@@ -574,6 +584,7 @@ void main() {
574584
logger: any(named: 'logger'),
575585
stdout: any(named: 'stdout'),
576586
stderr: any(named: 'stderr'),
587+
checkIgnore: any(named: 'checkIgnore'),
577588
),
578589
).thenThrow(exception);
579590
final result = await testCommand.run();
@@ -654,6 +665,7 @@ void main() {
654665
logger: any(named: 'logger'),
655666
stdout: any(named: 'stdout'),
656667
stderr: any(named: 'stderr'),
668+
checkIgnore: any(named: 'checkIgnore'),
657669
),
658670
).thenThrow(exception);
659671
final result = await testCommand.run();
@@ -732,5 +744,36 @@ void main() {
732744
).called(1);
733745
},
734746
);
747+
748+
test('completes normally --run-skipped', () async {
749+
when<dynamic>(() => argResults['run-skipped']).thenReturn(true);
750+
final result = await testCommand.run();
751+
expect(result, equals(ExitCode.success.code));
752+
verify(
753+
() => dartTest(
754+
optimizePerformance: true,
755+
arguments: ['--run-skipped', ...defaultArguments],
756+
logger: logger,
757+
stdout: logger.write,
758+
stderr: logger.err,
759+
),
760+
).called(1);
761+
});
762+
763+
test('completes normally --no-check-ignore', () async {
764+
when<dynamic>(() => argResults['check-ignore']).thenReturn(false);
765+
final result = await testCommand.run();
766+
expect(result, equals(ExitCode.success.code));
767+
verify(
768+
() => dartTest(
769+
optimizePerformance: true,
770+
arguments: defaultArguments,
771+
logger: logger,
772+
stdout: logger.write,
773+
stderr: logger.err,
774+
checkIgnore: false,
775+
),
776+
).called(1);
777+
});
735778
});
736779
}

test/src/mcp/mcp_server_test.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,8 @@ void main() {
335335
'dart-define': 'foo=bar',
336336
'dart-define-from-file': 'my_file.json',
337337
'platform': 'chrome',
338+
'run_skipped': true,
339+
'check_ignore': true,
338340
},
339341
),
340342
),
@@ -368,6 +370,8 @@ void main() {
368370
'my_file.json',
369371
'--platform',
370372
'chrome',
373+
'--run-skipped',
374+
'--check-ignore',
371375
]);
372376
});
373377

0 commit comments

Comments
 (0)