flutter/packages/flutter_tools/test/general.shard/emulator_test.dart
Ian Hickson 449f4a6673
License update (#45373)
* Update project.pbxproj files to say Flutter rather than Chromium

Also, the templates now have an empty organization so that we don't cause people to give their apps a Flutter copyright.

* Update the copyright notice checker to require a standard notice on all files

* Update copyrights on Dart files. (This was a mechanical commit.)

* Fix weird license headers on Dart files that deviate from our conventions; relicense Shrine.

Some were already marked "The Flutter Authors", not clear why. Their
dates have been normalized. Some were missing the blank line after the
license. Some were randomly different in trivial ways for no apparent
reason (e.g. missing the trailing period).

* Clean up the copyrights in non-Dart files. (Manual edits.)

Also, make sure templates don't have copyrights.

* Fix some more ORGANIZATIONNAMEs
2019-11-27 15:04:02 -08:00

263 lines
9.2 KiB
Dart

// Copyright 2014 The Flutter 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:convert';
import 'package:collection/collection.dart' show ListEquality;
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/base/config.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/emulator.dart';
import 'package:flutter_tools/src/ios/ios_emulators.dart';
import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
void main() {
MockProcessManager mockProcessManager;
MockConfig mockConfig;
MockAndroidSdk mockSdk;
MockXcode mockXcode;
setUp(() {
mockProcessManager = MockProcessManager();
mockConfig = MockConfig();
mockSdk = MockAndroidSdk();
mockXcode = MockXcode();
when(mockSdk.avdManagerPath).thenReturn('avdmanager');
when(mockSdk.emulatorPath).thenReturn('emulator');
});
group('EmulatorManager', () {
testUsingContext('getEmulators', () async {
// Test that EmulatorManager.getEmulators() doesn't throw.
final List<Emulator> emulators =
await emulatorManager.getAllAvailableEmulators();
expect(emulators, isList);
});
testUsingContext('getEmulatorsById', () async {
final _MockEmulator emulator1 =
_MockEmulator('Nexus_5', 'Nexus 5', 'Google');
final _MockEmulator emulator2 =
_MockEmulator('Nexus_5X_API_27_x86', 'Nexus 5X', 'Google');
final _MockEmulator emulator3 =
_MockEmulator('iOS Simulator', 'iOS Simulator', 'Apple');
final List<Emulator> emulators = <Emulator>[
emulator1,
emulator2,
emulator3,
];
final TestEmulatorManager testEmulatorManager =
TestEmulatorManager(emulators);
Future<void> expectEmulator(String id, List<Emulator> expected) async {
expect(await testEmulatorManager.getEmulatorsMatching(id), expected);
}
await expectEmulator('Nexus_5', <Emulator>[emulator1]);
await expectEmulator('Nexus_5X', <Emulator>[emulator2]);
await expectEmulator('Nexus_5X_API_27_x86', <Emulator>[emulator2]);
await expectEmulator('Nexus', <Emulator>[emulator1, emulator2]);
await expectEmulator('iOS Simulator', <Emulator>[emulator3]);
await expectEmulator('ios', <Emulator>[emulator3]);
});
testUsingContext('create emulator with an empty name does not fail', () async {
final CreateEmulatorResult res = await emulatorManager.createEmulator();
expect(res.success, equals(true));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Config: () => mockConfig,
AndroidSdk: () => mockSdk,
});
testUsingContext('create emulator with a unique name does not throw', () async {
final CreateEmulatorResult res =
await emulatorManager.createEmulator(name: 'test');
expect(res.success, equals(true));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Config: () => mockConfig,
AndroidSdk: () => mockSdk,
});
testUsingContext('create emulator with an existing name errors', () async {
final CreateEmulatorResult res =
await emulatorManager.createEmulator(name: 'existing-avd-1');
expect(res.success, equals(false));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Config: () => mockConfig,
AndroidSdk: () => mockSdk,
});
testUsingContext('create emulator without a name but when default exists adds a suffix', () async {
// First will get default name.
CreateEmulatorResult res = await emulatorManager.createEmulator();
expect(res.success, equals(true));
final String defaultName = res.emulatorName;
// Second...
res = await emulatorManager.createEmulator();
expect(res.success, equals(true));
expect(res.emulatorName, equals('${defaultName}_2'));
// Third...
res = await emulatorManager.createEmulator();
expect(res.success, equals(true));
expect(res.emulatorName, equals('${defaultName}_3'));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Config: () => mockConfig,
AndroidSdk: () => mockSdk,
});
});
group('ios_emulators', () {
bool didAttemptToRunSimulator = false;
setUp(() {
when(mockXcode.xcodeSelectPath).thenReturn('/fake/Xcode.app/Contents/Developer');
when(mockXcode.getSimulatorPath()).thenAnswer((_) => '/fake/simulator.app');
when(mockProcessManager.run(any)).thenAnswer((Invocation invocation) async {
final List<String> args = invocation.positionalArguments[0] as List<String>;
if (args.length >= 3 && args[0] == 'open' && args[1] == '-a' && args[2] == '/fake/simulator.app') {
didAttemptToRunSimulator = true;
}
return ProcessResult(101, 0, '', '');
});
});
testUsingContext('runs correct launch commands', () async {
final Emulator emulator = IOSEmulator('ios');
await emulator.launch();
expect(didAttemptToRunSimulator, equals(true));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Config: () => mockConfig,
Xcode: () => mockXcode,
});
});
}
class TestEmulatorManager extends EmulatorManager {
TestEmulatorManager(this.allEmulators);
final List<Emulator> allEmulators;
@override
Future<List<Emulator>> getAllAvailableEmulators() {
return Future<List<Emulator>>.value(allEmulators);
}
}
class _MockEmulator extends Emulator {
_MockEmulator(String id, this.name, this.manufacturer)
: super(id, true);
@override
final String name;
@override
final String manufacturer;
@override
Category get category => Category.mobile;
@override
PlatformType get platformType => PlatformType.android;
@override
Future<void> launch() {
throw UnimplementedError('Not implemented in Mock');
}
}
class MockConfig extends Mock implements Config {}
class MockProcessManager extends Mock implements ProcessManager {
/// We have to send a command that fails in order to get the list of valid
/// system images paths. This is an example of the output to use in the mock.
static const String mockCreateFailureOutput =
'Error: Package path (-k) not specified. Valid system image paths are:\n'
'system-images;android-27;google_apis;x86\n'
'system-images;android-P;google_apis;x86\n'
'system-images;android-27;google_apis_playstore;x86\n'
'null\n'; // Yep, these really end with null (on dantup's machine at least)
static const ListEquality<String> _equality = ListEquality<String>();
final List<String> _existingAvds = <String>['existing-avd-1'];
@override
ProcessResult runSync(
List<dynamic> command, {
String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding,
}) {
final String program = command[0] as String;
final List<String> args = command.sublist(1) as List<String>;
switch (program) {
case '/usr/bin/xcode-select':
throw ProcessException(program, args);
break;
case 'emulator':
return _handleEmulator(args);
case 'avdmanager':
return _handleAvdManager(args);
}
throw StateError('Unexpected process call: $command');
}
ProcessResult _handleEmulator(List<String> args) {
if (_equality.equals(args, <String>['-list-avds'])) {
return ProcessResult(101, 0, '${_existingAvds.join('\n')}\n', '');
}
throw ProcessException('emulator', args);
}
ProcessResult _handleAvdManager(List<String> args) {
if (_equality.equals(args, <String>['list', 'device', '-c'])) {
return ProcessResult(101, 0, 'test\ntest2\npixel\npixel-xl\n', '');
}
if (_equality.equals(args, <String>['create', 'avd', '-n', 'temp'])) {
return ProcessResult(101, 1, '', mockCreateFailureOutput);
}
if (args.length == 8 &&
_equality.equals(args,
<String>['create', 'avd', '-n', args[3], '-k', args[5], '-d', args[7]])) {
// In order to support testing auto generation of names we need to support
// tracking any created emulators and reject when they already exist so this
// mock will compare the name of the AVD being created with the fake existing
// list and either reject if it exists, or add it to the list and return success.
final String name = args[3];
// Error if this AVD already existed
if (_existingAvds.contains(name)) {
return ProcessResult(
101,
1,
'',
"Error: Android Virtual Device '$name' already exists.\n"
'Use --force if you want to replace it.');
} else {
_existingAvds.add(name);
return ProcessResult(101, 0, '', '');
}
}
throw ProcessException('emulator', args);
}
}
class MockXcode extends Mock implements Xcode {}