| // 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/platform.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/base/terminal.dart'; |
| import 'package:flutter_tools/src/cache.dart'; |
| import 'package:flutter_tools/src/context_runner.dart'; |
| import 'package:flutter_tools/src/usage.dart'; |
| import 'package:flutter_tools/src/version.dart'; |
| |
| import 'context.dart'; |
| |
| export 'package:flutter_tools/src/base/context.dart' show Generator; |
| |
| // A default value should be provided if one of the following criteria is met: |
| // - The vast majority of tests should use this provider. For example, |
| // [BufferLogger], [MemoryFileSystem]. |
| // - More TBD. |
| final Map<Type, Generator> _testbedDefaults = <Type, Generator>{ |
| // Keeps tests fast by avoid actual file system. |
| FileSystem: () => MemoryFileSystem(style: platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix), |
| Logger: () => BufferLogger(), // Allows reading logs and prevents stdout. |
| OutputPreferences: () => OutputPreferences(showColor: false), // configures BufferLogger to avoid color codes. |
| Usage: () => NoOpUsage(), // prevent addition of analytics from burdening test mocks |
| FlutterVersion: () => FakeFlutterVersion() // prevent requirement to mock git for test runner. |
| }; |
| |
| /// 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({FutureOr<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. |
| /// |
| /// `overrides` may be used to provide new context values for the single test |
| /// case or override any context values from the setup. |
| FutureOr<T> run<T>(FutureOr<T> Function() test, {Map<Type, Generator> overrides}) { |
| final Map<Type, Generator> testOverrides = <Type, Generator>{ |
| ..._testbedDefaults, |
| // Add the initial setUp overrides |
| ...?_overrides, |
| // Add the test-specific overrides |
| ...?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; |
| return null; |
| } |
| ); |
| }); |
| } |
| } |
| |
| /// A no-op implementation of [Usage] for testing. |
| class NoOpUsage implements Usage { |
| @override |
| bool enabled = false; |
| |
| @override |
| bool suppressAnalytics = true; |
| |
| @override |
| String get clientId => 'test'; |
| |
| @override |
| Future<void> ensureAnalyticsSent() { |
| return null; |
| } |
| |
| @override |
| bool get isFirstRun => false; |
| |
| @override |
| Stream<Map<String, Object>> get onSend => const Stream<Object>.empty(); |
| |
| @override |
| void printWelcome() {} |
| |
| @override |
| void sendCommand(String command, {Map<String, String> parameters}) {} |
| |
| @override |
| void sendEvent(String category, String parameter, {Map<String, String> parameters}) {} |
| |
| @override |
| void sendException(dynamic exception, StackTrace trace) {} |
| |
| @override |
| void sendTiming(String category, String variableName, Duration duration, {String label}) {} |
| } |
| |
| class FakeFlutterVersion implements FlutterVersion { |
| @override |
| String get channel => 'master'; |
| |
| @override |
| Future<void> checkFlutterVersionFreshness() async { } |
| |
| @override |
| bool checkRevisionAncestry({String tentativeDescendantRevision, String tentativeAncestorRevision}) { |
| throw UnimplementedError(); |
| } |
| |
| @override |
| String get dartSdkVersion => '12'; |
| |
| @override |
| String get engineRevision => '42.2'; |
| |
| @override |
| String get engineRevisionShort => '42'; |
| |
| @override |
| Future<void> ensureVersionFile() async { } |
| |
| @override |
| String get frameworkAge => null; |
| |
| @override |
| String get frameworkCommitDate => null; |
| |
| @override |
| String get frameworkDate => null; |
| |
| @override |
| String get frameworkRevision => null; |
| |
| @override |
| String get frameworkRevisionShort => null; |
| |
| @override |
| String get frameworkVersion => null; |
| |
| @override |
| String getBranchName({bool redactUnknownBranches = false}) { |
| return 'master'; |
| } |
| |
| @override |
| String getVersionString({bool redactUnknownBranches = false}) { |
| return 'v0.0.0'; |
| } |
| |
| @override |
| bool get isMaster => true; |
| |
| @override |
| String get repositoryUrl => null; |
| |
| @override |
| Map<String, Object> toJson() { |
| return null; |
| } |
| } |