[flutter_plugin_tools] Make no unit tests fatal for iOS/macOS (#4341)

Brings iOS and macOS into alignment with the other platforms, where
having unit tests set up is required.

- For deprecated plugins with no tests, `--exclude`s them, as on other platforms.
- For `quick_actions` and `share`, which have integration tests but no unit tests,
  sets up the unit test scaffolding. (This is done for `share` even though it's
  deprecated since unlike other platforms, iOS/macOS runs both native tests in the 
  same command, and setting up a special way to exclude just units tests for that
  one case would be much more effort.)

Fixes flutter/flutter#85469
This commit is contained in:
stuartmorgan
2021-09-13 19:37:12 -04:00
committed by GitHub
parent 2b615cad84
commit ae15095e05
3 changed files with 213 additions and 238 deletions

View File

@ -251,8 +251,6 @@ this command.
final bool hasIntegrationTests =
exampleHasNativeIntegrationTests(example);
// TODO(stuartmorgan): Make !hasUnitTests fatal. See
// https://github.com/flutter/flutter/issues/85469
if (mode.unit && !hasUnitTests) {
_printNoExampleTestsMessage(example, 'Android unit');
}
@ -355,33 +353,40 @@ this command.
List<String> extraFlags = const <String>[],
}) async {
String? testTarget;
const String unitTestTarget = 'RunnerTests';
if (mode.unitOnly) {
testTarget = 'RunnerTests';
testTarget = unitTestTarget;
} else if (mode.integrationOnly) {
testTarget = 'RunnerUITests';
}
bool ranUnitTests = false;
// Assume skipped until at least one test has run.
RunState overallResult = RunState.skipped;
for (final RepositoryPackage example in plugin.getExamples()) {
final String exampleName = example.displayName;
// TODO(stuartmorgan): Always check for RunnerTests, and make it fatal if
// no examples have it. See
// https://github.com/flutter/flutter/issues/85469
if (testTarget != null) {
final Directory project = example.directory
.childDirectory(platform.toLowerCase())
.childDirectory('Runner.xcodeproj');
// If running a specific target, check that. Otherwise, check if there
// are unit tests, since having no unit tests for a plugin is fatal
// (by repo policy) even if there are integration tests.
bool exampleHasUnitTests = false;
final String? targetToCheck =
testTarget ?? (mode.unit ? unitTestTarget : null);
final Directory xcodeProject = example.directory
.childDirectory(platform.toLowerCase())
.childDirectory('Runner.xcodeproj');
if (targetToCheck != null) {
final bool? hasTarget =
await _xcode.projectHasTarget(project, testTarget);
await _xcode.projectHasTarget(xcodeProject, targetToCheck);
if (hasTarget == null) {
printError('Unable to check targets for $exampleName.');
overallResult = RunState.failed;
continue;
} else if (!hasTarget) {
print('No "$testTarget" target in $exampleName; skipping.');
print('No "$targetToCheck" target in $exampleName; skipping.');
continue;
} else if (targetToCheck == unitTestTarget) {
exampleHasUnitTests = true;
}
}
@ -404,20 +409,39 @@ this command.
switch (exitCode) {
case _xcodebuildNoTestExitCode:
_printNoExampleTestsMessage(example, platform);
continue;
break;
case 0:
printSuccess('Successfully ran $platform xctest for $exampleName');
// If this is the first test, assume success until something fails.
if (overallResult == RunState.skipped) {
overallResult = RunState.succeeded;
}
if (exampleHasUnitTests) {
ranUnitTests = true;
}
break;
default:
// Any failure means a failure overall.
overallResult = RunState.failed;
// If unit tests ran, note that even if they failed.
if (exampleHasUnitTests) {
ranUnitTests = true;
}
break;
}
}
if (!mode.integrationOnly && !ranUnitTests) {
printError('No unit tests ran. Plugins are required to have unit tests.');
// Only return a specific summary error message about the missing unit
// tests if there weren't also failures, to avoid having a misleadingly
// specific message.
if (overallResult != RunState.failed) {
return _PlatformResult(RunState.failed,
error: 'No unit tests ran (use --exclude if this is intentional).');
}
}
return _PlatformResult(overallResult);
}