Initial sketch of tools testbed (#31765)
diff --git a/packages/flutter_tools/test/src/mocks.dart b/packages/flutter_tools/test/src/mocks.dart
index 70049bc..8c318bc 100644
--- a/packages/flutter_tools/test/src/mocks.dart
+++ b/packages/flutter_tools/test/src/mocks.dart
@@ -4,7 +4,7 @@
import 'dart:async';
import 'dart:convert';
-import 'dart:io' as io show IOSink;
+import 'dart:io' as io show IOSink, ProcessSignal;
import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/android/android_sdk.dart' show AndroidSdk;
@@ -196,6 +196,38 @@
final Stream<List<int>> stderr;
}
+/// A fake process implemenation which can be provided all necessary values.
+class FakeProcess implements Process {
+ FakeProcess({
+ this.pid = 1,
+ Future<int> exitCode,
+ Stream<List<int>> 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 {
diff --git a/packages/flutter_tools/test/src/testbed.dart b/packages/flutter_tools/test/src/testbed.dart
new file mode 100644
index 0000000..9582152
--- /dev/null
+++ b/packages/flutter_tools/test/src/testbed.dart
@@ -0,0 +1,86 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:file/memory.dart';
+import 'package:flutter_tools/src/base/context.dart';
+import 'package:flutter_tools/src/base/file_system.dart';
+import 'package:flutter_tools/src/base/logger.dart';
+import 'package:flutter_tools/src/cache.dart';
+import 'package:flutter_tools/src/context_runner.dart';
+
+export 'package:flutter_tools/src/base/context.dart' show Generator;
+
+final Map<Type, Generator> _testbedDefaults = <Type, Generator>{
+ FileSystem: () => MemoryFileSystem(),
+ Logger: () => BufferLogger(),
+};
+
+/// Manages interaction with the tool injection and runner system.
+///
+/// The Testbed automatically injects reasonable defaults through the context
+/// DI system such as a [BufferLogger] and a [MemoryFileSytem].
+///
+/// Example:
+///
+/// Testing that a filesystem operation works as expected
+///
+/// void main() {
+/// group('Example', () {
+/// Testbed testbed;
+///
+/// setUp(() {
+/// testbed = Testbed(setUp: () {
+/// fs.file('foo').createSync()
+/// });
+/// })
+///
+/// test('Can delete a file', () => testBed.run(() {
+/// expect(fs.file('foo').existsSync(), true);
+/// fs.file('foo').deleteSync();
+/// expect(fs.file('foo').existsSync(), false);
+/// }));
+/// });
+/// }
+///
+/// For a more detailed example, see the code in test_compiler_test.dart.
+class Testbed {
+ /// Creates a new [TestBed]
+ ///
+ /// `overrides` provides more overrides in addition to the test defaults.
+ /// `setup` may be provided to apply mocks within the tool managed zone,
+ /// including any specified overrides.
+ Testbed({Future<void> Function() setup, Map<Type, Generator> overrides})
+ : _setup = setup,
+ _overrides = overrides;
+
+
+ final Future<void> Function() _setup;
+ final Map<Type, Generator> _overrides;
+
+ /// Runs `test` within a tool zone.
+ FutureOr<T> run<T>(FutureOr<T> Function() test) {
+ final Map<Type, Generator> testOverrides = Map<Type, Generator>.from(_testbedDefaults);
+ if (_overrides != null) {
+ testOverrides.addAll(_overrides);
+ }
+ // Cache the original flutter root to restore after the test case.
+ final String originalFlutterRoot = Cache.flutterRoot;
+ return runInContext<T>(() {
+ return context.run<T>(
+ name: 'testbed',
+ overrides: testOverrides,
+ body: () async {
+ Cache.flutterRoot = '';
+ if (_setup != null) {
+ await _setup();
+ }
+ await test();
+ Cache.flutterRoot = originalFlutterRoot;
+ }
+ );
+ });
+ }
+}
\ No newline at end of file