Unverified Commit f7b8d62c authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tool] Refactor Logger and Terminal to (mostly) no longer depend...

[flutter_tool] Refactor Logger and Terminal to (mostly) no longer depend directly on context (#47269)
parent 0384c8c4
...@@ -15,6 +15,7 @@ import 'src/base/file_system.dart'; ...@@ -15,6 +15,7 @@ import 'src/base/file_system.dart';
import 'src/base/io.dart'; import 'src/base/io.dart';
import 'src/base/logger.dart'; import 'src/base/logger.dart';
import 'src/base/process.dart'; import 'src/base/process.dart';
import 'src/base/terminal.dart';
import 'src/base/utils.dart'; import 'src/base/utils.dart';
import 'src/context_runner.dart'; import 'src/context_runner.dart';
import 'src/doctor.dart'; import 'src/doctor.dart';
...@@ -223,7 +224,10 @@ Future<File> _createLocalCrashReport(List<String> args, dynamic error, StackTrac ...@@ -223,7 +224,10 @@ Future<File> _createLocalCrashReport(List<String> args, dynamic error, StackTrac
Future<String> _doctorText() async { Future<String> _doctorText() async {
try { try {
final BufferLogger logger = BufferLogger(); final BufferLogger logger = BufferLogger(
terminal: terminal,
outputPreferences: outputPreferences,
);
await context.run<bool>( await context.run<bool>(
body: () => doctor.diagnose(verbose: true, showColor: false), body: () => doctor.diagnose(verbose: true, showColor: false),
......
...@@ -247,11 +247,10 @@ class Stdio { ...@@ -247,11 +247,10 @@ class Stdio {
bool get supportsAnsiEscapes => hasTerminal && io.stdout.supportsAnsiEscapes; bool get supportsAnsiEscapes => hasTerminal && io.stdout.supportsAnsiEscapes;
} }
Stdio get stdio => context.get<Stdio>() ?? const Stdio(); io.Stdout get stdout => globals.stdio.stdout;
io.Stdout get stdout => stdio.stdout; Stream<List<int>> get stdin => globals.stdio.stdin;
Stream<List<int>> get stdin => stdio.stdin; io.IOSink get stderr => globals.stdio.stderr;
io.IOSink get stderr => stdio.stderr; bool get stdinHasTerminal => globals.stdio.stdinHasTerminal;
bool get stdinHasTerminal => stdio.stdinHasTerminal;
/// An overridable version of io.ProcessInfo. /// An overridable version of io.ProcessInfo.
abstract class ProcessInfo { abstract class ProcessInfo {
......
...@@ -8,8 +8,8 @@ import 'package:meta/meta.dart'; ...@@ -8,8 +8,8 @@ import 'package:meta/meta.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import 'io.dart'; import 'io.dart' hide stderr, stdin, stdout;
import 'terminal.dart'; import 'terminal.dart' show AnsiTerminal, TerminalColor, OutputPreferences;
import 'utils.dart'; import 'utils.dart';
const int kDefaultStatusPadding = 59; const int kDefaultStatusPadding = 59;
...@@ -44,9 +44,15 @@ abstract class Logger { ...@@ -44,9 +44,15 @@ abstract class Logger {
bool quiet = false; bool quiet = false;
bool get supportsColor => globals.terminal.supportsColor; bool get supportsColor;
bool get hasTerminal => stdio.hasTerminal; bool get hasTerminal;
AnsiTerminal get _terminal;
OutputPreferences get _outputPreferences;
TimeoutConfiguration get _timeoutConfiguration;
/// Display an error `message` to the user. Commands should use this if they /// Display an error `message` to the user. Commands should use this if they
/// fail in some way. /// fail in some way.
...@@ -155,11 +161,36 @@ abstract class Logger { ...@@ -155,11 +161,36 @@ abstract class Logger {
} }
class StdoutLogger extends Logger { class StdoutLogger extends Logger {
StdoutLogger({
@required AnsiTerminal terminal,
@required Stdio stdio,
@required OutputPreferences outputPreferences,
@required TimeoutConfiguration timeoutConfiguration,
})
: _stdio = stdio,
_terminal = terminal,
_timeoutConfiguration = timeoutConfiguration,
_outputPreferences = outputPreferences;
@override
final AnsiTerminal _terminal;
@override
final OutputPreferences _outputPreferences;
@override
final TimeoutConfiguration _timeoutConfiguration;
final Stdio _stdio;
Status _status; Status _status;
@override @override
bool get isVerbose => false; bool get isVerbose => false;
@override
bool get supportsColor => _terminal.supportsColor;
@override
bool get hasTerminal => _stdio.stdinHasTerminal;
@override @override
void printError( void printError(
String message, { String message, {
...@@ -172,14 +203,19 @@ class StdoutLogger extends Logger { ...@@ -172,14 +203,19 @@ class StdoutLogger extends Logger {
}) { }) {
_status?.pause(); _status?.pause();
message ??= ''; message ??= '';
message = wrapText(message, indent: indent, hangingIndent: hangingIndent, shouldWrap: wrap); message = wrapText(message,
indent: indent,
hangingIndent: hangingIndent,
shouldWrap: wrap ?? _outputPreferences.wrapText,
columnWidth: _outputPreferences.wrapColumn,
);
if (emphasis == true) { if (emphasis == true) {
message = globals.terminal.bolden(message); message = _terminal.bolden(message);
} }
message = globals.terminal.color(message, color ?? TerminalColor.red); message = _terminal.color(message, color ?? TerminalColor.red);
stderr.writeln(message); _stdio.stderr.writeln(message);
if (stackTrace != null) { if (stackTrace != null) {
stderr.writeln(stackTrace.toString()); _stdio.stderr.writeln(stackTrace.toString());
} }
_status?.resume(); _status?.resume();
} }
...@@ -196,12 +232,17 @@ class StdoutLogger extends Logger { ...@@ -196,12 +232,17 @@ class StdoutLogger extends Logger {
}) { }) {
_status?.pause(); _status?.pause();
message ??= ''; message ??= '';
message = wrapText(message, indent: indent, hangingIndent: hangingIndent, shouldWrap: wrap); message = wrapText(message,
indent: indent,
hangingIndent: hangingIndent,
shouldWrap: wrap ?? _outputPreferences.wrapText,
columnWidth: _outputPreferences.wrapColumn,
);
if (emphasis == true) { if (emphasis == true) {
message = globals.terminal.bolden(message); message = _terminal.bolden(message);
} }
if (color != null) { if (color != null) {
message = globals.terminal.color(message, color); message = _terminal.color(message, color);
} }
if (newline != false) { if (newline != false) {
message = '$message\n'; message = '$message\n';
...@@ -212,7 +253,7 @@ class StdoutLogger extends Logger { ...@@ -212,7 +253,7 @@ class StdoutLogger extends Logger {
@protected @protected
void writeToStdOut(String message) { void writeToStdOut(String message) {
stdout.write(message); _stdio.stdout.write(message);
} }
@override @override
...@@ -232,15 +273,18 @@ class StdoutLogger extends Logger { ...@@ -232,15 +273,18 @@ class StdoutLogger extends Logger {
return SilentStatus( return SilentStatus(
timeout: timeout, timeout: timeout,
onFinish: _clearStatus, onFinish: _clearStatus,
timeoutConfiguration: _timeoutConfiguration
)..start(); )..start();
} }
if (globals.terminal.supportsColor) { if (supportsColor) {
_status = AnsiStatus( _status = AnsiStatus(
message: message, message: message,
timeout: timeout, timeout: timeout,
multilineOutput: multilineOutput, multilineOutput: multilineOutput,
padding: progressIndicatorPadding, padding: progressIndicatorPadding,
onFinish: _clearStatus, onFinish: _clearStatus,
stdio: _stdio,
timeoutConfiguration: _timeoutConfiguration,
)..start(); )..start();
} else { } else {
_status = SummaryStatus( _status = SummaryStatus(
...@@ -248,6 +292,8 @@ class StdoutLogger extends Logger { ...@@ -248,6 +292,8 @@ class StdoutLogger extends Logger {
timeout: timeout, timeout: timeout,
padding: progressIndicatorPadding, padding: progressIndicatorPadding,
onFinish: _clearStatus, onFinish: _clearStatus,
stdio: _stdio,
timeoutConfiguration: _timeoutConfiguration,
)..start(); )..start();
} }
return _status; return _status;
...@@ -270,10 +316,22 @@ class StdoutLogger extends Logger { ...@@ -270,10 +316,22 @@ class StdoutLogger extends Logger {
/// fonts, should be replaced by this class with printable symbols. Otherwise, /// fonts, should be replaced by this class with printable symbols. Otherwise,
/// they will show up as the unrepresentable character symbol '�'. /// they will show up as the unrepresentable character symbol '�'.
class WindowsStdoutLogger extends StdoutLogger { class WindowsStdoutLogger extends StdoutLogger {
WindowsStdoutLogger({
@required AnsiTerminal terminal,
@required Stdio stdio,
@required OutputPreferences outputPreferences,
@required TimeoutConfiguration timeoutConfiguration,
}) : super(
terminal: terminal,
stdio: stdio,
outputPreferences: outputPreferences,
timeoutConfiguration: timeoutConfiguration,
);
@override @override
void writeToStdOut(String message) { void writeToStdOut(String message) {
// TODO(jcollins-g): wrong abstraction layer for this, move to [Stdio]. // TODO(jcollins-g): wrong abstraction layer for this, move to [Stdio].
stdout.write(message _stdio.stdout.write(message
.replaceAll('✗', 'X') .replaceAll('✗', 'X')
.replaceAll('✓', '√') .replaceAll('✓', '√')
); );
...@@ -281,9 +339,29 @@ class WindowsStdoutLogger extends StdoutLogger { ...@@ -281,9 +339,29 @@ class WindowsStdoutLogger extends StdoutLogger {
} }
class BufferLogger extends Logger { class BufferLogger extends Logger {
BufferLogger({
@required AnsiTerminal terminal,
@required OutputPreferences outputPreferences,
TimeoutConfiguration timeoutConfiguration = const TimeoutConfiguration()
}) : _outputPreferences = outputPreferences,
_terminal = terminal,
_timeoutConfiguration = timeoutConfiguration;
@override
final OutputPreferences _outputPreferences;
@override
final AnsiTerminal _terminal;
@override
final TimeoutConfiguration _timeoutConfiguration;
@override @override
bool get isVerbose => false; bool get isVerbose => false;
@override
bool get supportsColor => _terminal.supportsColor;
final StringBuffer _error = StringBuffer(); final StringBuffer _error = StringBuffer();
final StringBuffer _status = StringBuffer(); final StringBuffer _status = StringBuffer();
final StringBuffer _trace = StringBuffer(); final StringBuffer _trace = StringBuffer();
...@@ -305,8 +383,13 @@ class BufferLogger extends Logger { ...@@ -305,8 +383,13 @@ class BufferLogger extends Logger {
int hangingIndent, int hangingIndent,
bool wrap, bool wrap,
}) { }) {
_error.writeln(globals.terminal.color( _error.writeln(_terminal.color(
wrapText(message, indent: indent, hangingIndent: hangingIndent, shouldWrap: wrap), wrapText(message,
indent: indent,
hangingIndent: hangingIndent,
shouldWrap: wrap ?? _outputPreferences.wrapText,
columnWidth: _outputPreferences.wrapColumn,
),
color ?? TerminalColor.red, color ?? TerminalColor.red,
)); ));
} }
...@@ -322,9 +405,19 @@ class BufferLogger extends Logger { ...@@ -322,9 +405,19 @@ class BufferLogger extends Logger {
bool wrap, bool wrap,
}) { }) {
if (newline != false) { if (newline != false) {
_status.writeln(wrapText(message, indent: indent, hangingIndent: hangingIndent, shouldWrap: wrap)); _status.writeln(wrapText(message,
indent: indent,
hangingIndent: hangingIndent,
shouldWrap: wrap ?? _outputPreferences.wrapText,
columnWidth: _outputPreferences.wrapColumn,
));
} else { } else {
_status.write(wrapText(message, indent: indent, hangingIndent: hangingIndent, shouldWrap: wrap)); _status.write(wrapText(message,
indent: indent,
hangingIndent: hangingIndent,
shouldWrap: wrap ?? _outputPreferences.wrapText,
columnWidth: _outputPreferences.wrapColumn,
));
} }
} }
...@@ -341,7 +434,11 @@ class BufferLogger extends Logger { ...@@ -341,7 +434,11 @@ class BufferLogger extends Logger {
}) { }) {
assert(progressIndicatorPadding != null); assert(progressIndicatorPadding != null);
printStatus(message); printStatus(message);
return SilentStatus(timeout: timeout)..start(); return SilentStatus(
timeout: timeout,
timeoutConfiguration: _timeoutConfiguration,
)..start();
} }
/// Clears all buffers. /// Clears all buffers.
...@@ -356,13 +453,23 @@ class BufferLogger extends Logger { ...@@ -356,13 +453,23 @@ class BufferLogger extends Logger {
} }
class VerboseLogger extends Logger { class VerboseLogger extends Logger {
VerboseLogger(this.parent) : assert(globals.terminal != null) { VerboseLogger(this.parent, { @required Stopwatch stopwatch }) :
_stopwatch = stopwatch ?? context.get<Stopwatch>() ?? Stopwatch() {
_stopwatch.start(); _stopwatch.start();
} }
final Logger parent; final Logger parent;
final Stopwatch _stopwatch = context.get<Stopwatch>() ?? Stopwatch(); final Stopwatch _stopwatch;
@override
AnsiTerminal get _terminal => parent._terminal;
@override
OutputPreferences get _outputPreferences => parent._outputPreferences;
@override
TimeoutConfiguration get _timeoutConfiguration => parent._timeoutConfiguration;
@override @override
bool get isVerbose => true; bool get isVerbose => true;
...@@ -379,7 +486,12 @@ class VerboseLogger extends Logger { ...@@ -379,7 +486,12 @@ class VerboseLogger extends Logger {
}) { }) {
_emit( _emit(
_LogType.error, _LogType.error,
wrapText(message, indent: indent, hangingIndent: hangingIndent, shouldWrap: wrap), wrapText(message,
indent: indent,
hangingIndent: hangingIndent,
shouldWrap: wrap ?? _outputPreferences.wrapText,
columnWidth: _outputPreferences.wrapColumn,
),
stackTrace, stackTrace,
); );
} }
...@@ -394,7 +506,12 @@ class VerboseLogger extends Logger { ...@@ -394,7 +506,12 @@ class VerboseLogger extends Logger {
int hangingIndent, int hangingIndent,
bool wrap, bool wrap,
}) { }) {
_emit(_LogType.status, wrapText(message, indent: indent, hangingIndent: hangingIndent, shouldWrap: wrap)); _emit(_LogType.status, wrapText(message,
indent: indent,
hangingIndent: hangingIndent,
shouldWrap: wrap ?? _outputPreferences.wrapText,
columnWidth: _outputPreferences.wrapColumn,
));
} }
@override @override
...@@ -415,9 +532,10 @@ class VerboseLogger extends Logger { ...@@ -415,9 +532,10 @@ class VerboseLogger extends Logger {
final Stopwatch timer = Stopwatch()..start(); final Stopwatch timer = Stopwatch()..start();
return SilentStatus( return SilentStatus(
timeout: timeout, timeout: timeout,
timeoutConfiguration: _timeoutConfiguration,
onFinish: () { onFinish: () {
String time; String time;
if (timeout == null || timeout > timeoutConfiguration.fastOperation) { if (timeout == null || timeout > _timeoutConfiguration.fastOperation) {
time = getElapsedAsSeconds(timer.elapsed); time = getElapsedAsSeconds(timer.elapsed);
} else { } else {
time = getElapsedAsMilliseconds(timer.elapsed); time = getElapsedAsMilliseconds(timer.elapsed);
...@@ -446,7 +564,7 @@ class VerboseLogger extends Logger { ...@@ -446,7 +564,7 @@ class VerboseLogger extends Logger {
} else { } else {
prefix = '+$millis ms'.padLeft(prefixWidth); prefix = '+$millis ms'.padLeft(prefixWidth);
if (millis >= 100) { if (millis >= 100) {
prefix = globals.terminal.bolden(prefix); prefix = _terminal.bolden(prefix);
} }
} }
prefix = '[$prefix] '; prefix = '[$prefix] ';
...@@ -455,12 +573,12 @@ class VerboseLogger extends Logger { ...@@ -455,12 +573,12 @@ class VerboseLogger extends Logger {
final String indentMessage = message.replaceAll('\n', '\n$indent'); final String indentMessage = message.replaceAll('\n', '\n$indent');
if (type == _LogType.error) { if (type == _LogType.error) {
parent.printError(prefix + globals.terminal.bolden(indentMessage)); parent.printError(prefix + _terminal.bolden(indentMessage));
if (stackTrace != null) { if (stackTrace != null) {
parent.printError(indent + stackTrace.toString().replaceAll('\n', '\n$indent')); parent.printError(indent + stackTrace.toString().replaceAll('\n', '\n$indent'));
} }
} else if (type == _LogType.status) { } else if (type == _LogType.status) {
parent.printStatus(prefix + globals.terminal.bolden(indentMessage)); parent.printStatus(prefix + _terminal.bolden(indentMessage));
} else { } else {
parent.printStatus(prefix + indentMessage); parent.printStatus(prefix + indentMessage);
} }
...@@ -468,6 +586,12 @@ class VerboseLogger extends Logger { ...@@ -468,6 +586,12 @@ class VerboseLogger extends Logger {
@override @override
void sendEvent(String name, [Map<String, dynamic> args]) { } void sendEvent(String name, [Map<String, dynamic> args]) { }
@override
bool get supportsColor => parent.supportsColor;
@override
bool get hasTerminal => parent.hasTerminal;
} }
enum _LogType { error, status, trace } enum _LogType { error, status, trace }
...@@ -495,12 +619,17 @@ typedef SlowWarningCallback = String Function(); ...@@ -495,12 +619,17 @@ typedef SlowWarningCallback = String Function();
/// Generally, consider `logger.startProgress` instead of directly creating /// Generally, consider `logger.startProgress` instead of directly creating
/// a [Status] or one of its subclasses. /// a [Status] or one of its subclasses.
abstract class Status { abstract class Status {
Status({ @required this.timeout, this.onFinish }); Status({
@required this.timeout,
@required TimeoutConfiguration timeoutConfiguration,
this.onFinish,
}) : _timeoutConfiguration = timeoutConfiguration;
/// A [SilentStatus] or an [AnsiSpinner] (depending on whether the /// A [SilentStatus] or an [AnsiSpinner] (depending on whether the
/// terminal is fancy enough), already started. /// terminal is fancy enough), already started.
factory Status.withSpinner({ factory Status.withSpinner({
@required Duration timeout, @required Duration timeout,
@required TimeoutConfiguration timeoutConfiguration,
VoidCallback onFinish, VoidCallback onFinish,
SlowWarningCallback slowWarningCallback, SlowWarningCallback slowWarningCallback,
}) { }) {
...@@ -509,13 +638,19 @@ abstract class Status { ...@@ -509,13 +638,19 @@ abstract class Status {
timeout: timeout, timeout: timeout,
onFinish: onFinish, onFinish: onFinish,
slowWarningCallback: slowWarningCallback, slowWarningCallback: slowWarningCallback,
timeoutConfiguration: timeoutConfiguration,
)..start(); )..start();
} }
return SilentStatus(timeout: timeout, onFinish: onFinish)..start(); return SilentStatus(
timeout: timeout,
onFinish: onFinish,
timeoutConfiguration: timeoutConfiguration,
)..start();
} }
final Duration timeout; final Duration timeout;
final VoidCallback onFinish; final VoidCallback onFinish;
final TimeoutConfiguration _timeoutConfiguration;
@protected @protected
final Stopwatch _stopwatch = context.get<Stopwatch>() ?? Stopwatch(); final Stopwatch _stopwatch = context.get<Stopwatch>() ?? Stopwatch();
...@@ -526,7 +661,7 @@ abstract class Status { ...@@ -526,7 +661,7 @@ abstract class Status {
@protected @protected
String get elapsedTime { String get elapsedTime {
if (timeout == null || timeout > timeoutConfiguration.fastOperation) { if (timeout == null || timeout > _timeoutConfiguration.fastOperation) {
return getElapsedAsSeconds(_stopwatch.elapsed); return getElapsedAsSeconds(_stopwatch.elapsed);
} }
return getElapsedAsMilliseconds(_stopwatch.elapsed); return getElapsedAsMilliseconds(_stopwatch.elapsed);
...@@ -568,8 +703,13 @@ abstract class Status { ...@@ -568,8 +703,13 @@ abstract class Status {
class SilentStatus extends Status { class SilentStatus extends Status {
SilentStatus({ SilentStatus({
@required Duration timeout, @required Duration timeout,
@required TimeoutConfiguration timeoutConfiguration,
VoidCallback onFinish, VoidCallback onFinish,
}) : super(timeout: timeout, onFinish: onFinish); }) : super(
timeout: timeout,
onFinish: onFinish,
timeoutConfiguration: timeoutConfiguration,
);
} }
/// Constructor writes [message] to [stdout]. On [cancel] or [stop], will call /// Constructor writes [message] to [stdout]. On [cancel] or [stop], will call
...@@ -580,12 +720,16 @@ class SummaryStatus extends Status { ...@@ -580,12 +720,16 @@ class SummaryStatus extends Status {
@required Duration timeout, @required Duration timeout,
this.padding = kDefaultStatusPadding, this.padding = kDefaultStatusPadding,
VoidCallback onFinish, VoidCallback onFinish,
Stdio stdio,
@required TimeoutConfiguration timeoutConfiguration,
}) : assert(message != null), }) : assert(message != null),
assert(padding != null), assert(padding != null),
super(timeout: timeout, onFinish: onFinish); _stdio = stdio ?? globals.stdio,
super(timeout: timeout, onFinish: onFinish, timeoutConfiguration: timeoutConfiguration);
final String message; final String message;
final int padding; final int padding;
final Stdio _stdio;
bool _messageShowingOnCurrentLine = false; bool _messageShowingOnCurrentLine = false;
...@@ -597,7 +741,7 @@ class SummaryStatus extends Status { ...@@ -597,7 +741,7 @@ class SummaryStatus extends Status {
void _printMessage() { void _printMessage() {
assert(!_messageShowingOnCurrentLine); assert(!_messageShowingOnCurrentLine);
stdout.write('${message.padRight(padding)} '); _stdio.stdout.write('${message.padRight(padding)} ');
_messageShowingOnCurrentLine = true; _messageShowingOnCurrentLine = true;
} }
...@@ -608,14 +752,14 @@ class SummaryStatus extends Status { ...@@ -608,14 +752,14 @@ class SummaryStatus extends Status {
} }
super.stop(); super.stop();
writeSummaryInformation(); writeSummaryInformation();
stdout.write('\n'); _stdio.stdout.write('\n');
} }
@override @override
void cancel() { void cancel() {
super.cancel(); super.cancel();
if (_messageShowingOnCurrentLine) { if (_messageShowingOnCurrentLine) {
stdout.write('\n'); _stdio.stdout.write('\n');
} }
} }
...@@ -628,16 +772,16 @@ class SummaryStatus extends Status { ...@@ -628,16 +772,16 @@ class SummaryStatus extends Status {
/// Examples: ` 0.5s`, ` 150ms`, ` 1,600ms`, ` 3.1s (!)` /// Examples: ` 0.5s`, ` 150ms`, ` 1,600ms`, ` 3.1s (!)`
void writeSummaryInformation() { void writeSummaryInformation() {
assert(_messageShowingOnCurrentLine); assert(_messageShowingOnCurrentLine);
stdout.write(elapsedTime.padLeft(_kTimePadding)); _stdio.stdout.write(elapsedTime.padLeft(_kTimePadding));
if (seemsSlow) { if (seemsSlow) {
stdout.write(' (!)'); _stdio.stdout.write(' (!)');
} }
} }
@override @override
void pause() { void pause() {
super.pause(); super.pause();
stdout.write('\n'); _stdio.stdout.write('\n');
_messageShowingOnCurrentLine = false; _messageShowingOnCurrentLine = false;
} }
} }
...@@ -652,10 +796,14 @@ class AnsiSpinner extends Status { ...@@ -652,10 +796,14 @@ class AnsiSpinner extends Status {
@required Duration timeout, @required Duration timeout,
VoidCallback onFinish, VoidCallback onFinish,
this.slowWarningCallback, this.slowWarningCallback,
}) : super(timeout: timeout, onFinish: onFinish); Stdio stdio,
@required TimeoutConfiguration timeoutConfiguration,
}) : _stdio = stdio ?? globals.stdio,
super(timeout: timeout, onFinish: onFinish, timeoutConfiguration: timeoutConfiguration);
final String _backspaceChar = '\b'; final String _backspaceChar = '\b';
final String _clearChar = ' '; final String _clearChar = ' ';
final Stdio _stdio;
bool timedOut = false; bool timedOut = false;
...@@ -688,7 +836,7 @@ class AnsiSpinner extends Status { ...@@ -688,7 +836,7 @@ class AnsiSpinner extends Status {
} }
void _startSpinner() { void _startSpinner() {
stdout.write(_clear); // for _callback to backspace over _stdio.stdout.write(_clear); // for _callback to backspace over
timer = Timer.periodic(const Duration(milliseconds: 100), _callback); timer = Timer.periodic(const Duration(milliseconds: 100), _callback);
_callback(timer); _callback(timer);
} }
...@@ -697,21 +845,21 @@ class AnsiSpinner extends Status { ...@@ -697,21 +845,21 @@ class AnsiSpinner extends Status {
assert(this.timer == timer); assert(this.timer == timer);
assert(timer != null); assert(timer != null);
assert(timer.isActive); assert(timer.isActive);
stdout.write(_backspace); _stdio.stdout.write(_backspace);
ticks += 1; ticks += 1;
if (seemsSlow) { if (seemsSlow) {
if (!timedOut) { if (!timedOut) {
timedOut = true; timedOut = true;
stdout.write('$_clear\n'); _stdio.stdout.write('$_clear\n');
} }
if (slowWarningCallback != null) { if (slowWarningCallback != null) {
_slowWarning = slowWarningCallback(); _slowWarning = slowWarningCallback();
} else { } else {
_slowWarning = _defaultSlowWarning; _slowWarning = _defaultSlowWarning;
} }
stdout.write(_slowWarning); _stdio.stdout.write(_slowWarning);
} }
stdout.write('${_clearChar * spinnerIndent}$_currentAnimationFrame'); _stdio.stdout.write('${_clearChar * spinnerIndent}$_currentAnimationFrame');
} }
@override @override
...@@ -725,7 +873,7 @@ class AnsiSpinner extends Status { ...@@ -725,7 +873,7 @@ class AnsiSpinner extends Status {
} }
void _clearSpinner() { void _clearSpinner() {
stdout.write('$_backspace$_clear$_backspace'); _stdio.stdout.write('$_backspace$_clear$_backspace');
} }
@override @override
...@@ -759,10 +907,12 @@ class AnsiStatus extends AnsiSpinner { ...@@ -759,10 +907,12 @@ class AnsiStatus extends AnsiSpinner {
this.multilineOutput = false, this.multilineOutput = false,
this.padding = kDefaultStatusPadding, this.padding = kDefaultStatusPadding,
VoidCallback onFinish, VoidCallback onFinish,
Stdio stdio,
TimeoutConfiguration timeoutConfiguration,
}) : assert(message != null), }) : assert(message != null),
assert(multilineOutput != null), assert(multilineOutput != null),
assert(padding != null), assert(padding != null),
super(timeout: timeout, onFinish: onFinish); super(timeout: timeout, onFinish: onFinish, stdio: stdio, timeoutConfiguration: timeoutConfiguration);
final String message; final String message;
final bool multilineOutput; final bool multilineOutput;
...@@ -784,20 +934,20 @@ class AnsiStatus extends AnsiSpinner { ...@@ -784,20 +934,20 @@ class AnsiStatus extends AnsiSpinner {
void _startStatus() { void _startStatus() {
final String line = '${message.padRight(padding)}$_margin'; final String line = '${message.padRight(padding)}$_margin';
_totalMessageLength = line.length; _totalMessageLength = line.length;
stdout.write(line); _stdio.stdout.write(line);
} }
@override @override
void stop() { void stop() {
super.stop(); super.stop();
writeSummaryInformation(); writeSummaryInformation();
stdout.write('\n'); _stdio.stdout.write('\n');
} }
@override @override
void cancel() { void cancel() {
super.cancel(); super.cancel();
stdout.write('\n'); _stdio.stdout.write('\n');
} }
/// Print summary information when a task is done. /// Print summary information when a task is done.
...@@ -808,16 +958,16 @@ class AnsiStatus extends AnsiSpinner { ...@@ -808,16 +958,16 @@ class AnsiStatus extends AnsiSpinner {
/// line before writing the elapsed time. /// line before writing the elapsed time.
void writeSummaryInformation() { void writeSummaryInformation() {
if (multilineOutput) { if (multilineOutput) {
stdout.write('\n${'$message Done'.padRight(padding)}$_margin'); _stdio.stdout.write('\n${'$message Done'.padRight(padding)}$_margin');
} }
stdout.write(elapsedTime.padLeft(_kTimePadding)); _stdio.stdout.write(elapsedTime.padLeft(_kTimePadding));
if (seemsSlow) { if (seemsSlow) {
stdout.write(' (!)'); _stdio.stdout.write(' (!)');
} }
} }
void _clearStatus() { void _clearStatus() {
stdout.write('${_backspaceChar * _totalMessageLength}${_clearChar * _totalMessageLength}${_backspaceChar * _totalMessageLength}'); _stdio.stdout.write('${_backspaceChar * _totalMessageLength}${_clearChar * _totalMessageLength}${_backspaceChar * _totalMessageLength}');
} }
@override @override
......
...@@ -4,10 +4,14 @@ ...@@ -4,10 +4,14 @@
import 'dart:async'; import 'dart:async';
import 'package:meta/meta.dart';
import 'package:platform/platform.dart';
import '../convert.dart'; import '../convert.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import 'context.dart'; import 'context.dart';
import 'io.dart' as io; import 'io.dart' as io;
import 'logger.dart';
enum TerminalColor { enum TerminalColor {
red, red,
...@@ -41,12 +45,13 @@ class OutputPreferences { ...@@ -41,12 +45,13 @@ class OutputPreferences {
bool wrapText, bool wrapText,
int wrapColumn, int wrapColumn,
bool showColor, bool showColor,
}) : wrapText = wrapText ?? io.stdio.hasTerminal, }) : wrapText = wrapText ?? globals.stdio.hasTerminal,
_overrideWrapColumn = wrapColumn, _overrideWrapColumn = wrapColumn,
showColor = showColor ?? globals.platform.stdoutSupportsAnsi ?? false; showColor = showColor ?? globals.platform.stdoutSupportsAnsi ?? false;
/// A version of this class for use in tests. /// A version of this class for use in tests.
OutputPreferences.test() : wrapText = false, _overrideWrapColumn = null, showColor = false; OutputPreferences.test({this.wrapText = false, int wrapColumn = kDefaultTerminalColumns, this.showColor = false})
: _overrideWrapColumn = wrapColumn;
/// If [wrapText] is true, then any text sent to the context's [Logger] /// If [wrapText] is true, then any text sent to the context's [Logger]
/// instance (e.g. from the [printError] or [printStatus] functions) will be /// instance (e.g. from the [printError] or [printStatus] functions) will be
...@@ -66,7 +71,7 @@ class OutputPreferences { ...@@ -66,7 +71,7 @@ class OutputPreferences {
/// terminal, or to [kDefaultTerminalColumns] if not writing to a terminal. /// terminal, or to [kDefaultTerminalColumns] if not writing to a terminal.
final int _overrideWrapColumn; final int _overrideWrapColumn;
int get wrapColumn { int get wrapColumn {
return _overrideWrapColumn ?? io.stdio.terminalColumns ?? kDefaultTerminalColumns; return _overrideWrapColumn ?? globals.stdio.terminalColumns ?? kDefaultTerminalColumns;
} }
/// Whether or not to output ANSI color codes when writing to the output /// Whether or not to output ANSI color codes when writing to the output
...@@ -81,6 +86,13 @@ class OutputPreferences { ...@@ -81,6 +86,13 @@ class OutputPreferences {
} }
class AnsiTerminal { class AnsiTerminal {
AnsiTerminal({@required io.Stdio stdio, @required Platform platform})
: _stdio = stdio,
_platform = platform;
final io.Stdio _stdio;
final Platform _platform;
static const String bold = '\u001B[1m'; static const String bold = '\u001B[1m';
static const String resetAll = '\u001B[0m'; static const String resetAll = '\u001B[0m';
static const String resetColor = '\u001B[39m'; static const String resetColor = '\u001B[39m';
...@@ -107,7 +119,8 @@ class AnsiTerminal { ...@@ -107,7 +119,8 @@ class AnsiTerminal {
static String colorCode(TerminalColor color) => _colorMap[color]; static String colorCode(TerminalColor color) => _colorMap[color];
bool get supportsColor => globals.platform.stdoutSupportsAnsi ?? false; bool get supportsColor => _platform.stdoutSupportsAnsi ?? false;
final RegExp _boldControls = RegExp('(${RegExp.escape(resetBold)}|${RegExp.escape(bold)})'); final RegExp _boldControls = RegExp('(${RegExp.escape(resetBold)}|${RegExp.escape(bold)})');
/// Whether we are interacting with the flutter tool via the terminal. /// Whether we are interacting with the flutter tool via the terminal.
...@@ -159,10 +172,10 @@ class AnsiTerminal { ...@@ -159,10 +172,10 @@ class AnsiTerminal {
String clearScreen() => supportsColor ? clear : '\n\n'; String clearScreen() => supportsColor ? clear : '\n\n';
set singleCharMode(bool value) { set singleCharMode(bool value) {
if (!io.stdinHasTerminal) { if (!_stdio.stdinHasTerminal) {
return; return;
} }
final io.Stdin stdin = io.stdin as io.Stdin; final io.Stdin stdin = _stdio.stdin as io.Stdin;
// The order of setting lineMode and echoMode is important on Windows. // The order of setting lineMode and echoMode is important on Windows.
if (value) { if (value) {
stdin.echoMode = false; stdin.echoMode = false;
...@@ -179,7 +192,7 @@ class AnsiTerminal { ...@@ -179,7 +192,7 @@ class AnsiTerminal {
/// ///
/// Useful when the console is in [singleCharMode]. /// Useful when the console is in [singleCharMode].
Stream<String> get keystrokes { Stream<String> get keystrokes {
_broadcastStdInString ??= io.stdin.transform<String>(const AsciiDecoder(allowInvalid: true)).asBroadcastStream(); _broadcastStdInString ??= _stdio.stdin.transform<String>(const AsciiDecoder(allowInvalid: true)).asBroadcastStream();
return _broadcastStdInString; return _broadcastStdInString;
} }
...@@ -198,6 +211,7 @@ class AnsiTerminal { ...@@ -198,6 +211,7 @@ class AnsiTerminal {
/// If [usesTerminalUi] is false, throws a [StateError]. /// If [usesTerminalUi] is false, throws a [StateError].
Future<String> promptForCharInput( Future<String> promptForCharInput(
List<String> acceptedCharacters, { List<String> acceptedCharacters, {
@required Logger logger,
String prompt, String prompt,
int defaultChoiceIndex, int defaultChoiceIndex,
bool displayAcceptedCharacters = true, bool displayAcceptedCharacters = true,
...@@ -220,14 +234,14 @@ class AnsiTerminal { ...@@ -220,14 +234,14 @@ class AnsiTerminal {
singleCharMode = true; singleCharMode = true;
while (choice == null || choice.length > 1 || !acceptedCharacters.contains(choice)) { while (choice == null || choice.length > 1 || !acceptedCharacters.contains(choice)) {
if (prompt != null) { if (prompt != null) {
globals.printStatus(prompt, emphasis: true, newline: false); logger.printStatus(prompt, emphasis: true, newline: false);
if (displayAcceptedCharacters) { if (displayAcceptedCharacters) {
globals.printStatus(' [${charactersToDisplay.join("|")}]', newline: false); logger.printStatus(' [${charactersToDisplay.join("|")}]', newline: false);
} }
globals.printStatus(': ', emphasis: true, newline: false); logger.printStatus(': ', emphasis: true, newline: false);
} }
choice = await keystrokes.first; choice = await keystrokes.first;
globals.printStatus(choice); logger.printStatus(choice);
} }
singleCharMode = false; singleCharMode = false;
if (defaultChoiceIndex != null && choice == '\n') { if (defaultChoiceIndex != null && choice == '\n') {
......
...@@ -6,6 +6,7 @@ import 'dart:async'; ...@@ -6,6 +6,7 @@ import 'dart:async';
import 'dart:math' show Random, max; import 'dart:math' show Random, max;
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:meta/meta.dart';
import '../convert.dart'; import '../convert.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
...@@ -395,7 +396,7 @@ class _AnsiRun { ...@@ -395,7 +396,7 @@ class _AnsiRun {
/// If [outputPreferences.wrapText] is false, then the text will be returned /// If [outputPreferences.wrapText] is false, then the text will be returned
/// simply split at the newlines, but not wrapped. If [shouldWrap] is specified, /// simply split at the newlines, but not wrapped. If [shouldWrap] is specified,
/// then it overrides the [outputPreferences.wrapText] setting. /// then it overrides the [outputPreferences.wrapText] setting.
List<String> _wrapTextAsLines(String text, { int start = 0, int columnWidth, bool shouldWrap }) { List<String> _wrapTextAsLines(String text, { int start = 0, int columnWidth, @required bool shouldWrap }) {
if (text == null || text.isEmpty) { if (text == null || text.isEmpty) {
return <String>['']; return <String>[''];
} }
......
...@@ -974,7 +974,7 @@ class NotifyingLogger extends Logger { ...@@ -974,7 +974,7 @@ class NotifyingLogger extends Logger {
}) { }) {
assert(timeout != null); assert(timeout != null);
printStatus(message); printStatus(message);
return SilentStatus(timeout: timeout); return SilentStatus(timeout: timeout, timeoutConfiguration: timeoutConfiguration);
} }
void dispose() { void dispose() {
...@@ -983,6 +983,12 @@ class NotifyingLogger extends Logger { ...@@ -983,6 +983,12 @@ class NotifyingLogger extends Logger {
@override @override
void sendEvent(String name, [Map<String, dynamic> args]) { } void sendEvent(String name, [Map<String, dynamic> args]) { }
@override
bool get supportsColor => throw UnimplementedError();
@override
bool get hasTerminal => false;
} }
/// A running application, started by this daemon. /// A running application, started by this daemon.
...@@ -1167,6 +1173,7 @@ class _AppRunLogger extends Logger { ...@@ -1167,6 +1173,7 @@ class _AppRunLogger extends Logger {
_status = SilentStatus( _status = SilentStatus(
timeout: timeout, timeout: timeout,
timeoutConfiguration: timeoutConfiguration,
onFinish: () { onFinish: () {
_status = null; _status = null;
_sendProgressEvent(<String, dynamic>{ _sendProgressEvent(<String, dynamic>{
...@@ -1206,6 +1213,12 @@ class _AppRunLogger extends Logger { ...@@ -1206,6 +1213,12 @@ class _AppRunLogger extends Logger {
domain.sendEvent(name, args); domain.sendEvent(name, args);
} }
} }
@override
bool get supportsColor => throw UnimplementedError();
@override
bool get hasTerminal => false;
} }
class LogMessage { class LogMessage {
......
...@@ -19,6 +19,7 @@ import 'base/logger.dart'; ...@@ -19,6 +19,7 @@ import 'base/logger.dart';
import 'base/os.dart'; import 'base/os.dart';
import 'base/process.dart'; import 'base/process.dart';
import 'base/signals.dart'; import 'base/signals.dart';
import 'base/terminal.dart';
import 'base/time.dart'; import 'base/time.dart';
import 'base/user_messages.dart'; import 'base/user_messages.dart';
import 'base/utils.dart'; import 'base/utils.dart';
...@@ -101,7 +102,19 @@ Future<T> runInContext<T>( ...@@ -101,7 +102,19 @@ Future<T> runInContext<T>(
IOSWorkflow: () => const IOSWorkflow(), IOSWorkflow: () => const IOSWorkflow(),
KernelCompilerFactory: () => const KernelCompilerFactory(), KernelCompilerFactory: () => const KernelCompilerFactory(),
LinuxWorkflow: () => const LinuxWorkflow(), LinuxWorkflow: () => const LinuxWorkflow(),
Logger: () => globals.platform.isWindows ? WindowsStdoutLogger() : StdoutLogger(), Logger: () => globals.platform.isWindows
? WindowsStdoutLogger(
terminal: globals.terminal,
stdio: globals.stdio,
outputPreferences: outputPreferences,
timeoutConfiguration: timeoutConfiguration,
)
: StdoutLogger(
terminal: globals.terminal,
stdio: globals.stdio,
outputPreferences: outputPreferences,
timeoutConfiguration: timeoutConfiguration,
),
MacOSWorkflow: () => const MacOSWorkflow(), MacOSWorkflow: () => const MacOSWorkflow(),
MDnsObservatoryDiscovery: () => MDnsObservatoryDiscovery(), MDnsObservatoryDiscovery: () => MDnsObservatoryDiscovery(),
OperatingSystemUtils: () => OperatingSystemUtils(), OperatingSystemUtils: () => OperatingSystemUtils(),
......
...@@ -211,7 +211,12 @@ class Doctor { ...@@ -211,7 +211,12 @@ class Doctor {
lineBuffer.write(' (${result.statusInfo})'); lineBuffer.write(' (${result.statusInfo})');
} }
buffer.write(wrapText(lineBuffer.toString(), hangingIndent: result.leadingBox.length + 1)); buffer.write(wrapText(
lineBuffer.toString(),
hangingIndent: result.leadingBox.length + 1,
columnWidth: outputPreferences.wrapColumn,
shouldWrap: outputPreferences.wrapText,
));
buffer.writeln(); buffer.writeln();
if (result.type != ValidationType.installed) { if (result.type != ValidationType.installed) {
...@@ -253,6 +258,7 @@ class Doctor { ...@@ -253,6 +258,7 @@ class Doctor {
final Status status = Status.withSpinner( final Status status = Status.withSpinner(
timeout: timeoutConfiguration.fastOperation, timeout: timeoutConfiguration.fastOperation,
slowWarningCallback: () => validator.slowWarning, slowWarningCallback: () => validator.slowWarning,
timeoutConfiguration: timeoutConfiguration,
); );
ValidationResult result; ValidationResult result;
try { try {
......
...@@ -10,6 +10,7 @@ import 'base/config.dart'; ...@@ -10,6 +10,7 @@ import 'base/config.dart';
import 'base/context.dart'; import 'base/context.dart';
import 'base/error_handling_file_system.dart'; import 'base/error_handling_file_system.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/io.dart';
import 'base/logger.dart'; import 'base/logger.dart';
import 'base/terminal.dart'; import 'base/terminal.dart';
import 'cache.dart'; import 'cache.dart';
...@@ -103,4 +104,10 @@ AnsiTerminal get terminal { ...@@ -103,4 +104,10 @@ AnsiTerminal get terminal {
return context?.get<AnsiTerminal>() ?? _defaultAnsiTerminal; return context?.get<AnsiTerminal>() ?? _defaultAnsiTerminal;
} }
final AnsiTerminal _defaultAnsiTerminal = AnsiTerminal(); final AnsiTerminal _defaultAnsiTerminal = AnsiTerminal(
stdio: stdio,
platform: platform,
);
/// The global Stdio wrapper.
Stdio get stdio => context.get<Stdio>() ?? const Stdio();
...@@ -243,6 +243,7 @@ Future<String> _chooseSigningIdentity(List<String> validCodeSigningIdentities) a ...@@ -243,6 +243,7 @@ Future<String> _chooseSigningIdentity(List<String> validCodeSigningIdentities) a
prompt: 'Please select a certificate for code signing', prompt: 'Please select a certificate for code signing',
displayAcceptedCharacters: true, displayAcceptedCharacters: true,
defaultChoiceIndex: 0, // Just pressing enter chooses the first one. defaultChoiceIndex: 0, // Just pressing enter chooses the first one.
logger: globals.logger,
); );
if (choice == 'a') { if (choice == 'a') {
......
...@@ -284,6 +284,7 @@ class XcodeProjectInterpreter { ...@@ -284,6 +284,7 @@ class XcodeProjectInterpreter {
}) async { }) async {
final Status status = Status.withSpinner( final Status status = Status.withSpinner(
timeout: timeoutConfiguration.fastOperation, timeout: timeoutConfiguration.fastOperation,
timeoutConfiguration: timeoutConfiguration,
); );
final List<String> showBuildSettingsCommand = <String>[ final List<String> showBuildSettingsCommand = <String>[
_executable, _executable,
......
...@@ -13,7 +13,6 @@ import '../artifacts.dart'; ...@@ -13,7 +13,6 @@ import '../artifacts.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart' as io;
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/terminal.dart'; import '../base/terminal.dart';
import '../base/user_messages.dart'; import '../base/user_messages.dart';
...@@ -146,13 +145,20 @@ class FlutterCommandRunner extends CommandRunner<void> { ...@@ -146,13 +145,20 @@ class FlutterCommandRunner extends CommandRunner<void> {
@override @override
String get usageFooter { String get usageFooter {
return wrapText('Run "flutter help -v" for verbose help output, including less commonly used options.'); return wrapText('Run "flutter help -v" for verbose help output, including less commonly used options.',
columnWidth: outputPreferences.wrapColumn,
shouldWrap: outputPreferences.wrapText,
);
} }
@override @override
String get usage { String get usage {
final String usageWithoutDescription = super.usage.substring(description.length + 2); final String usageWithoutDescription = super.usage.substring(description.length + 2);
return '${wrapText(description)}\n\n$usageWithoutDescription'; final String prefix = wrapText(description,
shouldWrap: outputPreferences.wrapText,
columnWidth: outputPreferences.wrapColumn,
);
return '$prefix\n\n$usageWithoutDescription';
} }
static String get defaultFlutterRoot { static String get defaultFlutterRoot {
...@@ -233,7 +239,7 @@ class FlutterCommandRunner extends CommandRunner<void> { ...@@ -233,7 +239,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
// Check for verbose. // Check for verbose.
if (topLevelResults['verbose'] as bool) { if (topLevelResults['verbose'] as bool) {
// Override the logger. // Override the logger.
contextOverrides[Logger] = VerboseLogger(globals.logger); contextOverrides[Logger] = VerboseLogger(globals.logger, stopwatch: Stopwatch());
} }
// Don't set wrapColumns unless the user said to: if it's set, then all // Don't set wrapColumns unless the user said to: if it's set, then all
...@@ -255,7 +261,7 @@ class FlutterCommandRunner extends CommandRunner<void> { ...@@ -255,7 +261,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
// anything, unless the user explicitly said to. // anything, unless the user explicitly said to.
final bool useWrapping = topLevelResults.wasParsed('wrap') final bool useWrapping = topLevelResults.wasParsed('wrap')
? topLevelResults['wrap'] as bool ? topLevelResults['wrap'] as bool
: io.stdio.terminalColumns != null && topLevelResults['wrap'] as bool; : globals.stdio.terminalColumns != null && topLevelResults['wrap'] as bool;
contextOverrides[OutputPreferences] = OutputPreferences( contextOverrides[OutputPreferences] = OutputPreferences(
wrapText: useWrapping, wrapText: useWrapping,
showColor: topLevelResults['color'] as bool, showColor: topLevelResults['color'] as bool,
......
...@@ -699,7 +699,7 @@ class StreamLogger extends Logger { ...@@ -699,7 +699,7 @@ class StreamLogger extends Logger {
int progressIndicatorPadding = kDefaultStatusPadding, int progressIndicatorPadding = kDefaultStatusPadding,
}) { }) {
_log('[progress] $message'); _log('[progress] $message');
return SilentStatus(timeout: timeout)..start(); return SilentStatus(timeout: timeout, timeoutConfiguration: timeoutConfiguration)..start();
} }
bool _interrupt = false; bool _interrupt = false;
...@@ -722,6 +722,12 @@ class StreamLogger extends Logger { ...@@ -722,6 +722,12 @@ class StreamLogger extends Logger {
@override @override
void sendEvent(String name, [Map<String, dynamic> args]) { } void sendEvent(String name, [Map<String, dynamic> args]) { }
@override
bool get supportsColor => throw UnimplementedError();
@override
bool get hasTerminal => false;
} }
class LoggerInterrupted implements Exception { class LoggerInterrupted implements Exception {
......
...@@ -7,7 +7,6 @@ import 'package:platform/platform.dart'; ...@@ -7,7 +7,6 @@ import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/commands/clean.dart'; import 'package:flutter_tools/src/commands/clean.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/xcode.dart'; import 'package:flutter_tools/src/macos/xcode.dart';
...@@ -77,7 +76,6 @@ void main() { ...@@ -77,7 +76,6 @@ void main() {
verify(mockFile.deleteSync(recursive: true)).called(1); verify(mockFile.deleteSync(recursive: true)).called(1);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
Logger: () => BufferLogger(),
Xcode: () => mockXcode, Xcode: () => mockXcode,
}); });
...@@ -94,7 +92,6 @@ void main() { ...@@ -94,7 +92,6 @@ void main() {
verifyNever(mockFile.deleteSync(recursive: true)); verifyNever(mockFile.deleteSync(recursive: true));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
Logger: () => BufferLogger(),
Xcode: () => mockXcode, Xcode: () => mockXcode,
}); });
} }
......
...@@ -15,7 +15,6 @@ import 'package:flutter_tools/src/base/context.dart'; ...@@ -15,7 +15,6 @@ import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
...@@ -451,11 +450,9 @@ void main() { ...@@ -451,11 +450,9 @@ void main() {
}); });
group('Config files', () { group('Config files', () {
BufferLogger mockLogger;
Directory tempDir; Directory tempDir;
setUp(() { setUp(() {
mockLogger = BufferLogger();
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_settings_aar_test.'); tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_settings_aar_test.');
}); });
...@@ -498,13 +495,12 @@ include ':app' ...@@ -498,13 +495,12 @@ include ':app'
createSettingsAarGradle(tempDir); createSettingsAarGradle(tempDir);
expect(mockLogger.statusText, contains('created successfully')); expect(testLogger.statusText, contains('created successfully'));
expect(tempDir.childFile('settings_aar.gradle').existsSync(), isTrue); expect(tempDir.childFile('settings_aar.gradle').existsSync(), isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => MemoryFileSystem(),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
Logger: () => mockLogger,
}); });
testUsingContext('create settings_aar.gradle when current settings.gradle doesn\'t load plugins', () { testUsingContext('create settings_aar.gradle when current settings.gradle doesn\'t load plugins', () {
...@@ -532,13 +528,12 @@ include ':app' ...@@ -532,13 +528,12 @@ include ':app'
createSettingsAarGradle(tempDir); createSettingsAarGradle(tempDir);
expect(mockLogger.statusText, contains('created successfully')); expect(testLogger.statusText, contains('created successfully'));
expect(tempDir.childFile('settings_aar.gradle').existsSync(), isTrue); expect(tempDir.childFile('settings_aar.gradle').existsSync(), isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => MemoryFileSystem(),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
Logger: () => mockLogger,
}); });
}); });
......
...@@ -9,7 +9,6 @@ import 'package:file/memory.dart'; ...@@ -9,7 +9,6 @@ import 'package:file/memory.dart';
import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/asset.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/bundle.dart'; import 'package:flutter_tools/src/bundle.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/devfs.dart';
...@@ -183,16 +182,15 @@ flutter: ...@@ -183,16 +182,15 @@ flutter:
}); });
}); });
test('Failed directory delete shows message', () async { testUsingContext('Failed directory delete shows message', () async {
final MockDirectory mockDirectory = MockDirectory(); final MockDirectory mockDirectory = MockDirectory();
final BufferLogger bufferLogger = BufferLogger();
when(mockDirectory.existsSync()).thenReturn(true); when(mockDirectory.existsSync()).thenReturn(true);
when(mockDirectory.deleteSync(recursive: true)).thenThrow(const FileSystemException('ABCD')); when(mockDirectory.deleteSync(recursive: true)).thenThrow(const FileSystemException('ABCD'));
await writeBundle(mockDirectory, <String, DevFSContent>{}, loggerOverride: bufferLogger); await writeBundle(mockDirectory, <String, DevFSContent>{}, loggerOverride: testLogger);
verify(mockDirectory.createSync(recursive: true)).called(1); verify(mockDirectory.createSync(recursive: true)).called(1);
expect(bufferLogger.errorText, contains('ABCD')); expect(testLogger.errorText, contains('ABCD'));
}); });
} }
......
...@@ -13,7 +13,6 @@ import 'package:flutter_tools/src/base/build.dart'; ...@@ -13,7 +13,6 @@ import 'package:flutter_tools/src/base/build.dart';
import 'package:flutter_tools/src/base/context.dart'; import 'package:flutter_tools/src/base/context.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/macos/xcode.dart'; import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:flutter_tools/src/version.dart'; import 'package:flutter_tools/src/version.dart';
...@@ -225,7 +224,6 @@ void main() { ...@@ -225,7 +224,6 @@ void main() {
MockAndroidSdk mockAndroidSdk; MockAndroidSdk mockAndroidSdk;
MockArtifacts mockArtifacts; MockArtifacts mockArtifacts;
MockXcode mockXcode; MockXcode mockXcode;
BufferLogger bufferLogger;
setUp(() async { setUp(() async {
fs = MemoryFileSystem(); fs = MemoryFileSystem();
...@@ -247,7 +245,6 @@ void main() { ...@@ -247,7 +245,6 @@ void main() {
mockXcode = MockXcode(); mockXcode = MockXcode();
when(mockXcode.sdkLocation(any)).thenAnswer((_) => Future<String>.value(kSDKPath)); when(mockXcode.sdkLocation(any)).thenAnswer((_) => Future<String>.value(kSDKPath));
bufferLogger = BufferLogger();
for (final BuildMode mode in BuildMode.values) { for (final BuildMode mode in BuildMode.values) {
when(mockArtifacts.getArtifactPath(Artifact.snapshotDart, when(mockArtifacts.getArtifactPath(Artifact.snapshotDart,
platform: anyNamed('platform'), mode: mode)).thenReturn(kSnapshotDart); platform: anyNamed('platform'), mode: mode)).thenReturn(kSnapshotDart);
...@@ -261,7 +258,6 @@ void main() { ...@@ -261,7 +258,6 @@ void main() {
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
GenSnapshot: () => genSnapshot, GenSnapshot: () => genSnapshot,
Xcode: () => mockXcode, Xcode: () => mockXcode,
Logger: () => bufferLogger,
}; };
testUsingContext('iOS debug AOT snapshot is invalid', () async { testUsingContext('iOS debug AOT snapshot is invalid', () async {
...@@ -658,7 +654,7 @@ void main() { ...@@ -658,7 +654,7 @@ void main() {
expect(genSnapshotExitCode, 0); expect(genSnapshotExitCode, 0);
expect(genSnapshot.callCount, 1); expect(genSnapshot.callCount, 1);
expect(bufferLogger.statusText, matches(RegExp(r'snapshot\(CompileTime\): \d+ ms.'))); expect(testLogger.statusText, matches(RegExp(r'snapshot\(CompileTime\): \d+ ms.')));
}, overrides: contextOverrides); }, overrides: contextOverrides);
}); });
} }
...@@ -6,7 +6,6 @@ import 'dart:convert' show jsonEncode; ...@@ -6,7 +6,6 @@ import 'dart:convert' show jsonEncode;
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/context.dart'; 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/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/globals.dart' as globals;
...@@ -16,7 +15,7 @@ import '../../src/common.dart'; ...@@ -16,7 +15,7 @@ import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/mocks.dart'; import '../../src/mocks.dart';
final Generator _kNoAnsiPlatform = () => FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false; final Platform _kNoAnsiPlatform = FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false;
void main() { void main() {
final String red = RegExp.escape(AnsiTerminal.red); final String red = RegExp.escape(AnsiTerminal.red);
...@@ -30,9 +29,15 @@ void main() { ...@@ -30,9 +29,15 @@ void main() {
setUp(() { setUp(() {
fakeStopWatch = FakeStopwatch(); fakeStopWatch = FakeStopwatch();
}); });
testUsingContext('error', () async { testWithoutContext('error', () async {
final BufferLogger mockLogger = BufferLogger(); final BufferLogger mockLogger = BufferLogger(
final VerboseLogger verboseLogger = VerboseLogger(mockLogger); terminal: AnsiTerminal(
stdio: MockStdio(),
platform: _kNoAnsiPlatform,
),
outputPreferences: OutputPreferences.test(showColor: false),
);
final VerboseLogger verboseLogger = VerboseLogger(mockLogger, stopwatch: fakeStopWatch);
verboseLogger.printStatus('Hey Hey Hey Hey'); verboseLogger.printStatus('Hey Hey Hey Hey');
verboseLogger.printTrace('Oooh, I do I do I do'); verboseLogger.printTrace('Oooh, I do I do I do');
...@@ -42,15 +47,17 @@ void main() { ...@@ -42,15 +47,17 @@ void main() {
r'\[ (?: {0,2}\+[0-9]{1,4} ms| )\] Oooh, I do I do I do\n$')); r'\[ (?: {0,2}\+[0-9]{1,4} ms| )\] Oooh, I do I do I do\n$'));
expect(mockLogger.traceText, ''); expect(mockLogger.traceText, '');
expect(mockLogger.errorText, matches( r'^\[ (?: {0,2}\+[0-9]{1,4} ms| )\] Helpless!\n$')); expect(mockLogger.errorText, matches( r'^\[ (?: {0,2}\+[0-9]{1,4} ms| )\] Helpless!\n$'));
}, overrides: <Type, Generator>{
OutputPreferences: () => OutputPreferences(showColor: false),
Platform: _kNoAnsiPlatform,
Stopwatch: () => fakeStopWatch,
}); });
testUsingContext('ANSI colored errors', () async { testWithoutContext('ANSI colored errors', () async {
final BufferLogger mockLogger = BufferLogger(); final BufferLogger mockLogger = BufferLogger(
final VerboseLogger verboseLogger = VerboseLogger(mockLogger); terminal: AnsiTerminal(
stdio: MockStdio(),
platform: FakePlatform()..stdoutSupportsAnsi = true,
),
outputPreferences: OutputPreferences.test(showColor: true),
);
final VerboseLogger verboseLogger = VerboseLogger(mockLogger, stopwatch: fakeStopWatch);
verboseLogger.printStatus('Hey Hey Hey Hey'); verboseLogger.printStatus('Hey Hey Hey Hey');
verboseLogger.printTrace('Oooh, I do I do I do'); verboseLogger.printTrace('Oooh, I do I do I do');
...@@ -64,10 +71,6 @@ void main() { ...@@ -64,10 +71,6 @@ void main() {
expect( expect(
mockLogger.errorText, mockLogger.errorText,
matches('^$red' r'\[ (?: {0,2}\+[0-9]{1,4} ms| )\] ' '${bold}Helpless!$resetBold$resetColor' r'\n$')); matches('^$red' r'\[ (?: {0,2}\+[0-9]{1,4} ms| )\] ' '${bold}Helpless!$resetBold$resetColor' r'\n$'));
}, overrides: <Type, Generator>{
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform()..stdoutSupportsAnsi = true,
Stopwatch: () => fakeStopWatch,
}); });
}); });
...@@ -84,6 +87,8 @@ void main() { ...@@ -84,6 +87,8 @@ void main() {
timeout: const Duration(seconds: 2), timeout: const Duration(seconds: 2),
padding: 20, padding: 20,
onFinish: () => called += 1, onFinish: () => called += 1,
stdio: mockStdio,
timeoutConfiguration: const TimeoutConfiguration(),
); );
} }
...@@ -110,6 +115,8 @@ void main() { ...@@ -110,6 +115,8 @@ void main() {
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
final AnsiSpinner ansiSpinner = AnsiSpinner( final AnsiSpinner ansiSpinner = AnsiSpinner(
timeout: const Duration(hours: 10), timeout: const Duration(hours: 10),
stdio: mockStdio,
timeoutConfiguration: const TimeoutConfiguration(),
)..start(); )..start();
doWhileAsync(time, () => ansiSpinner.ticks < 10); doWhileAsync(time, () => ansiSpinner.ticks < 10);
List<String> lines = outputStdout(); List<String> lines = outputStdout();
...@@ -138,7 +145,6 @@ void main() { ...@@ -138,7 +145,6 @@ void main() {
expect(done, isTrue); expect(done, isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => FakePlatform(operatingSystem: testOs), Platform: () => FakePlatform(operatingSystem: testOs),
Stdio: () => mockStdio,
Stopwatch: () => mockStopwatch, Stopwatch: () => mockStopwatch,
}); });
...@@ -148,6 +154,8 @@ void main() { ...@@ -148,6 +154,8 @@ void main() {
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
final AnsiSpinner ansiSpinner = AnsiSpinner( final AnsiSpinner ansiSpinner = AnsiSpinner(
timeout: const Duration(seconds: 2), timeout: const Duration(seconds: 2),
stdio: mockStdio,
timeoutConfiguration: const TimeoutConfiguration(),
)..start(); )..start();
mockStopwatch.elapsed = const Duration(seconds: 1); mockStopwatch.elapsed = const Duration(seconds: 1);
doWhileAsync(time, () => ansiSpinner.ticks < 10); // one second doWhileAsync(time, () => ansiSpinner.ticks < 10); // one second
...@@ -165,14 +173,22 @@ void main() { ...@@ -165,14 +173,22 @@ void main() {
expect(done, isTrue); expect(done, isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => FakePlatform(operatingSystem: testOs), Platform: () => FakePlatform(operatingSystem: testOs),
Stdio: () => mockStdio,
Stopwatch: () => mockStopwatch, Stopwatch: () => mockStopwatch,
}); });
// Uses Stopwatch from context.
testUsingContext('Stdout startProgress on colored terminal for $testOs', () async { testUsingContext('Stdout startProgress on colored terminal for $testOs', () async {
bool done = false; bool done = false;
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: FakePlatform(operatingSystem: testOs)..stdoutSupportsAnsi = true,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(showColor: true),
timeoutConfiguration: const TimeoutConfiguration(),
);
final Status status = logger.startProgress( final Status status = logger.startProgress(
'Hello', 'Hello',
progressId: null, progressId: null,
...@@ -190,18 +206,21 @@ void main() { ...@@ -190,18 +206,21 @@ void main() {
done = true; done = true;
}); });
expect(done, isTrue); expect(done, isTrue);
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform(operatingSystem: testOs)..stdoutSupportsAnsi = true,
Stdio: () => mockStdio,
}); });
testUsingContext('Stdout startProgress on colored terminal pauses on $testOs', () async { testUsingContext('Stdout startProgress on colored terminal pauses on $testOs', () async {
bool done = false; bool done = false;
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
mockStopwatch.elapsed = const Duration(seconds: 5); mockStopwatch.elapsed = const Duration(seconds: 5);
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: FakePlatform(operatingSystem: testOs)..stdoutSupportsAnsi = true,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(showColor: true),
timeoutConfiguration: const TimeoutConfiguration(),
);
final Status status = logger.startProgress( final Status status = logger.startProgress(
'Knock Knock, Who\'s There', 'Knock Knock, Who\'s There',
timeout: const Duration(days: 10), timeout: const Duration(days: 10),
...@@ -232,10 +251,6 @@ void main() { ...@@ -232,10 +251,6 @@ void main() {
}); });
expect(done, isTrue); expect(done, isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform(operatingSystem: testOs)..stdoutSupportsAnsi = true,
Stdio: () => mockStdio,
Stopwatch: () => mockStopwatch, Stopwatch: () => mockStopwatch,
}); });
...@@ -270,7 +285,6 @@ void main() { ...@@ -270,7 +285,6 @@ void main() {
expect(done, isTrue); expect(done, isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => FakePlatform(operatingSystem: testOs), Platform: () => FakePlatform(operatingSystem: testOs),
Stdio: () => mockStdio,
Stopwatch: () => mockStopwatch, Stopwatch: () => mockStopwatch,
}); });
...@@ -307,7 +321,6 @@ void main() { ...@@ -307,7 +321,6 @@ void main() {
expect(done, isTrue); expect(done, isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => FakePlatform(operatingSystem: testOs), Platform: () => FakePlatform(operatingSystem: testOs),
Stdio: () => mockStdio,
Stopwatch: () => mockStopwatch, Stopwatch: () => mockStopwatch,
}); });
...@@ -353,7 +366,6 @@ void main() { ...@@ -353,7 +366,6 @@ void main() {
expect(done, isTrue); expect(done, isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => FakePlatform(operatingSystem: testOs), Platform: () => FakePlatform(operatingSystem: testOs),
Stdio: () => mockStdio,
Stopwatch: () => mockStopwatch, Stopwatch: () => mockStopwatch,
}); });
} }
...@@ -372,33 +384,48 @@ void main() { ...@@ -372,33 +384,48 @@ void main() {
timeout: timeoutConfiguration.slowOperation, timeout: timeoutConfiguration.slowOperation,
padding: 20, padding: 20,
onFinish: () => called++, onFinish: () => called++,
stdio: mockStdio,
timeoutConfiguration: const TimeoutConfiguration(),
); );
}); });
List<String> outputStdout() => mockStdio.writtenToStdout.join('').split('\n'); List<String> outputStdout() => mockStdio.writtenToStdout.join('').split('\n');
List<String> outputStderr() => mockStdio.writtenToStderr.join('').split('\n'); List<String> outputStderr() => mockStdio.writtenToStderr.join('').split('\n');
testUsingContext('Error logs are wrapped', () async { testWithoutContext('Error logs are wrapped', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printError('0123456789' * 15); logger.printError('0123456789' * 15);
final List<String> lines = outputStderr(); final List<String> lines = outputStderr();
expect(outputStdout().length, equals(1)); expect(outputStdout().length, equals(1));
expect(outputStdout().first, isEmpty); expect(outputStdout().first, isEmpty);
expect(lines[0], equals('0123456789' * 4)); expect(lines[0], equals('0123456789' * 4));
expect(lines[1], equals('0123456789' * 4)); expect(lines[1], equals('0123456789' * 4));
expect(lines[2], equals('0123456789' * 4)); expect(lines[2], equals('0123456789' * 4));
expect(lines[3], equals('0123456789' * 3)); expect(lines[3], equals('0123456789' * 3));
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40, showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('Error logs are wrapped and can be indented.', () async { testWithoutContext('Error logs are wrapped and can be indented.', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printError('0123456789' * 15, indent: 5); logger.printError('0123456789' * 15, indent: 5);
final List<String> lines = outputStderr(); final List<String> lines = outputStderr();
expect(outputStdout().length, equals(1)); expect(outputStdout().length, equals(1));
expect(outputStdout().first, isEmpty); expect(outputStdout().first, isEmpty);
expect(lines.length, equals(6)); expect(lines.length, equals(6));
...@@ -408,17 +435,21 @@ void main() { ...@@ -408,17 +435,21 @@ void main() {
expect(lines[3], equals(' 56789012345678901234567890123456789')); expect(lines[3], equals(' 56789012345678901234567890123456789'));
expect(lines[4], equals(' 0123456789')); expect(lines[4], equals(' 0123456789'));
expect(lines[5], isEmpty); expect(lines[5], isEmpty);
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40, showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('Error logs are wrapped and can have hanging indent.', () async { testWithoutContext('Error logs are wrapped and can have hanging indent.', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printError('0123456789' * 15, hangingIndent: 5); logger.printError('0123456789' * 15, hangingIndent: 5);
final List<String> lines = outputStderr(); final List<String> lines = outputStderr();
expect(outputStdout().length, equals(1)); expect(outputStdout().length, equals(1));
expect(outputStdout().first, isEmpty); expect(outputStdout().first, isEmpty);
expect(lines.length, equals(6)); expect(lines.length, equals(6));
...@@ -428,17 +459,21 @@ void main() { ...@@ -428,17 +459,21 @@ void main() {
expect(lines[3], equals(' 01234567890123456789012345678901234')); expect(lines[3], equals(' 01234567890123456789012345678901234'));
expect(lines[4], equals(' 56789')); expect(lines[4], equals(' 56789'));
expect(lines[5], isEmpty); expect(lines[5], isEmpty);
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40, showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('Error logs are wrapped, indented, and can have hanging indent.', () async { testWithoutContext('Error logs are wrapped, indented, and can have hanging indent.', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printError('0123456789' * 15, indent: 4, hangingIndent: 5); logger.printError('0123456789' * 15, indent: 4, hangingIndent: 5);
final List<String> lines = outputStderr(); final List<String> lines = outputStderr();
expect(outputStdout().length, equals(1)); expect(outputStdout().length, equals(1));
expect(outputStdout().first, isEmpty); expect(outputStdout().first, isEmpty);
expect(lines.length, equals(6)); expect(lines.length, equals(6));
...@@ -448,34 +483,42 @@ void main() { ...@@ -448,34 +483,42 @@ void main() {
expect(lines[3], equals(' 8901234567890123456789012345678')); expect(lines[3], equals(' 8901234567890123456789012345678'));
expect(lines[4], equals(' 901234567890123456789')); expect(lines[4], equals(' 901234567890123456789'));
expect(lines[5], isEmpty); expect(lines[5], isEmpty);
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40, showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('Stdout logs are wrapped', () async { testWithoutContext('Stdout logs are wrapped', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printStatus('0123456789' * 15); logger.printStatus('0123456789' * 15);
final List<String> lines = outputStdout(); final List<String> lines = outputStdout();
expect(outputStderr().length, equals(1)); expect(outputStderr().length, equals(1));
expect(outputStderr().first, isEmpty); expect(outputStderr().first, isEmpty);
expect(lines[0], equals('0123456789' * 4)); expect(lines[0], equals('0123456789' * 4));
expect(lines[1], equals('0123456789' * 4)); expect(lines[1], equals('0123456789' * 4));
expect(lines[2], equals('0123456789' * 4)); expect(lines[2], equals('0123456789' * 4));
expect(lines[3], equals('0123456789' * 3)); expect(lines[3], equals('0123456789' * 3));
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40, showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('Stdout logs are wrapped and can be indented.', () async { testWithoutContext('Stdout logs are wrapped and can be indented.', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printStatus('0123456789' * 15, indent: 5); logger.printStatus('0123456789' * 15, indent: 5);
final List<String> lines = outputStdout(); final List<String> lines = outputStdout();
expect(outputStderr().length, equals(1)); expect(outputStderr().length, equals(1));
expect(outputStderr().first, isEmpty); expect(outputStderr().first, isEmpty);
expect(lines.length, equals(6)); expect(lines.length, equals(6));
...@@ -485,17 +528,21 @@ void main() { ...@@ -485,17 +528,21 @@ void main() {
expect(lines[3], equals(' 56789012345678901234567890123456789')); expect(lines[3], equals(' 56789012345678901234567890123456789'));
expect(lines[4], equals(' 0123456789')); expect(lines[4], equals(' 0123456789'));
expect(lines[5], isEmpty); expect(lines[5], isEmpty);
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40, showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('Stdout logs are wrapped and can have hanging indent.', () async { testWithoutContext('Stdout logs are wrapped and can have hanging indent.', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printStatus('0123456789' * 15, hangingIndent: 5); logger.printStatus('0123456789' * 15, hangingIndent: 5);
final List<String> lines = outputStdout(); final List<String> lines = outputStdout();
expect(outputStderr().length, equals(1)); expect(outputStderr().length, equals(1));
expect(outputStderr().first, isEmpty); expect(outputStderr().first, isEmpty);
expect(lines.length, equals(6)); expect(lines.length, equals(6));
...@@ -505,17 +552,21 @@ void main() { ...@@ -505,17 +552,21 @@ void main() {
expect(lines[3], equals(' 01234567890123456789012345678901234')); expect(lines[3], equals(' 01234567890123456789012345678901234'));
expect(lines[4], equals(' 56789')); expect(lines[4], equals(' 56789'));
expect(lines[5], isEmpty); expect(lines[5], isEmpty);
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40, showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('Stdout logs are wrapped, indented, and can have hanging indent.', () async { testUsingContext('Stdout logs are wrapped, indented, and can have hanging indent.', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40, showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printStatus('0123456789' * 15, indent: 4, hangingIndent: 5); logger.printStatus('0123456789' * 15, indent: 4, hangingIndent: 5);
final List<String> lines = outputStdout(); final List<String> lines = outputStdout();
expect(outputStderr().length, equals(1)); expect(outputStderr().length, equals(1));
expect(outputStderr().first, isEmpty); expect(outputStderr().first, isEmpty);
expect(lines.length, equals(6)); expect(lines.length, equals(6));
...@@ -525,42 +576,54 @@ void main() { ...@@ -525,42 +576,54 @@ void main() {
expect(lines[3], equals(' 8901234567890123456789012345678')); expect(lines[3], equals(' 8901234567890123456789012345678'));
expect(lines[4], equals(' 901234567890123456789')); expect(lines[4], equals(' 901234567890123456789'));
expect(lines[5], isEmpty); expect(lines[5], isEmpty);
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40, showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('Error logs are red', () async { testWithoutContext('Error logs are red', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: FakePlatform()..stdoutSupportsAnsi = true,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(showColor: true),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printError('Pants on fire!'); logger.printError('Pants on fire!');
final List<String> lines = outputStderr(); final List<String> lines = outputStderr();
expect(outputStdout().length, equals(1)); expect(outputStdout().length, equals(1));
expect(outputStdout().first, isEmpty); expect(outputStdout().first, isEmpty);
expect(lines[0], equals('${AnsiTerminal.red}Pants on fire!${AnsiTerminal.resetColor}')); expect(lines[0], equals('${AnsiTerminal.red}Pants on fire!${AnsiTerminal.resetColor}'));
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform()..stdoutSupportsAnsi = true,
Stdio: () => mockStdio,
}); });
testUsingContext('Stdout logs are not colored', () async { testWithoutContext('Stdout logs are not colored', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: FakePlatform(),
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(showColor: true),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printStatus('All good.'); logger.printStatus('All good.');
final List<String> lines = outputStdout(); final List<String> lines = outputStdout();
expect(outputStderr().length, equals(1)); expect(outputStderr().length, equals(1));
expect(outputStderr().first, isEmpty); expect(outputStderr().first, isEmpty);
expect(lines[0], equals('All good.')); expect(lines[0], equals('All good.'));
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(showColor: true),
Stdio: () => mockStdio,
}); });
testUsingContext('Stdout printStatus handle null inputs on colored terminal', () async { testWithoutContext('Stdout printStatus handle null inputs on colored terminal', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: FakePlatform(),
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(showColor: true),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printStatus( logger.printStatus(
null, null,
emphasis: null, emphasis: null,
...@@ -569,17 +632,22 @@ void main() { ...@@ -569,17 +632,22 @@ void main() {
indent: null, indent: null,
); );
final List<String> lines = outputStdout(); final List<String> lines = outputStdout();
expect(outputStderr().length, equals(1)); expect(outputStderr().length, equals(1));
expect(outputStderr().first, isEmpty); expect(outputStderr().first, isEmpty);
expect(lines[0], equals('')); expect(lines[0], equals(''));
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(showColor: true),
Stdio: () => mockStdio,
}); });
testUsingContext('Stdout printStatus handle null inputs on non-color terminal', () async { testWithoutContext('Stdout printStatus handle null inputs on non-color terminal', () async {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.printStatus( logger.printStatus(
null, null,
emphasis: null, emphasis: null,
...@@ -591,21 +659,25 @@ void main() { ...@@ -591,21 +659,25 @@ void main() {
expect(outputStderr().length, equals(1)); expect(outputStderr().length, equals(1));
expect(outputStderr().first, isEmpty); expect(outputStderr().first, isEmpty);
expect(lines[0], equals('')); expect(lines[0], equals(''));
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('Stdout startProgress on non-color terminal', () async { // Status uses Stopwatch from context.
test('Stdout startProgress on non-color terminal', () async {
bool done = false; bool done = false;
FakeAsync().run((FakeAsync time) { FakeAsync().run((FakeAsync time) {
final Logger logger = context.get<Logger>(); final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
final Status status = logger.startProgress( final Status status = logger.startProgress(
'Hello', 'Hello',
progressId: null, progressId: null,
timeout: timeoutConfiguration.slowOperation, timeout: const TimeoutConfiguration().slowOperation,
progressIndicatorPadding: 20, // this minus the "Hello" equals the 15 below. progressIndicatorPadding: 20, // this minus the "Hello" equals the 15 below.
); );
expect(outputStderr().length, equals(1)); expect(outputStderr().length, equals(1));
...@@ -619,11 +691,6 @@ void main() { ...@@ -619,11 +691,6 @@ void main() {
done = true; done = true;
}); });
expect(done, isTrue); expect(done, isTrue);
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('SummaryStatus works when canceled', () async { testUsingContext('SummaryStatus works when canceled', () async {
...@@ -646,7 +713,9 @@ void main() { ...@@ -646,7 +713,9 @@ void main() {
// Verify that stopping or canceling multiple times throws. // Verify that stopping or canceling multiple times throws.
expect(() { summaryStatus.cancel(); }, throwsA(isInstanceOf<AssertionError>())); expect(() { summaryStatus.cancel(); }, throwsA(isInstanceOf<AssertionError>()));
expect(() { summaryStatus.stop(); }, throwsA(isInstanceOf<AssertionError>())); expect(() { summaryStatus.stop(); }, throwsA(isInstanceOf<AssertionError>()));
}, overrides: <Type, Generator>{Stdio: () => mockStdio, Platform: _kNoAnsiPlatform}); }, overrides: <Type, Generator>{
Platform: () => _kNoAnsiPlatform,
});
testUsingContext('SummaryStatus works when stopped', () async { testUsingContext('SummaryStatus works when stopped', () async {
summaryStatus.start(); summaryStatus.start();
...@@ -669,30 +738,53 @@ void main() { ...@@ -669,30 +738,53 @@ void main() {
// Verify that stopping or canceling multiple times throws. // Verify that stopping or canceling multiple times throws.
expect(() { summaryStatus.stop(); }, throwsA(isInstanceOf<AssertionError>())); expect(() { summaryStatus.stop(); }, throwsA(isInstanceOf<AssertionError>()));
expect(() { summaryStatus.cancel(); }, throwsA(isInstanceOf<AssertionError>())); expect(() { summaryStatus.cancel(); }, throwsA(isInstanceOf<AssertionError>()));
}, overrides: <Type, Generator>{Stdio: () => mockStdio, Platform: _kNoAnsiPlatform}); }, overrides: <Type, Generator>{
Platform: () => _kNoAnsiPlatform,
});
testUsingContext('sequential startProgress calls with StdoutLogger', () async { // Status still uses Stopwatch from context.
final Logger logger = context.get<Logger>(); // TODO(jonahwilliams): switch to testWithoutContext once logger uses a
logger.startProgress('AAA', timeout: timeoutConfiguration.fastOperation)..stop(); // TimerFactory.
logger.startProgress('BBB', timeout: timeoutConfiguration.fastOperation)..stop(); test('sequential startProgress calls with StdoutLogger', () async {
final Logger logger = StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(showColor: false),
timeoutConfiguration: const TimeoutConfiguration(),
);
logger.startProgress('AAA', timeout: const TimeoutConfiguration().fastOperation)..stop();
logger.startProgress('BBB', timeout: const TimeoutConfiguration().fastOperation)..stop();
final List<String> output = outputStdout(); final List<String> output = outputStdout();
expect(output.length, equals(3)); expect(output.length, equals(3));
// There's 61 spaces at the start: 59 (padding default) - 3 (length of AAA) + 5 (margin). // There's 61 spaces at the start: 59 (padding default) - 3 (length of AAA) + 5 (margin).
// Then there's a left-padded "0ms" 8 characters wide, so 5 spaces then "0ms" // Then there's a left-padded "0ms" 8 characters wide, so 5 spaces then "0ms"
// (except sometimes it's randomly slow so we handle up to "99,999ms"). // (except sometimes it's randomly slow so we handle up to "99,999ms").
expect(output[0], matches(RegExp(r'AAA[ ]{61}[\d, ]{5}[\d]ms'))); expect(output[0], matches(RegExp(r'AAA[ ]{61}[\d, ]{5}[\d]ms')));
expect(output[1], matches(RegExp(r'BBB[ ]{61}[\d, ]{5}[\d]ms'))); expect(output[1], matches(RegExp(r'BBB[ ]{61}[\d, ]{5}[\d]ms')));
}, overrides: <Type, Generator>{
Logger: () => StdoutLogger(),
OutputPreferences: () => OutputPreferences(showColor: false),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('sequential startProgress calls with VerboseLogger and StdoutLogger', () async { // Status still uses Stopwatch from context.
final Logger logger = context.get<Logger>(); test('sequential startProgress calls with VerboseLogger and StdoutLogger', () async {
logger.startProgress('AAA', timeout: timeoutConfiguration.fastOperation)..stop(); final Logger logger = VerboseLogger(
logger.startProgress('BBB', timeout: timeoutConfiguration.fastOperation)..stop(); StdoutLogger(
terminal: AnsiTerminal(
stdio: mockStdio,
platform: _kNoAnsiPlatform,
),
stdio: mockStdio,
outputPreferences: OutputPreferences.test(),
timeoutConfiguration: const TimeoutConfiguration(),
),
stopwatch: FakeStopwatch(),
);
logger.startProgress('AAA', timeout: const TimeoutConfiguration().fastOperation)..stop();
logger.startProgress('BBB', timeout: const TimeoutConfiguration().fastOperation)..stop();
expect(outputStdout(), <Matcher>[ expect(outputStdout(), <Matcher>[
matches(r'^\[ (?: {0,2}\+[0-9]{1,4} ms| )\] AAA$'), matches(r'^\[ (?: {0,2}\+[0-9]{1,4} ms| )\] AAA$'),
matches(r'^\[ (?: {0,2}\+[0-9]{1,4} ms| )\] AAA \(completed.*\)$'), matches(r'^\[ (?: {0,2}\+[0-9]{1,4} ms| )\] AAA \(completed.*\)$'),
...@@ -700,19 +792,21 @@ void main() { ...@@ -700,19 +792,21 @@ void main() {
matches(r'^\[ (?: {0,2}\+[0-9]{1,4} ms| )\] BBB \(completed.*\)$'), matches(r'^\[ (?: {0,2}\+[0-9]{1,4} ms| )\] BBB \(completed.*\)$'),
matches(r'^$'), matches(r'^$'),
]); ]);
}, overrides: <Type, Generator>{
Logger: () => VerboseLogger(StdoutLogger()),
Stdio: () => mockStdio,
Platform: _kNoAnsiPlatform,
}); });
testUsingContext('sequential startProgress calls with BufferLogger', () async { // Status still uses Stopwatch from context.
testLogger.startProgress('AAA', timeout: timeoutConfiguration.fastOperation)..stop(); test('sequential startProgress calls with BufferLogger', () async {
testLogger.startProgress('BBB', timeout: timeoutConfiguration.fastOperation)..stop(); final BufferLogger logger = BufferLogger(
expect(testLogger.statusText, 'AAA\nBBB\n'); terminal: AnsiTerminal(
}, overrides: <Type, Generator>{ stdio: mockStdio,
Logger: () => BufferLogger(), platform: _kNoAnsiPlatform,
Platform: _kNoAnsiPlatform, ),
outputPreferences: OutputPreferences.test(),
);
logger.startProgress('AAA', timeout: const TimeoutConfiguration().fastOperation)..stop();
logger.startProgress('BBB', timeout: const TimeoutConfiguration().fastOperation)..stop();
expect(logger.statusText, 'AAA\nBBB\n');
}); });
}); });
} }
......
...@@ -6,7 +6,6 @@ import 'dart:async'; ...@@ -6,7 +6,6 @@ import 'dart:async';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/terminal.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
...@@ -69,11 +68,9 @@ void main() { ...@@ -69,11 +68,9 @@ void main() {
group('output formatting', () { group('output formatting', () {
MockProcessManager mockProcessManager; MockProcessManager mockProcessManager;
BufferLogger mockLogger;
setUp(() { setUp(() {
mockProcessManager = MockProcessManager(); mockProcessManager = MockProcessManager();
mockLogger = BufferLogger();
}); });
MockProcess Function(List<String>) processMetaFactory(List<String> stdout, { List<String> stderr = const <String>[] }) { MockProcess Function(List<String>) processMetaFactory(List<String> stdout, { List<String> stderr = const <String>[] }) {
...@@ -88,10 +85,10 @@ void main() { ...@@ -88,10 +85,10 @@ void main() {
final List<String> testString = <String>['0123456789' * 10]; final List<String> testString = <String>['0123456789' * 10];
mockProcessManager.processFactory = processMetaFactory(testString, stderr: testString); mockProcessManager.processFactory = processMetaFactory(testString, stderr: testString);
await processUtils.stream(<String>['command']); await processUtils.stream(<String>['command']);
expect(mockLogger.statusText, equals('${testString[0]}\n'));
expect(mockLogger.errorText, equals('${testString[0]}\n')); expect(testLogger.statusText, equals('${testString[0]}\n'));
expect(testLogger.errorText, equals('${testString[0]}\n'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => mockLogger,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40), OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40),
Platform: () => FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false, Platform: () => FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false,
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/terminal.dart';
...@@ -11,24 +12,28 @@ import 'package:flutter_tools/src/globals.dart' as globals; ...@@ -11,24 +12,28 @@ import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart';
void main() { void main() {
group('output preferences', () { group('output preferences', () {
testUsingContext('can wrap output', () async { testWithoutContext('can wrap output', () async {
globals.printStatus('0123456789' * 8); final BufferLogger bufferLogger = BufferLogger(
expect(testLogger.statusText, equals(('0123456789' * 4 + '\n') * 2)); outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40),
}, overrides: <Type, Generator>{ terminal: TestTerminal(platform: FakePlatform()..stdoutSupportsAnsi = true),
OutputPreferences: () => OutputPreferences(wrapText: true, wrapColumn: 40), );
bufferLogger.printStatus('0123456789' * 8);
expect(bufferLogger.statusText, equals(('0123456789' * 4 + '\n') * 2));
}); });
testUsingContext('can turn off wrapping', () async { testWithoutContext('can turn off wrapping', () async {
final BufferLogger bufferLogger = BufferLogger(
outputPreferences: OutputPreferences.test(wrapText: false),
terminal: TestTerminal(platform: FakePlatform()..stdoutSupportsAnsi = true),
);
final String testString = '0123456789' * 20; final String testString = '0123456789' * 20;
globals.printStatus(testString); bufferLogger.printStatus(testString);
expect(testLogger.statusText, equals('$testString\n'));
}, overrides: <Type, Generator>{ expect(bufferLogger.statusText, equals('$testString\n'));
Platform: () => FakePlatform()..stdoutSupportsAnsi = true,
OutputPreferences: () => OutputPreferences(wrapText: false),
}); });
}); });
...@@ -36,32 +41,29 @@ void main() { ...@@ -36,32 +41,29 @@ void main() {
AnsiTerminal terminal; AnsiTerminal terminal;
setUp(() { setUp(() {
terminal = AnsiTerminal(); terminal = AnsiTerminal(
stdio: globals.stdio, // Danger, using real stdio.
platform: FakePlatform()..stdoutSupportsAnsi = true,
);
}); });
testUsingContext('adding colors works', () { testWithoutContext('adding colors works', () {
for (final TerminalColor color in TerminalColor.values) { for (final TerminalColor color in TerminalColor.values) {
expect( expect(
terminal.color('output', color), terminal.color('output', color),
equals('${AnsiTerminal.colorCode(color)}output${AnsiTerminal.resetColor}'), equals('${AnsiTerminal.colorCode(color)}output${AnsiTerminal.resetColor}'),
); );
} }
}, overrides: <Type, Generator>{
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform()..stdoutSupportsAnsi = true,
}); });
testUsingContext('adding bold works', () { testWithoutContext('adding bold works', () {
expect( expect(
terminal.bolden('output'), terminal.bolden('output'),
equals('${AnsiTerminal.bold}output${AnsiTerminal.resetBold}'), equals('${AnsiTerminal.bold}output${AnsiTerminal.resetBold}'),
); );
}, overrides: <Type, Generator>{
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform()..stdoutSupportsAnsi = true,
}); });
testUsingContext('nesting bold within color works', () { testWithoutContext('nesting bold within color works', () {
expect( expect(
terminal.color(terminal.bolden('output'), TerminalColor.blue), terminal.color(terminal.bolden('output'), TerminalColor.blue),
equals('${AnsiTerminal.blue}${AnsiTerminal.bold}output${AnsiTerminal.resetBold}${AnsiTerminal.resetColor}'), equals('${AnsiTerminal.blue}${AnsiTerminal.bold}output${AnsiTerminal.resetBold}${AnsiTerminal.resetColor}'),
...@@ -70,12 +72,9 @@ void main() { ...@@ -70,12 +72,9 @@ void main() {
terminal.color('non-bold ${terminal.bolden('output')} also non-bold', TerminalColor.blue), terminal.color('non-bold ${terminal.bolden('output')} also non-bold', TerminalColor.blue),
equals('${AnsiTerminal.blue}non-bold ${AnsiTerminal.bold}output${AnsiTerminal.resetBold} also non-bold${AnsiTerminal.resetColor}'), equals('${AnsiTerminal.blue}non-bold ${AnsiTerminal.bold}output${AnsiTerminal.resetBold} also non-bold${AnsiTerminal.resetColor}'),
); );
}, overrides: <Type, Generator>{
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform()..stdoutSupportsAnsi = true,
}); });
testUsingContext('nesting color within bold works', () { testWithoutContext('nesting color within bold works', () {
expect( expect(
terminal.bolden(terminal.color('output', TerminalColor.blue)), terminal.bolden(terminal.color('output', TerminalColor.blue)),
equals('${AnsiTerminal.bold}${AnsiTerminal.blue}output${AnsiTerminal.resetColor}${AnsiTerminal.resetBold}'), equals('${AnsiTerminal.bold}${AnsiTerminal.blue}output${AnsiTerminal.resetColor}${AnsiTerminal.resetBold}'),
...@@ -84,12 +83,9 @@ void main() { ...@@ -84,12 +83,9 @@ void main() {
terminal.bolden('non-color ${terminal.color('output', TerminalColor.blue)} also non-color'), terminal.bolden('non-color ${terminal.color('output', TerminalColor.blue)} also non-color'),
equals('${AnsiTerminal.bold}non-color ${AnsiTerminal.blue}output${AnsiTerminal.resetColor} also non-color${AnsiTerminal.resetBold}'), equals('${AnsiTerminal.bold}non-color ${AnsiTerminal.blue}output${AnsiTerminal.resetColor} also non-color${AnsiTerminal.resetBold}'),
); );
}, overrides: <Type, Generator>{
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform()..stdoutSupportsAnsi = true,
}); });
testUsingContext('nesting color within color works', () { testWithoutContext('nesting color within color works', () {
expect( expect(
terminal.color(terminal.color('output', TerminalColor.blue), TerminalColor.magenta), terminal.color(terminal.color('output', TerminalColor.blue), TerminalColor.magenta),
equals('${AnsiTerminal.magenta}${AnsiTerminal.blue}output${AnsiTerminal.resetColor}${AnsiTerminal.magenta}${AnsiTerminal.resetColor}'), equals('${AnsiTerminal.magenta}${AnsiTerminal.blue}output${AnsiTerminal.resetColor}${AnsiTerminal.magenta}${AnsiTerminal.resetColor}'),
...@@ -98,12 +94,9 @@ void main() { ...@@ -98,12 +94,9 @@ void main() {
terminal.color('magenta ${terminal.color('output', TerminalColor.blue)} also magenta', TerminalColor.magenta), terminal.color('magenta ${terminal.color('output', TerminalColor.blue)} also magenta', TerminalColor.magenta),
equals('${AnsiTerminal.magenta}magenta ${AnsiTerminal.blue}output${AnsiTerminal.resetColor}${AnsiTerminal.magenta} also magenta${AnsiTerminal.resetColor}'), equals('${AnsiTerminal.magenta}magenta ${AnsiTerminal.blue}output${AnsiTerminal.resetColor}${AnsiTerminal.magenta} also magenta${AnsiTerminal.resetColor}'),
); );
}, overrides: <Type, Generator>{
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform()..stdoutSupportsAnsi = true,
}); });
testUsingContext('nesting bold within bold works', () { testWithoutContext('nesting bold within bold works', () {
expect( expect(
terminal.bolden(terminal.bolden('output')), terminal.bolden(terminal.bolden('output')),
equals('${AnsiTerminal.bold}output${AnsiTerminal.resetBold}'), equals('${AnsiTerminal.bold}output${AnsiTerminal.resetBold}'),
...@@ -112,9 +105,6 @@ void main() { ...@@ -112,9 +105,6 @@ void main() {
terminal.bolden('bold ${terminal.bolden('output')} still bold'), terminal.bolden('bold ${terminal.bolden('output')} still bold'),
equals('${AnsiTerminal.bold}bold output still bold${AnsiTerminal.resetBold}'), equals('${AnsiTerminal.bold}bold output still bold${AnsiTerminal.resetBold}'),
); );
}, overrides: <Type, Generator>{
OutputPreferences: () => OutputPreferences(showColor: true),
Platform: () => FakePlatform()..stdoutSupportsAnsi = true,
}); });
}); });
...@@ -122,17 +112,22 @@ void main() { ...@@ -122,17 +112,22 @@ void main() {
AnsiTerminal terminalUnderTest; AnsiTerminal terminalUnderTest;
setUp(() { setUp(() {
terminalUnderTest = TestTerminal(); terminalUnderTest = TestTerminal(stdio: MockStdio());
}); });
testUsingContext('character prompt throws if usesTerminalUi is false', () async { testWithoutContext('character prompt throws if usesTerminalUi is false', () async {
expect(terminalUnderTest.promptForCharInput( expect(terminalUnderTest.promptForCharInput(
<String>['a', 'b', 'c'], <String>['a', 'b', 'c'],
prompt: 'Please choose something', prompt: 'Please choose something',
logger: null,
), throwsA(isInstanceOf<StateError>())); ), throwsA(isInstanceOf<StateError>()));
}); });
testUsingContext('character prompt', () async { testWithoutContext('character prompt', () async {
final BufferLogger bufferLogger = BufferLogger(
terminal: terminalUnderTest,
outputPreferences: OutputPreferences.test(),
);
terminalUnderTest.usesTerminalUi = true; terminalUnderTest.usesTerminalUi = true;
mockStdInStream = Stream<String>.fromFutures(<Future<String>>[ mockStdInStream = Stream<String>.fromFutures(<Future<String>>[
Future<String>.value('d'), // Not in accepted list. Future<String>.value('d'), // Not in accepted list.
...@@ -142,17 +137,22 @@ void main() { ...@@ -142,17 +137,22 @@ void main() {
final String choice = await terminalUnderTest.promptForCharInput( final String choice = await terminalUnderTest.promptForCharInput(
<String>['a', 'b', 'c'], <String>['a', 'b', 'c'],
prompt: 'Please choose something', prompt: 'Please choose something',
logger: bufferLogger,
); );
expect(choice, 'b'); expect(choice, 'b');
expect( expect(
testLogger.statusText, bufferLogger.statusText,
'Please choose something [a|b|c]: d\n' 'Please choose something [a|b|c]: d\n'
'Please choose something [a|b|c]: \n' 'Please choose something [a|b|c]: \n'
'\n' '\n'
'Please choose something [a|b|c]: b\n'); 'Please choose something [a|b|c]: b\n');
}); });
testUsingContext('default character choice without displayAcceptedCharacters', () async { testWithoutContext('default character choice without displayAcceptedCharacters', () async {
final BufferLogger bufferLogger = BufferLogger(
terminal: terminalUnderTest,
outputPreferences: OutputPreferences.test(),
);
terminalUnderTest.usesTerminalUi = true; terminalUnderTest.usesTerminalUi = true;
mockStdInStream = Stream<String>.fromFutures(<Future<String>>[ mockStdInStream = Stream<String>.fromFutures(<Future<String>>[
Future<String>.value('\n'), // Not in accepted list Future<String>.value('\n'), // Not in accepted list
...@@ -162,21 +162,26 @@ void main() { ...@@ -162,21 +162,26 @@ void main() {
prompt: 'Please choose something', prompt: 'Please choose something',
displayAcceptedCharacters: false, displayAcceptedCharacters: false,
defaultChoiceIndex: 1, // which is b. defaultChoiceIndex: 1, // which is b.
logger: bufferLogger,
); );
expect(choice, 'b'); expect(choice, 'b');
expect( expect(
testLogger.statusText, bufferLogger.statusText,
'Please choose something: \n' 'Please choose something: \n'
'\n'); '\n');
}); });
testUsingContext('Does not set single char mode when a terminal is not attached', () { testWithoutContext('Does not set single char mode when a terminal is not attached', () {
final Stdio stdio = MockStdio();
when(stdio.stdin).thenThrow(StateError('This should not be called')); when(stdio.stdin).thenThrow(StateError('This should not be called'));
when(stdio.stdinHasTerminal).thenReturn(false); when(stdio.stdinHasTerminal).thenReturn(false);
final AnsiTerminal ansiTerminal = AnsiTerminal(
stdio: stdio,
platform: const LocalPlatform()
);
globals.terminal.singleCharMode = true; expect(() => ansiTerminal.singleCharMode = true, returnsNormally);
}, overrides: <Type, Generator>{
Stdio: () => MockStdio(),
}); });
}); });
} }
...@@ -184,10 +189,17 @@ void main() { ...@@ -184,10 +189,17 @@ void main() {
Stream<String> mockStdInStream; Stream<String> mockStdInStream;
class TestTerminal extends AnsiTerminal { class TestTerminal extends AnsiTerminal {
TestTerminal({
Stdio stdio,
Platform platform = const LocalPlatform(),
}) : super(stdio: stdio, platform: platform);
@override @override
Stream<String> get keystrokes { Stream<String> get keystrokes {
return mockStdInStream; return mockStdInStream;
} }
bool singleCharMode = false;
} }
class MockStdio extends Mock implements Stdio {} class MockStdio extends Mock implements Stdio {}
...@@ -7,6 +7,7 @@ import 'dart:async'; ...@@ -7,6 +7,7 @@ import 'dart:async';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device.dart';
...@@ -15,6 +16,7 @@ import 'package:flutter_tools/src/run_cold.dart'; ...@@ -15,6 +16,7 @@ import 'package:flutter_tools/src/run_cold.dart';
import 'package:flutter_tools/src/vmservice.dart'; import 'package:flutter_tools/src/vmservice.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/context.dart'; import '../src/context.dart';
...@@ -26,7 +28,13 @@ void main() { ...@@ -26,7 +28,13 @@ void main() {
BufferLogger mockLogger; BufferLogger mockLogger;
setUp(() { setUp(() {
mockLogger = BufferLogger(); mockLogger = BufferLogger(
terminal: AnsiTerminal(
stdio: null,
platform: const LocalPlatform(),
),
outputPreferences: OutputPreferences.test(),
);
residentCompiler = MockResidentCompiler(); residentCompiler = MockResidentCompiler();
}); });
...@@ -114,23 +122,16 @@ void main() { ...@@ -114,23 +122,16 @@ void main() {
}); });
group('cold run', () { group('cold run', () {
BufferLogger mockLogger;
setUp(() {
mockLogger = BufferLogger();
});
testUsingContext('returns 1 if not prebuilt mode & mainPath does not exist', () async { testUsingContext('returns 1 if not prebuilt mode & mainPath does not exist', () async {
final MockDevice mockDevice = MockDevice(); final MockDevice mockDevice = MockDevice();
final MockFlutterDevice mockFlutterDevice = MockFlutterDevice(); final MockFlutterDevice mockFlutterDevice = MockFlutterDevice();
when(mockFlutterDevice.device).thenReturn(mockDevice); when(mockFlutterDevice.device).thenReturn(mockDevice);
final List<FlutterDevice> devices = <FlutterDevice>[mockFlutterDevice]; final List<FlutterDevice> devices = <FlutterDevice>[mockFlutterDevice];
final int result = await ColdRunner(devices).run(); final int result = await ColdRunner(devices).run();
expect(result, 1); expect(result, 1);
expect(mockLogger.errorText, matches(r'Tried to run .*, but that file does not exist\.')); expect(testLogger.errorText, matches(r'Tried to run .*, but that file does not exist\.'));
expect(mockLogger.errorText, matches(r'Consider using the -t option to specify the Dart file to start\.')); expect(testLogger.errorText, matches(r'Consider using the -t option to specify the Dart file to start\.'));
}, overrides: <Type, Generator>{
Logger: () => mockLogger,
}); });
testUsingContext('calls runCold on attached device', () async { testUsingContext('calls runCold on attached device', () async {
...@@ -148,13 +149,12 @@ void main() { ...@@ -148,13 +149,12 @@ void main() {
applicationBinary: applicationBinary, applicationBinary: applicationBinary,
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
).run(); ).run();
expect(result, 1); expect(result, 1);
verify(mockFlutterDevice.runCold( verify(mockFlutterDevice.runCold(
coldRunner: anyNamed('coldRunner'), coldRunner: anyNamed('coldRunner'),
route: anyNamed('route'), route: anyNamed('route'),
)); ));
}, overrides: <Type, Generator>{
Logger: () => mockLogger,
}); });
}); });
} }
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
...@@ -22,14 +21,12 @@ void main() { ...@@ -22,14 +21,12 @@ void main() {
MockXcode mockXcode; MockXcode mockXcode;
MemoryFileSystem memoryFileSystem; MemoryFileSystem memoryFileSystem;
MockProcessManager mockProcessManager; MockProcessManager mockProcessManager;
BufferLogger bufferLogger;
MockPlistUtils mockPlistUtils; MockPlistUtils mockPlistUtils;
setUp(() { setUp(() {
mockXcode = MockXcode(); mockXcode = MockXcode();
memoryFileSystem = MemoryFileSystem(style: FileSystemStyle.posix); memoryFileSystem = MemoryFileSystem(style: FileSystemStyle.posix);
mockProcessManager = MockProcessManager(); mockProcessManager = MockProcessManager();
bufferLogger = BufferLogger();
mockPlistUtils = MockPlistUtils(); mockPlistUtils = MockPlistUtils();
}); });
...@@ -67,7 +64,6 @@ void main() { ...@@ -67,7 +64,6 @@ void main() {
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Xcode: () => mockXcode, Xcode: () => mockXcode,
Logger: () => bufferLogger,
PlistParser: () => mockPlistUtils, PlistParser: () => mockPlistUtils,
}); });
...@@ -91,7 +87,6 @@ void main() { ...@@ -91,7 +87,6 @@ void main() {
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Xcode: () => mockXcode, Xcode: () => mockXcode,
Logger: () => bufferLogger,
PlistParser: () => mockPlistUtils, PlistParser: () => mockPlistUtils,
}); });
...@@ -114,7 +109,6 @@ void main() { ...@@ -114,7 +109,6 @@ void main() {
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Xcode: () => mockXcode, Xcode: () => mockXcode,
Logger: () => bufferLogger,
PlistParser: () => mockPlistUtils, PlistParser: () => mockPlistUtils,
}); });
...@@ -143,7 +137,6 @@ void main() { ...@@ -143,7 +137,6 @@ void main() {
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Xcode: () => mockXcode, Xcode: () => mockXcode,
Logger: () => bufferLogger,
PlistParser: () => mockPlistUtils, PlistParser: () => mockPlistUtils,
}); });
...@@ -162,13 +155,12 @@ void main() { ...@@ -162,13 +155,12 @@ void main() {
await validateBitcode(BuildMode.release, TargetPlatform.ios); await validateBitcode(BuildMode.release, TargetPlatform.ios);
expect(bufferLogger.statusText, ''); expect(testLogger.statusText, '');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Artifacts: () => LocalEngineArtifacts('/engine', 'ios_profile', 'host_profile'), Artifacts: () => LocalEngineArtifacts('/engine', 'ios_profile', 'host_profile'),
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Xcode: () => mockXcode, Xcode: () => mockXcode,
Logger: () => bufferLogger,
PlistParser: () => mockPlistUtils, PlistParser: () => mockPlistUtils,
}); });
...@@ -187,13 +179,12 @@ void main() { ...@@ -187,13 +179,12 @@ void main() {
await validateBitcode(BuildMode.release, TargetPlatform.ios); await validateBitcode(BuildMode.release, TargetPlatform.ios);
expect(bufferLogger.statusText, ''); expect(testLogger.statusText, '');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Artifacts: () => LocalEngineArtifacts('/engine', 'ios_profile', 'host_profile'), Artifacts: () => LocalEngineArtifacts('/engine', 'ios_profile', 'host_profile'),
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
Xcode: () => mockXcode, Xcode: () => mockXcode,
Logger: () => bufferLogger,
PlistParser: () => mockPlistUtils, PlistParser: () => mockPlistUtils,
}); });
} }
......
...@@ -6,7 +6,6 @@ import 'dart:async'; ...@@ -6,7 +6,6 @@ import 'dart:async';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/compile.dart';
...@@ -103,7 +102,6 @@ void main() { ...@@ -103,7 +102,6 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
OutputPreferences: () => OutputPreferences(showColor: false), OutputPreferences: () => OutputPreferences(showColor: false),
Logger: () => BufferLogger(),
Platform: kNoColorTerminalPlatform, Platform: kNoColorTerminalPlatform,
}); });
......
...@@ -6,6 +6,8 @@ import 'package:file/memory.dart'; ...@@ -6,6 +6,8 @@ import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/config.dart'; import 'package:flutter_tools/src/base/config.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:platform/platform.dart';
import '../src/common.dart'; import '../src/common.dart';
...@@ -49,7 +51,13 @@ void main() { ...@@ -49,7 +51,13 @@ void main() {
}); });
test('Config parse error', () { test('Config parse error', () {
final BufferLogger bufferLogger =BufferLogger(); final BufferLogger bufferLogger = BufferLogger(
terminal: AnsiTerminal(
stdio: null,
platform: const LocalPlatform(),
),
outputPreferences: OutputPreferences.test(),
);
final File file = memoryFileSystem.file('example') final File file = memoryFileSystem.file('example')
..writeAsStringSync('{"hello":"bar'); ..writeAsStringSync('{"hello":"bar');
config = Config(file, bufferLogger); config = Config(file, bufferLogger);
......
...@@ -6,7 +6,6 @@ import 'dart:async'; ...@@ -6,7 +6,6 @@ import 'dart:async';
import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/devfs.dart';
...@@ -269,12 +268,10 @@ void main() { ...@@ -269,12 +268,10 @@ void main() {
group('hot attach', () { group('hot attach', () {
MockResidentCompiler residentCompiler = MockResidentCompiler(); MockResidentCompiler residentCompiler = MockResidentCompiler();
BufferLogger mockLogger;
MockLocalEngineArtifacts mockArtifacts; MockLocalEngineArtifacts mockArtifacts;
setUp(() { setUp(() {
residentCompiler = MockResidentCompiler(); residentCompiler = MockResidentCompiler();
mockLogger = BufferLogger();
mockArtifacts = MockLocalEngineArtifacts(); mockArtifacts = MockLocalEngineArtifacts();
}); });
...@@ -298,13 +295,12 @@ void main() { ...@@ -298,13 +295,12 @@ void main() {
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
).attach(); ).attach();
expect(exitCode, 2); expect(exitCode, 2);
expect(mockLogger.statusText, contains('If you are using an emulator running Android Q Beta, ' expect(testLogger.statusText, contains('If you are using an emulator running Android Q Beta, '
'consider using an emulator running API level 29 or lower.')); 'consider using an emulator running API level 29 or lower.'));
expect(mockLogger.statusText, contains('Learn more about the status of this issue on ' expect(testLogger.statusText, contains('Learn more about the status of this issue on '
'https://issuetracker.google.com/issues/132325318')); 'https://issuetracker.google.com/issues/132325318'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Artifacts: () => mockArtifacts, Artifacts: () => mockArtifacts,
Logger: () => mockLogger,
HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true), HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true),
}); });
...@@ -327,13 +323,12 @@ void main() { ...@@ -327,13 +323,12 @@ void main() {
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
).attach(); ).attach();
expect(exitCode, 2); expect(exitCode, 2);
expect(mockLogger.statusText, contains('If you are using an emulator running Android Q Beta, ' expect(testLogger.statusText, contains('If you are using an emulator running Android Q Beta, '
'consider using an emulator running API level 29 or lower.')); 'consider using an emulator running API level 29 or lower.'));
expect(mockLogger.statusText, contains('Learn more about the status of this issue on ' expect(testLogger.statusText, contains('Learn more about the status of this issue on '
'https://issuetracker.google.com/issues/132325318')); 'https://issuetracker.google.com/issues/132325318'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Artifacts: () => mockArtifacts, Artifacts: () => mockArtifacts,
Logger: () => mockLogger,
HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true), HotRunnerConfig: () => TestHotRunnerConfig(successfulSetup: true),
}); });
}); });
......
...@@ -654,6 +654,8 @@ class MockConfig extends Mock implements Config {} ...@@ -654,6 +654,8 @@ class MockConfig extends Mock implements Config {}
Stream<String> mockTerminalStdInStream; Stream<String> mockTerminalStdInStream;
class TestTerminal extends AnsiTerminal { class TestTerminal extends AnsiTerminal {
TestTerminal() : super(stdio: globals.stdio, platform: globals.platform);
@override @override
String bolden(String message) => '<bold>$message</bold>'; String bolden(String message) => '<bold>$message</bold>';
......
...@@ -4,22 +4,36 @@ ...@@ -4,22 +4,36 @@
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/run_hot.dart'; import 'package:flutter_tools/src/run_hot.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/mocks.dart';
// assumption: tests have a timeout less than 100 days // assumption: tests have a timeout less than 100 days
final DateTime inFuture = DateTime.now().add(const Duration(days: 100)); final DateTime inFuture = DateTime.now().add(const Duration(days: 100));
void main() { void main() {
BufferLogger bufferLogger;
setUp(() {
bufferLogger = BufferLogger(
terminal: AnsiTerminal(
stdio: MockStdio(),
platform: FakePlatform(),
),
outputPreferences: OutputPreferences.test(),
);
});
for (final bool asyncScanning in <bool>[true, false]) { for (final bool asyncScanning in <bool>[true, false]) {
testWithoutContext('No last compile, asyncScanning: $asyncScanning', () async { testWithoutContext('No last compile, asyncScanning: $asyncScanning', () async {
final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator( final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(
fileSystem: MemoryFileSystem(), fileSystem: MemoryFileSystem(),
platform: FakePlatform(), platform: FakePlatform(),
logger: BufferLogger(), logger: bufferLogger,
); );
expect( expect(
...@@ -37,7 +51,7 @@ void main() { ...@@ -37,7 +51,7 @@ void main() {
final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator( final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(
fileSystem: MemoryFileSystem(), fileSystem: MemoryFileSystem(),
platform: FakePlatform(), platform: FakePlatform(),
logger: BufferLogger(), logger: bufferLogger,
); );
expect( expect(
...@@ -55,7 +69,7 @@ void main() { ...@@ -55,7 +69,7 @@ void main() {
final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator( final ProjectFileInvalidator projectFileInvalidator = ProjectFileInvalidator(
fileSystem: MemoryFileSystem(), fileSystem: MemoryFileSystem(),
platform: FakePlatform(), platform: FakePlatform(),
logger: BufferLogger(), logger: bufferLogger,
); );
expect( expect(
......
...@@ -7,6 +7,7 @@ import 'dart:async'; ...@@ -7,6 +7,7 @@ import 'dart:async';
import 'package:dwds/dwds.dart'; import 'package:dwds/dwds.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/base/net.dart'; import 'package:flutter_tools/src/base/net.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device.dart';
...@@ -17,6 +18,7 @@ import 'package:flutter_tools/src/build_runner/resident_web_runner.dart'; ...@@ -17,6 +18,7 @@ import 'package:flutter_tools/src/build_runner/resident_web_runner.dart';
import 'package:flutter_tools/src/build_runner/web_fs.dart'; import 'package:flutter_tools/src/build_runner/web_fs.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service.dart';
import '../src/common.dart'; import '../src/common.dart';
...@@ -84,7 +86,13 @@ void main() { ...@@ -84,7 +86,13 @@ void main() {
expect(debugConnectionInfo.wsUri, null); expect(debugConnectionInfo.wsUri, null);
verify(mockStatus.stop()).called(1); verify(mockStatus.stop()).called(1);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => DelegateLogger(BufferLogger()), Logger: () => DelegateLogger(BufferLogger(
terminal: AnsiTerminal(
stdio: null,
platform: const LocalPlatform(),
),
outputPreferences: OutputPreferences.test(),
)),
})); }));
test('Can full restart after attaching', () => testbed.run(() async { test('Can full restart after attaching', () => testbed.run(() async {
......
...@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/base/common.dart'; ...@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/net.dart'; import 'package:flutter_tools/src/base/net.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_runner/resident_web_runner.dart'; import 'package:flutter_tools/src/build_runner/resident_web_runner.dart';
import 'package:flutter_tools/src/build_runner/web_fs.dart'; import 'package:flutter_tools/src/build_runner/web_fs.dart';
...@@ -26,6 +27,7 @@ import 'package:flutter_tools/src/web/chrome.dart'; ...@@ -26,6 +27,7 @@ import 'package:flutter_tools/src/web/chrome.dart';
import 'package:flutter_tools/src/web/web_device.dart'; import 'package:flutter_tools/src/web/web_device.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service.dart';
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart';
...@@ -257,7 +259,13 @@ void main() { ...@@ -257,7 +259,13 @@ void main() {
expect(bufferLogger.statusText, contains('Debug service listening on ws://127.0.0.1/abcd/')); expect(bufferLogger.statusText, contains('Debug service listening on ws://127.0.0.1/abcd/'));
expect(debugConnectionInfo.wsUri.toString(), 'ws://127.0.0.1/abcd/'); expect(debugConnectionInfo.wsUri.toString(), 'ws://127.0.0.1/abcd/');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => DelegateLogger(BufferLogger()), Logger: () => DelegateLogger(BufferLogger(
terminal: AnsiTerminal(
stdio: null,
platform: const LocalPlatform(),
),
outputPreferences: OutputPreferences.test(),
)),
})); }));
test('Can successfully run and disconnect with --no-resident', () => testbed.run(() async { test('Can successfully run and disconnect with --no-resident', () => testbed.run(() async {
...@@ -1080,7 +1088,13 @@ void main() { ...@@ -1080,7 +1088,13 @@ void main() {
await expectation; await expectation;
verify(mockStatus.stop()).called(2); verify(mockStatus.stop()).called(2);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => DelegateLogger(BufferLogger()) Logger: () => DelegateLogger(BufferLogger(
terminal: AnsiTerminal(
stdio: null,
platform: const LocalPlatform(),
),
outputPreferences: OutputPreferences.test(),
))
})); }));
} }
......
...@@ -7,10 +7,12 @@ import 'dart:io'; ...@@ -7,10 +7,12 @@ import 'dart:io';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/vmservice.dart'; import 'package:flutter_tools/src/vmservice.dart';
import 'package:json_rpc_2/json_rpc_2.dart' as rpc; import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:quiver/testing/async.dart'; import 'package:quiver/testing/async.dart';
import '../src/common.dart'; import '../src/common.dart';
...@@ -167,6 +169,7 @@ class MockPeer implements rpc.Peer { ...@@ -167,6 +169,7 @@ class MockPeer implements rpc.Peer {
void main() { void main() {
MockStdio mockStdio; MockStdio mockStdio;
group('VMService', () { group('VMService', () {
setUp(() { setUp(() {
mockStdio = MockStdio(); mockStdio = MockStdio();
}); });
...@@ -188,8 +191,12 @@ void main() { ...@@ -188,8 +191,12 @@ void main() {
expect(mockStdio.writtenToStderr.join(''), ''); expect(mockStdio.writtenToStderr.join(''), '');
}); });
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => StdoutLogger(), Logger: () => StdoutLogger(
Stdio: () => mockStdio, outputPreferences: OutputPreferences.test(),
stdio: mockStdio,
terminal: AnsiTerminal(stdio: mockStdio, platform: const LocalPlatform()),
timeoutConfiguration: const TimeoutConfiguration(),
),
WebSocketConnector: () => (String url, {CompressionOptions compression}) async => throw const SocketException('test'), WebSocketConnector: () => (String url, {CompressionOptions compression}) async => throw const SocketException('test'),
}); });
...@@ -263,8 +270,12 @@ void main() { ...@@ -263,8 +270,12 @@ void main() {
expect(mockStdio.writtenToStderr.join(''), ''); expect(mockStdio.writtenToStderr.join(''), '');
}); });
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => StdoutLogger(), Logger: () => StdoutLogger(
Stdio: () => mockStdio, outputPreferences: outputPreferences,
terminal: AnsiTerminal(stdio: mockStdio, platform: const LocalPlatform()),
stdio: mockStdio,
timeoutConfiguration: const TimeoutConfiguration(),
),
}); });
testUsingContext('registers hot UI method', () { testUsingContext('registers hot UI method', () {
...@@ -276,8 +287,12 @@ void main() { ...@@ -276,8 +287,12 @@ void main() {
expect(mockPeer.registeredMethods, contains('reloadMethod')); expect(mockPeer.registeredMethods, contains('reloadMethod'));
}); });
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => StdoutLogger(), Logger: () => StdoutLogger(
Stdio: () => mockStdio, outputPreferences: outputPreferences,
terminal: AnsiTerminal(stdio: mockStdio, platform: const LocalPlatform()),
stdio: mockStdio,
timeoutConfiguration: const TimeoutConfiguration(),
),
}); });
testUsingContext('registers flutterMemoryInfo service', () { testUsingContext('registers flutterMemoryInfo service', () {
...@@ -290,8 +305,12 @@ void main() { ...@@ -290,8 +305,12 @@ void main() {
expect(mockPeer.registeredMethods, contains('flutterMemoryInfo')); expect(mockPeer.registeredMethods, contains('flutterMemoryInfo'));
}); });
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Logger: () => StdoutLogger(), Logger: () => StdoutLogger(
Stdio: () => mockStdio, outputPreferences: outputPreferences,
terminal: AnsiTerminal(stdio: mockStdio, platform: const LocalPlatform()),
stdio: mockStdio,
timeoutConfiguration: const TimeoutConfiguration(),
),
}); });
}); });
} }
......
...@@ -92,6 +92,7 @@ void testUsingContext( ...@@ -92,6 +92,7 @@ void testUsingContext(
return context.run<dynamic>( return context.run<dynamic>(
name: 'mocks', name: 'mocks',
overrides: <Type, Generator>{ overrides: <Type, Generator>{
AnsiTerminal: () => AnsiTerminal(platform: globals.platform, stdio: globals.stdio),
Config: () => buildConfig(globals.fs), Config: () => buildConfig(globals.fs),
DeviceManager: () => FakeDeviceManager(), DeviceManager: () => FakeDeviceManager(),
Doctor: () => FakeDoctor(), Doctor: () => FakeDoctor(),
...@@ -103,7 +104,10 @@ void testUsingContext( ...@@ -103,7 +104,10 @@ void testUsingContext(
return mock; return mock;
}, },
OutputPreferences: () => OutputPreferences.test(), OutputPreferences: () => OutputPreferences.test(),
Logger: () => BufferLogger(), Logger: () => BufferLogger(
terminal: globals.terminal,
outputPreferences: outputPreferences,
),
OperatingSystemUtils: () => FakeOperatingSystemUtils(), OperatingSystemUtils: () => FakeOperatingSystemUtils(),
PersistentToolState: () => buildPersistentToolState(globals.fs), PersistentToolState: () => buildPersistentToolState(globals.fs),
SimControl: () => MockSimControl(), SimControl: () => MockSimControl(),
......
...@@ -38,7 +38,10 @@ final Map<Type, Generator> _testbedDefaults = <Type, Generator>{ ...@@ -38,7 +38,10 @@ final Map<Type, Generator> _testbedDefaults = <Type, Generator>{
// Keeps tests fast by avoiding the actual file system. // Keeps tests fast by avoiding the actual file system.
FileSystem: () => MemoryFileSystem(style: globals.platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix), FileSystem: () => MemoryFileSystem(style: globals.platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
Logger: () => BufferLogger(), // Allows reading logs and prevents stdout. Logger: () => BufferLogger(
terminal: AnsiTerminal(stdio: globals.stdio, platform: globals.platform), // Danger, using real stdio.
outputPreferences: OutputPreferences.test(),
), // Allows reading logs and prevents stdout.
OperatingSystemUtils: () => FakeOperatingSystemUtils(), OperatingSystemUtils: () => FakeOperatingSystemUtils(),
OutputPreferences: () => OutputPreferences.test(), // configures BufferLogger to avoid color codes. OutputPreferences: () => OutputPreferences.test(), // configures BufferLogger to avoid color codes.
Usage: () => NoOpUsage(), // prevent addition of analytics from burdening test mocks Usage: () => NoOpUsage(), // prevent addition of analytics from burdening test mocks
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment