2019-11-27 23:04:02 +00:00
// Copyright 2014 The Flutter Authors. All rights reserved.
2019-05-25 02:51:02 +00:00
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
2020-06-01 19:33:01 +00:00
import ' dart:async ' ;
2020-01-23 23:03:04 +00:00
import ' package:file/memory.dart ' ;
2020-03-26 01:12:13 +00:00
import ' package:flutter_tools/src/artifacts.dart ' ;
2019-05-25 02:51:02 +00:00
import ' package:flutter_tools/src/base/io.dart ' show ProcessException , ProcessResult ;
2020-01-23 23:03:04 +00:00
import ' package:flutter_tools/src/base/logger.dart ' ;
2020-05-06 15:15:39 +00:00
import ' package:flutter_tools/src/base/platform.dart ' ;
2020-02-06 19:38:47 +00:00
import ' package:flutter_tools/src/build_info.dart ' ;
2020-03-26 01:12:13 +00:00
import ' package:flutter_tools/src/cache.dart ' ;
2020-02-06 19:38:47 +00:00
import ' package:flutter_tools/src/ios/devices.dart ' ;
2020-07-20 14:46:05 +00:00
import ' package:flutter_tools/src/ios/iproxy.dart ' ;
2019-05-25 02:51:02 +00:00
import ' package:flutter_tools/src/ios/xcodeproj.dart ' ;
import ' package:flutter_tools/src/macos/xcode.dart ' ;
import ' package:mockito/mockito.dart ' ;
import ' package:process/process.dart ' ;
2019-07-13 18:51:44 +00:00
import ' ../../src/common.dart ' ;
import ' ../../src/context.dart ' ;
2019-05-25 02:51:02 +00:00
void main ( ) {
2020-06-01 19:33:01 +00:00
BufferLogger logger ;
2020-01-23 23:03:04 +00:00
setUp ( ( ) {
2020-03-03 00:23:56 +00:00
logger = BufferLogger . test ( ) ;
2020-01-23 23:03:04 +00:00
} ) ;
2020-05-13 16:17:03 +00:00
// Group exists to work around https://github.com/flutter/flutter/issues/56415.
// Do not add more `MockProcessManager` tests.
group ( ' MockProcessManager ' , ( ) {
ProcessManager processManager ;
2020-02-06 19:38:47 +00:00
setUp ( ( ) {
2020-05-13 16:17:03 +00:00
processManager = MockProcessManager ( ) ;
2020-02-06 19:38:47 +00:00
} ) ;
2020-05-13 16:17:03 +00:00
group ( ' Xcode ' , ( ) {
Xcode xcode ;
setUp ( ( ) {
xcode = Xcode (
logger: logger ,
2020-10-14 22:24:32 +00:00
platform: FakePlatform ( operatingSystem: ' macos ' ) ,
2020-05-13 16:17:03 +00:00
fileSystem: MemoryFileSystem . test ( ) ,
processManager: processManager ,
xcodeProjectInterpreter: MockXcodeProjectInterpreter ( ) ,
) ;
} ) ;
testWithoutContext ( ' xcodeSelectPath returns null when xcode-select is not installed ' , ( ) {
when ( processManager . runSync ( < String > [ ' /usr/bin/xcode-select ' , ' --print-path ' ] ) )
2020-02-06 19:38:47 +00:00
. thenThrow ( const ProcessException ( ' /usr/bin/xcode-select ' , < String > [ ' --print-path ' ] ) ) ;
2020-05-13 16:17:03 +00:00
expect ( xcode . xcodeSelectPath , isNull ) ;
when ( processManager . runSync ( < String > [ ' /usr/bin/xcode-select ' , ' --print-path ' ] ) )
2020-10-12 22:53:16 +00:00
. thenThrow ( ArgumentError ( ' Invalid argument(s): Cannot find executable for /usr/bin/xcode-select ' ) ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
expect ( xcode . xcodeSelectPath , isNull ) ;
} ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
testWithoutContext ( ' eulaSigned is false when clang is not installed ' , ( ) {
2020-10-14 22:24:32 +00:00
when ( processManager . runSync ( < String > [ ' sysctl ' , ' hw.optional.arm64 ' ] ) )
. thenReturn ( ProcessResult ( 123 , 1 , ' ' , ' ' ) ) ;
when ( processManager . runSync ( < String > [ ' xcrun ' , ' clang ' ] ) )
. thenThrow ( const ProcessException ( ' xcrun ' , < String > [ ' clang ' ] ) ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
expect ( xcode . eulaSigned , isFalse ) ;
} ) ;
2020-02-06 19:38:47 +00:00
} ) ;
2020-05-13 16:17:03 +00:00
group ( ' xcdevice ' , ( ) {
XCDevice xcdevice ;
MockXcode mockXcode ;
setUp ( ( ) {
mockXcode = MockXcode ( ) ;
xcdevice = XCDevice (
processManager: processManager ,
logger: logger ,
xcode: mockXcode ,
platform: null ,
2020-09-30 21:53:57 +00:00
artifacts: Artifacts . test ( ) ,
cache: Cache . test ( ) ,
2020-07-20 14:46:05 +00:00
iproxy: IProxy . test ( logger: logger , processManager: processManager ) ,
2020-05-13 16:17:03 +00:00
) ;
2020-10-14 22:24:32 +00:00
when ( mockXcode . xcrunCommand ( ) ) . thenReturn ( < String > [ ' xcrun ' ] ) ;
2020-05-13 16:17:03 +00:00
} ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
testWithoutContext ( ' available devices xcdevice fails ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( true ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
when ( processManager . run ( < String > [ ' xcrun ' , ' xcdevice ' , ' list ' , ' --timeout ' , ' 2 ' ] ) )
. thenThrow ( const ProcessException ( ' xcrun ' , < String > [ ' xcdevice ' , ' list ' , ' --timeout ' , ' 2 ' ] ) ) ;
2020-02-06 19:38:47 +00:00
2020-05-29 22:50:23 +00:00
expect ( await xcdevice . getAvailableIOSDevices ( ) , isEmpty ) ;
2020-05-13 16:17:03 +00:00
} ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
testWithoutContext ( ' diagnostics xcdevice fails ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( true ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
when ( processManager . run ( < String > [ ' xcrun ' , ' xcdevice ' , ' list ' , ' --timeout ' , ' 2 ' ] ) )
. thenThrow ( const ProcessException ( ' xcrun ' , < String > [ ' xcdevice ' , ' list ' , ' --timeout ' , ' 2 ' ] ) ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
expect ( await xcdevice . getDiagnostics ( ) , isEmpty ) ;
} ) ;
2020-02-06 19:38:47 +00:00
} ) ;
2020-05-13 16:17:03 +00:00
} ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
group ( ' FakeProcessManager ' , ( ) {
FakeProcessManager fakeProcessManager ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
setUp ( ( ) {
fakeProcessManager = FakeProcessManager . list ( < FakeCommand > [ ] ) ;
2020-02-06 19:38:47 +00:00
} ) ;
2020-05-13 16:17:03 +00:00
group ( ' Xcode ' , ( ) {
MockXcodeProjectInterpreter mockXcodeProjectInterpreter ;
setUp ( ( ) {
mockXcodeProjectInterpreter = MockXcodeProjectInterpreter ( ) ;
2020-10-14 22:24:32 +00:00
} ) ;
testWithoutContext ( ' isInstalledAndMeetsVersionCheck is false when not macOS ' , ( ) {
final Xcode xcode = Xcode (
2020-05-13 16:17:03 +00:00
logger: logger ,
2020-10-14 22:24:32 +00:00
platform: FakePlatform ( operatingSystem: ' windows ' ) ,
2020-05-13 16:17:03 +00:00
fileSystem: MemoryFileSystem . test ( ) ,
processManager: fakeProcessManager ,
xcodeProjectInterpreter: mockXcodeProjectInterpreter ,
) ;
2020-07-15 00:16:02 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isInstalledAndMeetsVersionCheck , isFalse ) ;
2020-07-15 00:16:02 +00:00
} ) ;
2020-10-14 22:24:32 +00:00
group ( ' macOS ' , ( ) {
Xcode xcode ;
FakePlatform platform ;
setUp ( ( ) {
mockXcodeProjectInterpreter = MockXcodeProjectInterpreter ( ) ;
platform = FakePlatform ( operatingSystem: ' macos ' ) ;
xcode = Xcode (
logger: logger ,
platform: platform ,
fileSystem: MemoryFileSystem . test ( ) ,
processManager: fakeProcessManager ,
xcodeProjectInterpreter: mockXcodeProjectInterpreter ,
) ;
} ) ;
2020-03-16 23:02:22 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' xcodeSelectPath returns path when xcode-select is installed ' , ( ) {
const String xcodePath = ' /Applications/Xcode8.0.app/Contents/Developer ' ;
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' /usr/bin/xcode-select ' , ' --print-path ' ] ,
stdout: xcodePath ,
) ) ;
2020-03-16 23:02:22 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . xcodeSelectPath , xcodePath ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
2020-03-16 23:02:22 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' xcodeVersionSatisfactory is false when version is less than minimum ' , ( ) {
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( true ) ;
when ( mockXcodeProjectInterpreter . majorVersion ) . thenReturn ( 9 ) ;
when ( mockXcodeProjectInterpreter . minorVersion ) . thenReturn ( 0 ) ;
when ( mockXcodeProjectInterpreter . patchVersion ) . thenReturn ( 0 ) ;
2020-03-16 23:02:22 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isVersionSatisfactory , isFalse ) ;
} ) ;
2020-03-16 23:02:22 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' xcodeVersionSatisfactory is false when xcodebuild tools are not installed ' , ( ) {
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( false ) ;
2020-03-16 23:02:22 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isVersionSatisfactory , isFalse ) ;
} ) ;
2020-05-13 16:17:03 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' xcodeVersionSatisfactory is true when version meets minimum ' , ( ) {
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( true ) ;
when ( mockXcodeProjectInterpreter . majorVersion ) . thenReturn ( 11 ) ;
when ( mockXcodeProjectInterpreter . minorVersion ) . thenReturn ( 0 ) ;
when ( mockXcodeProjectInterpreter . patchVersion ) . thenReturn ( 0 ) ;
2020-03-16 23:02:22 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isVersionSatisfactory , isTrue ) ;
} ) ;
2020-05-13 16:17:03 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' xcodeVersionSatisfactory is true when major version exceeds minimum ' , ( ) {
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( true ) ;
when ( mockXcodeProjectInterpreter . majorVersion ) . thenReturn ( 12 ) ;
when ( mockXcodeProjectInterpreter . minorVersion ) . thenReturn ( 0 ) ;
when ( mockXcodeProjectInterpreter . patchVersion ) . thenReturn ( 0 ) ;
2020-01-23 23:03:04 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isVersionSatisfactory , isTrue ) ;
} ) ;
2020-02-06 19:38:47 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' xcodeVersionSatisfactory is true when minor version exceeds minimum ' , ( ) {
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( true ) ;
when ( mockXcodeProjectInterpreter . majorVersion ) . thenReturn ( 11 ) ;
when ( mockXcodeProjectInterpreter . minorVersion ) . thenReturn ( 3 ) ;
when ( mockXcodeProjectInterpreter . patchVersion ) . thenReturn ( 0 ) ;
2020-02-06 19:38:47 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isVersionSatisfactory , isTrue ) ;
} ) ;
2020-02-06 19:38:47 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' xcodeVersionSatisfactory is true when patch version exceeds minimum ' , ( ) {
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( true ) ;
when ( mockXcodeProjectInterpreter . majorVersion ) . thenReturn ( 11 ) ;
when ( mockXcodeProjectInterpreter . minorVersion ) . thenReturn ( 0 ) ;
when ( mockXcodeProjectInterpreter . patchVersion ) . thenReturn ( 1 ) ;
2020-02-06 19:38:47 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isVersionSatisfactory , isTrue ) ;
} ) ;
2020-02-06 19:38:47 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' isInstalledAndMeetsVersionCheck is false when not installed ' , ( ) {
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' /usr/bin/xcode-select ' , ' --print-path ' ] ,
stdout: ' /Applications/Xcode8.0.app/Contents/Developer ' ,
) ) ;
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( false ) ;
2020-02-06 19:38:47 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isInstalledAndMeetsVersionCheck , isFalse ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
2020-05-13 16:17:03 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' isInstalledAndMeetsVersionCheck is false when no xcode-select ' , ( ) {
2020-05-13 16:17:03 +00:00
fakeProcessManager . addCommand ( const FakeCommand (
2020-10-14 22:24:32 +00:00
command: < String > [ ' /usr/bin/xcode-select ' , ' --print-path ' ] ,
exitCode: 127 ,
stderr: ' ERROR ' ,
2020-05-13 16:17:03 +00:00
) ) ;
2020-10-14 22:24:32 +00:00
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( true ) ;
when ( mockXcodeProjectInterpreter . majorVersion ) . thenReturn ( 11 ) ;
when ( mockXcodeProjectInterpreter . minorVersion ) . thenReturn ( 0 ) ;
when ( mockXcodeProjectInterpreter . patchVersion ) . thenReturn ( 0 ) ;
2020-05-13 16:17:03 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isInstalledAndMeetsVersionCheck , isFalse ) ;
2020-05-13 16:17:03 +00:00
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' isInstalledAndMeetsVersionCheck is false when version not satisfied ' , ( ) {
2020-05-13 16:17:03 +00:00
fakeProcessManager . addCommand ( const FakeCommand (
2020-10-14 22:24:32 +00:00
command: < String > [ ' /usr/bin/xcode-select ' , ' --print-path ' ] ,
stdout: ' /Applications/Xcode8.0.app/Contents/Developer ' ,
2020-05-13 16:17:03 +00:00
) ) ;
2020-10-14 22:24:32 +00:00
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( true ) ;
when ( mockXcodeProjectInterpreter . majorVersion ) . thenReturn ( 10 ) ;
when ( mockXcodeProjectInterpreter . minorVersion ) . thenReturn ( 2 ) ;
when ( mockXcodeProjectInterpreter . patchVersion ) . thenReturn ( 0 ) ;
2020-05-13 16:17:03 +00:00
2020-10-14 22:24:32 +00:00
expect ( xcode . isInstalledAndMeetsVersionCheck , isFalse ) ;
2020-05-13 16:17:03 +00:00
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' xcrun runs natively on arm64 ' , ( ) {
fakeProcessManager . addCommands ( const < FakeCommand > [
FakeCommand (
command: < String > [
' sysctl ' ,
' hw.optional.arm64 ' ,
] ,
stdout: ' hw.optional.arm64: 1 ' ,
) ,
] ) ;
expect ( xcode . xcrunCommand ( ) , < String > [
' /usr/bin/arch ' ,
2020-10-23 20:48:38 +00:00
' -arm64e ' ,
2020-10-14 22:24:32 +00:00
' xcrun ' ,
] ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
testWithoutContext ( ' isInstalledAndMeetsVersionCheck is true when macOS and installed and version is satisfied ' , ( ) {
2020-05-13 16:17:03 +00:00
fakeProcessManager . addCommand ( const FakeCommand (
2020-10-14 22:24:32 +00:00
command: < String > [ ' /usr/bin/xcode-select ' , ' --print-path ' ] ,
stdout: ' /Applications/Xcode8.0.app/Contents/Developer ' ,
2020-05-13 16:17:03 +00:00
) ) ;
2020-10-14 22:24:32 +00:00
when ( mockXcodeProjectInterpreter . isInstalled ) . thenReturn ( true ) ;
when ( mockXcodeProjectInterpreter . majorVersion ) . thenReturn ( 11 ) ;
when ( mockXcodeProjectInterpreter . minorVersion ) . thenReturn ( 0 ) ;
when ( mockXcodeProjectInterpreter . patchVersion ) . thenReturn ( 0 ) ;
expect ( xcode . isInstalledAndMeetsVersionCheck , isTrue ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
2020-05-13 16:17:03 +00:00
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' eulaSigned is false when clang output indicates EULA not yet accepted ' , ( ) {
fakeProcessManager . addCommands ( const < FakeCommand > [
FakeCommand (
command: < String > [
' sysctl ' ,
' hw.optional.arm64 ' ,
] ,
exitCode: 1 ,
) ,
FakeCommand (
command: < String > [ ' xcrun ' , ' clang ' ] ,
exitCode: 1 ,
stderr:
' Xcode EULA has not been accepted. \n Launch Xcode and accept the license. ' ,
) ,
] ) ;
expect ( xcode . eulaSigned , isFalse ) ;
2020-05-13 16:17:03 +00:00
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
2020-10-14 22:24:32 +00:00
testWithoutContext ( ' eulaSigned is true when clang output indicates EULA has been accepted ' , ( ) {
fakeProcessManager . addCommands (
const < FakeCommand > [
FakeCommand (
command: < String > [
' sysctl ' ,
' hw.optional.arm64 ' ,
] ,
exitCode: 1 ,
) ,
FakeCommand (
command: < String > [ ' xcrun ' , ' clang ' ] ,
exitCode: 1 ,
stderr: ' clang: error: no input files ' ,
) ,
] ,
) ;
expect ( xcode . eulaSigned , isTrue ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
testWithoutContext ( ' SDK name ' , ( ) {
expect ( getNameForSdk ( SdkType . iPhone ) , ' iphoneos ' ) ;
expect ( getNameForSdk ( SdkType . iPhoneSimulator ) , ' iphonesimulator ' ) ;
expect ( getNameForSdk ( SdkType . macOS ) , ' macosx ' ) ;
} ) ;
group ( ' SDK location ' , ( ) {
setUp ( ( ) {
fakeProcessManager . addCommand (
const FakeCommand (
command: < String > [
' sysctl ' ,
' hw.optional.arm64 ' ,
] ,
exitCode: 1 ,
) ,
) ;
} ) ;
const String sdkroot = ' Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.2.sdk ' ;
testWithoutContext ( ' --show-sdk-path iphoneos ' , ( ) async {
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' xcrun ' , ' --sdk ' , ' iphoneos ' , ' --show-sdk-path ' ] ,
stdout: sdkroot ,
) ) ;
expect ( await xcode . sdkLocation ( SdkType . iPhone ) , sdkroot ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
testWithoutContext ( ' --show-sdk-path macosx ' , ( ) async {
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' xcrun ' , ' --sdk ' , ' macosx ' , ' --show-sdk-path ' ] ,
stdout: sdkroot ,
) ) ;
expect ( await xcode . sdkLocation ( SdkType . macOS ) , sdkroot ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
testWithoutContext ( ' --show-sdk-path fails ' , ( ) async {
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' xcrun ' , ' --sdk ' , ' iphoneos ' , ' --show-sdk-path ' ] ,
exitCode: 1 ,
stderr: ' xcrun: error: ' ,
) ) ;
expect ( ( ) async = > await xcode . sdkLocation ( SdkType . iPhone ) ,
throwsToolExit ( message: ' Could not find SDK location ' ) ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
} ) ;
2020-02-06 19:38:47 +00:00
} ) ;
} ) ;
2020-05-13 16:17:03 +00:00
group ( ' xcdevice ' , ( ) {
XCDevice xcdevice ;
MockXcode mockXcode ;
setUp ( ( ) {
mockXcode = MockXcode ( ) ;
xcdevice = XCDevice (
processManager: fakeProcessManager ,
logger: logger ,
xcode: mockXcode ,
platform: null ,
2020-09-30 21:53:57 +00:00
artifacts: Artifacts . test ( ) ,
cache: Cache . test ( ) ,
2020-07-20 14:46:05 +00:00
iproxy: IProxy . test ( logger: logger , processManager: fakeProcessManager ) ,
2020-05-13 16:17:03 +00:00
) ;
2020-10-14 22:24:32 +00:00
when ( mockXcode . xcrunCommand ( ) ) . thenReturn ( < String > [ ' xcrun ' ] ) ;
2020-02-06 19:38:47 +00:00
} ) ;
2020-05-13 16:17:03 +00:00
group ( ' installed ' , ( ) {
testWithoutContext ( ' Xcode not installed ' , ( ) {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( false ) ;
expect ( xcdevice . isInstalled , false ) ;
} ) ;
} ) ;
2020-02-06 19:38:47 +00:00
2020-06-01 19:33:01 +00:00
group ( ' observe device events ' , ( ) {
testWithoutContext ( ' Xcode not installed ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( false ) ;
expect ( xcdevice . observedDeviceEvents ( ) , isNull ) ;
expect ( logger . traceText , contains ( " Xcode not found. Run 'flutter doctor' for more information. " ) ) ;
} ) ;
testUsingContext ( ' relays events ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( true ) ;
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [
' script ' ,
' -t ' ,
' 0 ' ,
' /dev/null ' ,
' xcrun ' ,
' xcdevice ' ,
' observe ' ,
' --both ' ,
] , stdout: ' Attach: d83d5bc53967baa0ee18626ba87b6254b2ab5418 \n '
2020-07-28 17:29:34 +00:00
' Attach: 00008027-00192736010F802E \n '
' Detach: d83d5bc53967baa0ee18626ba87b6254b2ab5418 ' ,
2020-06-01 19:33:01 +00:00
stderr: ' Some error ' ,
) ) ;
2020-07-28 17:29:34 +00:00
final Completer < void > attach1 = Completer < void > ( ) ;
final Completer < void > attach2 = Completer < void > ( ) ;
final Completer < void > detach1 = Completer < void > ( ) ;
2020-06-01 19:33:01 +00:00
// Attach: d83d5bc53967baa0ee18626ba87b6254b2ab5418
2020-07-28 17:29:34 +00:00
// Attach: 00008027-00192736010F802E
2020-06-01 19:33:01 +00:00
// Detach: d83d5bc53967baa0ee18626ba87b6254b2ab5418
xcdevice . observedDeviceEvents ( ) . listen ( ( Map < XCDeviceEvent , String > event ) {
expect ( event . length , 1 ) ;
if ( event . containsKey ( XCDeviceEvent . attach ) ) {
2020-07-28 17:29:34 +00:00
if ( event [ XCDeviceEvent . attach ] = = ' d83d5bc53967baa0ee18626ba87b6254b2ab5418 ' ) {
attach1 . complete ( ) ;
} else
if ( event [ XCDeviceEvent . attach ] = = ' 00008027-00192736010F802E ' ) {
attach2 . complete ( ) ;
}
2020-06-01 19:33:01 +00:00
} else if ( event . containsKey ( XCDeviceEvent . detach ) ) {
expect ( event [ XCDeviceEvent . detach ] , ' d83d5bc53967baa0ee18626ba87b6254b2ab5418 ' ) ;
2020-07-28 17:29:34 +00:00
detach1 . complete ( ) ;
2020-06-01 19:33:01 +00:00
} else {
fail ( ' Unexpected event ' ) ;
}
} ) ;
2020-07-28 17:29:34 +00:00
await attach1 . future ;
await attach2 . future ;
await detach1 . future ;
2020-06-01 19:33:01 +00:00
expect ( logger . traceText , contains ( ' xcdevice observe error: Some error ' ) ) ;
} ) ;
} ) ;
2020-05-13 16:17:03 +00:00
group ( ' available devices ' , ( ) {
final FakePlatform macPlatform = FakePlatform ( operatingSystem: ' macos ' ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
testWithoutContext ( ' Xcode not installed ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( false ) ;
2020-02-06 19:38:47 +00:00
2020-05-29 22:50:23 +00:00
expect ( await xcdevice . getAvailableIOSDevices ( ) , isEmpty ) ;
2020-05-13 16:17:03 +00:00
} ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
testUsingContext ( ' returns devices ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( true ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
const String devicesOutput = '''
2020-02-06 19:38:47 +00:00
[
{
" simulator " : true ,
" operatingSystemVersion " : " 13.3 (17K446) " ,
" available " : true ,
" platform " : " com.apple.platform.appletvsimulator " ,
" modelCode " : " AppleTV5,3 " ,
" identifier " : " CBB5E1ED-2172-446E-B4E7-F2B5823DBBA6 " ,
" architecture " : " x86_64 " ,
" modelName " : " Apple TV " ,
" name " : " Apple TV "
} ,
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " usb " ,
" available " : true ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
2020-07-28 17:29:34 +00:00
" identifier " : " 00008027-00192736010F802E " ,
2020-02-06 19:38:47 +00:00
" architecture " : " arm64 " ,
" modelName " : " iPhone 6s " ,
" name " : " An iPhone (Space Gray) "
} ,
{
" simulator " : false ,
" operatingSystemVersion " : " 10.1 (14C54) " ,
" interface " : " usb " ,
" available " : true ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPad11,4 " ,
" identifier " : " 98206e7a4afd4aedaff06e687594e089dede3c44 " ,
" architecture " : " armv7 " ,
" modelName " : " iPad Air 3rd Gen " ,
" name " : " iPad 1 "
} ,
{
" simulator " : false ,
" operatingSystemVersion " : " 10.1 (14C54) " ,
" interface " : " network " ,
" available " : true ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPad11,4 " ,
" identifier " : " 234234234234234234345445687594e089dede3c44 " ,
" architecture " : " arm64 " ,
" modelName " : " iPad Air 3rd Gen " ,
" name " : " A networked iPad "
} ,
{
" simulator " : false ,
" operatingSystemVersion " : " 10.1 (14C54) " ,
" interface " : " usb " ,
" available " : true ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPad11,4 " ,
" identifier " : " f577a7903cc54959be2e34bc4f7f80b7009efcf4 " ,
" architecture " : " BOGUS " ,
" modelName " : " iPad Air 3rd Gen " ,
" name " : " iPad 2 "
} ,
{
" simulator " : true ,
" operatingSystemVersion " : " 6.1.1 (17S445) " ,
" available " : true ,
" platform " : " com.apple.platform.watchsimulator " ,
" modelCode " : " Watch5,4 " ,
" identifier " : " 2D74FB11-88A0-44D0-B81E-C0C142B1C94A " ,
" architecture " : " i386 " ,
" modelName " : " Apple Watch Series 5 - 44mm " ,
" name " : " Apple Watch Series 5 - 44mm "
} ,
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " usb " ,
" available " : false ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
" identifier " : " c4ca6f7a53027d1b7e4972e28478e7a28e2faee2 " ,
" architecture " : " arm64 " ,
" modelName " : " iPhone 6s " ,
" name " : " iPhone " ,
" error " : {
" code " : - 9 ,
" failureReason " : " " ,
" description " : " iPhone is not paired with your computer. " ,
" domain " : " com.apple.platform.iphoneos "
}
}
]
''' ;
2020-05-13 16:17:03 +00:00
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' xcrun ' , ' xcdevice ' , ' list ' , ' --timeout ' , ' 2 ' ] ,
stdout: devicesOutput ,
) ) ;
2020-05-29 22:50:23 +00:00
final List < IOSDevice > devices = await xcdevice . getAvailableIOSDevices ( ) ;
2020-05-13 16:17:03 +00:00
expect ( devices , hasLength ( 3 ) ) ;
2020-07-28 17:29:34 +00:00
expect ( devices [ 0 ] . id , ' 00008027-00192736010F802E ' ) ;
2020-05-13 16:17:03 +00:00
expect ( devices [ 0 ] . name , ' An iPhone (Space Gray) ' ) ;
expect ( await devices [ 0 ] . sdkNameAndVersion , ' iOS 13.3 ' ) ;
expect ( devices [ 0 ] . cpuArchitecture , DarwinArch . arm64 ) ;
expect ( devices [ 1 ] . id , ' 98206e7a4afd4aedaff06e687594e089dede3c44 ' ) ;
expect ( devices [ 1 ] . name , ' iPad 1 ' ) ;
expect ( await devices [ 1 ] . sdkNameAndVersion , ' iOS 10.1 ' ) ;
expect ( devices [ 1 ] . cpuArchitecture , DarwinArch . armv7 ) ;
expect ( devices [ 2 ] . id , ' f577a7903cc54959be2e34bc4f7f80b7009efcf4 ' ) ;
expect ( devices [ 2 ] . name , ' iPad 2 ' ) ;
expect ( await devices [ 2 ] . sdkNameAndVersion , ' iOS 10.1 ' ) ;
expect ( devices [ 2 ] . cpuArchitecture , DarwinArch . arm64 ) ; // Defaults to arm64 for unknown architecture.
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} , overrides: < Type , Generator > {
Platform: ( ) = > macPlatform ,
2020-06-26 20:36:06 +00:00
Artifacts: ( ) = > Artifacts . test ( ) ,
2020-05-13 16:17:03 +00:00
} ) ;
testWithoutContext ( ' uses timeout ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( true ) ;
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' xcrun ' , ' xcdevice ' , ' list ' , ' --timeout ' , ' 20 ' ] ,
stdout: ' [] ' ,
) ) ;
2020-05-29 22:50:23 +00:00
await xcdevice . getAvailableIOSDevices ( timeout: const Duration ( seconds: 20 ) ) ;
2020-05-13 16:17:03 +00:00
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} ) ;
testUsingContext ( ' ignores "Preparing debugger support for iPhone" error ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( true ) ;
const String devicesOutput = '''
2020-02-06 19:38:47 +00:00
[
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " usb " ,
" available " : false ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
" identifier " : " 43ad2fda7991b34fe1acbda82f9e2fd3d6ddc9f7 " ,
" architecture " : " arm64 " ,
" modelName " : " iPhone 6s " ,
" name " : " iPhone " ,
" error " : {
" code " : - 10 ,
" failureReason " : " " ,
" description " : " iPhone is busy: Preparing debugger support for iPhone " ,
" recoverySuggestion " : " Xcode will continue when iPhone is finished. " ,
" domain " : " com.apple.platform.iphoneos "
}
}
]
''' ;
2020-05-13 16:17:03 +00:00
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' xcrun ' , ' xcdevice ' , ' list ' , ' --timeout ' , ' 2 ' ] ,
stdout: devicesOutput ,
) ) ;
2020-05-29 22:50:23 +00:00
final List < IOSDevice > devices = await xcdevice . getAvailableIOSDevices ( ) ;
2020-05-13 16:17:03 +00:00
expect ( devices , hasLength ( 1 ) ) ;
expect ( devices [ 0 ] . id , ' 43ad2fda7991b34fe1acbda82f9e2fd3d6ddc9f7 ' ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} , overrides: < Type , Generator > {
Platform: ( ) = > macPlatform ,
2020-06-26 20:36:06 +00:00
Artifacts: ( ) = > Artifacts . test ( ) ,
2020-05-13 16:17:03 +00:00
} ) ;
testUsingContext ( ' handles unknown architectures ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( true ) ;
const String devicesOutput = '''
2020-04-16 22:18:33 +00:00
[
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " usb " ,
" available " : true ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
" identifier " : " d83d5bc53967baa0ee18626ba87b6254b2ab5418 " ,
" architecture " : " armv7x " ,
" modelName " : " iPad 3 BOGUS " ,
" name " : " iPad "
} ,
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " usb " ,
" available " : true ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
" identifier " : " d83d5bc53967baa0ee18626ba87b6254b2ab5418 " ,
" architecture " : " BOGUS " ,
" modelName " : " Future iPad " ,
" name " : " iPad "
}
]
''' ;
2020-05-13 16:17:03 +00:00
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' xcrun ' , ' xcdevice ' , ' list ' , ' --timeout ' , ' 2 ' ] ,
stdout: devicesOutput ,
) ) ;
2020-05-29 22:50:23 +00:00
final List < IOSDevice > devices = await xcdevice . getAvailableIOSDevices ( ) ;
2020-05-13 16:17:03 +00:00
expect ( devices [ 0 ] . cpuArchitecture , DarwinArch . armv7 ) ;
expect ( devices [ 1 ] . cpuArchitecture , DarwinArch . arm64 ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} , overrides: < Type , Generator > {
Platform: ( ) = > macPlatform ,
2020-06-26 20:36:06 +00:00
Artifacts: ( ) = > Artifacts . test ( ) ,
2020-05-13 16:17:03 +00:00
} ) ;
2020-04-16 22:18:33 +00:00
} ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
group ( ' diagnostics ' , ( ) {
final FakePlatform macPlatform = FakePlatform ( operatingSystem: ' macos ' ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
testWithoutContext ( ' Xcode not installed ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( false ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
expect ( await xcdevice . getDiagnostics ( ) , isEmpty ) ;
} ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
testUsingContext ( ' uses cache ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( true ) ;
2020-02-06 19:38:47 +00:00
2020-05-13 16:17:03 +00:00
const String devicesOutput = '''
2020-02-06 19:38:47 +00:00
[
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " network " ,
" available " : false ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
" identifier " : " d83d5bc53967baa0ee18626ba87b6254b2ab5418 " ,
" architecture " : " arm64 " ,
" modelName " : " iPhone 6s " ,
" error " : {
" code " : - 13 ,
" failureReason " : " " ,
" domain " : " com.apple.platform.iphoneos "
}
}
]
''' ;
2020-05-13 16:17:03 +00:00
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' xcrun ' , ' xcdevice ' , ' list ' , ' --timeout ' , ' 2 ' ] ,
stdout: devicesOutput ,
) ) ;
2020-05-29 22:50:23 +00:00
await xcdevice . getAvailableIOSDevices ( ) ;
2020-05-13 16:17:03 +00:00
final List < String > errors = await xcdevice . getDiagnostics ( ) ;
expect ( errors , hasLength ( 1 ) ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} , overrides: < Type , Generator > {
Platform: ( ) = > macPlatform ,
} ) ;
testUsingContext ( ' returns error message ' , ( ) async {
when ( mockXcode . isInstalledAndMeetsVersionCheck ) . thenReturn ( true ) ;
const String devicesOutput = '''
2020-02-06 19:38:47 +00:00
[
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " usb " ,
" available " : false ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
" identifier " : " 98206e7a4afd4aedaff06e687594e089dede3c44 " ,
" architecture " : " arm64 " ,
" modelName " : " iPhone 6s " ,
" name " : " An iPhone (Space Gray) " ,
" error " : {
" code " : - 9 ,
" failureReason " : " " ,
" underlyingErrors " : [
{
" code " : 5 ,
2020-10-26 19:42:05 +00:00
" failureReason " : " allowsSecureServices: 1. isConnected: 0. Platform: <DVTPlatform:0x7f804ce32880:'com.apple.platform.iphoneos':<DVTFilePath:0x7f804ce32800:'/Users/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform'>>. DTDKDeviceIdentifierIsIDID: 0 " ,
2020-02-06 19:38:47 +00:00
" description " : " 📱<DVTiOSDevice (0x7f801f190450), iPhone, iPhone, 13.3 (17C54), d83d5bc53967baa0ee18626ba87b6254b2ab5418> -- Failed _shouldMakeReadyForDevelopment check even though device is not locked by passcode. " ,
" recoverySuggestion " : " " ,
" domain " : " com.apple.platform.iphoneos "
}
] ,
" description " : " iPhone is not paired with your computer. " ,
" recoverySuggestion " : " To use iPhone with Xcode, unlock it and choose to trust this computer when prompted. " ,
" domain " : " com.apple.platform.iphoneos "
}
} ,
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " usb " ,
" available " : false ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
" identifier " : " d83d5bc53967baa0ee18626ba87b6254b2ab5418 " ,
" architecture " : " arm64 " ,
" modelName " : " iPhone 6s " ,
" name " : " iPhone " ,
" error " : {
" failureReason " : " " ,
" description " : " iPhone is not paired with your computer " ,
" domain " : " com.apple.platform.iphoneos "
}
} ,
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " network " ,
" available " : false ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
" identifier " : " d83d5bc53967baa0ee18626ba87b6254b2ab5418 " ,
" architecture " : " arm64 " ,
" modelName " : " iPhone 6s " ,
" error " : {
" code " : - 13 ,
" failureReason " : " " ,
" domain " : " com.apple.platform.iphoneos "
}
} ,
{
" simulator " : false ,
" operatingSystemVersion " : " 13.3 (17C54) " ,
" interface " : " usb " ,
" available " : false ,
" platform " : " com.apple.platform.iphoneos " ,
" modelCode " : " iPhone8,1 " ,
" identifier " : " 43ad2fda7991b34fe1acbda82f9e2fd3d6ddc9f7 " ,
" architecture " : " arm64 " ,
" modelName " : " iPhone 6s " ,
" name " : " iPhone " ,
" error " : {
" code " : - 10 ,
" failureReason " : " " ,
" description " : " iPhone is busy: Preparing debugger support for iPhone " ,
" recoverySuggestion " : " Xcode will continue when iPhone is finished. " ,
" domain " : " com.apple.platform.iphoneos "
}
}
]
''' ;
2020-05-13 16:17:03 +00:00
fakeProcessManager . addCommand ( const FakeCommand (
command: < String > [ ' xcrun ' , ' xcdevice ' , ' list ' , ' --timeout ' , ' 2 ' ] ,
stdout: devicesOutput ,
) ) ;
final List < String > errors = await xcdevice . getDiagnostics ( ) ;
expect ( errors , hasLength ( 4 ) ) ;
expect ( errors [ 0 ] , ' Error: iPhone is not paired with your computer. To use iPhone with Xcode, unlock it and choose to trust this computer when prompted. (code -9) ' ) ;
expect ( errors [ 1 ] , ' Error: iPhone is not paired with your computer. ' ) ;
expect ( errors [ 2 ] , ' Error: Xcode pairing error. (code -13) ' ) ;
expect ( errors [ 3 ] , ' Error: iPhone is busy: Preparing debugger support for iPhone. Xcode will continue when iPhone is finished. (code -10) ' ) ;
expect ( fakeProcessManager . hasRemainingExpectations , isFalse ) ;
} , overrides: < Type , Generator > {
Platform: ( ) = > macPlatform ,
} ) ;
2020-02-06 19:38:47 +00:00
} ) ;
} ) ;
2019-05-25 02:51:02 +00:00
} ) ;
}
2020-01-23 23:03:04 +00:00
2020-02-06 19:38:47 +00:00
class MockXcode extends Mock implements Xcode { }
2020-03-03 00:23:56 +00:00
class MockProcessManager extends Mock implements ProcessManager { }
class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter { }