Merge pull request #1859 from devoncarew/android_sdk_version
allow any android sdk version
This commit is contained in:
commit
981a7f378c
214
packages/flutter_tools/lib/src/android/android_sdk.dart
Normal file
214
packages/flutter_tools/lib/src/android/android_sdk.dart
Normal file
@ -0,0 +1,214 @@
|
||||
// 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:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
import '../base/globals.dart';
|
||||
import '../base/os.dart';
|
||||
|
||||
// Android SDK layout:
|
||||
//
|
||||
// $ANDROID_HOME/platform-tools/adb
|
||||
// $ANDROID_HOME/build-tools/19.1.0/aapt, dx, zipalign
|
||||
// $ANDROID_HOME/build-tools/22.0.1/aapt
|
||||
// $ANDROID_HOME/build-tools/23.0.2/aapt
|
||||
// $ANDROID_HOME/platforms/android-22/android.jar
|
||||
// $ANDROID_HOME/platforms/android-23/android.jar
|
||||
|
||||
// TODO(devoncarew): We need a way to locate the Android SDK w/o using an environment variable.
|
||||
// Perhaps something like `flutter config --android-home=foo/bar`.
|
||||
|
||||
/// Locate ADB. Prefer to use one from an Android SDK, if we can locate that.
|
||||
String getAdbPath() {
|
||||
AndroidSdk sdk = AndroidSdk.locateAndroidSdk();
|
||||
|
||||
if (sdk?.latestVersion == null) {
|
||||
return os.which('adb')?.path;
|
||||
} else {
|
||||
return sdk.adbPath;
|
||||
}
|
||||
}
|
||||
|
||||
class AndroidSdk {
|
||||
AndroidSdk(this.directory) {
|
||||
_init();
|
||||
}
|
||||
|
||||
final String directory;
|
||||
|
||||
List<AndroidSdkVersion> _sdkVersions;
|
||||
AndroidSdkVersion _latestVersion;
|
||||
|
||||
static AndroidSdk locateAndroidSdk() {
|
||||
// TODO: Use explicit configuration information from a metadata file?
|
||||
|
||||
if (Platform.environment.containsKey('ANDROID_HOME')) {
|
||||
String homeDir = Platform.environment['ANDROID_HOME'];
|
||||
if (validSdkDirectory(homeDir))
|
||||
return new AndroidSdk(homeDir);
|
||||
if (validSdkDirectory(path.join(homeDir, 'sdk')))
|
||||
return new AndroidSdk(path.join(homeDir, 'sdk'));
|
||||
}
|
||||
|
||||
File aaptBin = os.which('aapt'); // in build-tools/$version/aapt
|
||||
if (aaptBin != null) {
|
||||
String dir = aaptBin.parent.parent.parent.path;
|
||||
if (validSdkDirectory(dir))
|
||||
return new AndroidSdk(dir);
|
||||
}
|
||||
|
||||
File adbBin = os.which('adb'); // in platform-tools/adb
|
||||
if (adbBin != null) {
|
||||
String dir = adbBin.parent.parent.path;
|
||||
if (validSdkDirectory(dir))
|
||||
return new AndroidSdk(dir);
|
||||
}
|
||||
|
||||
// No dice.
|
||||
printTrace('Unable to locate an Android SDK.');
|
||||
return null;
|
||||
}
|
||||
|
||||
static bool validSdkDirectory(String dir) {
|
||||
return FileSystemEntity.isDirectorySync(path.join(dir, 'platform-tools'));
|
||||
}
|
||||
|
||||
List<AndroidSdkVersion> get sdkVersions => _sdkVersions;
|
||||
|
||||
AndroidSdkVersion get latestVersion => _latestVersion;
|
||||
|
||||
String get adbPath => getPlatformToolsPath('adb');
|
||||
|
||||
bool validateSdkWellFormed({ bool complain: false }) {
|
||||
if (!FileSystemEntity.isFileSync(adbPath)) {
|
||||
if (complain)
|
||||
printError('Android SDK file not found: $adbPath.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sdkVersions.isEmpty) {
|
||||
if (complain)
|
||||
printError('Android SDK does not have the proper build-tools.');
|
||||
return false;
|
||||
}
|
||||
|
||||
return latestVersion.validateSdkWellFormed(complain: complain);
|
||||
}
|
||||
|
||||
String getPlatformToolsPath(String binaryName) {
|
||||
return path.join(directory, 'platform-tools', binaryName);
|
||||
}
|
||||
|
||||
void _init() {
|
||||
List<String> platforms = <String>[]; // android-22, ...
|
||||
|
||||
Directory platformsDir = new Directory(path.join(directory, 'platforms'));
|
||||
if (platformsDir.existsSync()) {
|
||||
platforms = platformsDir
|
||||
.listSync()
|
||||
.map((FileSystemEntity entity) => path.basename(entity.path))
|
||||
.where((String name) => name.startsWith('android-'))
|
||||
.toList();
|
||||
}
|
||||
|
||||
List<Version> buildToolsVersions = <Version>[]; // 19.1.0, 22.0.1, ...
|
||||
|
||||
Directory buildToolsDir = new Directory(path.join(directory, 'build-tools'));
|
||||
if (buildToolsDir.existsSync()) {
|
||||
buildToolsVersions = buildToolsDir
|
||||
.listSync()
|
||||
.map((FileSystemEntity entity) {
|
||||
try {
|
||||
return new Version.parse(path.basename(entity.path));
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.where((Version version) => version != null)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Here we match up platforms with cooresponding build-tools. If we don't
|
||||
// have a match, we don't return anything for that platform version. So if
|
||||
// the user only have 'android-22' and 'build-tools/19.0.0', we don't find
|
||||
// an Android sdk.
|
||||
_sdkVersions = platforms.map((String platform) {
|
||||
int sdkVersion;
|
||||
|
||||
try {
|
||||
sdkVersion = int.parse(platform.substring('android-'.length));
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Version buildToolsVersion = Version.primary(buildToolsVersions.where((Version version) {
|
||||
return version.major == sdkVersion;
|
||||
}).toList());
|
||||
|
||||
if (buildToolsVersion == null)
|
||||
return null;
|
||||
|
||||
return new AndroidSdkVersion(this, platform, buildToolsVersion.toString());
|
||||
}).where((AndroidSdkVersion version) => version != null).toList();
|
||||
|
||||
_sdkVersions.sort();
|
||||
|
||||
_latestVersion = _sdkVersions.isEmpty ? null : _sdkVersions.last;
|
||||
}
|
||||
|
||||
String toString() => 'AndroidSdk: $directory';
|
||||
}
|
||||
|
||||
class AndroidSdkVersion implements Comparable<AndroidSdkVersion> {
|
||||
AndroidSdkVersion(this.sdk, this.androidVersion, this.buildToolsVersion);
|
||||
|
||||
final AndroidSdk sdk;
|
||||
final String androidVersion;
|
||||
final String buildToolsVersion;
|
||||
|
||||
int get sdkLevel => int.parse(androidVersion.substring('android-'.length));
|
||||
|
||||
String get androidJarPath => getPlatformsPath('android.jar');
|
||||
|
||||
String get aaptPath => getBuildToolsPath('aapt');
|
||||
|
||||
String get dxPath => getBuildToolsPath('dx');
|
||||
|
||||
String get zipalignPath => getBuildToolsPath('zipalign');
|
||||
|
||||
bool validateSdkWellFormed({ bool complain: false }) {
|
||||
return
|
||||
_exists(androidJarPath, complain: complain) &&
|
||||
_exists(aaptPath, complain: complain) &&
|
||||
_exists(dxPath, complain: complain) &&
|
||||
_exists(zipalignPath, complain: complain);
|
||||
}
|
||||
|
||||
String getPlatformsPath(String itemName) {
|
||||
return path.join(sdk.directory, 'platforms', androidVersion, itemName);
|
||||
}
|
||||
|
||||
String getBuildToolsPath(String binaryName) {
|
||||
return path.join(sdk.directory, 'build-tools', buildToolsVersion, binaryName);
|
||||
}
|
||||
|
||||
int compareTo(AndroidSdkVersion other) {
|
||||
return sdkLevel - other.sdkLevel;
|
||||
}
|
||||
|
||||
String toString() => '[${sdk.directory}, SDK version $sdkLevel, build-tools $buildToolsVersion]';
|
||||
|
||||
bool _exists(String path, { bool complain: false }) {
|
||||
if (!FileSystemEntity.isFileSync(path)) {
|
||||
if (complain)
|
||||
printError('Android SDK file not found: $path.');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -50,18 +50,6 @@ class AndroidDevice extends Device {
|
||||
}) : super(id) {
|
||||
if (connected != null)
|
||||
_connected = connected;
|
||||
|
||||
_adbPath = getAdbPath();
|
||||
_hasAdb = _checkForAdb();
|
||||
|
||||
// Checking for [minApiName] only needs to be done if we are starting an
|
||||
// app, but it has an important side effect, which is to discard any
|
||||
// progress messages if the adb server is restarted.
|
||||
_hasValidAndroid = _checkForSupportedAndroidVersion();
|
||||
|
||||
if (!_hasAdb || !_hasValidAndroid) {
|
||||
printError('Unable to run on Android.');
|
||||
}
|
||||
}
|
||||
|
||||
final String productID;
|
||||
@ -69,32 +57,9 @@ class AndroidDevice extends Device {
|
||||
final String deviceCodeName;
|
||||
|
||||
bool _connected;
|
||||
String _adbPath;
|
||||
String get adbPath => _adbPath;
|
||||
bool _hasAdb = false;
|
||||
bool _hasValidAndroid = false;
|
||||
|
||||
static String getAndroidSdkPath() {
|
||||
if (Platform.environment.containsKey('ANDROID_HOME')) {
|
||||
String androidHomeDir = Platform.environment['ANDROID_HOME'];
|
||||
if (FileSystemEntity.isDirectorySync(
|
||||
path.join(androidHomeDir, 'platform-tools'))) {
|
||||
return androidHomeDir;
|
||||
} else if (FileSystemEntity.isDirectorySync(
|
||||
path.join(androidHomeDir, 'sdk', 'platform-tools'))) {
|
||||
return path.join(androidHomeDir, 'sdk');
|
||||
} else {
|
||||
printError('Android SDK not found at $androidHomeDir');
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
printError('Android SDK not found. The ANDROID_HOME variable must be set.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
List<String> adbCommandForDevice(List<String> args) {
|
||||
return <String>[adbPath, '-s', id]..addAll(args);
|
||||
return <String>[androidSdk.adbPath, '-s', id]..addAll(args);
|
||||
}
|
||||
|
||||
bool _isValidAdbVersion(String adbVersion) {
|
||||
@ -121,24 +86,19 @@ class AndroidDevice extends Device {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _checkForAdb() {
|
||||
try {
|
||||
String adbVersion = runCheckedSync(<String>[adbPath, 'version']);
|
||||
if (_isValidAdbVersion(adbVersion)) {
|
||||
return true;
|
||||
}
|
||||
bool _checkForSupportedAdbVersion() {
|
||||
if (androidSdk == null)
|
||||
return false;
|
||||
|
||||
String locatedAdbPath = runCheckedSync(<String>['which', 'adb']);
|
||||
printError('"$locatedAdbPath" is too old. '
|
||||
'Please install version 1.0.32 or later.\n'
|
||||
'Try setting ANDROID_HOME to the path to your Android SDK install. '
|
||||
'Android builds are unavailable.');
|
||||
} catch (e) {
|
||||
printError('"adb" not found in \$PATH. '
|
||||
'Please install the Android SDK or set ANDROID_HOME '
|
||||
'to the path of your Android SDK install.');
|
||||
printTrace('$e');
|
||||
try {
|
||||
String adbVersion = runCheckedSync(<String>[androidSdk.adbPath, 'version']);
|
||||
if (_isValidAdbVersion(adbVersion))
|
||||
return true;
|
||||
printError('The ADB at "${androidSdk.adbPath}" is too old; please install version 1.0.32 or later.');
|
||||
} catch (error, trace) {
|
||||
printError('Error running ADB: $error', trace);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -150,34 +110,29 @@ class AndroidDevice extends Device {
|
||||
// * daemon started successfully *
|
||||
runCheckedSync(adbCommandForDevice(<String>['start-server']));
|
||||
|
||||
String ready = runSync(adbCommandForDevice(<String>['shell', 'echo', 'ready']));
|
||||
if (ready.trim() != 'ready') {
|
||||
printTrace('Android device not found.');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sample output: '22'
|
||||
String sdkVersion = runCheckedSync(
|
||||
adbCommandForDevice(<String>['shell', 'getprop', 'ro.build.version.sdk'])
|
||||
).trimRight();
|
||||
|
||||
int sdkVersionParsed =
|
||||
int.parse(sdkVersion, onError: (String source) => null);
|
||||
int sdkVersionParsed = int.parse(sdkVersion, onError: (String source) => null);
|
||||
if (sdkVersionParsed == null) {
|
||||
printError('Unexpected response from getprop: "$sdkVersion"');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sdkVersionParsed < minApiLevel) {
|
||||
printError(
|
||||
'The Android version ($sdkVersion) on the target device is too old. Please '
|
||||
'use a $minVersionName (version $minApiLevel / $minVersionText) device or later.');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
printError('Unexpected failure from adb: $e');
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String _getDeviceSha1Path(ApplicationPackage app) {
|
||||
@ -220,11 +175,15 @@ class AndroidDevice extends Device {
|
||||
printTrace('Android device not connected. Not installing.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FileSystemEntity.isFileSync(app.localPath)) {
|
||||
printError('"${app.localPath}" does not exist.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion())
|
||||
return false;
|
||||
|
||||
printStatus('Installing ${app.name} on device.');
|
||||
runCheckedSync(adbCommandForDevice(<String>['install', '-r', app.localPath]));
|
||||
runCheckedSync(adbCommandForDevice(<String>['shell', 'echo', '-n', _getSourceSha1(app), '>', _getDeviceSha1Path(app)]));
|
||||
@ -306,6 +265,9 @@ class AndroidDevice extends Device {
|
||||
int debugPort: observatoryDefaultPort,
|
||||
Map<String, dynamic> platformArgs
|
||||
}) async {
|
||||
if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion())
|
||||
return false;
|
||||
|
||||
flx.DirectoryResult buildResult = await flx.buildInTempDir(
|
||||
toolchain,
|
||||
mainPath: mainPath
|
||||
@ -420,7 +382,7 @@ class AndroidDevice extends Device {
|
||||
return null;
|
||||
}
|
||||
|
||||
bool isConnected() => _connected ?? _hasValidAndroid;
|
||||
bool isConnected() => _connected ?? androidSdk != null;
|
||||
|
||||
void setConnected(bool value) {
|
||||
_connected = value;
|
||||
@ -447,18 +409,12 @@ class AndroidDevice extends Device {
|
||||
}
|
||||
}
|
||||
|
||||
/// The [mockAndroid] argument is only to facilitate testing with mocks, so that
|
||||
/// we don't have to rely on the test setup having adb available to it.
|
||||
List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) {
|
||||
List<AndroidDevice> devices = [];
|
||||
String adbPath = (mockAndroid != null) ? mockAndroid.adbPath : getAdbPath();
|
||||
List<AndroidDevice> getAdbDevices() {
|
||||
if (androidSdk == null)
|
||||
return <AndroidDevice>[];
|
||||
|
||||
try {
|
||||
runCheckedSync(<String>[adbPath, 'version']);
|
||||
} catch (e) {
|
||||
printError('Unable to find adb. Is "adb" in your path?');
|
||||
return devices;
|
||||
}
|
||||
String adbPath = androidSdk.adbPath;
|
||||
List<AndroidDevice> devices = [];
|
||||
|
||||
List<String> output = runSync(<String>[adbPath, 'devices', '-l']).trim().split('\n');
|
||||
|
||||
@ -525,25 +481,6 @@ List<AndroidDevice> getAdbDevices([AndroidDevice mockAndroid]) {
|
||||
return devices;
|
||||
}
|
||||
|
||||
String getAdbPath() {
|
||||
if (Platform.environment.containsKey('ANDROID_HOME')) {
|
||||
String androidHomeDir = Platform.environment['ANDROID_HOME'];
|
||||
String adbPath1 = path.join(androidHomeDir, 'sdk', 'platform-tools', 'adb');
|
||||
String adbPath2 = path.join(androidHomeDir, 'platform-tools', 'adb');
|
||||
if (FileSystemEntity.isFileSync(adbPath1)) {
|
||||
return adbPath1;
|
||||
} else if (FileSystemEntity.isFileSync(adbPath2)) {
|
||||
return adbPath2;
|
||||
} else {
|
||||
printTrace('"adb" not found at\n "$adbPath1" or\n "$adbPath2"\n' +
|
||||
'using default path "$_defaultAdbPath"');
|
||||
return _defaultAdbPath;
|
||||
}
|
||||
} else {
|
||||
return _defaultAdbPath;
|
||||
}
|
||||
}
|
||||
|
||||
/// A log reader that logs from `adb logcat`. This will have the same output as
|
||||
/// another copy of [_AdbLogReader], and the two instances will be equivalent.
|
||||
class _AdbLogReader extends DeviceLogReader {
|
||||
|
@ -16,6 +16,14 @@ AppContext get context {
|
||||
class AppContext {
|
||||
Map<Type, dynamic> _instances = <Type, dynamic>{};
|
||||
|
||||
bool isSet(Type type) {
|
||||
if (_instances.containsKey(type))
|
||||
return true;
|
||||
|
||||
AppContext parent = _calcParent(Zone.current);
|
||||
return parent != null ? parent.isSet(type) : false;
|
||||
}
|
||||
|
||||
dynamic getVariable(Type type) {
|
||||
if (_instances.containsKey(type))
|
||||
return _instances[type];
|
||||
|
@ -2,12 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import '../android/android_sdk.dart';
|
||||
import '../device.dart';
|
||||
import 'context.dart';
|
||||
import 'logger.dart';
|
||||
|
||||
DeviceManager get deviceManager => context[DeviceManager];
|
||||
Logger get logger => context[Logger];
|
||||
AndroidSdk get androidSdk => context[AndroidSdk];
|
||||
|
||||
/// Display an error level message to the user. Commands should use this if they
|
||||
/// fail in some way.
|
||||
|
@ -18,12 +18,26 @@ abstract class OperatingSystemUtils {
|
||||
|
||||
/// Make the given file executable. This may be a no-op on some platforms.
|
||||
ProcessResult makeExecutable(File file);
|
||||
|
||||
/// Return the path (with symlinks resolved) to the given executable, or `null`
|
||||
/// if `which` was not able to locate the binary.
|
||||
File which(String execName);
|
||||
}
|
||||
|
||||
class _PosixUtils implements OperatingSystemUtils {
|
||||
ProcessResult makeExecutable(File file) {
|
||||
return Process.runSync('chmod', ['u+x', file.path]);
|
||||
}
|
||||
|
||||
/// Return the path (with symlinks resolved) to the given executable, or `null`
|
||||
/// if `which` was not able to locate the binary.
|
||||
File which(String execName) {
|
||||
ProcessResult result = Process.runSync('which', <String>[execName]);
|
||||
if (result.exitCode != 0)
|
||||
return null;
|
||||
String path = result.stdout.trim().split('\n').first.trim();
|
||||
return new File(new File(path).resolveSymbolicLinksSync());
|
||||
}
|
||||
}
|
||||
|
||||
class _WindowsUtils implements OperatingSystemUtils {
|
||||
@ -31,6 +45,10 @@ class _WindowsUtils implements OperatingSystemUtils {
|
||||
ProcessResult makeExecutable(File file) {
|
||||
return new ProcessResult(0, 0, null, null);
|
||||
}
|
||||
|
||||
File which(String execName) {
|
||||
throw new UnimplementedError('_WindowsUtils.which');
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> findAvailablePort() async {
|
||||
|
@ -7,11 +7,12 @@ import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import '../android/device_android.dart';
|
||||
import '../android/android_sdk.dart';
|
||||
import '../application_package.dart';
|
||||
import '../artifacts.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/globals.dart';
|
||||
import '../base/os.dart';
|
||||
import '../base/process.dart';
|
||||
import '../build_configuration.dart';
|
||||
import '../device.dart';
|
||||
@ -34,9 +35,6 @@ const String _kDebugKeystoreKeyAlias = "chromiumdebugkey";
|
||||
// Password for the Chromium debug keystore
|
||||
const String _kDebugKeystorePassword = "chromium";
|
||||
|
||||
const String _kAndroidPlatformVersion = '22';
|
||||
const String _kBuildToolsVersion = '22.0.1';
|
||||
|
||||
/// Copies files into a new directory structure.
|
||||
class _AssetBuilder {
|
||||
final Directory outDir;
|
||||
@ -59,30 +57,24 @@ class _AssetBuilder {
|
||||
|
||||
/// Builds an APK package using Android SDK tools.
|
||||
class _ApkBuilder {
|
||||
final String androidSdk;
|
||||
final AndroidSdkVersion sdk;
|
||||
|
||||
File _androidJar;
|
||||
File _aapt;
|
||||
File _dx;
|
||||
File _zipalign;
|
||||
String _jarsigner;
|
||||
File _jarsigner;
|
||||
|
||||
_ApkBuilder(this.androidSdk) {
|
||||
_androidJar = new File('$androidSdk/platforms/android-$_kAndroidPlatformVersion/android.jar');
|
||||
|
||||
String buildTools = '$androidSdk/build-tools/$_kBuildToolsVersion';
|
||||
_aapt = new File('$buildTools/aapt');
|
||||
_dx = new File('$buildTools/dx');
|
||||
_zipalign = new File('$buildTools/zipalign');
|
||||
_jarsigner = 'jarsigner';
|
||||
}
|
||||
|
||||
bool checkSdkPath() {
|
||||
return (_androidJar.existsSync() && _aapt.existsSync() && _dx.existsSync() && _zipalign.existsSync());
|
||||
_ApkBuilder(this.sdk) {
|
||||
_androidJar = new File(sdk.androidJarPath);
|
||||
_aapt = new File(sdk.aaptPath);
|
||||
_dx = new File(sdk.dxPath);
|
||||
_zipalign = new File(sdk.zipalignPath);
|
||||
_jarsigner = os.which('jarsigner');
|
||||
}
|
||||
|
||||
void compileClassesDex(File classesDex, List<File> jars) {
|
||||
List<String> packageArgs = [_dx.path,
|
||||
List<String> packageArgs = <String>[_dx.path,
|
||||
'--dex',
|
||||
'--force-jumbo',
|
||||
'--output', classesDex.path
|
||||
@ -94,7 +86,7 @@ class _ApkBuilder {
|
||||
}
|
||||
|
||||
void package(File outputApk, File androidManifest, Directory assets, Directory artifacts, Directory resources) {
|
||||
List<String> packageArgs = [_aapt.path,
|
||||
List<String> packageArgs = <String>[_aapt.path,
|
||||
'package',
|
||||
'-M', androidManifest.path,
|
||||
'-A', assets.path,
|
||||
@ -109,7 +101,7 @@ class _ApkBuilder {
|
||||
}
|
||||
|
||||
void sign(File keystore, String keystorePassword, String keyAlias, String keyPassword, File outputApk) {
|
||||
runCheckedSync([_jarsigner,
|
||||
runCheckedSync(<String>[_jarsigner.path,
|
||||
'-keystore', keystore.path,
|
||||
'-storepass', keystorePassword,
|
||||
'-keypass', keyPassword,
|
||||
@ -119,12 +111,11 @@ class _ApkBuilder {
|
||||
}
|
||||
|
||||
void align(File unalignedApk, File outputApk) {
|
||||
runCheckedSync([_zipalign.path, '-f', '4', unalignedApk.path, outputApk.path]);
|
||||
runCheckedSync(<String>[_zipalign.path, '-f', '4', unalignedApk.path, outputApk.path]);
|
||||
}
|
||||
}
|
||||
|
||||
class _ApkComponents {
|
||||
Directory androidSdk;
|
||||
File manifest;
|
||||
File icuData;
|
||||
List<File> jars;
|
||||
@ -135,11 +126,12 @@ class _ApkComponents {
|
||||
}
|
||||
|
||||
class ApkKeystoreInfo {
|
||||
ApkKeystoreInfo({ this.keystore, this.password, this.keyAlias, this.keyPassword });
|
||||
|
||||
String keystore;
|
||||
String password;
|
||||
String keyAlias;
|
||||
String keyPassword;
|
||||
ApkKeystoreInfo({ this.keystore, this.password, this.keyAlias, this.keyPassword });
|
||||
}
|
||||
|
||||
class ApkCommand extends FlutterCommand {
|
||||
@ -183,7 +175,19 @@ class ApkCommand extends FlutterCommand {
|
||||
|
||||
@override
|
||||
Future<int> runInProject() async {
|
||||
// Validate that we can find an android sdk.
|
||||
if (androidSdk == null) {
|
||||
printError('No Android SDK found.');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!androidSdk.validateSdkWellFormed(complain: true)) {
|
||||
printError('Try re-installing or updating your Android SDK.');
|
||||
return 1;
|
||||
}
|
||||
|
||||
await downloadToolchain();
|
||||
|
||||
return await buildAndroid(
|
||||
toolchain: toolchain,
|
||||
configs: buildConfigurations,
|
||||
@ -207,10 +211,8 @@ class ApkCommand extends FlutterCommand {
|
||||
Future<_ApkComponents> _findApkComponents(
|
||||
BuildConfiguration config, String enginePath, String manifest, String resources
|
||||
) async {
|
||||
String androidSdkPath;
|
||||
List<String> artifactPaths;
|
||||
if (enginePath != null) {
|
||||
androidSdkPath = '$enginePath/third_party/android_tools/sdk';
|
||||
artifactPaths = [
|
||||
'$enginePath/third_party/icu/android/icudtl.dat',
|
||||
'${config.buildDir}/gen/sky/shell/shell/classes.dex.jar',
|
||||
@ -218,9 +220,6 @@ Future<_ApkComponents> _findApkComponents(
|
||||
'$enginePath/build/android/ant/chromium-debug.keystore',
|
||||
];
|
||||
} else {
|
||||
androidSdkPath = AndroidDevice.getAndroidSdkPath();
|
||||
if (androidSdkPath == null)
|
||||
return null;
|
||||
List<ArtifactType> artifactTypes = <ArtifactType>[
|
||||
ArtifactType.androidIcuData,
|
||||
ArtifactType.androidClassesJar,
|
||||
@ -234,7 +233,6 @@ Future<_ApkComponents> _findApkComponents(
|
||||
}
|
||||
|
||||
_ApkComponents components = new _ApkComponents();
|
||||
components.androidSdk = new Directory(androidSdkPath);
|
||||
components.manifest = new File(manifest);
|
||||
components.icuData = new File(artifactPaths[0]);
|
||||
components.jars = [new File(artifactPaths[1])];
|
||||
@ -242,11 +240,7 @@ Future<_ApkComponents> _findApkComponents(
|
||||
components.debugKeystore = new File(artifactPaths[3]);
|
||||
components.resources = new Directory(resources);
|
||||
|
||||
await parseServiceConfigs(
|
||||
components.services,
|
||||
jars: components.jars,
|
||||
androidSdk: components.androidSdk.path
|
||||
);
|
||||
await parseServiceConfigs(components.services, jars: components.jars);
|
||||
|
||||
if (!components.resources.existsSync()) {
|
||||
// TODO(eseidel): This level should be higher when path is manually set.
|
||||
@ -254,16 +248,6 @@ Future<_ApkComponents> _findApkComponents(
|
||||
components.resources = null;
|
||||
}
|
||||
|
||||
if (!components.androidSdk.existsSync()) {
|
||||
printError('Can not locate Android SDK: $androidSdkPath');
|
||||
return null;
|
||||
}
|
||||
if (!(new _ApkBuilder(components.androidSdk.path).checkSdkPath())) {
|
||||
printError('Can not locate expected Android SDK tools at $androidSdkPath');
|
||||
printError('You must install version $_kAndroidPlatformVersion of the SDK platform');
|
||||
printError('and version $_kBuildToolsVersion of the build tools.');
|
||||
return null;
|
||||
}
|
||||
for (File f in [
|
||||
components.manifest, components.icuData, components.libSkyShell, components.debugKeystore
|
||||
]..addAll(components.jars)) {
|
||||
@ -281,7 +265,7 @@ int _buildApk(
|
||||
) {
|
||||
Directory tempDir = Directory.systemTemp.createTempSync('flutter_tools');
|
||||
try {
|
||||
_ApkBuilder builder = new _ApkBuilder(components.androidSdk.path);
|
||||
_ApkBuilder builder = new _ApkBuilder(androidSdk.latestVersion);
|
||||
|
||||
File classesDex = new File('${tempDir.path}/classes.dex');
|
||||
builder.compileClassesDex(classesDex, components.jars);
|
||||
|
@ -7,6 +7,7 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import '../android/adb.dart';
|
||||
import '../android/android_sdk.dart';
|
||||
import '../android/device_android.dart';
|
||||
import '../base/context.dart';
|
||||
import '../base/globals.dart';
|
||||
|
@ -32,7 +32,7 @@ class RefreshCommand extends FlutterCommand {
|
||||
downloadApplicationPackagesAndConnectToDevices(),
|
||||
], eagerError: true);
|
||||
|
||||
if (!devices.android.isConnected()) {
|
||||
if (devices.android == null || !devices.android.isConnected()) {
|
||||
printError('No device connected.');
|
||||
return 1;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class TraceCommand extends FlutterCommand {
|
||||
Future<int> runInProject() async {
|
||||
await downloadApplicationPackagesAndConnectToDevices();
|
||||
|
||||
if (!devices.android.isConnected()) {
|
||||
if (devices.android == null || !devices.android.isConnected()) {
|
||||
printError('No device connected, so no trace was completed.');
|
||||
return 1;
|
||||
}
|
||||
|
@ -402,6 +402,8 @@ class _IOSDeviceLogReader extends DeviceLogReader {
|
||||
if (!device.isConnected())
|
||||
return 2;
|
||||
|
||||
// TODO(devoncarew): This regex should use the CFBundleIdentifier value from
|
||||
// the user's plist (instead of `flutter.runner.Runner`).
|
||||
return await runCommandAndStreamOutput(
|
||||
<String>[device.loggerPath],
|
||||
prefix: '[$name] ',
|
||||
|
@ -9,7 +9,9 @@ import 'package:args/args.dart';
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import '../android/android_sdk.dart';
|
||||
import '../artifacts.dart';
|
||||
import '../base/context.dart';
|
||||
import '../base/globals.dart';
|
||||
import '../base/process.dart';
|
||||
import '../build_configuration.dart';
|
||||
@ -167,6 +169,22 @@ class FlutterCommandRunner extends CommandRunner {
|
||||
// See if the user specified a specific device.
|
||||
deviceManager.specifiedDeviceId = globalResults['device-id'];
|
||||
|
||||
// The Android SDK could already have been set by tests.
|
||||
if (!context.isSet(AndroidSdk)) {
|
||||
if (enginePath != null) {
|
||||
context[AndroidSdk] = new AndroidSdk('$enginePath/third_party/android_tools/sdk');
|
||||
} else {
|
||||
context[AndroidSdk] = AndroidSdk.locateAndroidSdk();
|
||||
}
|
||||
}
|
||||
|
||||
if (androidSdk != null) {
|
||||
printTrace('Using Android SDK at ${androidSdk.directory}.');
|
||||
|
||||
if (androidSdk.latestVersion != null)
|
||||
printTrace('${androidSdk.latestVersion}');
|
||||
}
|
||||
|
||||
ArtifactStore.flutterRoot = path.normalize(path.absolute(globalResults['flutter-root']));
|
||||
if (globalResults.wasParsed('package-root'))
|
||||
ArtifactStore.packageRoot = path.normalize(path.absolute(globalResults['package-root']));
|
||||
|
@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'artifacts.dart';
|
||||
import 'base/globals.dart';
|
||||
|
||||
const String _kFlutterManifestPath = 'flutter.yaml';
|
||||
|
||||
@ -23,7 +24,7 @@ dynamic _loadYamlFile(String path) {
|
||||
/// Loads all services specified in `flutter.yaml`. Parses each service config file,
|
||||
/// storing metadata in [services] and the list of jar files in [jars].
|
||||
Future parseServiceConfigs(
|
||||
List<Map<String, String>> services, { List<File> jars, String androidSdk }
|
||||
List<Map<String, String>> services, { List<File> jars }
|
||||
) async {
|
||||
if (!ArtifactStore.isPackageRootValid)
|
||||
return;
|
||||
@ -49,17 +50,17 @@ Future parseServiceConfigs(
|
||||
|
||||
if (jars != null) {
|
||||
for (String jar in serviceConfig['jars'])
|
||||
jars.add(new File(await getServiceFromUrl(jar, serviceRoot, service, androidSdk: androidSdk, unzip: false)));
|
||||
jars.add(new File(await getServiceFromUrl(jar, serviceRoot, service, unzip: false)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getServiceFromUrl(
|
||||
String url, String rootDir, String serviceName, { String androidSdk, bool unzip: false }
|
||||
String url, String rootDir, String serviceName, { bool unzip: false }
|
||||
) async {
|
||||
if (url.startsWith("android-sdk:")) {
|
||||
if (url.startsWith("android-sdk:") && androidSdk != null) {
|
||||
// It's something shipped in the standard android SDK.
|
||||
return url.replaceAll('android-sdk:', '$androidSdk/');
|
||||
return url.replaceAll('android-sdk:', '${androidSdk.directory}/');
|
||||
} else if (url.startsWith("http")) {
|
||||
// It's a regular file to download.
|
||||
return await ArtifactStore.getThirdPartyFile(url, serviceName, unzip);
|
||||
|
@ -15,6 +15,7 @@ dependencies:
|
||||
den_api: ^0.1.0
|
||||
mustache4dart: ^1.0.0
|
||||
path: ^1.3.0
|
||||
pub_semver: ^1.0.0
|
||||
stack_trace: ^1.4.0
|
||||
test: 0.12.6+1 # see note below
|
||||
yaml: ^2.1.3
|
||||
|
@ -5,7 +5,7 @@
|
||||
import 'package:flutter_tools/src/android/device_android.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/test_context.dart';
|
||||
import 'src/context.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
|
@ -11,7 +11,7 @@ import 'package:flutter_tools/src/commands/create.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/test_context.dart';
|
||||
import 'src/context.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
|
@ -16,11 +16,17 @@ import 'src/mocks.dart';
|
||||
main() => defineTests();
|
||||
|
||||
defineTests() {
|
||||
group('daemon', () {
|
||||
Daemon daemon;
|
||||
AppContext appContext;
|
||||
NotifyingLogger notifyingLogger;
|
||||
Daemon daemon;
|
||||
AppContext appContext;
|
||||
NotifyingLogger notifyingLogger;
|
||||
|
||||
void _testUsingContext(String description, dynamic testMethod()) {
|
||||
test(description, () {
|
||||
return appContext.runInZone(testMethod);
|
||||
});
|
||||
}
|
||||
|
||||
group('daemon', () {
|
||||
setUp(() {
|
||||
appContext = new AppContext();
|
||||
notifyingLogger = new NotifyingLogger();
|
||||
@ -32,7 +38,7 @@ defineTests() {
|
||||
return daemon.shutdown();
|
||||
});
|
||||
|
||||
test('daemon.version', () async {
|
||||
_testUsingContext('daemon.version', () async {
|
||||
StreamController<Map<String, dynamic>> commands = new StreamController();
|
||||
StreamController<Map<String, dynamic>> responses = new StreamController();
|
||||
daemon = new Daemon(
|
||||
@ -47,7 +53,7 @@ defineTests() {
|
||||
expect(response['result'] is String, true);
|
||||
});
|
||||
|
||||
test('daemon.logMessage', () {
|
||||
_testUsingContext('daemon.logMessage', () {
|
||||
return appContext.runInZone(() async {
|
||||
StreamController<Map<String, dynamic>> commands = new StreamController();
|
||||
StreamController<Map<String, dynamic>> responses = new StreamController();
|
||||
@ -68,7 +74,7 @@ defineTests() {
|
||||
});
|
||||
});
|
||||
|
||||
test('daemon.shutdown', () async {
|
||||
_testUsingContext('daemon.shutdown', () async {
|
||||
StreamController<Map<String, dynamic>> commands = new StreamController();
|
||||
StreamController<Map<String, dynamic>> responses = new StreamController();
|
||||
daemon = new Daemon(
|
||||
@ -82,7 +88,7 @@ defineTests() {
|
||||
});
|
||||
});
|
||||
|
||||
test('daemon.stopAll', () async {
|
||||
_testUsingContext('daemon.stopAll', () async {
|
||||
DaemonCommand command = new DaemonCommand();
|
||||
applyMocksToCommand(command);
|
||||
|
||||
@ -112,7 +118,7 @@ defineTests() {
|
||||
expect(response['result'], true);
|
||||
});
|
||||
|
||||
test('device.getDevices', () async {
|
||||
_testUsingContext('device.getDevices', () async {
|
||||
StreamController<Map<String, dynamic>> commands = new StreamController();
|
||||
StreamController<Map<String, dynamic>> responses = new StreamController();
|
||||
daemon = new Daemon(
|
||||
|
@ -5,7 +5,7 @@
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/test_context.dart';
|
||||
import 'src/context.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
|
@ -2,18 +2,19 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:flutter_tools/src/commands/install.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/common.dart';
|
||||
import 'src/context.dart';
|
||||
import 'src/mocks.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
defineTests() {
|
||||
group('install', () {
|
||||
test('returns 0 when Android is connected and ready for an install', () {
|
||||
testUsingContext('returns 0 when Android is connected and ready for an install', () {
|
||||
InstallCommand command = new InstallCommand();
|
||||
applyMocksToCommand(command);
|
||||
MockDeviceStore mockDevices = command.devices;
|
||||
@ -30,13 +31,12 @@ defineTests() {
|
||||
when(mockDevices.iOSSimulator.isAppInstalled(any)).thenReturn(false);
|
||||
when(mockDevices.iOSSimulator.installApp(any)).thenReturn(false);
|
||||
|
||||
|
||||
CommandRunner runner = new CommandRunner('test_flutter', '')
|
||||
..addCommand(command);
|
||||
return runner.run(['install']).then((int code) => expect(code, equals(0)));
|
||||
return createTestCommandRunner(command).run(['install']).then((int code) {
|
||||
expect(code, equals(0));
|
||||
});
|
||||
});
|
||||
|
||||
test('returns 0 when iOS is connected and ready for an install', () {
|
||||
testUsingContext('returns 0 when iOS is connected and ready for an install', () {
|
||||
InstallCommand command = new InstallCommand();
|
||||
applyMocksToCommand(command);
|
||||
MockDeviceStore mockDevices = command.devices;
|
||||
@ -53,9 +53,9 @@ defineTests() {
|
||||
when(mockDevices.iOSSimulator.isAppInstalled(any)).thenReturn(false);
|
||||
when(mockDevices.iOSSimulator.installApp(any)).thenReturn(false);
|
||||
|
||||
CommandRunner runner = new CommandRunner('test_flutter', '')
|
||||
..addCommand(command);
|
||||
return runner.run(['install']).then((int code) => expect(code, equals(0)));
|
||||
return createTestCommandRunner(command).run(['install']).then((int code) {
|
||||
expect(code, equals(0));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2,43 +2,34 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:flutter_tools/src/android/android_sdk.dart';
|
||||
import 'package:flutter_tools/src/commands/list.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/mocks.dart';
|
||||
import 'src/test_context.dart';
|
||||
import 'src/common.dart';
|
||||
import 'src/context.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
defineTests() {
|
||||
group('list', () {
|
||||
testUsingContext('returns 0 when called', () {
|
||||
final String mockCommand = Platform.isWindows ? 'cmd /c echo' : 'echo';
|
||||
|
||||
ListCommand command = new ListCommand();
|
||||
applyMocksToCommand(command);
|
||||
MockDeviceStore mockDevices = command.devices;
|
||||
return createTestCommandRunner(command).run(['list']).then((int code) {
|
||||
expect(code, equals(0));
|
||||
});
|
||||
});
|
||||
|
||||
// Avoid relying on adb being installed on the test system.
|
||||
// Instead, cause the test to run the echo command.
|
||||
when(mockDevices.android.adbPath).thenReturn(mockCommand);
|
||||
|
||||
// Avoid relying on idevice* being installed on the test system.
|
||||
// Instead, cause the test to run the echo command.
|
||||
when(mockDevices.iOS.informerPath).thenReturn(mockCommand);
|
||||
when(mockDevices.iOS.installerPath).thenReturn(mockCommand);
|
||||
when(mockDevices.iOS.listerPath).thenReturn(mockCommand);
|
||||
|
||||
// Avoid relying on xcrun being installed on the test system.
|
||||
// Instead, cause the test to run the echo command.
|
||||
when(mockDevices.iOSSimulator.xcrunPath).thenReturn(mockCommand);
|
||||
|
||||
CommandRunner runner = new CommandRunner('test_flutter', '')..addCommand(command);
|
||||
return runner.run(['list']).then((int code) => expect(code, equals(0)));
|
||||
testUsingContext('no error when no connected devices', () {
|
||||
ListCommand command = new ListCommand();
|
||||
return createTestCommandRunner(command).run(['list']).then((int code) {
|
||||
expect(code, equals(0));
|
||||
expect(testLogger.statusText, contains('No connected devices'));
|
||||
});
|
||||
}, overrides: <Type, dynamic>{
|
||||
AndroidSdk: null,
|
||||
DeviceManager: new DeviceManager()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2,14 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:flutter_tools/src/commands/listen.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/common.dart';
|
||||
import 'src/context.dart';
|
||||
import 'src/mocks.dart';
|
||||
import 'src/test_context.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
@ -24,8 +23,9 @@ defineTests() {
|
||||
when(mockDevices.iOS.isConnected()).thenReturn(false);
|
||||
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
|
||||
|
||||
CommandRunner runner = new FlutterCommandRunner()..addCommand(command);
|
||||
return runner.run(['listen']).then((int code) => expect(code, equals(0)));
|
||||
return createTestCommandRunner(command).run(['listen']).then((int code) {
|
||||
expect(code, equals(0));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2,13 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:flutter_tools/src/commands/logs.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/common.dart';
|
||||
import 'src/context.dart';
|
||||
import 'src/mocks.dart';
|
||||
import 'src/test_context.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
@ -17,8 +16,7 @@ defineTests() {
|
||||
testUsingContext('fail with a bad device id', () {
|
||||
LogsCommand command = new LogsCommand();
|
||||
applyMocksToCommand(command);
|
||||
CommandRunner runner = new FlutterCommandRunner()..addCommand(command);
|
||||
return runner.run(<String>['-d', 'abc123', 'logs']).then((int code) {
|
||||
return createTestCommandRunner(command).run(<String>['-d', 'abc123', 'logs']).then((int code) {
|
||||
expect(code, equals(1));
|
||||
});
|
||||
});
|
||||
|
11
packages/flutter_tools/test/src/common.dart
Normal file
11
packages/flutter_tools/test/src/common.dart
Normal file
@ -0,0 +1,11 @@
|
||||
// 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 'package:args/command_runner.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
|
||||
|
||||
CommandRunner createTestCommandRunner(FlutterCommand command) {
|
||||
return new FlutterCommandRunner()..addCommand(command);
|
||||
}
|
@ -9,12 +9,25 @@ import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void testUsingContext(String description, dynamic testMethod(), { Timeout timeout }) {
|
||||
/// Return the test logger. This assumes that the current Logger is a BufferLogger.
|
||||
BufferLogger get testLogger => context[Logger];
|
||||
|
||||
void testUsingContext(String description, dynamic testMethod(), {
|
||||
Timeout timeout,
|
||||
Map<Type, dynamic> overrides: const <Type, dynamic>{}
|
||||
}) {
|
||||
test(description, () {
|
||||
AppContext testContext = new AppContext();
|
||||
|
||||
testContext[Logger] = new BufferLogger();
|
||||
testContext[DeviceManager] = new MockDeviceManager();
|
||||
overrides.forEach((Type type, dynamic value) {
|
||||
testContext[type] = value;
|
||||
});
|
||||
|
||||
if (!overrides.containsKey(Logger))
|
||||
testContext[Logger] = new BufferLogger();
|
||||
|
||||
if (!overrides.containsKey(DeviceManager))
|
||||
testContext[DeviceManager] = new MockDeviceManager();
|
||||
|
||||
return testContext.runInZone(testMethod);
|
||||
}, timeout: timeout);
|
@ -2,18 +2,19 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:flutter_tools/src/commands/stop.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/common.dart';
|
||||
import 'src/context.dart';
|
||||
import 'src/mocks.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
defineTests() {
|
||||
group('stop', () {
|
||||
test('returns 0 when Android is connected and ready to be stopped', () {
|
||||
testUsingContext('returns 0 when Android is connected and ready to be stopped', () {
|
||||
StopCommand command = new StopCommand();
|
||||
applyMocksToCommand(command);
|
||||
MockDeviceStore mockDevices = command.devices;
|
||||
@ -27,12 +28,12 @@ defineTests() {
|
||||
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
|
||||
when(mockDevices.iOSSimulator.stopApp(any)).thenReturn(false);
|
||||
|
||||
CommandRunner runner = new CommandRunner('test_flutter', '')
|
||||
..addCommand(command);
|
||||
return runner.run(['stop']).then((int code) => expect(code, equals(0)));
|
||||
return createTestCommandRunner(command).run(['stop']).then((int code) {
|
||||
expect(code, equals(0));
|
||||
});
|
||||
});
|
||||
|
||||
test('returns 0 when iOS is connected and ready to be stopped', () {
|
||||
testUsingContext('returns 0 when iOS is connected and ready to be stopped', () {
|
||||
StopCommand command = new StopCommand();
|
||||
applyMocksToCommand(command);
|
||||
MockDeviceStore mockDevices = command.devices;
|
||||
@ -46,9 +47,9 @@ defineTests() {
|
||||
when(mockDevices.iOSSimulator.isConnected()).thenReturn(false);
|
||||
when(mockDevices.iOSSimulator.stopApp(any)).thenReturn(false);
|
||||
|
||||
CommandRunner runner = new CommandRunner('test_flutter', '')
|
||||
..addCommand(command);
|
||||
return runner.run(['stop']).then((int code) => expect(code, equals(0)));
|
||||
return createTestCommandRunner(command).run(['stop']).then((int code) {
|
||||
expect(code, equals(0));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -2,13 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:flutter_tools/src/commands/trace.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'src/common.dart';
|
||||
import 'src/context.dart';
|
||||
import 'src/mocks.dart';
|
||||
import 'src/test_context.dart';
|
||||
|
||||
main() => defineTests();
|
||||
|
||||
@ -21,9 +21,9 @@ defineTests() {
|
||||
|
||||
when(mockDevices.android.isConnected()).thenReturn(false);
|
||||
|
||||
CommandRunner runner = new CommandRunner('test_flutter', '')
|
||||
..addCommand(command);
|
||||
return runner.run(['trace']).then((int code) => expect(code, equals(1)));
|
||||
return createTestCommandRunner(command).run(['trace']).then((int code) {
|
||||
expect(code, equals(1));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user