Unverified Commit 18b1e23e authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] move some fakes out of mocks.dart (#74992)

parent e53c4896
......@@ -21,6 +21,7 @@ import 'package:fake_async/fake_async.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/mocks.dart';
import '../../src/testbed.dart';
......
......@@ -227,7 +227,7 @@ void main() {
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
DeviceManager: () => mockDeviceManager,
Stdio: () => MockStdio(),
Stdio: () => FakeStdio(),
});
testUsingContext('shows unsupported devices when no supported devices are found', () async {
......
......@@ -16,33 +16,33 @@ import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart';
import '../../src/fakes.dart';
void main() {
group('shell_completion', () {
MockStdio mockStdio;
FakeStdio fakeStdio;
setUp(() {
Cache.disableLocking();
mockStdio = MockStdio()..stdout.terminalColumns = 80;
fakeStdio = FakeStdio()..stdout.terminalColumns = 80;
});
testUsingContext('generates bash initialization script to stdout', () async {
final ShellCompletionCommand command = ShellCompletionCommand();
await createTestCommandRunner(command).run(<String>['bash-completion']);
expect(mockStdio.writtenToStdout.length, equals(1));
expect(mockStdio.writtenToStdout.first, contains('__flutter_completion'));
expect(fakeStdio.writtenToStdout.length, equals(1));
expect(fakeStdio.writtenToStdout.first, contains('__flutter_completion'));
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Stdio: () => fakeStdio,
});
testUsingContext('generates bash initialization script to stdout with arg', () async {
final ShellCompletionCommand command = ShellCompletionCommand();
await createTestCommandRunner(command).run(<String>['bash-completion', '-']);
expect(mockStdio.writtenToStdout.length, equals(1));
expect(mockStdio.writtenToStdout.first, contains('__flutter_completion'));
expect(fakeStdio.writtenToStdout.length, equals(1));
expect(fakeStdio.writtenToStdout.first, contains('__flutter_completion'));
}, overrides: <Type, Generator>{
Stdio: () => mockStdio,
Stdio: () => fakeStdio,
});
testUsingContext('generates bash initialization script to output file', () async {
......@@ -56,7 +56,7 @@ void main() {
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => mockStdio,
Stdio: () => fakeStdio,
});
testUsingContext("won't overwrite existing output file ", () async {
......@@ -77,7 +77,7 @@ void main() {
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => mockStdio,
Stdio: () => fakeStdio,
});
testUsingContext('will overwrite existing output file if given --overwrite', () async {
......@@ -92,7 +92,7 @@ void main() {
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => mockStdio,
Stdio: () => fakeStdio,
});
});
}
......@@ -17,12 +17,11 @@ import 'package:mockito/mockito.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart';
import '../../src/fakes.dart';
void main() {
MemoryFileSystem fileSystem;
MockStdio stdio;
FakeStdio stdio;
SymbolizeCommand command;
MockDwarfSymbolizationService mockDwarfSymbolizationService;
......@@ -32,7 +31,7 @@ void main() {
setUp(() {
fileSystem = MemoryFileSystem.test();
stdio = MockStdio();
stdio = FakeStdio();
mockDwarfSymbolizationService = MockDwarfSymbolizationService();
command = SymbolizeCommand(
stdio: stdio,
......
......@@ -20,7 +20,8 @@ import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart' show MockProcessManager, MockStdio, PromptingProcess, AlwaysTrueBotDetector, AlwaysFalseBotDetector;
import '../../src/fakes.dart';
import '../../src/mocks.dart' show MockProcessManager, AlwaysTrueBotDetector, AlwaysFalseBotDetector;
import '../../src/testbed.dart';
void main() {
......@@ -376,7 +377,7 @@ void main() {
expectDependenciesResolved(projectPath);
expectZeroPluginsInjected(projectPath);
}, overrides: <Type, Generator>{
Stdio: () => MockStdio()..stdout.terminalColumns = 80,
Stdio: () => FakeStdio()..stdout.terminalColumns = 80,
Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
......@@ -438,11 +439,11 @@ void main() {
group('packages test/pub', () {
MockProcessManager mockProcessManager;
MockStdio mockStdio;
FakeStdio mockStdio;
setUp(() {
mockProcessManager = MockProcessManager();
mockStdio = MockStdio()..stdout.terminalColumns = 80;
mockStdio = FakeStdio()..stdout.terminalColumns = 80;
});
testUsingContext('test without bot', () async {
......
......@@ -26,7 +26,7 @@ import 'package:usage/usage_io.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
import '../src/fakes.dart';
void main() {
setUpAll(() {
......@@ -152,14 +152,14 @@ void main() {
group('analytics with mocks', () {
MemoryFileSystem memoryFileSystem;
MockStdio mockStdio;
FakeStdio fakeStdio;
TestUsage testUsage;
FakeClock fakeClock;
Doctor mockDoctor;
setUp(() {
memoryFileSystem = MemoryFileSystem.test();
mockStdio = MockStdio();
fakeStdio = FakeStdio();
testUsage = TestUsage();
fakeClock = FakeClock();
mockDoctor = MockDoctor();
......@@ -251,7 +251,7 @@ void main() {
'FLUTTER_ANALYTICS_LOG_FILE': 'analytics.log',
},
),
Stdio: () => mockStdio,
Stdio: () => fakeStdio,
});
testUsingContext('event sends localtime', () async {
......@@ -281,7 +281,7 @@ void main() {
'FLUTTER_ANALYTICS_LOG_FILE': 'analytics.log',
},
),
Stdio: () => mockStdio,
Stdio: () => fakeStdio,
});
});
......
......@@ -18,7 +18,8 @@ import 'package:mockito/mockito.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart' show MockAndroidSdk, MockProcess, MockProcessManager, MockStdio;
import '../../src/fakes.dart';
import '../../src/mocks.dart' show MockAndroidSdk, MockProcess, MockProcessManager;
import '../../src/testbed.dart';
class MockAndroidSdkVersion extends Mock implements AndroidSdkVersion {}
......@@ -29,7 +30,7 @@ void main() {
Logger logger;
MemoryFileSystem fileSystem;
MockProcessManager processManager;
MockStdio stdio;
FakeStdio stdio;
setUp(() {
sdk = MockAndroidSdk();
......@@ -37,7 +38,7 @@ void main() {
fileSystem.directory('/home/me').createSync(recursive: true);
logger = BufferLogger.test();
processManager = MockProcessManager();
stdio = MockStdio();
stdio = FakeStdio();
});
MockProcess Function(List<String>) processMetaFactory(List<String> stdout) {
......
......@@ -18,7 +18,7 @@ import 'package:flutter_tools/src/cache.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart';
import '../src/mocks.dart';
import '../src/fakes.dart';
final Platform testPlatform = FakePlatform(environment: const <String, String>{});
......@@ -171,7 +171,7 @@ void main() {
final MemoryFileSystem fileSystem = MemoryFileSystem.test();
final Logger logger = StdoutLogger(
terminal: Terminal.test(supportsColor: true),
stdio: MockStdio(),
stdio: FakeStdio(),
outputPreferences: OutputPreferences.test(),
);
final ArtifactUpdater artifactUpdater = ArtifactUpdater(
......
......@@ -16,12 +16,12 @@ import 'package:mockito/mockito.dart';
import 'package:fake_async/fake_async.dart';
import '../../src/common.dart';
import '../../src/mocks.dart';
import '../../src/fakes.dart';
void main() {
group('BotDetector', () {
FakePlatform fakePlatform;
MockStdio mockStdio;
FakeStdio fakeStdio;
MockHttpClient mockHttpClient;
MockHttpClientRequest mockHttpClientRequest;
MockHttpHeaders mockHttpHeaders;
......@@ -30,7 +30,7 @@ void main() {
setUp(() {
fakePlatform = FakePlatform()..environment = <String, String>{};
mockStdio = MockStdio();
fakeStdio = FakeStdio();
mockHttpClient = MockHttpClient();
mockHttpClientRequest = MockHttpClientRequest();
mockHttpHeaders = MockHttpHeaders();
......@@ -66,9 +66,9 @@ void main() {
when(mockHttpClient.getUrl(any)).thenAnswer((_) {
throw const SocketException('HTTP connection timed out');
});
mockStdio.stdout.hasTerminal = true;
fakeStdio.stdout.hasTerminal = true;
expect(await botDetector.isRunningOnBot, isFalse);
mockStdio.stdout.hasTerminal = false;
fakeStdio.stdout.hasTerminal = false;
expect(await botDetector.isRunningOnBot, isFalse);
expect(persistentToolState.isRunningOnBot, isFalse);
});
......
......@@ -11,7 +11,7 @@ import 'package:flutter_tools/src/base/terminal.dart' show AnsiTerminal, OutputP
import 'package:meta/meta.dart';
import '../../src/common.dart';
import '../../src/mocks.dart' show MockStdio;
import '../../src/fakes.dart';
CommandHelp _createCommandHelp({
@required bool ansi,
......@@ -23,7 +23,7 @@ CommandHelp _createCommandHelp({
return CommandHelp(
logger: BufferLogger.test(),
terminal: AnsiTerminal(
stdio: MockStdio(),
stdio: FakeStdio(),
platform: platform,
),
platform: platform,
......
......@@ -14,23 +14,15 @@ import 'package:flutter_tools/src/base/io.dart' as io;
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/net.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:fake_async/fake_async.dart';
import '../../src/common.dart';
import '../../src/mocks.dart' show MockStdio;
void main() {
BufferLogger testLogger;
setUp(() {
testLogger = BufferLogger(
terminal: AnsiTerminal(
stdio: MockStdio(),
platform: FakePlatform(stdoutSupportsAnsi: false),
),
outputPreferences: OutputPreferences.test(),
);
testLogger = BufferLogger.test();
});
Net createNet(io.HttpClient client) {
......
......@@ -15,9 +15,9 @@ import 'package:mockito/mockito.dart';
import 'package:fake_async/fake_async.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/mocks.dart' show MockProcess,
MockProcessManager,
MockStdio,
flakyProcessFactory;
void main() {
......@@ -90,7 +90,7 @@ void main() {
mockProcessManager = MockProcessManager();
mockLogger = BufferLogger(
terminal: AnsiTerminal(
stdio: MockStdio(),
stdio: FakeStdio(),
platform: FakePlatform(stdoutSupportsAnsi: false),
),
outputPreferences: OutputPreferences(wrapText: true, wrapColumn: 40),
......@@ -280,7 +280,7 @@ void main() {
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[]);
testLogger = BufferLogger(
terminal: AnsiTerminal(
stdio: MockStdio(),
stdio: FakeStdio(),
platform: FakePlatform(stdinSupportsAnsi: false),
),
outputPreferences: OutputPreferences(wrapText: true, wrapColumn: 40),
......
......@@ -22,7 +22,7 @@ import 'package:mockito/mockito.dart';
import '../../../src/common.dart';
import '../../../src/context.dart';
import '../../../src/mocks.dart' as mocks;
import '../../../src/fakes.dart';
final Platform kNoAnsiPlatform = FakePlatform(stdoutSupportsAnsi: false);
const List<int> _kTtfHeaderBytes = <int>[0, 1, 0, 0, 0, 15, 0, 128, 0, 3, 0, 112];
......@@ -68,7 +68,7 @@ void main() {
int exitCode = 0,
String stdout = '',
String stderr = '',
@required mocks.CompleterIOSink stdinSink,
@required CompleterIOSink stdinSink,
}) {
assert(stdinSink != null);
stdinSink.writes.clear();
......@@ -90,7 +90,7 @@ void main() {
fileSystem = MemoryFileSystem.test();
logger = BufferLogger(
terminal: AnsiTerminal(
stdio: mocks.MockStdio(),
stdio: FakeStdio(),
platform: kNoAnsiPlatform,
),
outputPreferences: OutputPreferences.test(showColor: false),
......@@ -248,7 +248,7 @@ void main() {
artifacts: artifacts,
);
final mocks.CompleterIOSink stdinSink = mocks.CompleterIOSink();
final CompleterIOSink stdinSink = CompleterIOSink();
_addConstFinderInvocation(appDill.path, stdout: validConstFinderResult);
_resetFontSubsetInvocation(stdinSink: stdinSink);
......@@ -290,7 +290,7 @@ void main() {
artifacts: artifacts,
);
final mocks.CompleterIOSink stdinSink = mocks.CompleterIOSink();
final CompleterIOSink stdinSink = CompleterIOSink();
_addConstFinderInvocation(appDill.path, stdout: validConstFinderResult);
_resetFontSubsetInvocation(stdinSink: stdinSink);
......@@ -325,7 +325,7 @@ void main() {
artifacts: artifacts,
);
final mocks.CompleterIOSink stdinSink = mocks.CompleterIOSink();
final CompleterIOSink stdinSink = CompleterIOSink();
_addConstFinderInvocation(appDill.path, stdout: validConstFinderResult);
_resetFontSubsetInvocation(stdinSink: stdinSink);
......@@ -396,7 +396,7 @@ void main() {
artifacts: artifacts,
);
final mocks.CompleterIOSink stdinSink = mocks.CompleterIOSink();
final CompleterIOSink stdinSink = CompleterIOSink();
_addConstFinderInvocation(appDill.path, stdout: validConstFinderResult);
_resetFontSubsetInvocation(exitCode: -1, stdinSink: stdinSink);
......@@ -430,7 +430,7 @@ void main() {
artifacts: artifacts,
);
final mocks.CompleterIOSink stdinSink = mocks.CompleterIOSink(throwOnAdd: true);
final CompleterIOSink stdinSink = CompleterIOSink(throwOnAdd: true);
_addConstFinderInvocation(appDill.path, stdout: validConstFinderResult);
_resetFontSubsetInvocation(exitCode: -1, stdinSink: stdinSink);
......
......@@ -18,6 +18,7 @@ import 'package:fake_async/fake_async.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/fake_devices.dart';
import '../src/fakes.dart';
import '../src/mocks.dart';
void main() {
......
......@@ -8,7 +8,7 @@ import 'package:flutter_tools/src/test/event_printer.dart';
import 'package:flutter_tools/src/test/watcher.dart';
import '../../src/common.dart';
import '../../src/mocks.dart';
import '../../src/fakes.dart';
void main() {
testWithoutContext('EventPrinter handles a null parent', () {
......
......@@ -11,6 +11,7 @@ import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/test/flutter_web_goldens.dart';
import '../../src/common.dart';
import '../../src/fakes.dart';
import '../../src/mocks.dart';
import '../../src/testbed.dart';
......
......@@ -14,7 +14,7 @@ import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import '../../src/common.dart';
import '../../src/mocks.dart';
import '../../src/fakes.dart';
import '../../src/testbed.dart';
void main() {
......
......@@ -5,11 +5,15 @@
// @dart = 2.8
import 'dart:async';
import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException;
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/device.dart';
/// A fake implementation of the [DeviceLogReader].
......@@ -65,3 +69,332 @@ class FakeDyldEnvironmentArtifact extends ArtifactSet {
Future<void> update(ArtifactUpdater artifactUpdater, Logger logger, FileSystem fileSystem, OperatingSystemUtils operatingSystemUtils) async {
}
}
/// A fake process implementation which can be provided all necessary values.
class FakeProcess implements Process {
FakeProcess({
this.pid = 1,
Future<int> exitCode,
IOSink stdin,
this.stdout = const Stream<List<int>>.empty(),
this.stderr = const Stream<List<int>>.empty(),
}) : exitCode = exitCode ?? Future<int>.value(0),
stdin = stdin ?? MemoryIOSink();
@override
final int pid;
@override
final Future<int> exitCode;
@override
final io.IOSink stdin;
@override
final Stream<List<int>> stdout;
@override
final Stream<List<int>> stderr;
@override
bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) {
return true;
}
}
/// A process that prompts the user to proceed, then asynchronously writes
/// some lines to stdout before it exits.
class PromptingProcess implements Process {
PromptingProcess({
bool stdinError = false,
}) : _stdin = CompleterIOSink(throwOnAdd: stdinError);
Future<void> showPrompt(String prompt, List<String> outputLines) async {
try {
_stdoutController.add(utf8.encode(prompt));
final List<int> bytesOnStdin = await _stdin.future;
// Echo stdin to stdout.
_stdoutController.add(bytesOnStdin);
if (bytesOnStdin.isNotEmpty && bytesOnStdin[0] == utf8.encode('y')[0]) {
for (final String line in outputLines) {
_stdoutController.add(utf8.encode('$line\n'));
}
}
} finally {
await _stdoutController.close();
}
}
final StreamController<List<int>> _stdoutController = StreamController<List<int>>();
final CompleterIOSink _stdin;
@override
Stream<List<int>> get stdout => _stdoutController.stream;
@override
Stream<List<int>> get stderr => const Stream<List<int>>.empty();
@override
IOSink get stdin => _stdin;
@override
Future<int> get exitCode async {
await _stdoutController.done;
return 0;
}
@override
dynamic noSuchMethod(Invocation invocation) => null;
}
/// An IOSink that completes a future with the first line written to it.
class CompleterIOSink extends MemoryIOSink {
CompleterIOSink({
this.throwOnAdd = false,
});
final bool throwOnAdd;
final Completer<List<int>> _completer = Completer<List<int>>();
Future<List<int>> get future => _completer.future;
@override
void add(List<int> data) {
if (!_completer.isCompleted) {
// When throwOnAdd is true, complete with empty so any expected output
// doesn't appear.
_completer.complete(throwOnAdd ? <int>[] : data);
}
if (throwOnAdd) {
throw Exception('CompleterIOSink Error');
}
super.add(data);
}
}
/// An IOSink that collects whatever is written to it.
class MemoryIOSink implements IOSink {
@override
Encoding encoding = utf8;
final List<List<int>> writes = <List<int>>[];
@override
void add(List<int> data) {
writes.add(data);
}
@override
Future<void> addStream(Stream<List<int>> stream) {
final Completer<void> completer = Completer<void>();
StreamSubscription<List<int>> sub;
sub = stream.listen(
(List<int> data) {
try {
add(data);
// Catches all exceptions to propagate them to the completer.
} catch (err, stack) { // ignore: avoid_catches_without_on_clauses
sub.cancel();
completer.completeError(err, stack);
}
},
onError: completer.completeError,
onDone: completer.complete,
cancelOnError: true,
);
return completer.future;
}
@override
void writeCharCode(int charCode) {
add(<int>[charCode]);
}
@override
void write(Object obj) {
add(encoding.encode('$obj'));
}
@override
void writeln([ Object obj = '' ]) {
add(encoding.encode('$obj\n'));
}
@override
void writeAll(Iterable<dynamic> objects, [ String separator = '' ]) {
bool addSeparator = false;
for (final dynamic object in objects) {
if (addSeparator) {
write(separator);
}
write(object);
addSeparator = true;
}
}
@override
void addError(dynamic error, [ StackTrace stackTrace ]) {
throw UnimplementedError();
}
@override
Future<void> get done => close();
@override
Future<void> close() async { }
@override
Future<void> flush() async { }
}
class MemoryStdout extends MemoryIOSink implements io.Stdout {
@override
bool get hasTerminal => _hasTerminal;
set hasTerminal(bool value) {
assert(value != null);
_hasTerminal = value;
}
bool _hasTerminal = true;
@override
io.IOSink get nonBlocking => this;
@override
bool get supportsAnsiEscapes => _supportsAnsiEscapes;
set supportsAnsiEscapes(bool value) {
assert(value != null);
_supportsAnsiEscapes = value;
}
bool _supportsAnsiEscapes = true;
@override
int get terminalColumns {
if (_terminalColumns != null) {
return _terminalColumns;
}
throw const io.StdoutException('unspecified mock value');
}
set terminalColumns(int value) => _terminalColumns = value;
int _terminalColumns;
@override
int get terminalLines {
if (_terminalLines != null) {
return _terminalLines;
}
throw const io.StdoutException('unspecified mock value');
}
set terminalLines(int value) => _terminalLines = value;
int _terminalLines;
}
/// A Stdio that collects stdout and supports simulated stdin.
class FakeStdio extends Stdio {
final MemoryStdout _stdout = MemoryStdout();
final MemoryIOSink _stderr = MemoryIOSink();
final StreamController<List<int>> _stdin = StreamController<List<int>>();
@override
MemoryStdout get stdout => _stdout;
@override
MemoryIOSink get stderr => _stderr;
@override
Stream<List<int>> get stdin => _stdin.stream;
void simulateStdin(String line) {
_stdin.add(utf8.encode('$line\n'));
}
List<String> get writtenToStdout => _stdout.writes.map<String>(_stdout.encoding.decode).toList();
List<String> get writtenToStderr => _stderr.writes.map<String>(_stderr.encoding.decode).toList();
}
class FakePollingDeviceDiscovery extends PollingDeviceDiscovery {
FakePollingDeviceDiscovery() : super('mock');
final List<Device> _devices = <Device>[];
final StreamController<Device> _onAddedController = StreamController<Device>.broadcast();
final StreamController<Device> _onRemovedController = StreamController<Device>.broadcast();
@override
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
lastPollingTimeout = timeout;
return _devices;
}
Duration lastPollingTimeout;
@override
bool get supportsPlatform => true;
@override
bool get canListAnything => true;
void addDevice(Device device) {
_devices.add(device);
_onAddedController.add(device);
}
void _removeDevice(Device device) {
_devices.remove(device);
_onRemovedController.add(device);
}
void setDevices(List<Device> devices) {
while(_devices.isNotEmpty) {
_removeDevice(_devices.first);
}
devices.forEach(addDevice);
}
@override
Stream<Device> get onAdded => _onAddedController.stream;
@override
Stream<Device> get onRemoved => _onRemovedController.stream;
}
class LongPollingDeviceDiscovery extends PollingDeviceDiscovery {
LongPollingDeviceDiscovery() : super('forever');
final Completer<List<Device>> _completer = Completer<List<Device>>();
@override
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
return _completer.future;
}
@override
Future<void> stopPolling() async {
_completer.complete();
}
@override
Future<void> dispose() async {
_completer.complete();
}
@override
bool get supportsPlatform => true;
@override
bool get canListAnything => true;
}
class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery {
ThrowingPollingDeviceDiscovery() : super('throw');
@override
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
throw const ProcessException('fake-discovery', <String>[]);
}
@override
bool get supportsPlatform => true;
@override
bool get canListAnything => true;
}
......@@ -6,7 +6,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException;
import 'dart:io' as io show IOSink;
import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/android/android_sdk.dart' show AndroidSdk;
......@@ -17,7 +17,6 @@ import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/ios/devices.dart';
import 'package:flutter_tools/src/project.dart';
......@@ -26,6 +25,7 @@ import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
import 'common.dart';
import 'fakes.dart';
// TODO(fujino): replace FakePlatform.fromPlatform() with FakePlatform()
final Generator kNoColorTerminalPlatform = () {
......@@ -213,335 +213,6 @@ class MockProcess extends Mock implements Process {
final Stream<List<int>> stderr;
}
/// A fake process implementation which can be provided all necessary values.
class FakeProcess implements Process {
FakeProcess({
this.pid = 1,
Future<int> exitCode,
IOSink stdin,
this.stdout = const Stream<List<int>>.empty(),
this.stderr = const Stream<List<int>>.empty(),
}) : exitCode = exitCode ?? Future<int>.value(0),
stdin = stdin ?? MemoryIOSink();
@override
final int pid;
@override
final Future<int> exitCode;
@override
final io.IOSink stdin;
@override
final Stream<List<int>> stdout;
@override
final Stream<List<int>> stderr;
@override
bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) {
return true;
}
}
/// A process that prompts the user to proceed, then asynchronously writes
/// some lines to stdout before it exits.
class PromptingProcess implements Process {
PromptingProcess({
bool stdinError = false,
}) : _stdin = CompleterIOSink(throwOnAdd: stdinError);
Future<void> showPrompt(String prompt, List<String> outputLines) async {
try {
_stdoutController.add(utf8.encode(prompt));
final List<int> bytesOnStdin = await _stdin.future;
// Echo stdin to stdout.
_stdoutController.add(bytesOnStdin);
if (bytesOnStdin.isNotEmpty && bytesOnStdin[0] == utf8.encode('y')[0]) {
for (final String line in outputLines) {
_stdoutController.add(utf8.encode('$line\n'));
}
}
} finally {
await _stdoutController.close();
}
}
final StreamController<List<int>> _stdoutController = StreamController<List<int>>();
final CompleterIOSink _stdin;
@override
Stream<List<int>> get stdout => _stdoutController.stream;
@override
Stream<List<int>> get stderr => const Stream<List<int>>.empty();
@override
IOSink get stdin => _stdin;
@override
Future<int> get exitCode async {
await _stdoutController.done;
return 0;
}
@override
dynamic noSuchMethod(Invocation invocation) => null;
}
/// An IOSink that completes a future with the first line written to it.
class CompleterIOSink extends MemoryIOSink {
CompleterIOSink({
this.throwOnAdd = false,
});
final bool throwOnAdd;
final Completer<List<int>> _completer = Completer<List<int>>();
Future<List<int>> get future => _completer.future;
@override
void add(List<int> data) {
if (!_completer.isCompleted) {
// When throwOnAdd is true, complete with empty so any expected output
// doesn't appear.
_completer.complete(throwOnAdd ? <int>[] : data);
}
if (throwOnAdd) {
throw Exception('CompleterIOSink Error');
}
super.add(data);
}
}
/// An IOSink that collects whatever is written to it.
class MemoryIOSink implements IOSink {
@override
Encoding encoding = utf8;
final List<List<int>> writes = <List<int>>[];
@override
void add(List<int> data) {
writes.add(data);
}
@override
Future<void> addStream(Stream<List<int>> stream) {
final Completer<void> completer = Completer<void>();
StreamSubscription<List<int>> sub;
sub = stream.listen(
(List<int> data) {
try {
add(data);
// Catches all exceptions to propagate them to the completer.
} catch (err, stack) { // ignore: avoid_catches_without_on_clauses
sub.cancel();
completer.completeError(err, stack);
}
},
onError: completer.completeError,
onDone: completer.complete,
cancelOnError: true,
);
return completer.future;
}
@override
void writeCharCode(int charCode) {
add(<int>[charCode]);
}
@override
void write(Object obj) {
add(encoding.encode('$obj'));
}
@override
void writeln([ Object obj = '' ]) {
add(encoding.encode('$obj\n'));
}
@override
void writeAll(Iterable<dynamic> objects, [ String separator = '' ]) {
bool addSeparator = false;
for (final dynamic object in objects) {
if (addSeparator) {
write(separator);
}
write(object);
addSeparator = true;
}
}
@override
void addError(dynamic error, [ StackTrace stackTrace ]) {
throw UnimplementedError();
}
@override
Future<void> get done => close();
@override
Future<void> close() async { }
@override
Future<void> flush() async { }
}
class MemoryStdout extends MemoryIOSink implements io.Stdout {
@override
bool get hasTerminal => _hasTerminal;
set hasTerminal(bool value) {
assert(value != null);
_hasTerminal = value;
}
bool _hasTerminal = true;
@override
io.IOSink get nonBlocking => this;
@override
bool get supportsAnsiEscapes => _supportsAnsiEscapes;
set supportsAnsiEscapes(bool value) {
assert(value != null);
_supportsAnsiEscapes = value;
}
bool _supportsAnsiEscapes = true;
@override
int get terminalColumns {
if (_terminalColumns != null) {
return _terminalColumns;
}
throw const io.StdoutException('unspecified mock value');
}
set terminalColumns(int value) => _terminalColumns = value;
int _terminalColumns;
@override
int get terminalLines {
if (_terminalLines != null) {
return _terminalLines;
}
throw const io.StdoutException('unspecified mock value');
}
set terminalLines(int value) => _terminalLines = value;
int _terminalLines;
}
/// A Stdio that collects stdout and supports simulated stdin.
class MockStdio extends Stdio {
final MemoryStdout _stdout = MemoryStdout();
final MemoryIOSink _stderr = MemoryIOSink();
final StreamController<List<int>> _stdin = StreamController<List<int>>();
@override
MemoryStdout get stdout => _stdout;
@override
MemoryIOSink get stderr => _stderr;
@override
Stream<List<int>> get stdin => _stdin.stream;
void simulateStdin(String line) {
_stdin.add(utf8.encode('$line\n'));
}
List<String> get writtenToStdout => _stdout.writes.map<String>(_stdout.encoding.decode).toList();
List<String> get writtenToStderr => _stderr.writes.map<String>(_stderr.encoding.decode).toList();
}
class FakePollingDeviceDiscovery extends PollingDeviceDiscovery {
FakePollingDeviceDiscovery() : super('mock');
final List<Device> _devices = <Device>[];
final StreamController<Device> _onAddedController = StreamController<Device>.broadcast();
final StreamController<Device> _onRemovedController = StreamController<Device>.broadcast();
@override
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
lastPollingTimeout = timeout;
return _devices;
}
Duration lastPollingTimeout;
@override
bool get supportsPlatform => true;
@override
bool get canListAnything => true;
void addDevice(Device device) {
_devices.add(device);
_onAddedController.add(device);
}
void _removeDevice(Device device) {
_devices.remove(device);
_onRemovedController.add(device);
}
void setDevices(List<Device> devices) {
while(_devices.isNotEmpty) {
_removeDevice(_devices.first);
}
devices.forEach(addDevice);
}
@override
Stream<Device> get onAdded => _onAddedController.stream;
@override
Stream<Device> get onRemoved => _onRemovedController.stream;
}
class LongPollingDeviceDiscovery extends PollingDeviceDiscovery {
LongPollingDeviceDiscovery() : super('forever');
final Completer<List<Device>> _completer = Completer<List<Device>>();
@override
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
return _completer.future;
}
@override
Future<void> stopPolling() async {
_completer.complete();
}
@override
Future<void> dispose() async {
_completer.complete();
}
@override
bool get supportsPlatform => true;
@override
bool get canListAnything => true;
}
class ThrowingPollingDeviceDiscovery extends PollingDeviceDiscovery {
ThrowingPollingDeviceDiscovery() : super('throw');
@override
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
throw const ProcessException('fake-discovery', <String>[]);
}
@override
bool get supportsPlatform => true;
@override
bool get canListAnything => true;
}
class MockIosProject extends Mock implements IosProject {
static const String bundleId = 'com.example.test';
static const String appBundleName = 'My Super Awesome App.app';
......
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