blob: 027164dcc3d7a69a0f657ebc94c3d9972a458768 [file] [log] [blame]
// 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 'package:flutter_tools/src/android/android_emulator.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:test/fake.dart';
import '../../src/common.dart';
import '../../src/fake_process_manager.dart';
const String emulatorID = 'i1234';
const String errorText = '[Android emulator test error]';
const List<String> kEmulatorLaunchCommand = <String>[
'emulator', '-avd', emulatorID,
];
void main() {
group('android_emulator', () {
testWithoutContext('flags emulators without config', () {
const String emulatorID = '1234';
final AndroidEmulator emulator = AndroidEmulator(
emulatorID,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
androidSdk: FakeAndroidSdk(),
);
expect(emulator.id, emulatorID);
expect(emulator.hasConfig, false);
});
testWithoutContext('flags emulators with config', () {
const String emulatorID = '1234';
final AndroidEmulator emulator = AndroidEmulator(
emulatorID,
properties: const <String, String>{'name': 'test'},
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
androidSdk: FakeAndroidSdk(),
);
expect(emulator.id, emulatorID);
expect(emulator.hasConfig, true);
});
testWithoutContext('reads expected metadata', () {
const String emulatorID = '1234';
const String manufacturer = 'Me';
const String displayName = 'The best one';
final Map<String, String> properties = <String, String>{
'hw.device.manufacturer': manufacturer,
'avd.ini.displayname': displayName,
};
final AndroidEmulator emulator = AndroidEmulator(
emulatorID,
properties: properties,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
androidSdk: FakeAndroidSdk(),
);
expect(emulator.id, emulatorID);
expect(emulator.name, displayName);
expect(emulator.manufacturer, manufacturer);
expect(emulator.category, Category.mobile);
expect(emulator.platformType, PlatformType.android);
});
testWithoutContext('prefers displayname for name', () {
const String emulatorID = '1234';
const String displayName = 'The best one';
final Map<String, String> properties = <String, String>{
'avd.ini.displayname': displayName,
};
final AndroidEmulator emulator = AndroidEmulator(
emulatorID,
properties: properties,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
androidSdk: FakeAndroidSdk(),
);
expect(emulator.name, displayName);
});
testWithoutContext('uses cleaned up ID if no displayname is set', () {
// Android Studio uses the ID with underscores replaced with spaces
// for the name if displayname is not set so we do the same.
const String emulatorID = 'This_is_my_ID';
final Map<String, String> properties = <String, String>{
'avd.ini.notadisplayname': 'this is not a display name',
};
final AndroidEmulator emulator = AndroidEmulator(
emulatorID,
properties: properties,
logger: BufferLogger.test(),
processManager: FakeProcessManager.any(),
androidSdk: FakeAndroidSdk(),
);
expect(emulator.name, 'This is my ID');
});
testWithoutContext('parses ini files', () {
const String iniFile = '''
hw.device.name=My Test Name
#hw.device.name=Bad Name
hw.device.manufacturer=Me
avd.ini.displayname = dispName
''';
final Map<String, String> results = parseIniLines(iniFile.split('\n'));
expect(results['hw.device.name'], 'My Test Name');
expect(results['hw.device.manufacturer'], 'Me');
expect(results['avd.ini.displayname'], 'dispName');
});
});
group('Android emulator launch ', () {
late FakeAndroidSdk mockSdk;
setUp(() {
mockSdk = FakeAndroidSdk();
mockSdk.emulatorPath = 'emulator';
});
testWithoutContext('succeeds', () async {
final AndroidEmulator emulator = AndroidEmulator(emulatorID,
processManager: FakeProcessManager.list(<FakeCommand>[
const FakeCommand(command: kEmulatorLaunchCommand),
]),
androidSdk: mockSdk,
logger: BufferLogger.test(),
);
await emulator.launch(startupDuration: Duration.zero);
});
testWithoutContext('succeeds with coldboot launch', () async {
final List<String> kEmulatorLaunchColdBootCommand = <String>[
...kEmulatorLaunchCommand,
'-no-snapshot-load',
];
final AndroidEmulator emulator = AndroidEmulator(emulatorID,
processManager: FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: kEmulatorLaunchColdBootCommand),
]),
androidSdk: mockSdk,
logger: BufferLogger.test(),
);
await emulator.launch(startupDuration: Duration.zero, coldBoot: true);
});
testWithoutContext('prints error on failure', () async {
final BufferLogger logger = BufferLogger.test();
final AndroidEmulator emulator = AndroidEmulator(emulatorID,
processManager: FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: kEmulatorLaunchCommand,
exitCode: 1,
stderr: errorText,
stdout: 'dummy text',
),
]),
androidSdk: mockSdk,
logger: logger,
);
await emulator.launch(startupDuration: Duration.zero);
expect(logger.errorText, contains(errorText));
});
testWithoutContext('prints nothing on late failure with empty stderr', () async {
final BufferLogger logger = BufferLogger.test();
final AndroidEmulator emulator = AndroidEmulator(emulatorID,
processManager: FakeProcessManager.list(<FakeCommand>[
FakeCommand(
command: kEmulatorLaunchCommand,
exitCode: 1,
stdout: 'dummy text',
completer: Completer<void>(),
),
]),
androidSdk: mockSdk,
logger: logger,
);
await emulator.launch(startupDuration: Duration.zero);
expect(logger.errorText, isEmpty);
});
testWithoutContext('throws if emulator not found', () async {
mockSdk.emulatorPath = null;
final AndroidEmulator emulator = AndroidEmulator(
emulatorID,
processManager: FakeProcessManager.empty(),
androidSdk: mockSdk,
logger: BufferLogger.test(),
);
await expectLater(
() => emulator.launch(startupDuration: Duration.zero),
throwsA(isException.having(
(Exception exception) => exception.toString(),
'description',
contains('Emulator is missing from the Android SDK'),
)),
);
});
});
}
class FakeAndroidSdk extends Fake implements AndroidSdk {
@override
String? emulatorPath;
}