Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code coverage #2294

Merged
merged 31 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4ce06bd
Basic coverage
gogolon Jun 6, 2024
9639f11
Use new coverage version, exclude generated files, fix bug causing pa…
gogolon Aug 2, 2024
e1280ee
WIP pause isolates on exit
gogolon Aug 6, 2024
54bc5af
Collect coverage from paused isolates
gogolon Aug 6, 2024
d7634d0
Use rxdart, split coverage related code into files
gogolon Aug 17, 2024
dd48f98
Use wrapper for port forwarding
gogolon Aug 17, 2024
d4a2722
Fix disposing serviceClient, unify named params usage
gogolon Aug 17, 2024
3ee5bce
Rename stopped => coverageCollected
gogolon Aug 17, 2024
143d85e
Only collect coverage from paused isolates if event type is pauseExit
gogolon Aug 17, 2024
8a2e6c7
Do not collect coverage from isolates to avoid duplicate entries
gogolon Aug 22, 2024
1673280
Add doc comment about the host port
gogolon Aug 22, 2024
d6c6945
Use named import
gogolon Aug 22, 2024
b79bc9c
Avoid dart:io platform, refactor & test VMConnectionDetails, commas
gogolon Aug 27, 2024
faee594
Remove rxdart
gogolon Aug 27, 2024
c045089
Use completer
gogolon Aug 29, 2024
f6394cd
Automatically find and forward an unused port instead of using a hard…
gogolon Sep 8, 2024
73053cd
Merge with main
gogolon Sep 9, 2024
96b9d07
Use adb 0.4.0
gogolon Sep 11, 2024
5774f60
Bump patrol & patrol_cli version, fill compatibility map in Compatibi…
gogolon Sep 11, 2024
0b1d919
Update table in docs
gogolon Sep 11, 2024
4e3c740
Swap columns in the docs table
gogolon Sep 12, 2024
c8786ce
Rework VesionComparator, write tests
gogolon Sep 12, 2024
c038ad0
Fix version comparator
gogolon Sep 12, 2024
bcf3a7c
Extract VersionComparator to a separate file
gogolon Sep 12, 2024
3026f87
Add missing import
gogolon Sep 12, 2024
c0cbf9b
Rename field, change comment
gogolon Sep 12, 2024
351cf7b
Remove redundant code
gogolon Sep 12, 2024
dd11d0a
Update changelog and docs
gogolon Sep 12, 2024
c303877
Merge remote-tracking branch 'upstream/master' into features/code-cov…
gogolon Sep 13, 2024
4c905f6
Fix changelog
gogolon Sep 13, 2024
569dc8c
Add empty line to CLI changelog
gogolon Sep 13, 2024
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
26 changes: 26 additions & 0 deletions packages/patrol/lib/src/binding.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io' as io;
import 'dart:isolate';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -93,6 +95,29 @@ class PatrolBinding extends LiveTestWidgetsFlutterBinding {
final nameOfRequestedTest = await patrolAppService.testExecutionRequested;

if (nameOfRequestedTest == _currentDartTest) {
if (const bool.fromEnvironment('COVERAGE_ENABLED')) {
postEvent(
'waitForCoverageCollection',
{'mainIsolateId': Service.getIsolateId(Isolate.current)},
);

var coverageCollected = false;

registerExtension(
'ext.patrol.markTestCompleted',
(method, parameters) async {
coverageCollected = true;
return ServiceExtensionResponse.result(jsonEncode({}));
},
);

while (!coverageCollected) {
// The loop is needed to keep this isolate alive until the coverage
// data is collected.
await Future<void>.delayed(const Duration(seconds: 1));
}
piotruela marked this conversation as resolved.
Show resolved Hide resolved
}

logger(
'finished test $_currentDartTest. Will report its status back to the native side',
);
Expand All @@ -101,6 +126,7 @@ class PatrolBinding extends LiveTestWidgetsFlutterBinding {
logger(
'tearDown(): test "$testName" in group "$_currentDartTest", passed: $passed',
);

await patrolAppService.markDartTestAsCompleted(
dartFileName: _currentDartTest!,
passed: passed,
Expand Down
24 changes: 20 additions & 4 deletions packages/patrol/lib/src/common.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:io' as io;

import 'package:flutter/foundation.dart';
Expand Down Expand Up @@ -237,19 +238,34 @@ String deduplicateGroupEntryName(String parentName, String currentName) {
);
}

/// Recursively prints the structure of the test suite.
/// Recursively prints the structure of the test suite and reports test count
/// of the top-most group
@internal
void printGroupStructure(DartGroupEntry group, {int indentation = 0}) {
int reportGroupStructure(DartGroupEntry group, {int indentation = 0}) {
gogolon marked this conversation as resolved.
Show resolved Hide resolved
var testCount = group.type == GroupEntryType.test ? 1 : 0;

final indent = ' ' * indentation;
debugPrint("$indent-- group: '${group.name}'");
final tag = group.type == GroupEntryType.group ? 'group' : 'test';
debugPrint("$indent-- $tag: '${group.name}'");

for (final entry in group.entries) {
if (entry.type == GroupEntryType.test) {
++testCount;
debugPrint("$indent -- test: '${entry.name}'");
} else {
for (final subgroup in entry.entries) {
printGroupStructure(subgroup, indentation: indentation + 5);
testCount +=
reportGroupStructure(subgroup, indentation: indentation + 5);
}
}
}

if (indentation == 0) {
postEvent(
'testCount',
{'testCount': testCount},
);
}

return testCount;
}
33 changes: 33 additions & 0 deletions packages/patrol_cli/lib/src/commands/test.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import 'dart:async';

import 'package:glob/glob.dart';
import 'package:patrol_cli/src/analytics/analytics.dart';
import 'package:patrol_cli/src/android/android_test_backend.dart';
import 'package:patrol_cli/src/base/extensions/core.dart';
import 'package:patrol_cli/src/base/logger.dart';
import 'package:patrol_cli/src/compatibility_checker.dart';
import 'package:patrol_cli/src/coverage/coverage_tool.dart';
import 'package:patrol_cli/src/crossplatform/app_options.dart';
import 'package:patrol_cli/src/dart_defines_reader.dart';
import 'package:patrol_cli/src/devices.dart';
Expand All @@ -26,6 +28,7 @@ class TestCommand extends PatrolCommand {
required AndroidTestBackend androidTestBackend,
required IOSTestBackend iosTestBackend,
required MacOSTestBackend macOSTestBackend,
required CoverageTool coverageTool,
required Analytics analytics,
required Logger logger,
}) : _deviceFinder = deviceFinder,
Expand All @@ -37,6 +40,7 @@ class TestCommand extends PatrolCommand {
_androidTestBackend = androidTestBackend,
_iosTestBackend = iosTestBackend,
_macosTestBackend = macOSTestBackend,
_coverageTool = coverageTool,
_analytics = analytics,
_logger = logger {
usesTargetOption();
Expand All @@ -47,6 +51,7 @@ class TestCommand extends PatrolCommand {
usesLabelOption();
usesWaitOption();
usesPortOptions();
useCoverageOptions();

usesUninstallOption();

Expand All @@ -63,6 +68,7 @@ class TestCommand extends PatrolCommand {
final AndroidTestBackend _androidTestBackend;
final IOSTestBackend _iosTestBackend;
final MacOSTestBackend _macosTestBackend;
final CoverageTool _coverageTool;

final Analytics _analytics;
final Logger _logger;
Expand Down Expand Up @@ -146,6 +152,8 @@ See https://github.com/leancodepl/patrol/issues/1316 to learn more.
final wait = intArg('wait') ?? defaultWait;
final displayLabel = boolArg('label');
final uninstall = boolArg('uninstall');
final coverageEnabled = boolArg('coverage');
final ignoreGlobs = stringsArg('coverage-ignore').map(Glob.new).toSet();

final customDartDefines = {
..._dartDefinesReader.fromFile(),
Expand All @@ -162,6 +170,7 @@ See https://github.com/leancodepl/patrol/issues/1316 to learn more.
'PATROL_TEST_LABEL_ENABLED': displayLabel.toString(),
'PATROL_TEST_SERVER_PORT': super.testServerPort.toString(),
'PATROL_APP_SERVER_PORT': super.appServerPort.toString(),
'COVERAGE_ENABLED': coverageEnabled.toString(),
}.withNullsRemoved();

final dartDefines = {...customDartDefines, ...internalDartDefines};
Expand Down Expand Up @@ -214,6 +223,18 @@ See https://github.com/leancodepl/patrol/issues/1316 to learn more.

await _build(androidOpts, iosOpts, macosOpts, device);
await _preExecute(androidOpts, iosOpts, macosOpts, device, uninstall);

if (coverageEnabled) {
unawaited(
_coverageTool.run(
flutterPackageName: config.flutterPackageName,
platform: device.targetPlatform,
logger: _logger,
ignoreGlobs: ignoreGlobs,
),
);
}

final allPassed = await _execute(
flutterOpts,
androidOpts,
Expand Down Expand Up @@ -340,4 +361,16 @@ See https://github.com/leancodepl/patrol/issues/1316 to learn more.

return allPassed;
}

void useCoverageOptions() {
argParser
..addFlag(
'coverage',
help: 'Generate coverage.',
)
..addMultiOption(
'coverage-ignore',
help: 'Exclude files from coverage using glob patterns.',
);
}
}
Loading
Loading