mirror of
https://github.com/flutter/flutter
synced 2024-10-14 04:02:56 +00:00
2d81adf74c
This reverts commit e438632165
because it breaks 160 benchmarks, and several devicelab tests,
due to changing the format of the output.
341 lines
14 KiB
Dart
341 lines
14 KiB
Dart
// Copyright 2017 The Chromium 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:async';
|
|
|
|
import 'package:flutter_tools/src/base/context.dart';
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/base/platform.dart';
|
|
import 'package:flutter_tools/src/base/terminal.dart';
|
|
|
|
import '../src/common.dart';
|
|
import '../src/context.dart';
|
|
import '../src/mocks.dart';
|
|
|
|
void main() {
|
|
final String red = RegExp.escape(AnsiTerminal.red);
|
|
final String bold = RegExp.escape(AnsiTerminal.bold);
|
|
final String reset = RegExp.escape(AnsiTerminal.reset);
|
|
|
|
group('AppContext', () {
|
|
test('error', () async {
|
|
final BufferLogger mockLogger = BufferLogger();
|
|
final VerboseLogger verboseLogger = VerboseLogger(mockLogger);
|
|
verboseLogger.supportsColor = false;
|
|
|
|
verboseLogger.printStatus('Hey Hey Hey Hey');
|
|
verboseLogger.printTrace('Oooh, I do I do I do');
|
|
verboseLogger.printError('Helpless!');
|
|
|
|
expect(mockLogger.statusText, matches(r'^\[ (?: {0,2}\+[0-9]{1,3} ms| )\] Hey Hey Hey Hey\n'
|
|
r'\[ (?: {0,2}\+[0-9]{1,3} ms| )\] Oooh, I do I do I do\n$'));
|
|
expect(mockLogger.traceText, '');
|
|
expect(mockLogger.errorText, matches( r'^\[ (?: {0,2}\+[0-9]{1,3} ms| )\] Helpless!\n$'));
|
|
});
|
|
|
|
test('ANSI colored errors', () async {
|
|
final BufferLogger mockLogger = BufferLogger();
|
|
final VerboseLogger verboseLogger = VerboseLogger(mockLogger);
|
|
verboseLogger.supportsColor = true;
|
|
|
|
verboseLogger.printStatus('Hey Hey Hey Hey');
|
|
verboseLogger.printTrace('Oooh, I do I do I do');
|
|
verboseLogger.printError('Helpless!');
|
|
|
|
expect(
|
|
mockLogger.statusText,
|
|
matches(r'^\[ (?: {0,2}\+[0-9]{1,3} ms| )\] ' '${bold}Hey Hey Hey Hey$reset'
|
|
r'\n\[ (?: {0,2}\+[0-9]{1,3} ms| )\] Oooh, I do I do I do\n$'));
|
|
expect(mockLogger.traceText, '');
|
|
expect(
|
|
mockLogger.errorText,
|
|
matches('^$red' r'\[ (?: {0,2}\+[0-9]{1,3} ms| )\] ' '${bold}Helpless!$reset$reset' r'\n$'));
|
|
});
|
|
});
|
|
|
|
group('Spinners', () {
|
|
MockStdio mockStdio;
|
|
AnsiSpinner ansiSpinner;
|
|
AnsiStatus ansiStatus;
|
|
SummaryStatus summaryStatus;
|
|
int called;
|
|
const List<String> testPlatforms = <String>['linux', 'macos', 'windows', 'fuchsia'];
|
|
final RegExp secondDigits = RegExp(r'[^\b]\b\b\b\b\b[0-9]+[.][0-9]+(?:s|ms)');
|
|
|
|
setUp(() {
|
|
mockStdio = MockStdio();
|
|
ansiSpinner = AnsiSpinner();
|
|
called = 0;
|
|
ansiStatus = AnsiStatus(
|
|
message: 'Hello world',
|
|
expectSlowOperation: true,
|
|
padding: 20,
|
|
onFinish: () => called++,
|
|
);
|
|
summaryStatus = SummaryStatus(
|
|
message: 'Hello world',
|
|
expectSlowOperation: true,
|
|
padding: 20,
|
|
onFinish: () => called++,
|
|
);
|
|
});
|
|
|
|
List<String> outputStdout() => mockStdio.writtenToStdout.join('').split('\n');
|
|
List<String> outputStderr() => mockStdio.writtenToStderr.join('').split('\n');
|
|
|
|
Future<void> doWhileAsync(bool doThis()) async {
|
|
return Future.doWhile(() {
|
|
// We want to let other tasks run at the same time, so we schedule these
|
|
// using a timer rather than a microtask.
|
|
return Future<bool>.delayed(Duration.zero, doThis);
|
|
});
|
|
}
|
|
|
|
for (String testOs in testPlatforms) {
|
|
testUsingContext('AnsiSpinner works for $testOs', () async {
|
|
ansiSpinner.start();
|
|
await doWhileAsync(() => ansiSpinner.ticks < 10);
|
|
List<String> lines = outputStdout();
|
|
expect(lines[0], startsWith(platform.isWindows
|
|
? ' \b-\b\\\b|\b/\b-\b\\\b|\b/'
|
|
: ' \b⣾\b⣽\b⣻\b⢿\b⡿\b⣟\b⣯\b⣷\b⣾\b⣽'));
|
|
expect(lines[0].endsWith('\n'), isFalse);
|
|
expect(lines.length, equals(1));
|
|
ansiSpinner.stop();
|
|
lines = outputStdout();
|
|
expect(lines[0], endsWith('\b \b'));
|
|
expect(lines.length, equals(1));
|
|
|
|
// Verify that stopping or canceling multiple times throws.
|
|
expect(() {
|
|
ansiSpinner.stop();
|
|
}, throwsA(isInstanceOf<AssertionError>()));
|
|
expect(() {
|
|
ansiSpinner.cancel();
|
|
}, throwsA(isInstanceOf<AssertionError>()));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Platform: () => FakePlatform(operatingSystem: testOs),
|
|
});
|
|
|
|
testUsingContext('Stdout startProgress handle null inputs on colored terminal for $testOs', () async {
|
|
context[Logger].startProgress(null, progressId: null,
|
|
expectSlowOperation: null,
|
|
progressIndicatorPadding: null,
|
|
);
|
|
final List<String> lines = outputStdout();
|
|
expect(outputStderr().length, equals(1));
|
|
expect(outputStderr().first, isEmpty);
|
|
expect(lines[0], matches(platform.isWindows ? r'[ ]{64} [\b]-' : r'[ ]{64} [\b]⣾'));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Platform: () => FakePlatform(operatingSystem: testOs),
|
|
Logger: () => StdoutLogger()..supportsColor = true,
|
|
});
|
|
|
|
testUsingContext('AnsiStatus works when cancelled for $testOs', () async {
|
|
ansiStatus.start();
|
|
await doWhileAsync(() => ansiStatus.ticks < 10);
|
|
List<String> lines = outputStdout();
|
|
expect(lines[0], startsWith(platform.isWindows
|
|
? 'Hello world \b-\b\\\b|\b/\b-\b\\\b|\b/'
|
|
: 'Hello world \b⣾\b⣽\b⣻\b⢿\b⡿\b⣟\b⣯\b⣷\b⣾\b⣽'));
|
|
expect(lines.length, equals(1));
|
|
expect(lines[0].endsWith('\n'), isFalse);
|
|
|
|
// Verify a cancel does _not_ print the time and prints a newline.
|
|
ansiStatus.cancel();
|
|
lines = outputStdout();
|
|
final List<Match> matches = secondDigits.allMatches(lines[0]).toList();
|
|
expect(matches, isEmpty);
|
|
expect(lines[0], endsWith('\b \b'));
|
|
expect(called, equals(1));
|
|
expect(lines.length, equals(2));
|
|
expect(lines[1], equals(''));
|
|
|
|
// Verify that stopping or canceling multiple times throws.
|
|
expect(() { ansiStatus.cancel(); }, throwsA(isInstanceOf<AssertionError>()));
|
|
expect(() { ansiStatus.stop(); }, throwsA(isInstanceOf<AssertionError>()));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Platform: () => FakePlatform(operatingSystem: testOs),
|
|
});
|
|
|
|
testUsingContext('AnsiStatus works when stopped for $testOs', () async {
|
|
ansiStatus.start();
|
|
await doWhileAsync(() => ansiStatus.ticks < 10);
|
|
List<String> lines = outputStdout();
|
|
expect(lines[0], startsWith(platform.isWindows
|
|
? 'Hello world \b-\b\\\b|\b/\b-\b\\\b|\b/'
|
|
: 'Hello world \b⣾\b⣽\b⣻\b⢿\b⡿\b⣟\b⣯\b⣷\b⣾\b⣽'));
|
|
expect(lines.length, equals(1));
|
|
|
|
// Verify a stop prints the time.
|
|
ansiStatus.stop();
|
|
lines = outputStdout();
|
|
final List<Match> matches = secondDigits.allMatches(lines[0]).toList();
|
|
expect(matches, isNotNull);
|
|
expect(matches, hasLength(1));
|
|
final Match match = matches.first;
|
|
expect(lines[0], endsWith(match.group(0)));
|
|
expect(called, equals(1));
|
|
expect(lines.length, equals(2));
|
|
expect(lines[1], equals(''));
|
|
|
|
// Verify that stopping or canceling multiple times throws.
|
|
expect(() { ansiStatus.stop(); }, throwsA(isInstanceOf<AssertionError>()));
|
|
expect(() { ansiStatus.cancel(); }, throwsA(isInstanceOf<AssertionError>()));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Platform: () => FakePlatform(operatingSystem: testOs),
|
|
});
|
|
}
|
|
|
|
testUsingContext('Error logs are red', () async {
|
|
context[Logger].printError('Pants on fire!');
|
|
final List<String> lines = outputStderr();
|
|
expect(outputStdout().length, equals(1));
|
|
expect(outputStdout().first, isEmpty);
|
|
expect(lines[0], equals('${AnsiTerminal.red}Pants on fire!${AnsiTerminal.reset}'));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Logger: () => StdoutLogger()..supportsColor = true,
|
|
});
|
|
|
|
testUsingContext('Stdout logs are not colored', () async {
|
|
context[Logger].printStatus('All good.');
|
|
final List<String> lines = outputStdout();
|
|
expect(outputStderr().length, equals(1));
|
|
expect(outputStderr().first, isEmpty);
|
|
expect(lines[0], equals('All good.'));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Logger: () => StdoutLogger()..supportsColor = true,
|
|
});
|
|
|
|
testUsingContext('Stdout printStatus handle null inputs on colored terminal', () async {
|
|
context[Logger].printStatus(null, emphasis: null,
|
|
color: null,
|
|
newline: null,
|
|
indent: null);
|
|
final List<String> lines = outputStdout();
|
|
expect(outputStderr().length, equals(1));
|
|
expect(outputStderr().first, isEmpty);
|
|
expect(lines[0], equals(''));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Logger: () => StdoutLogger()..supportsColor = true,
|
|
});
|
|
|
|
testUsingContext('Stdout printStatus handle null inputs on regular terminal', () async {
|
|
context[Logger].printStatus(null, emphasis: null,
|
|
color: null,
|
|
newline: null,
|
|
indent: null);
|
|
final List<String> lines = outputStdout();
|
|
expect(outputStderr().length, equals(1));
|
|
expect(outputStderr().first, isEmpty);
|
|
expect(lines[0], equals(''));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Logger: () => StdoutLogger()..supportsColor = false,
|
|
});
|
|
|
|
testUsingContext('Stdout startProgress handle null inputs on regular terminal', () async {
|
|
context[Logger].startProgress(null, progressId: null,
|
|
expectSlowOperation: null,
|
|
progressIndicatorPadding: null,
|
|
);
|
|
final List<String> lines = outputStdout();
|
|
expect(outputStderr().length, equals(1));
|
|
expect(outputStderr().first, isEmpty);
|
|
expect(lines[0], matches('[ ]{64}'));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Logger: () => StdoutLogger()..supportsColor = false,
|
|
});
|
|
|
|
testUsingContext('SummaryStatus works when cancelled', () async {
|
|
summaryStatus.start();
|
|
List<String> lines = outputStdout();
|
|
expect(lines[0], startsWith('Hello world '));
|
|
expect(lines.length, equals(1));
|
|
expect(lines[0].endsWith('\n'), isFalse);
|
|
|
|
// Verify a cancel does _not_ print the time and prints a newline.
|
|
summaryStatus.cancel();
|
|
lines = outputStdout();
|
|
final List<Match> matches = secondDigits.allMatches(lines[0]).toList();
|
|
expect(matches, isEmpty);
|
|
expect(lines[0], endsWith(' '));
|
|
expect(called, equals(1));
|
|
expect(lines.length, equals(2));
|
|
expect(lines[1], equals(''));
|
|
|
|
// Verify that stopping or canceling multiple times throws.
|
|
expect(() { summaryStatus.cancel(); }, throwsA(isInstanceOf<AssertionError>()));
|
|
expect(() { summaryStatus.stop(); }, throwsA(isInstanceOf<AssertionError>()));
|
|
}, overrides: <Type, Generator>{Stdio: () => mockStdio});
|
|
|
|
testUsingContext('SummaryStatus works when stopped', () async {
|
|
summaryStatus.start();
|
|
List<String> lines = outputStdout();
|
|
expect(lines[0], startsWith('Hello world '));
|
|
expect(lines.length, equals(1));
|
|
|
|
// Verify a stop prints the time.
|
|
summaryStatus.stop();
|
|
lines = outputStdout();
|
|
final List<Match> matches = secondDigits.allMatches(lines[0]).toList();
|
|
expect(matches, isNotNull);
|
|
expect(matches, hasLength(1));
|
|
final Match match = matches.first;
|
|
expect(lines[0], endsWith(match.group(0)));
|
|
expect(called, equals(1));
|
|
expect(lines.length, equals(2));
|
|
expect(lines[1], equals(''));
|
|
|
|
// Verify that stopping or canceling multiple times throws.
|
|
expect(() { summaryStatus.stop(); }, throwsA(isInstanceOf<AssertionError>()));
|
|
expect(() { summaryStatus.cancel(); }, throwsA(isInstanceOf<AssertionError>()));
|
|
}, overrides: <Type, Generator>{Stdio: () => mockStdio});
|
|
|
|
testUsingContext('sequential startProgress calls with StdoutLogger', () async {
|
|
context[Logger].startProgress('AAA')..stop();
|
|
context[Logger].startProgress('BBB')..stop();
|
|
expect(outputStdout().length, equals(3));
|
|
expect(outputStdout()[0], matches(RegExp(r'AAA[ ]{60}[\d ]{3}[\d]ms')));
|
|
expect(outputStdout()[1], matches(RegExp(r'BBB[ ]{60}[\d ]{3}[\d]ms')));
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Logger: () => StdoutLogger()..supportsColor = false,
|
|
});
|
|
|
|
testUsingContext('sequential startProgress calls with VerboseLogger and StdoutLogger', () async {
|
|
context[Logger].startProgress('AAA')..stop();
|
|
context[Logger].startProgress('BBB')..stop();
|
|
expect(outputStdout(), <Matcher>[
|
|
matches(r'^\[ (?: {0,2}\+[0-9]{1,3} ms| )\] AAA$'),
|
|
matches(r'^\[ (?: {0,2}\+[0-9]{1,3} ms| )\] AAA \(completed\)$'),
|
|
matches(r'^\[ (?: {0,2}\+[0-9]{1,3} ms| )\] BBB$'),
|
|
matches(r'^\[ (?: {0,2}\+[0-9]{1,3} ms| )\] BBB \(completed\)$'),
|
|
matches(r'^$'),
|
|
]);
|
|
}, overrides: <Type, Generator>{
|
|
Stdio: () => mockStdio,
|
|
Logger: () => VerboseLogger(StdoutLogger()),
|
|
});
|
|
|
|
testUsingContext('sequential startProgress calls with BufferLogger', () async {
|
|
context[Logger].startProgress('AAA')..stop();
|
|
context[Logger].startProgress('BBB')..stop();
|
|
final BufferLogger logger = context[Logger];
|
|
expect(logger.statusText, 'AAA\nBBB\n');
|
|
}, overrides: <Type, Generator>{
|
|
Logger: () => BufferLogger(),
|
|
});
|
|
});
|
|
}
|