Give `_runFlutterTest` the ability to validate command output
In another change (#37646), I want to test that a test fails and
prints expected output. I didn't see an existing way to do that, so
I modified `_runFlutterTest` and `runCommand` to allow capturing the
output. Currently capturing and printing output are mutually
exclusive since we don't need both.
Some awkward bits:
* There already exists a `runAndGetStdout` function that is very
similar to `runCommand`, and this change makes the conceptual
distinction more confusing.
* `runFlutterTest` has multiple code paths for different
configurations. I don't understand what the different paths are
for, and I added output checking only along one of them.
diff --git a/dev/bots/run_command.dart b/dev/bots/run_command.dart
index 507ce59..d96abb1 100644
--- a/dev/bots/run_command.dart
+++ b/dev/bots/run_command.dart
@@ -83,12 +83,15 @@
bool expectNonZeroExit = false,
int expectedExitCode,
String failureMessage,
- bool printOutput = true,
+ OutputMode outputMode = OutputMode.print,
+ CapturedOutput output,
bool skip = false,
bool expectFlaky = false,
Duration timeout = _kLongTimeout,
bool Function(String) removeLine,
}) async {
+ assert((outputMode == OutputMode.capture) == (output != null));
+
final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}';
final String relativeWorkingDir = path.relative(workingDirectory);
if (skip) {
@@ -110,7 +113,7 @@
.where((String line) => removeLine == null || !removeLine(line))
.map((String line) => '$line\n')
.transform(const Utf8Encoder());
- if (printOutput) {
+ if (outputMode == OutputMode.print) {
await Future.wait<void>(<Future<void>>[
stdout.addStream(stdoutSource),
stderr.addStream(process.stderr),
@@ -125,6 +128,12 @@
return (expectNonZeroExit || expectFlaky) ? 0 : 1;
});
print('$clock ELAPSED TIME: $bold${elapsedTime(start)}$reset for $commandDescription in $relativeWorkingDir: ');
+
+ if (output != null) {
+ output.stdout = flattenToString(await savedStdout);
+ output.stderr = flattenToString(await savedStderr);
+ }
+
// If the test is flaky we don't care about the actual exit.
if (expectFlaky) {
return;
@@ -133,9 +142,12 @@
if (failureMessage != null) {
print(failureMessage);
}
- if (!printOutput) {
- stdout.writeln(utf8.decode((await savedStdout).expand<int>((List<int> ints) => ints).toList()));
- stderr.writeln(utf8.decode((await savedStderr).expand<int>((List<int> ints) => ints).toList()));
+
+ // Print the output when we get unexpected results (unless output was
+ // printed already).
+ if (outputMode != OutputMode.print) {
+ stdout.writeln(flattenToString(await savedStdout));
+ stderr.writeln(flattenToString(await savedStderr));
}
print(
'$redLine\n'
@@ -147,3 +159,18 @@
exit(1);
}
}
+
+T identity<T>(T x) => x;
+
+/// Flattens a nested list of UTF-8 code units into a single string.
+String flattenToString(List<List<int>> chunks) =>
+ utf8.decode(chunks.expand<int>(identity).toList(growable: false));
+
+/// Specifies what to do with command output from [runCommand].
+enum OutputMode { print, capture, discard }
+
+/// Stores command output from [runCommand] when used with [OutputMode.capture].
+class CapturedOutput {
+ String stdout;
+ String stderr;
+}