Commit 66502138 authored by Chris Bracken's avatar Chris Bracken Committed by GitHub

Extract all libimobiledevice invocations to IMobileDevice class (#10793)

Moves all remaining calls to tools that are part of the libimobiledevice
suite of tools to the IMobileDevice class. This allows for better
tracking of this dependency, and easier mocking in tests.
parent 03393510
......@@ -43,8 +43,6 @@ class IOSDevice extends Device {
IOSDevice(String id, { this.name }) : super(id) {
_installerPath = _checkForCommand('ideviceinstaller');
_iproxyPath = _checkForCommand('iproxy');
_loggerPath = _checkForCommand('idevicesyslog');
_screenshotPath = _checkForCommand('idevicescreenshot');
_pusherPath = _checkForCommand(
'ios-deploy',
'To copy files to iOS devices, please install ios-deploy. To install, run:\n'
......@@ -55,8 +53,6 @@ class IOSDevice extends Device {
String _installerPath;
String _iproxyPath;
String _loggerPath;
String _screenshotPath;
String _pusherPath;
@override
......@@ -335,12 +331,10 @@ class IOSDevice extends Device {
}
@override
bool get supportsScreenshot => _screenshotPath != null && _screenshotPath.isNotEmpty;
bool get supportsScreenshot => iMobileDevice.isInstalled;
@override
Future<Null> takeScreenshot(File outputFile) {
return runCheckedAsync(<String>[_screenshotPath, outputFile.path]);
}
Future<Null> takeScreenshot(File outputFile) => iMobileDevice.takeScreenshot(outputFile);
}
class _IOSDeviceLogReader extends DeviceLogReader {
......@@ -372,7 +366,7 @@ class _IOSDeviceLogReader extends DeviceLogReader {
String get name => device.name;
void _start() {
runCommand(<String>[device._loggerPath]).then<Null>((Process process) {
iMobileDevice.startLogger().then<Null>((Process process) {
_process = process;
_process.stdout.transform(UTF8.decoder).transform(const LineSplitter()).listen(_onLine);
_process.stderr.transform(UTF8.decoder).transform(const LineSplitter()).listen(_onLine);
......
......@@ -84,6 +84,14 @@ class IMobileDevice {
String getInfoForDevice(String deviceID, String key) {
return runSync(<String>['ideviceinfo', '-k', key, '-u', deviceID]).trim();
}
/// Starts `idevicesyslog` and returns the running process.
Future<Process> startLogger() => runCommand(<String>['idevicesyslog']);
/// Captures a screenshot to the specified outputfile.
Future<Null> takeScreenshot(File outputFile) {
return runCheckedAsync(<String>['idevicescreenshot', outputFile.path]);
}
}
class Xcode {
......
......@@ -2,9 +2,6 @@
// 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' show ProcessResult;
import 'package:file/file.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/ios/devices.dart';
......@@ -68,78 +65,4 @@ void main() {
});
});
group('screenshot', () {
MockProcessManager mockProcessManager;
MockFile mockOutputFile;
IOSDevice iosDeviceUnderTest;
setUp(() {
mockProcessManager = new MockProcessManager();
mockOutputFile = new MockFile();
});
testUsingContext('error if idevicescreenshot is not installed', () async {
when(mockOutputFile.path).thenReturn(fs.path.join('some', 'test', 'path', 'image.png'));
// Let everything else return exit code 0 so process.dart doesn't crash.
// The matcher order is important.
when(
mockProcessManager.run(any, environment: null, workingDirectory: null)
).thenReturn(
new Future<ProcessResult>.value(new ProcessResult(2, 0, '', ''))
);
// Let `which idevicescreenshot` fail with exit code 1.
when(
mockProcessManager.runSync(
<String>['which', 'idevicescreenshot'], environment: null, workingDirectory: null)
).thenReturn(
new ProcessResult(1, 1, '', '')
);
iosDeviceUnderTest = new IOSDevice('1234');
await iosDeviceUnderTest.takeScreenshot(mockOutputFile);
verify(mockProcessManager.runSync(
<String>['which', 'idevicescreenshot'], environment: null, workingDirectory: null));
verifyNever(mockProcessManager.run(
<String>['idevicescreenshot', fs.path.join('some', 'test', 'path', 'image.png')],
environment: null,
workingDirectory: null
));
expect(testLogger.errorText, contains('brew install ideviceinstaller'));
},
overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Platform: () => osx,
});
testUsingContext('idevicescreenshot captures and returns screenshot', () async {
when(mockOutputFile.path).thenReturn(fs.path.join('some', 'test', 'path', 'image.png'));
// Let everything else return exit code 0.
// The matcher order is important.
when(
mockProcessManager.run(any, environment: null, workingDirectory: null)
).thenReturn(
new Future<ProcessResult>.value(new ProcessResult(4, 0, '', ''))
);
// Let there be idevicescreenshot in the PATH.
when(
mockProcessManager.runSync(
<String>['which', 'idevicescreenshot'], environment: null, workingDirectory: null)
).thenReturn(
new ProcessResult(3, 0, fs.path.join('some', 'path', 'to', 'iscreenshot'), '')
);
iosDeviceUnderTest = new IOSDevice('1234');
await iosDeviceUnderTest.takeScreenshot(mockOutputFile);
verify(mockProcessManager.runSync(
<String>['which', 'idevicescreenshot'], environment: null, workingDirectory: null));
verify(mockProcessManager.run(
<String>[
fs.path.join('some', 'path', 'to', 'iscreenshot'),
fs.path.join('some', 'test', 'path', 'image.png')
],
environment: null,
workingDirectory: null
));
}, overrides: <Type, Generator>{ProcessManager: () => mockProcessManager});
});
}
......@@ -2,13 +2,69 @@
// 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/file.dart';
import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart' show ProcessResult;
import 'package:flutter_tools/src/ios/mac.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';
import 'package:test/test.dart';
import '../src/context.dart';
class MockProcessManager extends Mock implements ProcessManager {}
class MockFile extends Mock implements File {}
void main() {
final FakePlatform osx = new FakePlatform.fromPlatform(const LocalPlatform());
osx.operatingSystem = 'macos';
group('IMobileDevice', () {
group('screenshot', () {
final String outputPath = fs.path.join('some', 'test', 'path', 'image.png');
MockProcessManager mockProcessManager;
MockFile mockOutputFile;
setUp(() {
mockProcessManager = new MockProcessManager();
mockOutputFile = new MockFile();
});
testUsingContext('error if idevicescreenshot is not installed', () async {
when(mockOutputFile.path).thenReturn(outputPath);
// Let `idevicescreenshot` fail with exit code 1.
when(mockProcessManager.run(<String>['idevicescreenshot', outputPath],
environment: null,
workingDirectory: null
)).thenReturn(new ProcessResult(4, 1, '', ''));
expect(() async => await iMobileDevice.takeScreenshot(mockOutputFile), throwsA(anything));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
Platform: () => osx,
});
testUsingContext('idevicescreenshot captures and returns screenshot', () async {
when(mockOutputFile.path).thenReturn(outputPath);
when(mockProcessManager.run(any, environment: null, workingDirectory: null))
.thenReturn(new Future<ProcessResult>.value(new ProcessResult(4, 0, '', '')));
await iMobileDevice.takeScreenshot(mockOutputFile);
verify(mockProcessManager.run(<String>['idevicescreenshot', outputPath],
environment: null,
workingDirectory: null
));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
});
});
group('Diagnose Xcode build failure', () {
BuildableIOSApp app;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment