mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
310 lines
9.0 KiB
Dart
310 lines
9.0 KiB
Dart
// Copyright 2016 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 'dart:io' as io;
|
|
|
|
import 'package:flutter_tools/src/android/android_workflow.dart';
|
|
import 'package:flutter_tools/src/base/config.dart';
|
|
import 'package:flutter_tools/src/base/context.dart';
|
|
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/base/port_scanner.dart';
|
|
import 'package:flutter_tools/src/cache.dart';
|
|
import 'package:flutter_tools/src/context_runner.dart';
|
|
import 'package:flutter_tools/src/device.dart';
|
|
import 'package:flutter_tools/src/doctor.dart';
|
|
import 'package:flutter_tools/src/ios/simulators.dart';
|
|
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
|
import 'package:flutter_tools/src/usage.dart';
|
|
import 'package:flutter_tools/src/version.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:quiver/time.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import 'common.dart';
|
|
|
|
export 'package:flutter_tools/src/base/context.dart' show Generator;
|
|
|
|
/// Return the test logger. This assumes that the current Logger is a BufferLogger.
|
|
BufferLogger get testLogger => context[Logger];
|
|
|
|
MockDeviceManager get testDeviceManager => context[DeviceManager];
|
|
MockDoctor get testDoctor => context[Doctor];
|
|
|
|
typedef void ContextInitializer(AppContext testContext);
|
|
|
|
void testUsingContext(String description, dynamic testMethod(), {
|
|
Timeout timeout,
|
|
Map<Type, Generator> overrides: const <Type, Generator>{},
|
|
bool initializeFlutterRoot: true,
|
|
String testOn,
|
|
bool skip, // should default to `false`, but https://github.com/dart-lang/test/issues/545 doesn't allow this
|
|
}) {
|
|
// Ensure we don't rely on the default [Config] constructor which will
|
|
// leak a sticky $HOME/.flutter_settings behind!
|
|
Directory configDir;
|
|
tearDown(() {
|
|
configDir?.deleteSync(recursive: true);
|
|
configDir = null;
|
|
});
|
|
Config buildConfig(FileSystem fs) {
|
|
configDir = fs.systemTempDirectory.createTempSync('config-dir');
|
|
final File settingsFile = fs.file(
|
|
fs.path.join(configDir.path, '.flutter_settings'));
|
|
return new Config(settingsFile);
|
|
}
|
|
|
|
test(description, () async {
|
|
await runInContext<dynamic>(() {
|
|
return context.run<dynamic>(
|
|
name: 'mocks',
|
|
overrides: <Type, Generator>{
|
|
Config: () => buildConfig(fs),
|
|
DeviceManager: () => new MockDeviceManager(),
|
|
Doctor: () => new MockDoctor(),
|
|
FlutterVersion: () => new MockFlutterVersion(),
|
|
HttpClient: () => new MockHttpClient(),
|
|
IOSSimulatorUtils: () {
|
|
final MockIOSSimulatorUtils mock = new MockIOSSimulatorUtils();
|
|
when(mock.getAttachedDevices()).thenReturn(<IOSSimulator>[]);
|
|
return mock;
|
|
},
|
|
Logger: () => new BufferLogger(),
|
|
OperatingSystemUtils: () => new MockOperatingSystemUtils(),
|
|
PortScanner: () => new MockPortScanner(),
|
|
SimControl: () => new MockSimControl(),
|
|
Usage: () => new MockUsage(),
|
|
XcodeProjectInterpreter: () => new MockXcodeProjectInterpreter(),
|
|
},
|
|
body: () {
|
|
final String flutterRoot = getFlutterRoot();
|
|
|
|
return runZoned(() {
|
|
try {
|
|
return context.run<dynamic>(
|
|
// Apply the overrides to the test context in the zone since their
|
|
// instantiation may reference items already stored on the context.
|
|
overrides: overrides,
|
|
name: 'test-specific overrides',
|
|
body: () async {
|
|
if (initializeFlutterRoot) {
|
|
// Provide a sane default for the flutterRoot directory. Individual
|
|
// tests can override this either in the test or during setup.
|
|
Cache.flutterRoot ??= flutterRoot;
|
|
}
|
|
|
|
return await testMethod();
|
|
},
|
|
);
|
|
} catch (error) {
|
|
_printBufferedErrors(context);
|
|
rethrow;
|
|
}
|
|
}, onError: (dynamic error, StackTrace stackTrace) {
|
|
io.stdout.writeln(error);
|
|
io.stdout.writeln(stackTrace);
|
|
_printBufferedErrors(context);
|
|
throw error;
|
|
});
|
|
},
|
|
);
|
|
});
|
|
}, timeout: timeout, testOn: testOn, skip: skip);
|
|
}
|
|
|
|
void _printBufferedErrors(AppContext testContext) {
|
|
if (testContext[Logger] is BufferLogger) {
|
|
final BufferLogger bufferLogger = testContext[Logger];
|
|
if (bufferLogger.errorText.isNotEmpty)
|
|
print(bufferLogger.errorText);
|
|
bufferLogger.clear();
|
|
}
|
|
}
|
|
|
|
class MockPortScanner extends PortScanner {
|
|
static int _nextAvailablePort = 12345;
|
|
|
|
@override
|
|
Future<bool> isPortAvailable(int port) async => true;
|
|
|
|
@override
|
|
Future<int> findAvailablePort() async => _nextAvailablePort++;
|
|
}
|
|
|
|
class MockDeviceManager implements DeviceManager {
|
|
List<Device> devices = <Device>[];
|
|
|
|
String _specifiedDeviceId;
|
|
|
|
@override
|
|
String get specifiedDeviceId {
|
|
if (_specifiedDeviceId == null || _specifiedDeviceId == 'all')
|
|
return null;
|
|
return _specifiedDeviceId;
|
|
}
|
|
|
|
@override
|
|
set specifiedDeviceId(String id) {
|
|
_specifiedDeviceId = id;
|
|
}
|
|
|
|
@override
|
|
bool get hasSpecifiedDeviceId => specifiedDeviceId != null;
|
|
|
|
@override
|
|
bool get hasSpecifiedAllDevices {
|
|
return _specifiedDeviceId != null && _specifiedDeviceId == 'all';
|
|
}
|
|
|
|
@override
|
|
Stream<Device> getAllConnectedDevices() => new Stream<Device>.fromIterable(devices);
|
|
|
|
@override
|
|
Stream<Device> getDevicesById(String deviceId) {
|
|
return new Stream<Device>.fromIterable(
|
|
devices.where((Device device) => device.id == deviceId));
|
|
}
|
|
|
|
@override
|
|
Stream<Device> getDevices() {
|
|
return hasSpecifiedDeviceId
|
|
? getDevicesById(specifiedDeviceId)
|
|
: getAllConnectedDevices();
|
|
}
|
|
|
|
void addDevice(Device device) => devices.add(device);
|
|
|
|
@override
|
|
bool get canListAnything => true;
|
|
|
|
@override
|
|
Future<List<String>> getDeviceDiagnostics() async => <String>[];
|
|
}
|
|
|
|
class MockAndroidWorkflowValidator extends AndroidWorkflow {
|
|
@override
|
|
Future<LicensesAccepted> get licensesAccepted async => LicensesAccepted.all;
|
|
}
|
|
|
|
class MockDoctor extends Doctor {
|
|
// True for testing.
|
|
@override
|
|
bool get canListAnything => true;
|
|
|
|
// True for testing.
|
|
@override
|
|
bool get canLaunchAnything => true;
|
|
|
|
@override
|
|
/// Replaces the android workflow with a version that overrides licensesAccepted,
|
|
/// to prevent individual tests from having to mock out the process for
|
|
/// the Doctor.
|
|
List<DoctorValidator> get validators {
|
|
final List<DoctorValidator> superValidators = super.validators;
|
|
return superValidators.map((DoctorValidator v) {
|
|
if (v is AndroidWorkflow) {
|
|
return new MockAndroidWorkflowValidator();
|
|
}
|
|
return v;
|
|
}).toList();
|
|
}
|
|
}
|
|
|
|
class MockSimControl extends Mock implements SimControl {
|
|
MockSimControl() {
|
|
when(getConnectedDevices()).thenReturn(<SimDevice>[]);
|
|
}
|
|
}
|
|
|
|
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {
|
|
@override
|
|
List<File> whichAll(String execName) => <File>[];
|
|
|
|
@override
|
|
String get name => 'fake OS name and version';
|
|
|
|
@override
|
|
String get pathVarSeparator => ';';
|
|
}
|
|
|
|
class MockIOSSimulatorUtils extends Mock implements IOSSimulatorUtils {}
|
|
|
|
class MockUsage implements Usage {
|
|
@override
|
|
bool get isFirstRun => false;
|
|
|
|
@override
|
|
bool get suppressAnalytics => false;
|
|
|
|
@override
|
|
set suppressAnalytics(bool value) { }
|
|
|
|
@override
|
|
bool get enabled => true;
|
|
|
|
@override
|
|
set enabled(bool value) { }
|
|
|
|
@override
|
|
String get clientId => '00000000-0000-4000-0000-000000000000';
|
|
|
|
@override
|
|
void sendCommand(String command, { Map<String, String> parameters }) { }
|
|
|
|
@override
|
|
void sendEvent(String category, String parameter, { Map<String, String> parameters }) { }
|
|
|
|
@override
|
|
void sendTiming(String category, String variableName, Duration duration, { String label }) { }
|
|
|
|
@override
|
|
void sendException(dynamic exception, StackTrace trace) { }
|
|
|
|
@override
|
|
Stream<Map<String, dynamic>> get onSend => null;
|
|
|
|
@override
|
|
Future<Null> ensureAnalyticsSent() => new Future<Null>.value();
|
|
|
|
@override
|
|
void printWelcome() { }
|
|
}
|
|
|
|
class MockXcodeProjectInterpreter implements XcodeProjectInterpreter {
|
|
@override
|
|
bool get isInstalled => true;
|
|
|
|
@override
|
|
String get versionText => 'Xcode 9.2';
|
|
|
|
@override
|
|
int get majorVersion => 9;
|
|
|
|
@override
|
|
int get minorVersion => 2;
|
|
|
|
@override
|
|
Map<String, String> getBuildSettings(String projectPath, String target) {
|
|
return <String, String>{};
|
|
}
|
|
|
|
@override
|
|
XcodeProjectInfo getInfo(String projectPath) {
|
|
return new XcodeProjectInfo(
|
|
<String>['Runner'],
|
|
<String>['Debug', 'Release'],
|
|
<String>['Runner'],
|
|
);
|
|
}
|
|
}
|
|
|
|
class MockFlutterVersion extends Mock implements FlutterVersion {}
|
|
|
|
class MockClock extends Mock implements Clock {}
|
|
|
|
class MockHttpClient extends Mock implements HttpClient {}
|