mirror of
https://github.com/flutter/flutter
synced 2024-08-25 02:46:31 +00:00
More helpful test.dart output (#140175)
Each error section is numbered, so you can all be sure you're talking about the same one. A message is printed at the very end telling you how to find the error blocks in the verbose logs.
This commit is contained in:
parent
b0b0e423d6
commit
11119cff38
|
@ -188,15 +188,7 @@ Future<CommandResult> runCommand(String executable, List<String> arguments, {
|
|||
print(result.flattenedStdout);
|
||||
print(result.flattenedStderr);
|
||||
}
|
||||
String allOutput;
|
||||
if (failureMessage == null) {
|
||||
allOutput = '${result.flattenedStdout}\n${result.flattenedStderr}';
|
||||
if (allOutput.split('\n').length > 10) {
|
||||
allOutput = '(stdout/stderr output was more than 10 lines)';
|
||||
}
|
||||
} else {
|
||||
allOutput = '';
|
||||
}
|
||||
final String allOutput = '${result.flattenedStdout}\n${result.flattenedStderr}';
|
||||
foundError(<String>[
|
||||
if (failureMessage != null)
|
||||
failureMessage,
|
||||
|
@ -204,7 +196,7 @@ Future<CommandResult> runCommand(String executable, List<String> arguments, {
|
|||
if (failureMessage == null)
|
||||
'$bold${red}Command exited with exit code ${result.exitCode} but expected ${expectNonZeroExit ? (expectedExitCode ?? 'non-zero') : 'zero'} exit code.$reset',
|
||||
'${bold}Working directory: $cyan${path.absolute(relativeWorkingDir)}$reset',
|
||||
if (allOutput.isNotEmpty)
|
||||
if (allOutput.isNotEmpty && allOutput.length < 512)
|
||||
'${bold}stdout and stderr output:\n$allOutput',
|
||||
]);
|
||||
} else {
|
||||
|
|
|
@ -69,7 +69,7 @@ void main() {
|
|||
})
|
||||
.join('\n');
|
||||
expect(result,
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════\n'
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════\n'
|
||||
'$lines\n'
|
||||
'║ See: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes\n'
|
||||
'╚═══════════════════════════════════════════════════════════════════════════════\n'
|
||||
|
@ -88,7 +88,7 @@ void main() {
|
|||
.map((String line) => line.replaceAll('/', Platform.isWindows ? r'\' : '/'))
|
||||
.toList();
|
||||
expect(result.length, 4 + lines.length, reason: 'output had unexpected number of lines:\n${result.join('\n')}');
|
||||
expect(result[0], '╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════');
|
||||
expect(result[0], '╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════');
|
||||
expect(result.getRange(1, result.length - 3).toSet(), lines.toSet());
|
||||
expect(result[result.length - 3], '║ See: https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter');
|
||||
expect(result[result.length - 2], '╚═══════════════════════════════════════════════════════════════════════════════');
|
||||
|
@ -100,7 +100,7 @@ void main() {
|
|||
final String file = 'test/analyze-test-input/root/packages/foo/foo.dart'
|
||||
.replaceAll('/', Platform.isWindows ? r'\' : '/');
|
||||
expect(result,
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════\n'
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════\n'
|
||||
'║ The following file does not have the right license header for dart files:\n'
|
||||
'║ $file\n'
|
||||
'║ The expected license header is:\n'
|
||||
|
@ -121,7 +121,7 @@ void main() {
|
|||
.map((String line) => line.replaceAll('/', Platform.isWindows ? r'\' : '/'))
|
||||
.join('\n');
|
||||
expect(result,
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════\n'
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════\n'
|
||||
'$lines\n'
|
||||
'╚═══════════════════════════════════════════════════════════════════════════════\n'
|
||||
);
|
||||
|
@ -139,7 +139,7 @@ void main() {
|
|||
.map((String line) => line.replaceAll('/', Platform.isWindows ? r'\' : '/'))
|
||||
.join('\n');
|
||||
expect(result,
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════\n'
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════\n'
|
||||
'$lines\n'
|
||||
'╚═══════════════════════════════════════════════════════════════════════════════\n'
|
||||
);
|
||||
|
@ -152,7 +152,7 @@ void main() {
|
|||
), shouldHaveErrors: !Platform.isWindows);
|
||||
if (!Platform.isWindows) {
|
||||
expect(result,
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════\n'
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════\n'
|
||||
'║ test/analyze-test-input/root/packages/foo/serviceaccount.enc:0: file is not valid UTF-8\n'
|
||||
'║ All files in this repository must be UTF-8. In particular, images and other binaries\n'
|
||||
'║ must not be checked into this repository. This is because we are very sensitive to the\n'
|
||||
|
@ -229,7 +229,7 @@ void main() {
|
|||
.map((String line) => line.replaceAll('/', Platform.isWindows ? r'\' : '/'))
|
||||
.join('\n');
|
||||
expect(result,
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════\n'
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════\n'
|
||||
'$lines\n'
|
||||
'║ \n'
|
||||
'║ For performance reasons, we use a custom "clampDouble" function instead of using "double.clamp".\n'
|
||||
|
@ -259,7 +259,7 @@ void main() {
|
|||
.map((String line) => line.replaceAll('/', Platform.isWindows ? r'\' : '/'))
|
||||
.join('\n');
|
||||
expect(result,
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════\n'
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════\n'
|
||||
'$lines\n'
|
||||
'║ \n'
|
||||
'║ Stopwatches introduce flakes by falling out of sync with the FakeAsync used in testing.\n'
|
||||
|
|
|
@ -119,7 +119,7 @@ void main() {
|
|||
shouldHaveErrors: true,
|
||||
);
|
||||
final String lines = <String>[
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════',
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════',
|
||||
'║ The following examples are not linked from any source file API doc comments:',
|
||||
'║ examples/api/lib/layer/missing_example.0.dart',
|
||||
'║ Either link them to a source file API doc comment, or remove them.',
|
||||
|
@ -142,7 +142,7 @@ void main() {
|
|||
);
|
||||
final bool isWindows = Platform.isWindows;
|
||||
final String lines = <String>[
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════',
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════',
|
||||
'║ The following examples are not linked from any source file API doc comments:',
|
||||
if (!isWindows) '║ examples/api/lib/animation/curves/curve2_d.0.dart',
|
||||
if (!isWindows) '║ examples/api/lib/layer/foo_example.0.dart',
|
||||
|
@ -152,7 +152,7 @@ void main() {
|
|||
if (isWindows) r'║ examples\api\lib\layer\bar_example.0.dart',
|
||||
'║ Either link them to a source file API doc comment, or remove them.',
|
||||
'╚═══════════════════════════════════════════════════════════════════════════════',
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════',
|
||||
'╔═╡ERROR #2╞════════════════════════════════════════════════════════════════════',
|
||||
'║ The following malformed links were found in API doc comments:',
|
||||
if (!isWindows) '║ /flutter sdk/packages/flutter/lib/src/animation/curves.dart:6: ///* see code in examples/api/lib/animation/curves/curve2_d.0.dart *',
|
||||
if (!isWindows) '║ /flutter sdk/packages/flutter/lib/src/layer/foo.dart:6: ///*See Code *',
|
||||
|
@ -178,7 +178,7 @@ void main() {
|
|||
shouldHaveErrors: true,
|
||||
);
|
||||
final String lines = <String>[
|
||||
'╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════',
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════',
|
||||
'║ The following example test files are missing:',
|
||||
'║ examples/api/test/layer/bar_example.0_test.dart',
|
||||
'╚═══════════════════════════════════════════════════════════════════════════════',
|
||||
|
|
65
dev/bots/test/run_command_test.dart
Normal file
65
dev/bots/test/run_command_test.dart
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2014 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 'dart:io' as io;
|
||||
|
||||
import '../run_command.dart';
|
||||
import '../utils.dart';
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
void main() {
|
||||
// These tests only run on Linux. They test platform-agnostic code that is
|
||||
// triggered by platform-sensitive code. To avoid having to complicate our
|
||||
// test harness by using a mockable process manager, the tests rely on one
|
||||
// platform's conventions (Linux having `sh`). The logic being tested is not
|
||||
// so critical that it matters that we're only testing it on one platform.
|
||||
|
||||
test('short output on runCommand failure', () async {
|
||||
final List<Object?> log = <String>[];
|
||||
final PrintCallback oldPrint = print;
|
||||
print = log.add;
|
||||
try {
|
||||
await runCommand('/usr/bin/sh', <String>['-c', 'echo test; false']);
|
||||
expect(log, <Object>[
|
||||
startsWith('RUNNING:'),
|
||||
'workingDirectory: null, executable: /usr/bin/sh, arguments: [-c, echo test; false]',
|
||||
'test',
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════',
|
||||
startsWith('║ Command: '),
|
||||
'║ Command exited with exit code 1 but expected zero exit code.',
|
||||
startsWith('║ Working directory: '),
|
||||
'║ stdout and stderr output:',
|
||||
'║ test',
|
||||
'║ ',
|
||||
'╚═══════════════════════════════════════════════════════════════════════════════'
|
||||
]);
|
||||
} finally {
|
||||
print = oldPrint;
|
||||
resetErrorStatus();
|
||||
}
|
||||
}, skip: !io.Platform.isLinux); // [intended] See comments above.
|
||||
|
||||
test('long output on runCommand failure', () async {
|
||||
final List<Object?> log = <String>[];
|
||||
final PrintCallback oldPrint = print;
|
||||
print = log.add;
|
||||
try {
|
||||
await runCommand('/usr/bin/sh', <String>['-c', 'echo ${"meow" * 1024}; false']);
|
||||
expect(log, <Object>[
|
||||
startsWith('RUNNING:'),
|
||||
'workingDirectory: null, executable: /usr/bin/sh, arguments: [-c, echo ${"meow" * 1024}; false]',
|
||||
'meow' * 1024,
|
||||
'╔═╡ERROR #1╞════════════════════════════════════════════════════════════════════',
|
||||
startsWith('║ Command: '),
|
||||
'║ Command exited with exit code 1 but expected zero exit code.',
|
||||
startsWith('║ Working directory: '),
|
||||
'╚═══════════════════════════════════════════════════════════════════════════════'
|
||||
]);
|
||||
} finally {
|
||||
print = oldPrint;
|
||||
resetErrorStatus();
|
||||
}
|
||||
}, skip: !io.Platform.isLinux); // [intended] See comments above.
|
||||
}
|
|
@ -95,7 +95,8 @@ void foundError(List<String> messages) {
|
|||
// Make the error message easy to notice in the logs by
|
||||
// wrapping it in a red box.
|
||||
final int width = math.max(15, (hasColor ? stdout.terminalColumns : 80) - 1);
|
||||
print('$red╔═╡${bold}ERROR$reset$red╞═${"═" * (width - 9)}');
|
||||
final String title = 'ERROR #${_errorMessages.length + 1}';
|
||||
print('$red╔═╡$bold$title$reset$red╞═${"═" * (width - 4 - title.length)}');
|
||||
for (final String message in messages.expand((String line) => line.split('\n'))) {
|
||||
print('$red║$reset $message');
|
||||
}
|
||||
|
@ -145,6 +146,7 @@ Never reportErrorsAndExit(String message) {
|
|||
}
|
||||
}
|
||||
print(redLine);
|
||||
print('You may find the errors by searching for "╡ERROR #" in the logs.');
|
||||
system.exit(1);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue