forked from flutter/packages
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathdart_test_command.dart
More file actions
185 lines (165 loc) · 6.9 KB
/
Copy pathdart_test_command.dart
File metadata and controls
185 lines (165 loc) · 6.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:file/file.dart';
import 'common/core.dart';
import 'common/package_looping_command.dart';
import 'common/plugin_utils.dart';
import 'common/pub_utils.dart';
import 'common/repository_package.dart';
/// A command to run Dart unit tests for packages.
class DartTestCommand extends PackageLoopingCommand {
/// Creates an instance of the test command.
DartTestCommand(
super.packagesDir, {
super.processRunner,
super.platform,
}) {
argParser.addOption(
kEnableExperiment,
defaultsTo: '',
help:
'Runs Dart unit tests in Dart VM with the given experiments enabled. '
'See https://github.com/dart-lang/sdk/blob/main/docs/process/experimental-flags.md '
'for details.',
);
argParser.addOption(
_platformFlag,
help: 'Runs tests on the given platform instead of the default platform '
'("vm" in most cases, "chrome" for web plugin implementations).',
);
}
static const String _platformFlag = 'platform';
@override
final String name = 'dart-test';
// TODO(stuartmorgan): Eventually remove 'test', which is a legacy name from
// before there were other test commands that made it ambiguous. For now it's
// an alias to avoid breaking people's workflows.
@override
List<String> get aliases => <String>['test', 'test-dart'];
@override
final String description = 'Runs the Dart tests for all packages.\n\n'
'This command requires "flutter" to be in your path.';
@override
PackageLoopingType get packageLoopingType =>
PackageLoopingType.includeAllSubpackages;
@override
Future<PackageResult> runForPackage(RepositoryPackage package) async {
if (!package.testDirectory.existsSync()) {
return PackageResult.skip('No test/ directory.');
}
String? platform = getNullableStringArg(_platformFlag);
// Skip running plugin tests for non-web-supporting plugins (or non-web
// federated plugin implementations) on web, since there's no reason to
// expect them to work.
final bool webPlatform = platform != null && platform != 'vm';
final bool explicitVMPlatform = platform == 'vm';
final bool isWebOnlyPluginImplementation = pluginSupportsPlatform(
platformWeb, package,
requiredMode: PlatformSupport.inline) &&
package.directory.basename.endsWith('_web');
if (webPlatform) {
if (isFlutterPlugin(package) &&
!pluginSupportsPlatform(platformWeb, package)) {
return PackageResult.skip(
"Non-web plugin tests don't need web testing.");
}
if (_requiresVM(package)) {
// This explict skip is necessary because trying to run tests in a mode
// that the package has opted out of returns a non-zero exit code.
return PackageResult.skip('Package has opted out of non-vm testing.');
}
} else if (explicitVMPlatform) {
if (isWebOnlyPluginImplementation) {
return PackageResult.skip("Web plugin tests don't need vm testing.");
}
if (_requiresNonVM(package)) {
// This explict skip is necessary because trying to run tests in a mode
// that the package has opted out of returns a non-zero exit code.
return PackageResult.skip('Package has opted out of vm testing.');
}
} else if (platform == null && isWebOnlyPluginImplementation) {
// If no explicit mode is requested, run web plugin implementations in
// Chrome since their tests are not expected to work in vm mode. This
// allows easily running all unit tests locally, without having to run
// both modes.
platform = 'chrome';
}
bool passed;
if (package.requiresFlutter()) {
passed = await _runFlutterTests(package, platform: platform);
} else {
passed = await _runDartTests(package, platform: platform);
}
return passed ? PackageResult.success() : PackageResult.fail();
}
/// Runs the Dart tests for a Flutter package, returning true on success.
Future<bool> _runFlutterTests(RepositoryPackage package,
{String? platform}) async {
final String experiment = getStringArg(kEnableExperiment);
final int exitCode = await processRunner.runAndStream(
flutterCommand,
<String>[
'test',
'--color',
if (experiment.isNotEmpty) '--enable-experiment=$experiment',
// Flutter defaults to VM mode (under a different name) and explicitly
// setting it is deprecated, so pass nothing in that case.
if (platform != null && platform != 'vm') '--platform=$platform',
],
workingDir: package.directory,
);
return exitCode == 0;
}
/// Runs the Dart tests for a non-Flutter package, returning true on success.
Future<bool> _runDartTests(RepositoryPackage package,
{String? platform}) async {
// Unlike `flutter test`, `dart run test` does not automatically get
// packages
if (!await runPubGet(package, processRunner, super.platform)) {
printError('Unable to fetch dependencies.');
return false;
}
final String experiment = getStringArg(kEnableExperiment);
final int exitCode = await processRunner.runAndStream(
'dart',
<String>[
'run',
if (experiment.isNotEmpty) '--enable-experiment=$experiment',
'test',
if (platform != null) '--platform=$platform',
],
workingDir: package.directory,
);
return exitCode == 0;
}
bool _requiresVM(RepositoryPackage package) {
final File testConfig = package.directory.childFile('dart_test.yaml');
if (!testConfig.existsSync()) {
return false;
}
// test_on lines can be very complex, but in pratice the packages in this
// repo currently only need the ability to require vm or not, so that
// simple directive is all that is currently supported.
final RegExp vmRequrimentRegex = RegExp(r'^test_on:\s*vm$');
return testConfig
.readAsLinesSync()
.any((String line) => vmRequrimentRegex.hasMatch(line));
}
bool _requiresNonVM(RepositoryPackage package) {
final File testConfig = package.directory.childFile('dart_test.yaml');
if (!testConfig.existsSync()) {
return false;
}
// test_on lines can be very complex, but in pratice the packages in this
// repo currently only need the ability to require vm or not, so a simple
// one-target directive is all that's supported currently. Making it
// deliberately strict avoids the possibility of accidentally skipping vm
// coverage due to a complex expression that's not handled correctly.
final RegExp testOnRegex = RegExp(r'^test_on:\s*([a-z])*\s*$');
return testConfig.readAsLinesSync().any((String line) {
final RegExpMatch? match = testOnRegex.firstMatch(line);
return match != null && match.group(1) != 'vm';
});
}
}