mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
[flutter_tools] Print emojis in Windows Terminal (#50446)
This commit is contained in:
parent
5f4658973b
commit
c23d9cd4ce
|
@ -36,58 +36,122 @@ class CommandHelp {
|
|||
final OutputPreferences _outputPreferences;
|
||||
|
||||
CommandHelpOption _L;
|
||||
CommandHelpOption get L => _L ??= _makeOption('L', 'Dump layer tree to the console.', 'debugDumpLayerTree');
|
||||
CommandHelpOption get L => _L ??= _makeOption(
|
||||
'L',
|
||||
'Dump layer tree to the console.',
|
||||
'debugDumpLayerTree',
|
||||
);
|
||||
|
||||
CommandHelpOption _P;
|
||||
CommandHelpOption get P => _P ??= _makeOption('P', 'Toggle performance overlay.', 'WidgetsApp.showPerformanceOverlay');
|
||||
CommandHelpOption get P => _P ??= _makeOption(
|
||||
'P',
|
||||
'Toggle performance overlay.',
|
||||
'WidgetsApp.showPerformanceOverlay',
|
||||
);
|
||||
|
||||
CommandHelpOption _R;
|
||||
CommandHelpOption get R => _R ??= _makeOption('R', 'Hot restart.');
|
||||
CommandHelpOption get R => _R ??= _makeOption(
|
||||
'R',
|
||||
'Hot restart.',
|
||||
);
|
||||
|
||||
CommandHelpOption _S;
|
||||
CommandHelpOption get S => _S ??= _makeOption('S', 'Dump accessibility tree in traversal order.', 'debugDumpSemantics');
|
||||
CommandHelpOption get S => _S ??= _makeOption(
|
||||
'S',
|
||||
'Dump accessibility tree in traversal order.',
|
||||
'debugDumpSemantics',
|
||||
);
|
||||
|
||||
CommandHelpOption _U;
|
||||
CommandHelpOption get U => _U ??= _makeOption('U', 'Dump accessibility tree in inverse hit test order.', 'debugDumpSemantics');
|
||||
CommandHelpOption get U => _U ??= _makeOption(
|
||||
'U',
|
||||
'Dump accessibility tree in inverse hit test order.',
|
||||
'debugDumpSemantics',
|
||||
);
|
||||
|
||||
CommandHelpOption _a;
|
||||
CommandHelpOption get a => _a ??= _makeOption('a', 'Toggle timeline events for all widget build methods.', 'debugProfileWidgetBuilds');
|
||||
CommandHelpOption get a => _a ??= _makeOption(
|
||||
'a',
|
||||
'Toggle timeline events for all widget build methods.',
|
||||
'debugProfileWidgetBuilds',
|
||||
);
|
||||
|
||||
CommandHelpOption _c;
|
||||
CommandHelpOption get c => _c ??= _makeOption('c', 'Clear the screen');
|
||||
CommandHelpOption get c => _c ??= _makeOption(
|
||||
'c',
|
||||
'Clear the screen',
|
||||
);
|
||||
|
||||
CommandHelpOption _d;
|
||||
CommandHelpOption get d => _d ??= _makeOption('d', 'Detach (terminate "flutter run" but leave application running).');
|
||||
CommandHelpOption get d => _d ??= _makeOption(
|
||||
'd',
|
||||
'Detach (terminate "flutter run" but leave application running).',
|
||||
);
|
||||
|
||||
CommandHelpOption _h;
|
||||
CommandHelpOption get h => _h ??= _makeOption('h', 'Repeat this help message.');
|
||||
CommandHelpOption get h => _h ??= _makeOption(
|
||||
'h',
|
||||
'Repeat this help message.',
|
||||
);
|
||||
|
||||
CommandHelpOption _i;
|
||||
CommandHelpOption get i => _i ??= _makeOption('i', 'Toggle widget inspector.', 'WidgetsApp.showWidgetInspectorOverride');
|
||||
CommandHelpOption get i => _i ??= _makeOption(
|
||||
'i',
|
||||
'Toggle widget inspector.',
|
||||
'WidgetsApp.showWidgetInspectorOverride',
|
||||
);
|
||||
|
||||
CommandHelpOption _o;
|
||||
CommandHelpOption get o => _o ??= _makeOption('o', 'Simulate different operating systems.', 'defaultTargetPlatform');
|
||||
CommandHelpOption get o => _o ??= _makeOption(
|
||||
'o',
|
||||
'Simulate different operating systems.',
|
||||
'defaultTargetPlatform',
|
||||
);
|
||||
|
||||
CommandHelpOption _p;
|
||||
CommandHelpOption get p => _p ??= _makeOption('p', 'Toggle the display of construction lines.', 'debugPaintSizeEnabled');
|
||||
CommandHelpOption get p => _p ??= _makeOption(
|
||||
'p',
|
||||
'Toggle the display of construction lines.',
|
||||
'debugPaintSizeEnabled',
|
||||
);
|
||||
|
||||
CommandHelpOption _q;
|
||||
CommandHelpOption get q => _q ??= _makeOption('q', 'Quit (terminate the application on the device).');
|
||||
CommandHelpOption get q => _q ??= _makeOption(
|
||||
'q',
|
||||
'Quit (terminate the application on the device).',
|
||||
);
|
||||
|
||||
CommandHelpOption _r;
|
||||
CommandHelpOption get r => _r ??= _makeOption('r', 'Hot reload. $fire$fire$fire');
|
||||
CommandHelpOption get r => _r ??= _makeOption(
|
||||
'r',
|
||||
'Hot reload. $fire$fire$fire',
|
||||
);
|
||||
|
||||
CommandHelpOption _s;
|
||||
CommandHelpOption get s => _s ??= _makeOption('s', 'Save a screenshot to flutter.png.');
|
||||
CommandHelpOption get s => _s ??= _makeOption(
|
||||
's',
|
||||
'Save a screenshot to flutter.png.',
|
||||
);
|
||||
|
||||
CommandHelpOption _t;
|
||||
CommandHelpOption get t => _t ??= _makeOption('t', 'Dump rendering tree to the console.', 'debugDumpRenderTree');
|
||||
CommandHelpOption get t => _t ??= _makeOption(
|
||||
't',
|
||||
'Dump rendering tree to the console.',
|
||||
'debugDumpRenderTree',
|
||||
);
|
||||
|
||||
CommandHelpOption _w;
|
||||
CommandHelpOption get w => _w ??= _makeOption('w', 'Dump widget hierarchy to the console.', 'debugDumpApp');
|
||||
CommandHelpOption get w => _w ??= _makeOption(
|
||||
'w',
|
||||
'Dump widget hierarchy to the console.',
|
||||
'debugDumpApp',
|
||||
);
|
||||
|
||||
CommandHelpOption _z;
|
||||
CommandHelpOption get z => _z ??= _makeOption('z', 'Toggle elevation checker.');
|
||||
CommandHelpOption get z => _z ??= _makeOption(
|
||||
'z',
|
||||
'Toggle elevation checker.',
|
||||
);
|
||||
|
||||
CommandHelpOption _makeOption(String key, String description, [
|
||||
String inParenthesis = '',
|
||||
|
@ -142,25 +206,30 @@ class CommandHelpOption {
|
|||
String toString() {
|
||||
final StringBuffer message = StringBuffer();
|
||||
message.writeAll(<String>[_terminal.bolden(key), description], ' ');
|
||||
|
||||
if (_hasTextInParenthesis) {
|
||||
bool wrap = false;
|
||||
final int maxWidth = math.max(_outputPreferences.wrapColumn ?? 0, maxLineWidth);
|
||||
int width = maxWidth - (_platform.stdoutSupportsAnsi ? _rawMessageLength + 1 : message.length);
|
||||
final String parentheticalText = '($inParenthesis)';
|
||||
if (width < parentheticalText.length) {
|
||||
width = maxWidth;
|
||||
wrap = true;
|
||||
}
|
||||
|
||||
if (wrap) {
|
||||
message.write('\n');
|
||||
}
|
||||
// pad according to the raw text
|
||||
message.write(''.padLeft(width - parentheticalText.length));
|
||||
|
||||
message.write(_terminal.color(parentheticalText, TerminalColor.grey));
|
||||
if (!_hasTextInParenthesis) {
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
bool wrap = false;
|
||||
final int maxWidth = math.max(
|
||||
_outputPreferences.wrapColumn ?? 0,
|
||||
maxLineWidth,
|
||||
);
|
||||
final int adjustedMessageLength = _platform.stdoutSupportsAnsi
|
||||
? _rawMessageLength + 1
|
||||
: message.length;
|
||||
int width = maxWidth - adjustedMessageLength;
|
||||
final String parentheticalText = '($inParenthesis)';
|
||||
if (width < parentheticalText.length) {
|
||||
width = maxWidth;
|
||||
wrap = true;
|
||||
}
|
||||
if (wrap) {
|
||||
message.write('\n');
|
||||
}
|
||||
// pad according to the raw text
|
||||
message.write(''.padLeft(width - parentheticalText.length));
|
||||
message.write(_terminal.color(parentheticalText, TerminalColor.grey));
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
import '../base/context.dart';
|
||||
import '../globals.dart' as globals;
|
||||
|
@ -179,15 +178,13 @@ class StdoutLogger extends Logger {
|
|||
@required Stdio stdio,
|
||||
@required OutputPreferences outputPreferences,
|
||||
@required TimeoutConfiguration timeoutConfiguration,
|
||||
@required Platform platform,
|
||||
StopwatchFactory stopwatchFactory = const StopwatchFactory(),
|
||||
})
|
||||
: _stdio = stdio,
|
||||
_terminal = terminal,
|
||||
_timeoutConfiguration = timeoutConfiguration,
|
||||
_outputPreferences = outputPreferences,
|
||||
_stopwatchFactory = stopwatchFactory,
|
||||
_platform = platform;
|
||||
_stopwatchFactory = stopwatchFactory;
|
||||
|
||||
@override
|
||||
final AnsiTerminal _terminal;
|
||||
|
@ -197,7 +194,6 @@ class StdoutLogger extends Logger {
|
|||
final TimeoutConfiguration _timeoutConfiguration;
|
||||
final Stdio _stdio;
|
||||
final StopwatchFactory _stopwatchFactory;
|
||||
final Platform _platform;
|
||||
|
||||
Status _status;
|
||||
|
||||
|
@ -306,8 +302,8 @@ class StdoutLogger extends Logger {
|
|||
onFinish: _clearStatus,
|
||||
stdio: _stdio,
|
||||
timeoutConfiguration: _timeoutConfiguration,
|
||||
platform: _platform,
|
||||
stopwatch: _stopwatchFactory.createStopwatch(),
|
||||
terminal: _terminal,
|
||||
)..start();
|
||||
} else {
|
||||
_status = SummaryStatus(
|
||||
|
@ -352,7 +348,6 @@ class WindowsStdoutLogger extends StdoutLogger {
|
|||
@required Stdio stdio,
|
||||
@required OutputPreferences outputPreferences,
|
||||
@required TimeoutConfiguration timeoutConfiguration,
|
||||
@required Platform platform,
|
||||
StopwatchFactory stopwatchFactory = const StopwatchFactory(),
|
||||
}) : super(
|
||||
terminal: terminal,
|
||||
|
@ -360,15 +355,16 @@ class WindowsStdoutLogger extends StdoutLogger {
|
|||
outputPreferences: outputPreferences,
|
||||
timeoutConfiguration: timeoutConfiguration,
|
||||
stopwatchFactory: stopwatchFactory,
|
||||
platform: platform,
|
||||
);
|
||||
|
||||
@override
|
||||
void writeToStdOut(String message) {
|
||||
// TODO(jcollins-g): wrong abstraction layer for this, move to [Stdio].
|
||||
final String windowsMessage = message
|
||||
.replaceAll('✗', 'X')
|
||||
.replaceAll('✓', '√');
|
||||
final String windowsMessage = _terminal.supportsEmoji
|
||||
? message
|
||||
: message.replaceAll('🔥', '')
|
||||
.replaceAll('✗', 'X')
|
||||
.replaceAll('✓', '√');
|
||||
_stdio.stdoutWrite(windowsMessage);
|
||||
}
|
||||
}
|
||||
|
@ -681,19 +677,18 @@ abstract class Status {
|
|||
@required Duration timeout,
|
||||
@required TimeoutConfiguration timeoutConfiguration,
|
||||
@required Stopwatch stopwatch,
|
||||
@required bool supportsColor,
|
||||
@required Platform platform,
|
||||
@required AnsiTerminal terminal,
|
||||
VoidCallback onFinish,
|
||||
SlowWarningCallback slowWarningCallback,
|
||||
}) {
|
||||
if (supportsColor) {
|
||||
if (terminal.supportsColor) {
|
||||
return AnsiSpinner(
|
||||
timeout: timeout,
|
||||
onFinish: onFinish,
|
||||
slowWarningCallback: slowWarningCallback,
|
||||
timeoutConfiguration: timeoutConfiguration,
|
||||
stopwatch: stopwatch,
|
||||
platform: platform,
|
||||
terminal: terminal,
|
||||
)..start();
|
||||
}
|
||||
return SilentStatus(
|
||||
|
@ -862,12 +857,12 @@ class AnsiSpinner extends Status {
|
|||
@required Duration timeout,
|
||||
@required TimeoutConfiguration timeoutConfiguration,
|
||||
@required Stopwatch stopwatch,
|
||||
@required Platform platform,
|
||||
@required AnsiTerminal terminal,
|
||||
VoidCallback onFinish,
|
||||
this.slowWarningCallback,
|
||||
Stdio stdio,
|
||||
}) : _stdio = stdio ?? globals.stdio,
|
||||
_isWindows = platform.isWindows,
|
||||
_terminal = terminal,
|
||||
super(
|
||||
timeout: timeout,
|
||||
onFinish: onFinish,
|
||||
|
@ -878,7 +873,7 @@ class AnsiSpinner extends Status {
|
|||
final String _backspaceChar = '\b';
|
||||
final String _clearChar = ' ';
|
||||
final Stdio _stdio;
|
||||
final bool _isWindows;
|
||||
final AnsiTerminal _terminal;
|
||||
|
||||
bool timedOut = false;
|
||||
|
||||
|
@ -886,7 +881,7 @@ class AnsiSpinner extends Status {
|
|||
Timer timer;
|
||||
|
||||
// Windows console font has a limited set of Unicode characters.
|
||||
List<String> get _animation => _isWindows
|
||||
List<String> get _animation => !_terminal.supportsEmoji
|
||||
? const <String>[r'-', r'\', r'|', r'/']
|
||||
: const <String>['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
|
||||
|
||||
|
@ -984,7 +979,7 @@ class AnsiStatus extends AnsiSpinner {
|
|||
this.padding = kDefaultStatusPadding,
|
||||
@required Duration timeout,
|
||||
@required Stopwatch stopwatch,
|
||||
@required Platform platform,
|
||||
@required AnsiTerminal terminal,
|
||||
VoidCallback onFinish,
|
||||
Stdio stdio,
|
||||
TimeoutConfiguration timeoutConfiguration,
|
||||
|
@ -997,7 +992,7 @@ class AnsiStatus extends AnsiSpinner {
|
|||
stdio: stdio,
|
||||
timeoutConfiguration: timeoutConfiguration,
|
||||
stopwatch: stopwatch,
|
||||
platform: platform,
|
||||
terminal: terminal,
|
||||
);
|
||||
|
||||
final String message;
|
||||
|
|
|
@ -86,7 +86,10 @@ class OutputPreferences {
|
|||
}
|
||||
|
||||
class AnsiTerminal {
|
||||
AnsiTerminal({@required io.Stdio stdio, @required Platform platform})
|
||||
AnsiTerminal({
|
||||
@required io.Stdio stdio,
|
||||
@required Platform platform,
|
||||
})
|
||||
: _stdio = stdio,
|
||||
_platform = platform;
|
||||
|
||||
|
@ -121,7 +124,16 @@ class AnsiTerminal {
|
|||
|
||||
bool get supportsColor => _platform.stdoutSupportsAnsi ?? false;
|
||||
|
||||
final RegExp _boldControls = RegExp('(${RegExp.escape(resetBold)}|${RegExp.escape(bold)})');
|
||||
// Assume unicode emojis are supported when not on Windows.
|
||||
// If we are on Windows, unicode emojis are supported in Windows Terminal,
|
||||
// which sets the WT_SESSION environment variable. See:
|
||||
// https://github.com/microsoft/terminal/blob/master/doc/user-docs/index.md#tips-and-tricks
|
||||
bool get supportsEmoji => !_platform.isWindows
|
||||
|| _platform.environment.containsKey('WT_SESSION');
|
||||
|
||||
final RegExp _boldControls = RegExp(
|
||||
'(${RegExp.escape(resetBold)}|${RegExp.escape(bold)})',
|
||||
);
|
||||
|
||||
/// Whether we are interacting with the flutter tool via the terminal.
|
||||
///
|
||||
|
|
|
@ -127,14 +127,12 @@ Future<T> runInContext<T>(
|
|||
stdio: globals.stdio,
|
||||
outputPreferences: outputPreferences,
|
||||
timeoutConfiguration: timeoutConfiguration,
|
||||
platform: globals.platform,
|
||||
)
|
||||
: StdoutLogger(
|
||||
terminal: globals.terminal,
|
||||
stdio: globals.stdio,
|
||||
outputPreferences: outputPreferences,
|
||||
timeoutConfiguration: timeoutConfiguration,
|
||||
platform: globals.platform,
|
||||
),
|
||||
MacOSWorkflow: () => const MacOSWorkflow(),
|
||||
MDnsObservatoryDiscovery: () => MDnsObservatoryDiscovery(),
|
||||
|
|
|
@ -258,8 +258,7 @@ class Doctor {
|
|||
slowWarningCallback: () => validator.slowWarning,
|
||||
timeoutConfiguration: timeoutConfiguration,
|
||||
stopwatch: Stopwatch(),
|
||||
supportsColor: globals.terminal.supportsColor,
|
||||
platform: globals.platform,
|
||||
terminal: globals.terminal,
|
||||
);
|
||||
ValidationResult result;
|
||||
try {
|
||||
|
|
|
@ -314,9 +314,8 @@ class XcodeProjectInterpreter {
|
|||
final Status status = Status.withSpinner(
|
||||
timeout: const TimeoutConfiguration().fastOperation,
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: _platform,
|
||||
stopwatch: Stopwatch(),
|
||||
supportsColor: _terminal.supportsColor,
|
||||
terminal: _terminal,
|
||||
);
|
||||
final List<String> showBuildSettingsCommand = <String>[
|
||||
_executable,
|
||||
|
|
|
@ -112,7 +112,6 @@ void main() {
|
|||
stdio: stdio,
|
||||
outputPreferences: OutputPreferences.test(),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printStatus('message');
|
||||
logger.printError('error message');
|
||||
|
@ -125,7 +124,33 @@ void main() {
|
|||
FakeStopwatch mockStopwatch;
|
||||
FakeStopwatchFactory stopwatchFactory;
|
||||
int called;
|
||||
const List<String> testPlatforms = <String>['linux', 'macos', 'windows', 'fuchsia'];
|
||||
final List<Platform> testPlatforms = <Platform>[
|
||||
FakePlatform(
|
||||
operatingSystem: 'linux',
|
||||
environment: <String, String>{},
|
||||
executableArguments: <String>[],
|
||||
),
|
||||
FakePlatform(
|
||||
operatingSystem: 'macos',
|
||||
environment: <String, String>{},
|
||||
executableArguments: <String>[],
|
||||
),
|
||||
FakePlatform(
|
||||
operatingSystem: 'windows',
|
||||
environment: <String, String>{},
|
||||
executableArguments: <String>[],
|
||||
),
|
||||
FakePlatform(
|
||||
operatingSystem: 'windows',
|
||||
environment: <String, String>{'WT_SESSION': ''},
|
||||
executableArguments: <String>[],
|
||||
),
|
||||
FakePlatform(
|
||||
operatingSystem: 'fuchsia',
|
||||
environment: <String, String>{},
|
||||
executableArguments: <String>[],
|
||||
),
|
||||
];
|
||||
final RegExp secondDigits = RegExp(r'[0-9,.]*[0-9]m?s');
|
||||
|
||||
setUp(() {
|
||||
|
@ -145,278 +170,297 @@ void main() {
|
|||
} while (doThis());
|
||||
}
|
||||
|
||||
for (final String testOs in testPlatforms) {
|
||||
Platform currentPlatform() => FakePlatform(operatingSystem: testOs);
|
||||
for (final Platform testPlatform in testPlatforms) {
|
||||
group('(${testPlatform.operatingSystem})', () {
|
||||
Platform platform;
|
||||
Platform ansiPlatform;
|
||||
AnsiTerminal terminal;
|
||||
AnsiTerminal coloredTerminal;
|
||||
AnsiStatus ansiStatus;
|
||||
|
||||
AnsiStatus createAnsiStatus() {
|
||||
return AnsiStatus(
|
||||
message: 'Hello world',
|
||||
timeout: const Duration(seconds: 2),
|
||||
padding: 20,
|
||||
onFinish: () => called += 1,
|
||||
stdio: mockStdio,
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
stopwatch: stopwatchFactory.createStopwatch(),
|
||||
platform: currentPlatform(),
|
||||
);
|
||||
}
|
||||
testWithoutContext('AnsiSpinner works for $testOs (1)', () async {
|
||||
bool done = false;
|
||||
mockStopwatch = FakeStopwatch();
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
final AnsiSpinner ansiSpinner = AnsiSpinner(
|
||||
timeout: const Duration(hours: 10),
|
||||
setUp(() {
|
||||
platform = FakePlatform.fromPlatform(testPlatform)..stdoutSupportsAnsi = false;
|
||||
ansiPlatform = FakePlatform.fromPlatform(testPlatform)..stdoutSupportsAnsi = true;
|
||||
|
||||
terminal = AnsiTerminal(
|
||||
stdio: mockStdio,
|
||||
platform: platform,
|
||||
);
|
||||
coloredTerminal = AnsiTerminal(
|
||||
stdio: mockStdio,
|
||||
platform: ansiPlatform,
|
||||
);
|
||||
|
||||
ansiStatus = AnsiStatus(
|
||||
message: 'Hello world',
|
||||
timeout: const Duration(seconds: 2),
|
||||
padding: 20,
|
||||
onFinish: () => called += 1,
|
||||
stdio: mockStdio,
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
stopwatch: stopwatchFactory.createStopwatch(),
|
||||
platform: currentPlatform(),
|
||||
)..start();
|
||||
doWhileAsync(time, () => ansiSpinner.ticks < 10);
|
||||
List<String> lines = outputStdout();
|
||||
expect(lines[0], startsWith(
|
||||
currentPlatform().isWindows
|
||||
? ' \b\\\b|\b/\b-\b\\\b|\b/\b-'
|
||||
: ' \b⣽\b⣻\b⢿\b⡿\b⣟\b⣯\b⣷\b⣾\b⣽\b⣻'
|
||||
),
|
||||
terminal: terminal,
|
||||
);
|
||||
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, throwsAssertionError);
|
||||
expect(ansiSpinner.cancel, throwsAssertionError);
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
|
||||
testWithoutContext('AnsiSpinner works for $testOs (2)', () async {
|
||||
bool done = false;
|
||||
mockStopwatch = FakeStopwatch();
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
final AnsiSpinner ansiSpinner = AnsiSpinner(
|
||||
timeout: const Duration(seconds: 2),
|
||||
stdio: mockStdio,
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
stopwatch: mockStopwatch,
|
||||
platform: FakePlatform(operatingSystem: testOs),
|
||||
)..start();
|
||||
mockStopwatch.elapsed = const Duration(seconds: 1);
|
||||
doWhileAsync(time, () => ansiSpinner.ticks < 10); // one second
|
||||
|
||||
expect(ansiSpinner.seemsSlow, isFalse);
|
||||
expect(outputStdout().join('\n'), isNot(contains('This is taking an unexpectedly long time.')));
|
||||
mockStopwatch.elapsed = const Duration(seconds: 3);
|
||||
doWhileAsync(time, () => ansiSpinner.ticks < 30); // three seconds
|
||||
|
||||
expect(ansiSpinner.seemsSlow, isTrue);
|
||||
// Check the 2nd line to verify there's a newline before the warning
|
||||
expect(outputStdout()[1], contains('This is taking an unexpectedly long time.'));
|
||||
ansiSpinner.stop();
|
||||
expect(outputStdout().join('\n'), isNot(contains('(!)')));
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
|
||||
testWithoutContext('Stdout startProgress on colored terminal for $testOs', () async {
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
final Logger logger = StdoutLogger(
|
||||
terminal: AnsiTerminal(
|
||||
testWithoutContext('AnsiSpinner works (1)', () async {
|
||||
bool done = false;
|
||||
mockStopwatch = FakeStopwatch();
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
final AnsiSpinner ansiSpinner = AnsiSpinner(
|
||||
timeout: const Duration(hours: 10),
|
||||
stdio: mockStdio,
|
||||
platform: FakePlatform(operatingSystem: testOs)..stdoutSupportsAnsi = true,
|
||||
),
|
||||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: true),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
stopwatchFactory: stopwatchFactory,
|
||||
platform: currentPlatform(),
|
||||
);
|
||||
final Status status = logger.startProgress(
|
||||
'Hello',
|
||||
progressId: null,
|
||||
timeout: const TimeoutConfiguration().slowOperation,
|
||||
progressIndicatorPadding: 20, // this minus the "Hello" equals the 15 below.
|
||||
);
|
||||
expect(outputStderr().length, equals(1));
|
||||
expect(outputStderr().first, isEmpty);
|
||||
// the 5 below is the margin that is always included between the message and the time.
|
||||
expect(outputStdout().join('\n'),
|
||||
matches(currentPlatform().isWindows ? r'^Hello {15} {5} {8}[\b]{8} {7}\\$' :
|
||||
r'^Hello {15} {5} {8}[\b]{8} {7}⣽$'));
|
||||
status.stop();
|
||||
expect(outputStdout().join('\n'),
|
||||
matches(currentPlatform().isWindows ? r'^Hello {15} {5} {8}[\b]{8} {7}\\[\b]{8} {8}[\b]{8}[\d, ]{4}[\d]\.[\d]s[\n]$' :
|
||||
r'^Hello {15} {5} {8}[\b]{8} {7}⣽[\b]{8} {8}[\b]{8}[\d, ]{4}[\d]\.[\d]s[\n]$'));
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
stopwatch: stopwatchFactory.createStopwatch(),
|
||||
terminal: terminal,
|
||||
)..start();
|
||||
doWhileAsync(time, () => ansiSpinner.ticks < 10);
|
||||
List<String> lines = outputStdout();
|
||||
expect(lines[0], startsWith(
|
||||
terminal.supportsEmoji
|
||||
? ' \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));
|
||||
|
||||
testWithoutContext('Stdout startProgress on colored terminal pauses on $testOs', () async {
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
mockStopwatch.elapsed = const Duration(seconds: 5);
|
||||
final Logger logger = StdoutLogger(
|
||||
terminal: AnsiTerminal(
|
||||
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, throwsAssertionError);
|
||||
expect(ansiSpinner.cancel, throwsAssertionError);
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
|
||||
testWithoutContext('AnsiSpinner works (2)', () async {
|
||||
bool done = false;
|
||||
mockStopwatch = FakeStopwatch();
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
final AnsiSpinner ansiSpinner = AnsiSpinner(
|
||||
timeout: const Duration(seconds: 2),
|
||||
stdio: mockStdio,
|
||||
platform: FakePlatform(operatingSystem: testOs)..stdoutSupportsAnsi = true,
|
||||
),
|
||||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: true),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
stopwatchFactory: stopwatchFactory,
|
||||
platform: currentPlatform(),
|
||||
);
|
||||
final Status status = logger.startProgress(
|
||||
'Knock Knock, Who\'s There',
|
||||
timeout: const Duration(days: 10),
|
||||
progressIndicatorPadding: 10,
|
||||
);
|
||||
logger.printStatus('Rude Interrupting Cow');
|
||||
status.stop();
|
||||
final String a = currentPlatform().isWindows ? r'\' : '⣽';
|
||||
final String b = currentPlatform().isWindows ? '|' : '⣻';
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
stopwatch: mockStopwatch,
|
||||
terminal: terminal,
|
||||
)..start();
|
||||
mockStopwatch.elapsed = const Duration(seconds: 1);
|
||||
doWhileAsync(time, () => ansiSpinner.ticks < 10); // one second
|
||||
|
||||
expect(
|
||||
outputStdout().join('\n'),
|
||||
'Knock Knock, Who\'s There ' // initial message
|
||||
' ' // placeholder so that spinner can backspace on its first tick
|
||||
'\b\b\b\b\b\b\b\b $a' // first tick
|
||||
'\b\b\b\b\b\b\b\b ' // clearing the spinner
|
||||
'\b\b\b\b\b\b\b\b' // clearing the clearing of the spinner
|
||||
'\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ' // clearing the message
|
||||
'\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b' // clearing the clearing of the message
|
||||
'Rude Interrupting Cow\n' // message
|
||||
'Knock Knock, Who\'s There ' // message restoration
|
||||
' ' // placeholder so that spinner can backspace on its second tick
|
||||
'\b\b\b\b\b\b\b\b $b' // second tick
|
||||
'\b\b\b\b\b\b\b\b ' // clearing the spinner to put the time
|
||||
'\b\b\b\b\b\b\b\b' // clearing the clearing of the spinner
|
||||
' 5.0s\n', // replacing it with the time
|
||||
);
|
||||
done = true;
|
||||
expect(ansiSpinner.seemsSlow, isFalse);
|
||||
expect(outputStdout().join('\n'), isNot(contains('This is taking an unexpectedly long time.')));
|
||||
mockStopwatch.elapsed = const Duration(seconds: 3);
|
||||
doWhileAsync(time, () => ansiSpinner.ticks < 30); // three seconds
|
||||
|
||||
expect(ansiSpinner.seemsSlow, isTrue);
|
||||
// Check the 2nd line to verify there's a newline before the warning
|
||||
expect(outputStdout()[1], contains('This is taking an unexpectedly long time.'));
|
||||
ansiSpinner.stop();
|
||||
expect(outputStdout().join('\n'), isNot(contains('(!)')));
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
|
||||
testWithoutContext('AnsiStatus works for $testOs', () {
|
||||
final AnsiStatus ansiStatus = createAnsiStatus();
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
ansiStatus.start();
|
||||
mockStopwatch.elapsed = const Duration(seconds: 1);
|
||||
doWhileAsync(time, () => ansiStatus.ticks < 10); // one second
|
||||
testWithoutContext('Stdout startProgress on colored terminal', () async {
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
final Logger logger = StdoutLogger(
|
||||
terminal: coloredTerminal,
|
||||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: true),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
stopwatchFactory: stopwatchFactory,
|
||||
);
|
||||
final Status status = logger.startProgress(
|
||||
'Hello',
|
||||
progressId: null,
|
||||
timeout: const TimeoutConfiguration().slowOperation,
|
||||
progressIndicatorPadding: 20, // this minus the "Hello" equals the 15 below.
|
||||
);
|
||||
expect(outputStderr().length, equals(1));
|
||||
expect(outputStderr().first, isEmpty);
|
||||
// the 5 below is the margin that is always included between the message and the time.
|
||||
expect(
|
||||
outputStdout().join('\n'),
|
||||
matches(terminal.supportsEmoji
|
||||
? r'^Hello {15} {5} {8}[\b]{8} {7}⣽$'
|
||||
: r'^Hello {15} {5} {8}[\b]{8} {7}\\$'),
|
||||
);
|
||||
status.stop();
|
||||
expect(
|
||||
outputStdout().join('\n'),
|
||||
matches(
|
||||
terminal.supportsEmoji
|
||||
? r'^Hello {15} {5} {8}[\b]{8} {7}⣽[\b]{8} {8}[\b]{8}[\d, ]{4}[\d]\.[\d]s[\n]$'
|
||||
: r'^Hello {15} {5} {8}[\b]{8} {7}\\[\b]{8} {8}[\b]{8}[\d, ]{4}[\d]\.[\d]s[\n]$',
|
||||
),
|
||||
);
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
|
||||
expect(ansiStatus.seemsSlow, isFalse);
|
||||
expect(outputStdout().join('\n'), isNot(contains('This is taking an unexpectedly long time.')));
|
||||
expect(outputStdout().join('\n'), isNot(contains('(!)')));
|
||||
mockStopwatch.elapsed = const Duration(seconds: 3);
|
||||
doWhileAsync(time, () => ansiStatus.ticks < 30); // three seconds
|
||||
testWithoutContext('Stdout startProgress on colored terminal pauses', () async {
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
mockStopwatch.elapsed = const Duration(seconds: 5);
|
||||
final Logger logger = StdoutLogger(
|
||||
terminal: coloredTerminal,
|
||||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: true),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
stopwatchFactory: stopwatchFactory,
|
||||
);
|
||||
final Status status = logger.startProgress(
|
||||
'Knock Knock, Who\'s There',
|
||||
timeout: const Duration(days: 10),
|
||||
progressIndicatorPadding: 10,
|
||||
);
|
||||
logger.printStatus('Rude Interrupting Cow');
|
||||
status.stop();
|
||||
final String a = terminal.supportsEmoji ? '⣽' : r'\';
|
||||
final String b = terminal.supportsEmoji ? '⣻' : '|';
|
||||
|
||||
expect(ansiStatus.seemsSlow, isTrue);
|
||||
expect(outputStdout().join('\n'), contains('This is taking an unexpectedly long time.'));
|
||||
expect(
|
||||
outputStdout().join('\n'),
|
||||
'Knock Knock, Who\'s There ' // initial message
|
||||
' ' // placeholder so that spinner can backspace on its first tick
|
||||
'\b\b\b\b\b\b\b\b $a' // first tick
|
||||
'\b\b\b\b\b\b\b\b ' // clearing the spinner
|
||||
'\b\b\b\b\b\b\b\b' // clearing the clearing of the spinner
|
||||
'\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b ' // clearing the message
|
||||
'\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b' // clearing the clearing of the message
|
||||
'Rude Interrupting Cow\n' // message
|
||||
'Knock Knock, Who\'s There ' // message restoration
|
||||
' ' // placeholder so that spinner can backspace on its second tick
|
||||
'\b\b\b\b\b\b\b\b $b' // second tick
|
||||
'\b\b\b\b\b\b\b\b ' // clearing the spinner to put the time
|
||||
'\b\b\b\b\b\b\b\b' // clearing the clearing of the spinner
|
||||
' 5.0s\n', // replacing it with the time
|
||||
);
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
|
||||
// Test that the number of '\b' is correct.
|
||||
for (final String line in outputStdout()) {
|
||||
int currLength = 0;
|
||||
for (int i = 0; i < line.length; i += 1) {
|
||||
currLength += line[i] == '\b' ? -1 : 1;
|
||||
expect(currLength, isNonNegative, reason: 'The following line has overflow backtraces:\n' + jsonEncode(line));
|
||||
testWithoutContext('AnsiStatus works', () {
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
ansiStatus.start();
|
||||
mockStopwatch.elapsed = const Duration(seconds: 1);
|
||||
doWhileAsync(time, () => ansiStatus.ticks < 10); // one second
|
||||
|
||||
expect(ansiStatus.seemsSlow, isFalse);
|
||||
expect(outputStdout().join('\n'), isNot(contains('This is taking an unexpectedly long time.')));
|
||||
expect(outputStdout().join('\n'), isNot(contains('(!)')));
|
||||
mockStopwatch.elapsed = const Duration(seconds: 3);
|
||||
doWhileAsync(time, () => ansiStatus.ticks < 30); // three seconds
|
||||
|
||||
expect(ansiStatus.seemsSlow, isTrue);
|
||||
expect(outputStdout().join('\n'), contains('This is taking an unexpectedly long time.'));
|
||||
|
||||
// Test that the number of '\b' is correct.
|
||||
for (final String line in outputStdout()) {
|
||||
int currLength = 0;
|
||||
for (int i = 0; i < line.length; i += 1) {
|
||||
currLength += line[i] == '\b' ? -1 : 1;
|
||||
expect(currLength, isNonNegative, reason: 'The following line has overflow backtraces:\n' + jsonEncode(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ansiStatus.stop();
|
||||
expect(outputStdout().join('\n'), contains('(!)'));
|
||||
done = true;
|
||||
ansiStatus.stop();
|
||||
expect(outputStdout().join('\n'), contains('(!)'));
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
|
||||
testWithoutContext('AnsiStatus works when canceled for $testOs', () async {
|
||||
final AnsiStatus ansiStatus = createAnsiStatus();
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
ansiStatus.start();
|
||||
mockStopwatch.elapsed = const Duration(seconds: 1);
|
||||
doWhileAsync(time, () => ansiStatus.ticks < 10);
|
||||
List<String> lines = outputStdout();
|
||||
testWithoutContext('AnsiStatus works when canceled', () async {
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
ansiStatus.start();
|
||||
mockStopwatch.elapsed = const Duration(seconds: 1);
|
||||
doWhileAsync(time, () => ansiStatus.ticks < 10);
|
||||
List<String> lines = outputStdout();
|
||||
|
||||
expect(lines[0], startsWith(testOs == 'windows'
|
||||
? 'Hello world \b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |\b\b\b\b\b\b\b\b /\b\b\b\b\b\b\b\b -\b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |\b\b\b\b\b\b\b\b /\b\b\b\b\b\b\b\b -\b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |'
|
||||
: 'Hello world \b\b\b\b\b\b\b\b ⣽\b\b\b\b\b\b\b\b ⣻\b\b\b\b\b\b\b\b ⢿\b\b\b\b\b\b\b\b ⡿\b\b\b\b\b\b\b\b ⣟\b\b\b\b\b\b\b\b ⣯\b\b\b\b\b\b\b\b ⣷\b\b\b\b\b\b\b\b ⣾\b\b\b\b\b\b\b\b ⣽\b\b\b\b\b\b\b\b ⣻'));
|
||||
expect(lines.length, equals(1));
|
||||
expect(lines[0].endsWith('\n'), isFalse);
|
||||
expect(lines[0], startsWith(
|
||||
terminal.supportsEmoji
|
||||
? 'Hello world \b\b\b\b\b\b\b\b ⣽\b\b\b\b\b\b\b\b ⣻\b\b\b\b\b\b\b\b ⢿\b\b\b\b\b\b\b\b ⡿\b\b\b\b\b\b\b\b ⣟\b\b\b\b\b\b\b\b ⣯\b\b\b\b\b\b\b\b ⣷\b\b\b\b\b\b\b\b ⣾\b\b\b\b\b\b\b\b ⣽\b\b\b\b\b\b\b\b ⣻'
|
||||
: 'Hello world \b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |\b\b\b\b\b\b\b\b /\b\b\b\b\b\b\b\b -\b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |\b\b\b\b\b\b\b\b /\b\b\b\b\b\b\b\b -\b\b\b\b\b\b\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);
|
||||
final String leading = currentPlatform().isWindows ? '|' : '⣻';
|
||||
// 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);
|
||||
final String leading = terminal.supportsEmoji ? '⣻' : '|';
|
||||
|
||||
expect(lines[0], endsWith('$leading\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b'));
|
||||
expect(called, equals(1));
|
||||
expect(lines.length, equals(2));
|
||||
expect(lines[1], equals(''));
|
||||
expect(lines[0], endsWith('$leading\b\b\b\b\b\b\b\b \b\b\b\b\b\b\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(); }, throwsAssertionError);
|
||||
expect(() { ansiStatus.stop(); }, throwsAssertionError);
|
||||
done = true;
|
||||
// Verify that stopping or canceling multiple times throws.
|
||||
expect(() { ansiStatus.cancel(); }, throwsAssertionError);
|
||||
expect(() { ansiStatus.stop(); }, throwsAssertionError);
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
|
||||
testWithoutContext('AnsiStatus works when stopped for $testOs', () async {
|
||||
final AnsiStatus ansiStatus = createAnsiStatus();
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
ansiStatus.start();
|
||||
mockStopwatch.elapsed = const Duration(seconds: 1);
|
||||
doWhileAsync(time, () => ansiStatus.ticks < 10);
|
||||
List<String> lines = outputStdout();
|
||||
testWithoutContext('AnsiStatus works when stopped', () async {
|
||||
bool done = false;
|
||||
FakeAsync().run((FakeAsync time) {
|
||||
ansiStatus.start();
|
||||
mockStopwatch.elapsed = const Duration(seconds: 1);
|
||||
doWhileAsync(time, () => ansiStatus.ticks < 10);
|
||||
List<String> lines = outputStdout();
|
||||
|
||||
expect(lines, hasLength(1));
|
||||
expect(lines[0],
|
||||
currentPlatform().isWindows
|
||||
? 'Hello world \b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |\b\b\b\b\b\b\b\b /\b\b\b\b\b\b\b\b -\b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |\b\b\b\b\b\b\b\b /\b\b\b\b\b\b\b\b -\b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |'
|
||||
: 'Hello world \b\b\b\b\b\b\b\b ⣽\b\b\b\b\b\b\b\b ⣻\b\b\b\b\b\b\b\b ⢿\b\b\b\b\b\b\b\b ⡿\b\b\b\b\b\b\b\b ⣟\b\b\b\b\b\b\b\b ⣯\b\b\b\b\b\b\b\b ⣷\b\b\b\b\b\b\b\b ⣾\b\b\b\b\b\b\b\b ⣽\b\b\b\b\b\b\b\b ⣻',
|
||||
);
|
||||
expect(lines, hasLength(1));
|
||||
expect(
|
||||
lines[0],
|
||||
terminal.supportsEmoji
|
||||
? 'Hello world \b\b\b\b\b\b\b\b ⣽\b\b\b\b\b\b\b\b ⣻\b\b\b\b\b\b\b\b ⢿\b\b\b\b\b\b\b\b ⡿\b\b\b\b\b\b\b\b ⣟\b\b\b\b\b\b\b\b ⣯\b\b\b\b\b\b\b\b ⣷\b\b\b\b\b\b\b\b ⣾\b\b\b\b\b\b\b\b ⣽\b\b\b\b\b\b\b\b ⣻'
|
||||
: 'Hello world \b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |\b\b\b\b\b\b\b\b /\b\b\b\b\b\b\b\b -\b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |\b\b\b\b\b\b\b\b /\b\b\b\b\b\b\b\b -\b\b\b\b\b\b\b\b \\\b\b\b\b\b\b\b\b |',
|
||||
);
|
||||
|
||||
// Verify a stop prints the time.
|
||||
ansiStatus.stop();
|
||||
lines = outputStdout();
|
||||
expect(lines, hasLength(2));
|
||||
expect(lines[0], matches(
|
||||
currentPlatform().isWindows
|
||||
? r'Hello world {8}[\b]{8} {7}\\[\b]{8} {7}|[\b]{8} {7}/[\b]{8} {7}-[\b]{8} {7}\\[\b]{8} {7}|[\b]{8} {7}/[\b]{8} {7}-[\b]{8} {7}\\[\b]{8} {7}|[\b]{8} {7} [\b]{8}[\d., ]{6}[\d]ms$'
|
||||
: r'Hello world {8}[\b]{8} {7}⣽[\b]{8} {7}⣻[\b]{8} {7}⢿[\b]{8} {7}⡿[\b]{8} {7}⣟[\b]{8} {7}⣯[\b]{8} {7}⣷[\b]{8} {7}⣾[\b]{8} {7}⣽[\b]{8} {7}⣻[\b]{8} {7} [\b]{8}[\d., ]{5}[\d]ms$'
|
||||
));
|
||||
expect(lines[1], isEmpty);
|
||||
final List<Match> times = secondDigits.allMatches(lines[0]).toList();
|
||||
expect(times, isNotNull);
|
||||
expect(times, hasLength(1));
|
||||
final Match match = times.single;
|
||||
// Verify a stop prints the time.
|
||||
ansiStatus.stop();
|
||||
lines = outputStdout();
|
||||
expect(lines, hasLength(2));
|
||||
expect(lines[0], matches(
|
||||
terminal.supportsEmoji
|
||||
? r'Hello world {8}[\b]{8} {7}⣽[\b]{8} {7}⣻[\b]{8} {7}⢿[\b]{8} {7}⡿[\b]{8} {7}⣟[\b]{8} {7}⣯[\b]{8} {7}⣷[\b]{8} {7}⣾[\b]{8} {7}⣽[\b]{8} {7}⣻[\b]{8} {7} [\b]{8}[\d., ]{5}[\d]ms$'
|
||||
: r'Hello world {8}[\b]{8} {7}\\[\b]{8} {7}|[\b]{8} {7}/[\b]{8} {7}-[\b]{8} {7}\\[\b]{8} {7}|[\b]{8} {7}/[\b]{8} {7}-[\b]{8} {7}\\[\b]{8} {7}|[\b]{8} {7} [\b]{8}[\d., ]{6}[\d]ms$',
|
||||
));
|
||||
expect(lines[1], isEmpty);
|
||||
final List<Match> times = secondDigits.allMatches(lines[0]).toList();
|
||||
expect(times, isNotNull);
|
||||
expect(times, hasLength(1));
|
||||
final Match match = times.single;
|
||||
|
||||
expect(lines[0], endsWith(match.group(0)));
|
||||
expect(called, equals(1));
|
||||
expect(lines.length, equals(2));
|
||||
expect(lines[1], equals(''));
|
||||
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, throwsAssertionError);
|
||||
expect(ansiStatus.cancel, throwsAssertionError);
|
||||
done = true;
|
||||
// Verify that stopping or canceling multiple times throws.
|
||||
expect(ansiStatus.stop, throwsAssertionError);
|
||||
expect(ansiStatus.cancel, throwsAssertionError);
|
||||
done = true;
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
expect(done, isTrue);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -453,7 +497,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printError('0123456789' * 15);
|
||||
final List<String> lines = outputStderr();
|
||||
|
@ -475,7 +518,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printError('0123456789' * 15, indent: 5);
|
||||
final List<String> lines = outputStderr();
|
||||
|
@ -500,7 +542,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printError('0123456789' * 15, hangingIndent: 5);
|
||||
final List<String> lines = outputStderr();
|
||||
|
@ -525,7 +566,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printError('0123456789' * 15, indent: 4, hangingIndent: 5);
|
||||
final List<String> lines = outputStderr();
|
||||
|
@ -550,7 +590,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printStatus('0123456789' * 15);
|
||||
final List<String> lines = outputStdout();
|
||||
|
@ -572,7 +611,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printStatus('0123456789' * 15, indent: 5);
|
||||
final List<String> lines = outputStdout();
|
||||
|
@ -597,7 +635,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printStatus('0123456789' * 15, hangingIndent: 5);
|
||||
final List<String> lines = outputStdout();
|
||||
|
@ -622,7 +659,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printStatus('0123456789' * 15, indent: 4, hangingIndent: 5);
|
||||
final List<String> lines = outputStdout();
|
||||
|
@ -647,7 +683,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: true),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printError('Pants on fire!');
|
||||
final List<String> lines = outputStderr();
|
||||
|
@ -666,7 +701,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: true),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printStatus('All good.');
|
||||
|
||||
|
@ -685,7 +719,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: true),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printStatus(
|
||||
null,
|
||||
|
@ -710,7 +743,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.printStatus(
|
||||
null,
|
||||
|
@ -736,7 +768,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
final Status status = logger.startProgress(
|
||||
'Hello',
|
||||
|
@ -818,7 +849,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(showColor: false),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
);
|
||||
logger.startProgress('AAA', timeout: const TimeoutConfiguration().fastOperation)..stop();
|
||||
logger.startProgress('BBB', timeout: const TimeoutConfiguration().fastOperation)..stop();
|
||||
|
@ -843,7 +873,6 @@ void main() {
|
|||
stdio: mockStdio,
|
||||
outputPreferences: OutputPreferences.test(),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
),
|
||||
stopwatchFactory: FakeStopwatchFactory(),
|
||||
);
|
||||
|
|
|
@ -204,9 +204,11 @@ void main() {
|
|||
Logger: () => StdoutLogger(
|
||||
outputPreferences: OutputPreferences.test(),
|
||||
stdio: mockStdio,
|
||||
terminal: AnsiTerminal(stdio: mockStdio, platform: const LocalPlatform()),
|
||||
terminal: AnsiTerminal(
|
||||
stdio: mockStdio,
|
||||
platform: const LocalPlatform(),
|
||||
),
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
),
|
||||
WebSocketConnector: () => (String url, {CompressionOptions compression}) async => throw const SocketException('test'),
|
||||
});
|
||||
|
@ -283,10 +285,12 @@ void main() {
|
|||
}, overrides: <Type, Generator>{
|
||||
Logger: () => StdoutLogger(
|
||||
outputPreferences: outputPreferences,
|
||||
terminal: AnsiTerminal(stdio: mockStdio, platform: const LocalPlatform()),
|
||||
terminal: AnsiTerminal(
|
||||
stdio: mockStdio,
|
||||
platform: const LocalPlatform(),
|
||||
),
|
||||
stdio: mockStdio,
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
),
|
||||
});
|
||||
|
||||
|
@ -301,10 +305,12 @@ void main() {
|
|||
}, overrides: <Type, Generator>{
|
||||
Logger: () => StdoutLogger(
|
||||
outputPreferences: outputPreferences,
|
||||
terminal: AnsiTerminal(stdio: mockStdio, platform: const LocalPlatform()),
|
||||
terminal: AnsiTerminal(
|
||||
stdio: mockStdio,
|
||||
platform: const LocalPlatform(),
|
||||
),
|
||||
stdio: mockStdio,
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
),
|
||||
});
|
||||
|
||||
|
@ -320,10 +326,12 @@ void main() {
|
|||
}, overrides: <Type, Generator>{
|
||||
Logger: () => StdoutLogger(
|
||||
outputPreferences: outputPreferences,
|
||||
terminal: AnsiTerminal(stdio: mockStdio, platform: const LocalPlatform()),
|
||||
terminal: AnsiTerminal(
|
||||
stdio: mockStdio,
|
||||
platform: const LocalPlatform(),
|
||||
),
|
||||
stdio: mockStdio,
|
||||
timeoutConfiguration: const TimeoutConfiguration(),
|
||||
platform: FakePlatform(),
|
||||
),
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue