Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
ef15eac8
Commit
ef15eac8
authored
Jan 23, 2020
by
Jonah Williams
Committed by
Flutter GitHub Bot
Jan 23, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] Remove context from Xcode and most of Xcodeproj (#48661)
parent
7cf2ff1f
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
576 additions
and
511 deletions
+576
-511
context_runner.dart
packages/flutter_tools/lib/src/context_runner.dart
+14
-2
mac.dart
packages/flutter_tools/lib/src/ios/mac.dart
+1
-1
xcodeproj.dart
packages/flutter_tools/lib/src/ios/xcodeproj.dart
+37
-16
build_macos.dart
packages/flutter_tools/lib/src/macos/build_macos.dart
+1
-1
xcode.dart
packages/flutter_tools/lib/src/macos/xcode.dart
+37
-15
xcodeproj_test.dart
.../flutter_tools/test/general.shard/ios/xcodeproj_test.dart
+337
-307
xcode_test.dart
...es/flutter_tools/test/general.shard/macos/xcode_test.dart
+149
-169
No files found.
packages/flutter_tools/lib/src/context_runner.dart
View file @
ef15eac8
...
...
@@ -145,8 +145,20 @@ Future<T> runInContext<T>(
VisualStudioValidator:
()
=>
const
VisualStudioValidator
(),
WebWorkflow:
()
=>
const
WebWorkflow
(),
WindowsWorkflow:
()
=>
const
WindowsWorkflow
(),
Xcode:
()
=>
Xcode
(),
XcodeProjectInterpreter:
()
=>
XcodeProjectInterpreter
(),
Xcode:
()
=>
Xcode
(
logger:
globals
.
logger
,
processManager:
globals
.
processManager
,
platform:
globals
.
platform
,
fileSystem:
globals
.
fs
,
xcodeProjectInterpreter:
xcodeProjectInterpreter
,
),
XcodeProjectInterpreter:
()
=>
XcodeProjectInterpreter
(
logger:
globals
.
logger
,
processManager:
globals
.
processManager
,
platform:
globals
.
platform
,
fileSystem:
globals
.
fs
,
terminal:
globals
.
terminal
,
),
XcodeValidator:
()
=>
const
XcodeValidator
(),
},
);
...
...
packages/flutter_tools/lib/src/ios/mac.dart
View file @
ef15eac8
...
...
@@ -458,7 +458,7 @@ Future<XcodeBuildResult> buildXcodeProject({
// e.g. `flutter build bundle`.
buildCommands
.
add
(
'FLUTTER_SUPPRESS_ANALYTICS=true'
);
buildCommands
.
add
(
'COMPILER_INDEX_STORE_ENABLE=NO'
);
buildCommands
.
addAll
(
environmentVariablesAsXcodeBuildSettings
());
buildCommands
.
addAll
(
environmentVariablesAsXcodeBuildSettings
(
globals
.
platform
));
final
Stopwatch
sw
=
Stopwatch
()..
start
();
initialBuildStatus
=
globals
.
logger
.
startProgress
(
'Running Xcode build...'
,
timeout:
timeoutConfiguration
.
fastOperation
);
...
...
packages/flutter_tools/lib/src/ios/xcodeproj.dart
View file @
ef15eac8
...
...
@@ -5,6 +5,8 @@
import
'dart:async'
;
import
'package:meta/meta.dart'
;
import
'package:platform/platform.dart'
;
import
'package:process/process.dart'
;
import
'../artifacts.dart'
;
import
'../base/common.dart'
;
...
...
@@ -14,6 +16,7 @@ import '../base/io.dart';
import
'../base/logger.dart'
;
import
'../base/os.dart'
;
import
'../base/process.dart'
;
import
'../base/terminal.dart'
;
import
'../base/utils.dart'
;
import
'../build_info.dart'
;
import
'../cache.dart'
;
...
...
@@ -221,15 +224,33 @@ XcodeProjectInterpreter get xcodeProjectInterpreter => context.get<XcodeProjectI
/// Interpreter of Xcode projects.
class
XcodeProjectInterpreter
{
XcodeProjectInterpreter
({
@required
Platform
platform
,
@required
ProcessManager
processManager
,
@required
Logger
logger
,
@required
FileSystem
fileSystem
,
@required
AnsiTerminal
terminal
,
})
:
_platform
=
platform
,
_fileSystem
=
fileSystem
,
_terminal
=
terminal
,
_logger
=
logger
,
_processUtils
=
ProcessUtils
(
logger:
logger
,
processManager:
processManager
);
final
Platform
_platform
;
final
FileSystem
_fileSystem
;
final
ProcessUtils
_processUtils
;
final
AnsiTerminal
_terminal
;
final
Logger
_logger
;
static
const
String
_executable
=
'/usr/bin/xcodebuild'
;
static
final
RegExp
_versionRegex
=
RegExp
(
r'Xcode ([0-9.]+)'
);
void
_updateVersion
()
{
if
(!
globals
.
platform
.
isMacOS
||
!
globals
.
fs
.
file
(
_executable
).
existsSync
())
{
if
(!
_platform
.
isMacOS
||
!
_fileSystem
.
file
(
_executable
).
existsSync
())
{
return
;
}
try
{
final
RunResult
result
=
processUtils
.
runSync
(
final
RunResult
result
=
_
processUtils
.
runSync
(
<
String
>[
_executable
,
'-version'
],
);
if
(
result
.
exitCode
!=
0
)
{
...
...
@@ -283,26 +304,26 @@ class XcodeProjectInterpreter {
Duration
timeout
=
const
Duration
(
minutes:
1
),
})
async
{
final
Status
status
=
Status
.
withSpinner
(
timeout:
timeoutConfiguration
.
fastOperation
,
timeoutConfiguration:
timeoutConfiguration
,
platform:
globals
.
platform
,
timeout:
const
TimeoutConfiguration
()
.
fastOperation
,
timeoutConfiguration:
const
TimeoutConfiguration
()
,
platform:
_
platform
,
stopwatch:
Stopwatch
(),
supportsColor:
globals
.
terminal
.
supportsColor
,
supportsColor:
_
terminal
.
supportsColor
,
);
final
List
<
String
>
showBuildSettingsCommand
=
<
String
>[
_executable
,
'-project'
,
globals
.
fs
.
path
.
absolute
(
projectPath
),
_fileSystem
.
path
.
absolute
(
projectPath
),
'-target'
,
target
,
'-showBuildSettings'
,
...
environmentVariablesAsXcodeBuildSettings
()
...
environmentVariablesAsXcodeBuildSettings
(
_platform
)
];
try
{
// showBuildSettings is reported to occasionally timeout. Here, we give it
// a lot of wiggle room (locally on Flutter Gallery, this takes ~1s).
// When there is a timeout, we retry once.
final
RunResult
result
=
await
processUtils
.
run
(
final
RunResult
result
=
await
_
processUtils
.
run
(
showBuildSettingsCommand
,
throwOnError:
true
,
workingDirectory:
projectPath
,
...
...
@@ -317,7 +338,7 @@ class XcodeProjectInterpreter {
command:
showBuildSettingsCommand
.
join
(
' '
),
).
send
();
}
globals
.
printTrace
(
'Unexpected failure to get the build settings:
$error
.'
);
_logger
.
printTrace
(
'Unexpected failure to get the build settings:
$error
.'
);
return
const
<
String
,
String
>{};
}
finally
{
status
.
stop
();
...
...
@@ -325,7 +346,7 @@ class XcodeProjectInterpreter {
}
void
cleanWorkspace
(
String
workspacePath
,
String
scheme
)
{
processUtils
.
runSync
(<
String
>[
_
processUtils
.
runSync
(<
String
>[
_executable
,
'-workspace'
,
workspacePath
,
...
...
@@ -333,8 +354,8 @@ class XcodeProjectInterpreter {
scheme
,
'-quiet'
,
'clean'
,
...
environmentVariablesAsXcodeBuildSettings
()
],
workingDirectory:
globals
.
fs
.
currentDirectory
.
path
);
...
environmentVariablesAsXcodeBuildSettings
(
_platform
)
],
workingDirectory:
_fileSystem
.
currentDirectory
.
path
);
}
Future
<
XcodeProjectInfo
>
getInfo
(
String
projectPath
,
{
String
projectFilename
})
async
{
...
...
@@ -342,7 +363,7 @@ class XcodeProjectInterpreter {
// * -project is passed and the given project isn't there, or
// * no -project is passed and there isn't a project.
const
int
missingProjectExitCode
=
66
;
final
RunResult
result
=
await
processUtils
.
run
(
final
RunResult
result
=
await
_
processUtils
.
run
(
<
String
>[
_executable
,
'-list'
,
...
...
@@ -363,9 +384,9 @@ class XcodeProjectInterpreter {
/// This allows developers to pass arbitrary build settings in without the tool needing to make a flag
/// for or be aware of each one. This could be used to set code signing build settings in a CI
/// environment without requiring settings changes in the Xcode project.
List
<
String
>
environmentVariablesAsXcodeBuildSettings
()
{
List
<
String
>
environmentVariablesAsXcodeBuildSettings
(
Platform
platform
)
{
const
String
xcodeBuildSettingPrefix
=
'FLUTTER_XCODE_'
;
return
globals
.
platform
.
environment
.
entries
.
where
((
MapEntry
<
String
,
String
>
mapEntry
)
{
return
platform
.
environment
.
entries
.
where
((
MapEntry
<
String
,
String
>
mapEntry
)
{
return
mapEntry
.
key
.
startsWith
(
xcodeBuildSettingPrefix
);
}).
expand
<
String
>((
MapEntry
<
String
,
String
>
mapEntry
)
{
// Remove FLUTTER_XCODE_ prefix from the environment variable to get the build setting.
...
...
packages/flutter_tools/lib/src/macos/build_macos.dart
View file @
ef15eac8
...
...
@@ -85,7 +85,7 @@ Future<void> buildMacOS({
'OBJROOT=
${globals.fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Intermediates.noindex')}
'
,
'SYMROOT=
${globals.fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Products')}
'
,
'COMPILER_INDEX_STORE_ENABLE=NO'
,
...
environmentVariablesAsXcodeBuildSettings
()
...
environmentVariablesAsXcodeBuildSettings
(
globals
.
platform
)
],
trace:
true
);
}
finally
{
status
.
cancel
();
...
...
packages/flutter_tools/lib/src/macos/xcode.dart
View file @
ef15eac8
...
...
@@ -4,11 +4,16 @@
import
'dart:async'
;
import
'package:meta/meta.dart'
;
import
'package:platform/platform.dart'
;
import
'package:process/process.dart'
;
import
'../base/common.dart'
;
import
'../base/context.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/process.dart'
;
import
'../globals.dart'
as
globals
;
import
'../ios/xcodeproj.dart'
;
const
int
kXcodeRequiredVersionMajor
=
10
;
...
...
@@ -41,14 +46,31 @@ String getNameForSdk(SdkType sdk) {
return
null
;
}
/// A utility class for interacting with Xcode command line tools.
class
Xcode
{
bool
get
isInstalledAndMeetsVersionCheck
=>
globals
.
platform
.
isMacOS
&&
isInstalled
&&
isVersionSatisfactory
;
Xcode
({
@required
Platform
platform
,
@required
ProcessManager
processManager
,
@required
Logger
logger
,
@required
FileSystem
fileSystem
,
@required
XcodeProjectInterpreter
xcodeProjectInterpreter
,
})
:
_platform
=
platform
,
_fileSystem
=
fileSystem
,
_xcodeProjectInterpreter
=
xcodeProjectInterpreter
,
_processUtils
=
ProcessUtils
(
logger:
logger
,
processManager:
processManager
);
final
Platform
_platform
;
final
ProcessUtils
_processUtils
;
final
FileSystem
_fileSystem
;
final
XcodeProjectInterpreter
_xcodeProjectInterpreter
;
bool
get
isInstalledAndMeetsVersionCheck
=>
_platform
.
isMacOS
&&
isInstalled
&&
isVersionSatisfactory
;
String
_xcodeSelectPath
;
String
get
xcodeSelectPath
{
if
(
_xcodeSelectPath
==
null
)
{
try
{
_xcodeSelectPath
=
processUtils
.
runSync
(
_xcodeSelectPath
=
_
processUtils
.
runSync
(
<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
],
).
stdout
.
trim
();
}
on
ProcessException
{
...
...
@@ -64,21 +86,21 @@ class Xcode {
if
(
xcodeSelectPath
==
null
||
xcodeSelectPath
.
isEmpty
)
{
return
false
;
}
return
xcodeProjectInterpreter
.
isInstalled
;
return
_
xcodeProjectInterpreter
.
isInstalled
;
}
int
get
majorVersion
=>
xcodeProjectInterpreter
.
majorVersion
;
int
get
majorVersion
=>
_
xcodeProjectInterpreter
.
majorVersion
;
int
get
minorVersion
=>
xcodeProjectInterpreter
.
minorVersion
;
int
get
minorVersion
=>
_
xcodeProjectInterpreter
.
minorVersion
;
String
get
versionText
=>
xcodeProjectInterpreter
.
versionText
;
String
get
versionText
=>
_
xcodeProjectInterpreter
.
versionText
;
bool
_eulaSigned
;
/// Has the EULA been signed?
bool
get
eulaSigned
{
if
(
_eulaSigned
==
null
)
{
try
{
final
RunResult
result
=
processUtils
.
runSync
(
final
RunResult
result
=
_
processUtils
.
runSync
(
<
String
>[
'/usr/bin/xcrun'
,
'clang'
],
);
if
(
result
.
stdout
!=
null
&&
result
.
stdout
.
contains
(
'license'
))
{
...
...
@@ -103,7 +125,7 @@ class Xcode {
try
{
// This command will error if additional components need to be installed in
// xcode 9.2 and above.
final
RunResult
result
=
processUtils
.
runSync
(
final
RunResult
result
=
_
processUtils
.
runSync
(
<
String
>[
'/usr/bin/xcrun'
,
'simctl'
,
'list'
],
);
_isSimctlInstalled
=
result
.
stderr
==
null
||
result
.
stderr
==
''
;
...
...
@@ -115,7 +137,7 @@ class Xcode {
}
bool
get
isVersionSatisfactory
{
if
(!
xcodeProjectInterpreter
.
isInstalled
)
{
if
(!
_
xcodeProjectInterpreter
.
isInstalled
)
{
return
false
;
}
if
(
majorVersion
>
kXcodeRequiredVersionMajor
)
{
...
...
@@ -128,14 +150,14 @@ class Xcode {
}
Future
<
RunResult
>
cc
(
List
<
String
>
args
)
{
return
processUtils
.
run
(
return
_
processUtils
.
run
(
<
String
>[
'xcrun'
,
'cc'
,
...
args
],
throwOnError:
true
,
);
}
Future
<
RunResult
>
clang
(
List
<
String
>
args
)
{
return
processUtils
.
run
(
return
_
processUtils
.
run
(
<
String
>[
'xcrun'
,
'clang'
,
...
args
],
throwOnError:
true
,
);
...
...
@@ -143,7 +165,7 @@ class Xcode {
Future
<
String
>
sdkLocation
(
SdkType
sdk
)
async
{
assert
(
sdk
!=
null
);
final
RunResult
runResult
=
await
processUtils
.
run
(
final
RunResult
runResult
=
await
_
processUtils
.
run
(
<
String
>[
'xcrun'
,
'--sdk'
,
getNameForSdk
(
sdk
),
'--show-sdk-path'
],
throwOnError:
true
,
);
...
...
@@ -158,10 +180,10 @@ class Xcode {
return
null
;
}
final
List
<
String
>
searchPaths
=
<
String
>[
globals
.
fs
.
path
.
join
(
xcodeSelectPath
,
'Applications'
,
'Simulator.app'
),
_fileSystem
.
path
.
join
(
xcodeSelectPath
,
'Applications'
,
'Simulator.app'
),
];
return
searchPaths
.
where
((
String
p
)
=>
p
!=
null
).
firstWhere
(
(
String
p
)
=>
globals
.
fs
.
directory
(
p
).
existsSync
(),
(
String
p
)
=>
_fileSystem
.
directory
(
p
).
existsSync
(),
orElse:
()
=>
null
,
);
}
...
...
packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart
View file @
ef15eac8
...
...
@@ -8,6 +8,8 @@ import 'package:file/memory.dart';
import
'package:flutter_tools/src/artifacts.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/base/terminal.dart'
;
import
'package:flutter_tools/src/build_info.dart'
;
import
'package:flutter_tools/src/ios/xcodeproj.dart'
;
import
'package:flutter_tools/src/project.dart'
;
...
...
@@ -24,258 +26,272 @@ import '../../src/pubspec_schema.dart';
const
String
xcodebuild
=
'/usr/bin/xcodebuild'
;
void
main
(
)
{
group
(
'xcodebuild commands'
,
()
{
mocks
.
MockProcessManager
mockProcessManager
;
XcodeProjectInterpreter
xcodeProjectInterpreter
;
FakePlatform
macOS
;
FileSystem
fs
;
mocks
.
MockProcessManager
processManager
;
XcodeProjectInterpreter
xcodeProjectInterpreter
;
FakePlatform
platform
;
FileSystem
fileSystem
;
BufferLogger
logger
;
AnsiTerminal
terminal
;
setUp
(()
{
processManager
=
mocks
.
MockProcessManager
();
platform
=
fakePlatform
(
'macos'
);
fileSystem
=
MemoryFileSystem
();
fileSystem
.
file
(
xcodebuild
).
createSync
(
recursive:
true
);
terminal
=
MockAnsiTerminal
();
logger
=
BufferLogger
(
outputPreferences:
OutputPreferences
.
test
(),
terminal:
terminal
);
xcodeProjectInterpreter
=
XcodeProjectInterpreter
(
logger:
logger
,
fileSystem:
fileSystem
,
platform:
platform
,
processManager:
processManager
,
terminal:
terminal
,
);
});
setUp
(()
{
mockProcessManager
=
mocks
.
MockProcessManager
();
xcodeProjectInterpreter
=
XcodeProjectInterpreter
();
macOS
=
fakePlatform
(
'macos'
);
fs
=
MemoryFileSystem
();
fs
.
file
(
xcodebuild
).
createSync
(
recursive:
true
);
});
testWithoutContext
(
'xcodebuild versionText returns null when xcodebuild is not installed'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenThrow
(
const
ProcessException
(
xcodebuild
,
<
String
>[
'-version'
]));
void
testUsingOsxContext
(
String
description
,
dynamic
testMethod
())
{
testUsingContext
(
description
,
testMethod
,
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
macOS
,
FileSystem:
()
=>
fs
,
ProcessManager:
()
=>
mockProcessManager
,
});
}
expect
(
xcodeProjectInterpreter
.
versionText
,
isNull
);
});
testUsingOsxContext
(
'versionText returns null when xcodebuild is not installed'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenThrow
(
const
ProcessException
(
xcodebuild
,
<
String
>[
'-version'
]));
expect
(
xcodeProjectInterpreter
.
versionText
,
isNull
);
});
testWithoutContext
(
'xcodebuild versionText returns null when xcodebuild is not fully installed'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
])).
thenReturn
(
ProcessResult
(
0
,
1
,
"xcode-select: error: tool 'xcodebuild' requires Xcode, "
"but active developer directory '/Library/Developer/CommandLineTools' "
'is a command line tools instance'
,
''
,
),
);
testUsingOsxContext
(
'versionText returns null when xcodebuild is not fully installed'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
])).
thenReturn
(
ProcessResult
(
0
,
1
,
"xcode-select: error: tool 'xcodebuild' requires Xcode, "
"but active developer directory '/Library/Developer/CommandLineTools' "
'is a command line tools instance'
,
''
,
),
);
expect
(
xcodeProjectInterpreter
.
versionText
,
isNull
);
});
expect
(
xcodeProjectInterpreter
.
versionText
,
isNull
);
});
testUsingOsxContext
(
'versionText returns formatted version text'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 8.3.3
\n
Build version 8E3004b'
,
''
));
expect
(
xcodeProjectInterpreter
.
versionText
,
'Xcode 8.3.3, Build version 8E3004b'
);
});
testWithoutContext
(
'xcodebuild versionText returns formatted version text'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 8.3.3
\n
Build version 8E3004b'
,
''
));
testUsingOsxContext
(
'versionText handles Xcode version string with unexpected format'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode Ultra5000
\n
Build version 8E3004b'
,
''
));
expect
(
xcodeProjectInterpreter
.
versionText
,
'Xcode Ultra5000, Build version 8E3004b'
);
});
expect
(
xcodeProjectInterpreter
.
versionText
,
'Xcode 8.3.3, Build version 8E3004b'
);
});
testUsingOsxContext
(
'majorVersion returns major version'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 10.3.3
\n
Build version 8E3004b'
,
''
));
expect
(
xcodeProjectInterpreter
.
majorVersion
,
10
);
});
testWithoutContext
(
'xcodebuild versionText handles Xcode version string with unexpected format'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode Ultra5000
\n
Build version 8E3004b'
,
''
));
testUsingOsxContext
(
'majorVersion is null when version has unexpected format'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode Ultra5000
\n
Build version 8E3004b'
,
''
));
expect
(
xcodeProjectInterpreter
.
majorVersion
,
isNull
);
});
expect
(
xcodeProjectInterpreter
.
versionText
,
'Xcode Ultra5000, Build version 8E3004b'
);
});
testUsingOsxContext
(
'minorVersion returns minor version'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 8.3.3
\n
Build version 8E3004b'
,
''
));
expect
(
xcodeProjectInterpreter
.
minorVersion
,
3
);
});
testWithoutContext
(
'xcodebuild majorVersion returns major version'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 10.3.3
\n
Build version 8E3004b'
,
''
));
testUsingOsxContext
(
'minorVersion returns 0 when minor version is unspecified'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 8
\n
Build version 8E3004b'
,
''
));
expect
(
xcodeProjectInterpreter
.
minorVersion
,
0
);
});
expect
(
xcodeProjectInterpreter
.
majorVersion
,
10
);
});
testUsingOsxContext
(
'minorVersion is null when version has unexpected format'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode Ultra5000
\n
Build version 8E3004b'
,
''
));
expect
(
xcodeProjectInterpreter
.
minorVersion
,
isNull
);
});
testWithoutContext
(
'xcodebuild majorVersion is null when version has unexpected format'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode Ultra5000
\n
Build version 8E3004b'
,
''
));
testUsingContext
(
'isInstalled is false when not on MacOS'
,
()
{
fs
.
file
(
xcodebuild
).
deleteSync
();
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
fakePlatform
(
'notMacOS'
),
});
expect
(
xcodeProjectInterpreter
.
majorVersion
,
isNull
);
});
testUsingOsxContext
(
'isInstalled is false when xcodebuild does not exist'
,
()
{
fs
.
file
(
xcodebuild
).
deleteSync
();
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isFalse
);
});
testWithoutContext
(
'xcodebuild inorVersion returns minor version'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 8.3.3
\n
Build version 8E3004b'
,
''
));
testUsingOsxContext
(
'isInstalled is false when Xcode is not fully installed'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
])).
thenReturn
(
ProcessResult
(
0
,
1
,
"xcode-select: error: tool 'xcodebuild' requires Xcode, "
"but active developer directory '/Library/Developer/CommandLineTools' "
'is a command line tools instance'
,
''
,
),
);
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isFalse
);
});
expect
(
xcodeProjectInterpreter
.
minorVersion
,
3
);
});
testUsingOsxContext
(
'isInstalled is false when version has unexpected format'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode Ultra5000
\n
Build version 8E3004b'
,
''
));
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isFalse
);
});
testWithoutContext
(
'xcodebuild minorVersion returns 0 when minor version is unspecified'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 8
\n
Build version 8E3004b'
,
''
));
testUsingOsxContext
(
'isInstalled is true when version has expected format'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 8.3.3
\n
Build version 8E3004b'
,
''
));
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isTrue
);
});
expect
(
xcodeProjectInterpreter
.
minorVersion
,
0
);
});
testUsingOsxContext
(
'build settings is empty when xcodebuild failed to get the build settings'
,
()
async
{
when
(
mockProcessManager
.
runSync
(
argThat
(
contains
(
xcodebuild
)),
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenReturn
(
ProcessResult
(
0
,
1
,
''
,
''
));
expect
(
await
xcodeProjectInterpreter
.
getBuildSettings
(
''
,
''
),
const
<
String
,
String
>{});
});
testWithoutContext
(
'xcodebuild minorVersion is null when version has unexpected format'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode Ultra5000
\n
Build version 8E3004b'
,
''
));
testUsingContext
(
'build settings flakes'
,
()
async
{
const
Duration
delay
=
Duration
(
seconds:
1
);
mockProcessManager
.
processFactory
=
mocks
.
flakyProcessFactory
(
flakes:
1
,
delay:
delay
+
const
Duration
(
seconds:
1
),
);
expect
(
await
xcodeProjectInterpreter
.
getBuildSettings
(
''
,
''
,
timeout:
delay
),
const
<
String
,
String
>{});
// build settings times out and is killed once, then succeeds.
verify
(
mockProcessManager
.
killPid
(
any
)).
called
(
1
);
// The verbose logs should tell us something timed out.
expect
(
testLogger
.
traceText
,
contains
(
'timed out'
));
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
macOS
,
FileSystem:
()
=>
fs
,
ProcessManager:
()
=>
mockProcessManager
,
});
expect
(
xcodeProjectInterpreter
.
minorVersion
,
isNull
);
});
testUsingOsxContext
(
'build settings contains Flutter Xcode environment variables'
,
()
async
{
macOS
.
environment
=
Map
<
String
,
String
>.
unmodifiable
(<
String
,
String
>{
'FLUTTER_XCODE_CODE_SIGN_STYLE'
:
'Manual'
,
'FLUTTER_XCODE_ARCHS'
:
'arm64'
});
when
(
mockProcessManager
.
runSync
(<
String
>[
xcodebuild
,
'-project'
,
macOS
.
pathSeparator
,
'-target'
,
testWithoutContext
(
'xcodebuild isInstalled is false when not on MacOS'
,
()
{
final
Platform
platform
=
fakePlatform
(
'notMacOS'
);
xcodeProjectInterpreter
=
XcodeProjectInterpreter
(
logger:
logger
,
fileSystem:
fileSystem
,
platform:
platform
,
processManager:
processManager
,
terminal:
terminal
,
);
fileSystem
.
file
(
xcodebuild
).
deleteSync
();
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isFalse
);
});
testWithoutContext
(
'xcodebuild isInstalled is false when xcodebuild does not exist'
,
()
{
fileSystem
.
file
(
xcodebuild
).
deleteSync
();
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isFalse
);
});
testWithoutContext
(
'xcodebuild isInstalled is false when Xcode is not fully installed'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
])).
thenReturn
(
ProcessResult
(
0
,
1
,
"xcode-select: error: tool 'xcodebuild' requires Xcode, "
"but active developer directory '/Library/Developer/CommandLineTools' "
'is a command line tools instance'
,
''
,
'-showBuildSettings'
,
'CODE_SIGN_STYLE=Manual'
,
'ARCHS=arm64'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenReturn
(
ProcessResult
(
1
,
0
,
''
,
''
));
expect
(
await
xcodeProjectInterpreter
.
getBuildSettings
(
''
,
''
),
const
<
String
,
String
>{});
});
),
);
testUsingOsxContext
(
'clean contains Flutter Xcode environment variables'
,
()
async
{
macOS
.
environment
=
Map
<
String
,
String
>.
unmodifiable
(<
String
,
String
>{
'FLUTTER_XCODE_CODE_SIGN_STYLE'
:
'Manual'
,
'FLUTTER_XCODE_ARCHS'
:
'arm64'
});
when
(
mockProcessManager
.
runSync
(
any
,
workingDirectory:
anyNamed
(
'workingDirectory'
)))
.
thenReturn
(
ProcessResult
(
1
,
0
,
''
,
''
));
xcodeProjectInterpreter
.
cleanWorkspace
(
'workspace_path'
,
'Runner'
);
final
List
<
dynamic
>
captured
=
verify
(
mockProcessManager
.
runSync
(
captureAny
,
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
))).
captured
;
expect
(
captured
.
first
,
<
String
>[
xcodebuild
,
'-workspace'
,
'workspace_path'
,
'-scheme'
,
'Runner'
,
'-quiet'
,
'clean'
,
'CODE_SIGN_STYLE=Manual'
,
'ARCHS=arm64'
]);
});
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isFalse
);
});
group
(
'xcodebuild -list'
,
()
{
mocks
.
MockProcessManager
mockProcessManager
;
FakePlatform
macOS
;
FileSystem
fs
;
testWithoutContext
(
'xcodebuild isInstalled is false when version has unexpected format'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode Ultra5000
\n
Build version 8E3004b'
,
''
));
setUp
(()
{
mockProcessManager
=
mocks
.
MockProcessManager
();
macOS
=
fakePlatform
(
'macos'
);
fs
=
MemoryFileSystem
();
fs
.
file
(
xcodebuild
).
createSync
(
recursive:
true
);
});
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isFalse
);
});
void
testUsingOsxContext
(
String
description
,
dynamic
testMethod
())
{
testUsingContext
(
description
,
testMethod
,
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
macOS
,
FileSystem:
()
=>
fs
,
ProcessManager:
()
=>
mockProcessManager
,
});
}
testWithoutContext
(
'xcodebuild isInstalled is true when version has expected format'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-version'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
'Xcode 8.3.3
\n
Build version 8E3004b'
,
''
));
testUsingOsxContext
(
'getInfo returns something when xcodebuild -list succeeds'
,
()
async
{
const
String
workingDirectory
=
'/'
;
when
(
mockProcessManager
.
run
(
<
String
>[
xcodebuild
,
'-list'
],
environment:
anyNamed
(
'environment'
),
workingDirectory:
workingDirectory
),
).
thenAnswer
((
_
)
{
return
Future
<
ProcessResult
>.
value
(
ProcessResult
(
1
,
0
,
''
,
''
));
});
final
XcodeProjectInterpreter
xcodeProjectInterpreter
=
XcodeProjectInterpreter
();
expect
(
await
xcodeProjectInterpreter
.
getInfo
(
workingDirectory
),
isNotNull
);
});
expect
(
xcodeProjectInterpreter
.
isInstalled
,
isTrue
);
});
testUsingOsxContext
(
'getInfo throws a tool exit when it is unable to find a project'
,
()
async
{
const
String
workingDirectory
=
'/'
;
const
String
stderr
=
'Useful Xcode failure message about missing project.'
;
when
(
mockProcessManager
.
run
(
<
String
>[
xcodebuild
,
'-list'
],
environment:
anyNamed
(
'environment'
),
workingDirectory:
workingDirectory
),
).
thenAnswer
((
_
)
{
return
Future
<
ProcessResult
>.
value
(
ProcessResult
(
1
,
66
,
''
,
stderr
));
});
final
XcodeProjectInterpreter
xcodeProjectInterpreter
=
XcodeProjectInterpreter
();
expect
(
()
async
=>
await
xcodeProjectInterpreter
.
getInfo
(
workingDirectory
),
throwsToolExit
(
message:
stderr
));
});
testWithoutContext
(
'xcodebuild build settings is empty when xcodebuild failed to get the build settings'
,
()
async
{
when
(
processManager
.
runSync
(
argThat
(
contains
(
xcodebuild
)),
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenReturn
(
ProcessResult
(
0
,
1
,
''
,
''
));
expect
(
await
xcodeProjectInterpreter
.
getBuildSettings
(
''
,
''
),
const
<
String
,
String
>{});
});
group
(
'Xcode project properties'
,
()
{
test
(
'properties from default project can be parsed'
,
()
{
const
String
output
=
'''
testWithoutContext
(
'xcodebuild build settings flakes'
,
()
async
{
const
Duration
delay
=
Duration
(
seconds:
1
);
processManager
.
processFactory
=
mocks
.
flakyProcessFactory
(
flakes:
1
,
delay:
delay
+
const
Duration
(
seconds:
1
),
);
expect
(
await
xcodeProjectInterpreter
.
getBuildSettings
(
''
,
''
,
timeout:
delay
),
const
<
String
,
String
>{});
// build settings times out and is killed once, then succeeds.
verify
(
processManager
.
killPid
(
any
)).
called
(
1
);
// The verbose logs should tell us something timed out.
expect
(
logger
.
traceText
,
contains
(
'timed out'
));
});
testWithoutContext
(
'xcodebuild build settings contains Flutter Xcode environment variables'
,
()
async
{
platform
.
environment
=
Map
<
String
,
String
>.
unmodifiable
(<
String
,
String
>{
'FLUTTER_XCODE_CODE_SIGN_STYLE'
:
'Manual'
,
'FLUTTER_XCODE_ARCHS'
:
'arm64'
});
when
(
processManager
.
runSync
(<
String
>[
xcodebuild
,
'-project'
,
platform
.
pathSeparator
,
'-target'
,
''
,
'-showBuildSettings'
,
'CODE_SIGN_STYLE=Manual'
,
'ARCHS=arm64'
],
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
)))
.
thenReturn
(
ProcessResult
(
1
,
0
,
''
,
''
));
expect
(
await
xcodeProjectInterpreter
.
getBuildSettings
(
''
,
''
),
const
<
String
,
String
>{});
});
testWithoutContext
(
'xcodebuild clean contains Flutter Xcode environment variables'
,
()
async
{
platform
.
environment
=
Map
<
String
,
String
>.
unmodifiable
(<
String
,
String
>{
'FLUTTER_XCODE_CODE_SIGN_STYLE'
:
'Manual'
,
'FLUTTER_XCODE_ARCHS'
:
'arm64'
});
when
(
processManager
.
runSync
(
any
,
workingDirectory:
anyNamed
(
'workingDirectory'
)))
.
thenReturn
(
ProcessResult
(
1
,
0
,
''
,
''
));
xcodeProjectInterpreter
.
cleanWorkspace
(
'workspace_path'
,
'Runner'
);
final
List
<
dynamic
>
captured
=
verify
(
processManager
.
runSync
(
captureAny
,
workingDirectory:
anyNamed
(
'workingDirectory'
),
environment:
anyNamed
(
'environment'
))).
captured
;
expect
(
captured
.
first
,
<
String
>[
xcodebuild
,
'-workspace'
,
'workspace_path'
,
'-scheme'
,
'Runner'
,
'-quiet'
,
'clean'
,
'CODE_SIGN_STYLE=Manual'
,
'ARCHS=arm64'
]);
});
testWithoutContext
(
'xcodebuild -list getInfo returns something when xcodebuild -list succeeds'
,
()
async
{
const
String
workingDirectory
=
'/'
;
when
(
processManager
.
run
(
<
String
>[
xcodebuild
,
'-list'
],
environment:
anyNamed
(
'environment'
),
workingDirectory:
workingDirectory
),
).
thenAnswer
((
_
)
{
return
Future
<
ProcessResult
>.
value
(
ProcessResult
(
1
,
0
,
''
,
''
));
});
final
XcodeProjectInterpreter
xcodeProjectInterpreter
=
XcodeProjectInterpreter
(
logger:
logger
,
fileSystem:
fileSystem
,
platform:
platform
,
processManager:
processManager
,
terminal:
terminal
,
);
expect
(
await
xcodeProjectInterpreter
.
getInfo
(
workingDirectory
),
isNotNull
);
});
testWithoutContext
(
'xcodebuild -list getInfo throws a tool exit when it is unable to find a project'
,
()
async
{
const
String
workingDirectory
=
'/'
;
const
String
stderr
=
'Useful Xcode failure message about missing project.'
;
when
(
processManager
.
run
(
<
String
>[
xcodebuild
,
'-list'
],
environment:
anyNamed
(
'environment'
),
workingDirectory:
workingDirectory
),
).
thenAnswer
((
_
)
{
return
Future
<
ProcessResult
>.
value
(
ProcessResult
(
1
,
66
,
''
,
stderr
));
});
final
XcodeProjectInterpreter
xcodeProjectInterpreter
=
XcodeProjectInterpreter
(
logger:
logger
,
fileSystem:
fileSystem
,
platform:
platform
,
processManager:
processManager
,
terminal:
terminal
,
);
expect
(
()
async
=>
await
xcodeProjectInterpreter
.
getInfo
(
workingDirectory
),
throwsToolExit
(
message:
stderr
));
});
testWithoutContext
(
'Xcode project properties from default project can be parsed'
,
()
{
const
String
output
=
'''
Information about project "Runner":
Targets:
Runner
...
...
@@ -290,13 +306,14 @@ Information about project "Runner":
Runner
'''
;
final
XcodeProjectInfo
info
=
XcodeProjectInfo
.
fromXcodeBuildOutput
(
output
);
expect
(
info
.
targets
,
<
String
>[
'Runner'
]);
expect
(
info
.
schemes
,
<
String
>[
'Runner'
]);
expect
(
info
.
buildConfigurations
,
<
String
>[
'Debug'
,
'Release'
]);
});
test
(
'properties from project with custom schemes can be parsed'
,
()
{
const
String
output
=
'''
final
XcodeProjectInfo
info
=
XcodeProjectInfo
.
fromXcodeBuildOutput
(
output
);
expect
(
info
.
targets
,
<
String
>[
'Runner'
]);
expect
(
info
.
schemes
,
<
String
>[
'Runner'
]);
expect
(
info
.
buildConfigurations
,
<
String
>[
'Debug'
,
'Release'
]);
});
testWithoutContext
(
'Xcode project properties from project with custom schemes can be parsed'
,
()
{
const
String
output
=
'''
Information about project "Runner":
Targets:
Runner
...
...
@@ -314,97 +331,105 @@ Information about project "Runner":
Paid
'''
;
final
XcodeProjectInfo
info
=
XcodeProjectInfo
.
fromXcodeBuildOutput
(
output
);
expect
(
info
.
targets
,
<
String
>[
'Runner'
]);
expect
(
info
.
schemes
,
<
String
>[
'Free'
,
'Paid'
]);
expect
(
info
.
buildConfigurations
,
<
String
>[
'Debug (Free)'
,
'Debug (Paid)'
,
'Release (Free)'
,
'Release (Paid)'
]);
});
test
(
'expected scheme for non-flavored build is Runner'
,
()
{
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
BuildInfo
.
debug
),
'Runner'
);
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
BuildInfo
.
profile
),
'Runner'
);
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
BuildInfo
.
release
),
'Runner'
);
});
test
(
'expected build configuration for non-flavored build is derived from BuildMode'
,
()
{
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
BuildInfo
.
debug
,
'Runner'
),
'Debug'
);
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
BuildInfo
.
profile
,
'Runner'
),
'Profile'
);
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
BuildInfo
.
release
,
'Runner'
),
'Release'
);
});
test
(
'expected scheme for flavored build is the title-cased flavor'
,
()
{
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'hello'
)),
'Hello'
);
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'HELLO'
)),
'HELLO'
);
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
const
BuildInfo
(
BuildMode
.
release
,
'Hello'
)),
'Hello'
);
});
test
(
'expected build configuration for flavored build is Mode-Flavor'
,
()
{
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'hello'
),
'Hello'
),
'Debug-Hello'
);
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'HELLO'
),
'Hello'
),
'Profile-Hello'
);
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
release
,
'Hello'
),
'Hello'
),
'Release-Hello'
);
});
test
(
'scheme for default project is Runner'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(<
String
>[
'Runner'
],
<
String
>[
'Debug'
,
'Release'
],
<
String
>[
'Runner'
]);
expect
(
info
.
schemeFor
(
BuildInfo
.
debug
),
'Runner'
);
expect
(
info
.
schemeFor
(
BuildInfo
.
profile
),
'Runner'
);
expect
(
info
.
schemeFor
(
BuildInfo
.
release
),
'Runner'
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'unknown'
)),
isNull
);
});
test
(
'build configuration for default project is matched against BuildMode'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(<
String
>[
'Runner'
],
<
String
>[
'Debug'
,
'Profile'
,
'Release'
],
<
String
>[
'Runner'
]);
expect
(
info
.
buildConfigurationFor
(
BuildInfo
.
debug
,
'Runner'
),
'Debug'
);
expect
(
info
.
buildConfigurationFor
(
BuildInfo
.
profile
,
'Runner'
),
'Profile'
);
expect
(
info
.
buildConfigurationFor
(
BuildInfo
.
release
,
'Runner'
),
'Release'
);
});
test
(
'scheme for project with custom schemes is matched against flavor'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(
<
String
>[
'Runner'
],
<
String
>[
'Debug (Free)'
,
'Debug (Paid)'
,
'Release (Free)'
,
'Release (Paid)'
],
<
String
>[
'Free'
,
'Paid'
],
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'free'
)),
'Free'
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'Free'
)),
'Free'
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
release
,
'paid'
)),
'Paid'
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
null
)),
isNull
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'unknown'
)),
isNull
);
});
test
(
'build configuration for project with custom schemes is matched against BuildMode and flavor'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(
<
String
>[
'Runner'
],
<
String
>[
'debug (free)'
,
'Debug paid'
,
'profile - Free'
,
'Profile-Paid'
,
'release - Free'
,
'Release-Paid'
],
<
String
>[
'Free'
,
'Paid'
],
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'free'
),
'Free'
),
'debug (free)'
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'Paid'
),
'Paid'
),
'Debug paid'
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'FREE'
),
'Free'
),
'profile - Free'
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
release
,
'paid'
),
'Paid'
),
'Release-Paid'
);
});
test
(
'build configuration for project with inconsistent naming is null'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(
<
String
>[
'Runner'
],
<
String
>[
'Debug-F'
,
'Dbg Paid'
,
'Rel Free'
,
'Release Full'
],
<
String
>[
'Free'
,
'Paid'
],
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'Free'
),
'Free'
),
null
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'Free'
),
'Free'
),
null
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
release
,
'Paid'
),
'Paid'
),
null
);
});
final
XcodeProjectInfo
info
=
XcodeProjectInfo
.
fromXcodeBuildOutput
(
output
);
expect
(
info
.
targets
,
<
String
>[
'Runner'
]);
expect
(
info
.
schemes
,
<
String
>[
'Free'
,
'Paid'
]);
expect
(
info
.
buildConfigurations
,
<
String
>[
'Debug (Free)'
,
'Debug (Paid)'
,
'Release (Free)'
,
'Release (Paid)'
]);
});
testWithoutContext
(
'expected scheme for non-flavored build is Runner'
,
()
{
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
BuildInfo
.
debug
),
'Runner'
);
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
BuildInfo
.
profile
),
'Runner'
);
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
BuildInfo
.
release
),
'Runner'
);
});
testWithoutContext
(
'expected build configuration for non-flavored build is derived from BuildMode'
,
()
{
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
BuildInfo
.
debug
,
'Runner'
),
'Debug'
);
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
BuildInfo
.
profile
,
'Runner'
),
'Profile'
);
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
BuildInfo
.
release
,
'Runner'
),
'Release'
);
});
group
(
'environmentVariablesAsXcodeBuildSettings'
,
()
{
testWithoutContext
(
'expected scheme for flavored build is the title-cased flavor'
,
()
{
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'hello'
)),
'Hello'
);
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'HELLO'
)),
'HELLO'
);
expect
(
XcodeProjectInfo
.
expectedSchemeFor
(
const
BuildInfo
(
BuildMode
.
release
,
'Hello'
)),
'Hello'
);
});
testWithoutContext
(
'expected build configuration for flavored build is Mode-Flavor'
,
()
{
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'hello'
),
'Hello'
),
'Debug-Hello'
);
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'HELLO'
),
'Hello'
),
'Profile-Hello'
);
expect
(
XcodeProjectInfo
.
expectedBuildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
release
,
'Hello'
),
'Hello'
),
'Release-Hello'
);
});
testWithoutContext
(
'scheme for default project is Runner'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(<
String
>[
'Runner'
],
<
String
>[
'Debug'
,
'Release'
],
<
String
>[
'Runner'
]);
expect
(
info
.
schemeFor
(
BuildInfo
.
debug
),
'Runner'
);
expect
(
info
.
schemeFor
(
BuildInfo
.
profile
),
'Runner'
);
expect
(
info
.
schemeFor
(
BuildInfo
.
release
),
'Runner'
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'unknown'
)),
isNull
);
});
testWithoutContext
(
'build configuration for default project is matched against BuildMode'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(<
String
>[
'Runner'
],
<
String
>[
'Debug'
,
'Profile'
,
'Release'
],
<
String
>[
'Runner'
]);
expect
(
info
.
buildConfigurationFor
(
BuildInfo
.
debug
,
'Runner'
),
'Debug'
);
expect
(
info
.
buildConfigurationFor
(
BuildInfo
.
profile
,
'Runner'
),
'Profile'
);
expect
(
info
.
buildConfigurationFor
(
BuildInfo
.
release
,
'Runner'
),
'Release'
);
});
testWithoutContext
(
'scheme for project with custom schemes is matched against flavor'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(
<
String
>[
'Runner'
],
<
String
>[
'Debug (Free)'
,
'Debug (Paid)'
,
'Release (Free)'
,
'Release (Paid)'
],
<
String
>[
'Free'
,
'Paid'
],
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'free'
)),
'Free'
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'Free'
)),
'Free'
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
release
,
'paid'
)),
'Paid'
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
null
)),
isNull
);
expect
(
info
.
schemeFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'unknown'
)),
isNull
);
});
testWithoutContext
(
'build configuration for project with custom schemes is matched against BuildMode and flavor'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(
<
String
>[
'Runner'
],
<
String
>[
'debug (free)'
,
'Debug paid'
,
'profile - Free'
,
'Profile-Paid'
,
'release - Free'
,
'Release-Paid'
],
<
String
>[
'Free'
,
'Paid'
],
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'free'
),
'Free'
),
'debug (free)'
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'Paid'
),
'Paid'
),
'Debug paid'
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'FREE'
),
'Free'
),
'profile - Free'
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
release
,
'paid'
),
'Paid'
),
'Release-Paid'
);
});
testWithoutContext
(
'build configuration for project with inconsistent naming is null'
,
()
{
final
XcodeProjectInfo
info
=
XcodeProjectInfo
(
<
String
>[
'Runner'
],
<
String
>[
'Debug-F'
,
'Dbg Paid'
,
'Rel Free'
,
'Release Full'
],
<
String
>[
'Free'
,
'Paid'
],
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
debug
,
'Free'
),
'Free'
),
null
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
profile
,
'Free'
),
'Free'
),
null
);
expect
(
info
.
buildConfigurationFor
(
const
BuildInfo
(
BuildMode
.
release
,
'Paid'
),
'Paid'
),
null
);
});
group
(
'environmentVariablesAsXcodeBuildSettings'
,
()
{
FakePlatform
platform
;
setUp
(()
{
platform
=
fakePlatform
(
'ignored'
);
});
test
Using
Context
(
'environment variables as Xcode build settings'
,
()
{
test
Without
Context
(
'environment variables as Xcode build settings'
,
()
{
platform
.
environment
=
Map
<
String
,
String
>.
unmodifiable
(<
String
,
String
>{
'Ignored'
:
'Bogus'
,
'FLUTTER_NOT_XCODE'
:
'Bogus'
,
'FLUTTER_XCODE_CODE_SIGN_STYLE'
:
'Manual'
,
'FLUTTER_XCODE_ARCHS'
:
'arm64'
});
final
List
<
String
>
environmentVariablesAsBuildSettings
=
environmentVariablesAsXcodeBuildSettings
();
final
List
<
String
>
environmentVariablesAsBuildSettings
=
environmentVariablesAsXcodeBuildSettings
(
platform
);
expect
(
environmentVariablesAsBuildSettings
,
<
String
>[
'CODE_SIGN_STYLE=Manual'
,
'ARCHS=arm64'
]);
},
overrides:
<
Type
,
Generator
>{
Platform:
()
=>
platform
});
});
...
...
@@ -729,4 +754,9 @@ FakePlatform fakePlatform(String name) {
class
MockLocalEngineArtifacts
extends
Mock
implements
LocalEngineArtifacts
{}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{}
class
MockXcodeProjectInterpreter
extends
Mock
implements
XcodeProjectInterpreter
{
}
class
MockXcodeProjectInterpreter
extends
Mock
implements
XcodeProjectInterpreter
{}
class
MockLogger
extends
Mock
implements
Logger
{}
class
MockAnsiTerminal
extends
Mock
implements
AnsiTerminal
{
@override
bool
get
supportsColor
=>
false
;
}
packages/flutter_tools/test/general.shard/macos/xcode_test.dart
View file @
ef15eac8
...
...
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:file/memory.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/io.dart'
show
ProcessException
,
ProcessResult
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/ios/xcodeproj.dart'
;
import
'package:flutter_tools/src/macos/xcode.dart'
;
import
'package:mockito/mockito.dart'
;
...
...
@@ -17,184 +20,161 @@ class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterprete
class
MockPlatform
extends
Mock
implements
Platform
{}
void
main
(
)
{
group
(
'Xcode'
,
()
{
MockProcessManager
mockProcessManager
;
Xcode
xcode
;
MockXcodeProjectInterpreter
mockXcodeProjectInterpreter
;
MockPlatform
mockPlatform
;
setUp
(()
{
mockProcessManager
=
MockProcessManager
();
mockXcodeProjectInterpreter
=
MockXcodeProjectInterpreter
();
xcode
=
Xcode
();
mockPlatform
=
MockPlatform
();
});
testUsingContext
(
'xcodeSelectPath returns null when xcode-select is not installed'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenThrow
(
const
ProcessException
(
'/usr/bin/xcode-select'
,
<
String
>[
'--print-path'
]));
expect
(
xcode
.
xcodeSelectPath
,
isNull
);
when
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenThrow
(
ArgumentError
(
'Invalid argument(s): Cannot find executable for /usr/bin/xcode-select'
));
expect
(
xcode
.
xcodeSelectPath
,
isNull
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
'xcodeSelectPath returns path when xcode-select is installed'
,
()
{
const
String
xcodePath
=
'/Applications/Xcode8.0.app/Contents/Developer'
;
when
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
xcodePath
,
''
));
expect
(
xcode
.
xcodeSelectPath
,
xcodePath
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
'xcodeVersionSatisfactory is false when version is less than minimum'
,
()
{
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
9
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
0
);
expect
(
xcode
.
isVersionSatisfactory
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
});
testUsingContext
(
'xcodeVersionSatisfactory is false when xcodebuild tools are not installed'
,
()
{
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
false
);
expect
(
xcode
.
isVersionSatisfactory
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
});
testUsingContext
(
'xcodeVersionSatisfactory is true when version meets minimum'
,
()
{
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
10
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
2
);
expect
(
xcode
.
isVersionSatisfactory
,
isTrue
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
});
testUsingContext
(
'xcodeVersionSatisfactory is true when major version exceeds minimum'
,
()
{
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
11
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
2
);
expect
(
xcode
.
isVersionSatisfactory
,
isTrue
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
});
testUsingContext
(
'xcodeVersionSatisfactory is true when minor version exceeds minimum'
,
()
{
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
10
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
3
);
expect
(
xcode
.
isVersionSatisfactory
,
isTrue
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
});
testUsingContext
(
'isInstalledAndMeetsVersionCheck is false when not macOS'
,
()
{
when
(
mockPlatform
.
isMacOS
).
thenReturn
(
false
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
Platform:
()
=>
mockPlatform
,
});
testUsingContext
(
'isInstalledAndMeetsVersionCheck is false when not installed'
,
()
{
when
(
mockPlatform
.
isMacOS
).
thenReturn
(
true
);
const
String
xcodePath
=
'/Applications/Xcode8.0.app/Contents/Developer'
;
when
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
ProcessManager
processManager
;
Xcode
xcode
;
MockXcodeProjectInterpreter
mockXcodeProjectInterpreter
;
MockPlatform
platform
;
Logger
logger
;
FileSystem
fileSystem
;
setUp
(()
{
logger
=
MockLogger
();
fileSystem
=
MemoryFileSystem
();
processManager
=
MockProcessManager
();
mockXcodeProjectInterpreter
=
MockXcodeProjectInterpreter
();
platform
=
MockPlatform
();
xcode
=
Xcode
(
logger:
logger
,
platform:
platform
,
fileSystem:
fileSystem
,
processManager:
processManager
,
xcodeProjectInterpreter:
mockXcodeProjectInterpreter
,
);
});
testWithoutContext
(
'xcodeSelectPath returns null when xcode-select is not installed'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenThrow
(
const
ProcessException
(
'/usr/bin/xcode-select'
,
<
String
>[
'--print-path'
]));
expect
(
xcode
.
xcodeSelectPath
,
isNull
);
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenThrow
(
ArgumentError
(
'Invalid argument(s): Cannot find executable for /usr/bin/xcode-select'
));
expect
(
xcode
.
xcodeSelectPath
,
isNull
);
});
testWithoutContext
(
'xcodeSelectPath returns path when xcode-select is installed'
,
()
{
const
String
xcodePath
=
'/Applications/Xcode8.0.app/Contents/Developer'
;
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
xcodePath
,
''
));
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
false
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
Platform:
()
=>
mockPlatform
,
ProcessManager:
()
=>
mockProcessManager
,
});
expect
(
xcode
.
xcodeSelectPath
,
xcodePath
);
});
testUsingContext
(
'isInstalledAndMeetsVersionCheck is false when no xcode-select'
,
()
{
when
(
mockPlatform
.
isMacOS
).
thenReturn
(
true
);
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
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenReturn
(
ProcessResult
(
1
,
127
,
''
,
'ERROR'
)
);
expect
(
xcode
.
isVersionSatisfactory
,
isFalse
);
}
);
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
10
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
2
);
testWithoutContext
(
'xcodeVersionSatisfactory is false when xcodebuild tools are not installed'
,
()
{
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
false
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
Platform:
()
=>
mockPlatform
,
ProcessManager:
()
=>
mockProcessManager
,
});
expect
(
xcode
.
isVersionSatisfactory
,
isFalse
);
});
testUsingContext
(
'isInstalledAndMeetsVersionCheck is false when version not satisfied'
,
()
{
when
(
mockPlatform
.
isMacOS
).
thenReturn
(
true
);
testWithoutContext
(
'xcodeVersionSatisfactory is true when version meets minimum'
,
()
{
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
10
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
2
);
const
String
xcodePath
=
'/Applications/Xcode8.0.app/Contents/Developer'
;
when
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
xcodePath
,
''
));
expect
(
xcode
.
isVersionSatisfactory
,
isTrue
);
});
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
9
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
0
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
Platform:
()
=>
mockPlatform
,
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
'isInstalledAndMeetsVersionCheck is true when macOS and installed and version is satisfied'
,
()
{
when
(
mockPlatform
.
isMacOS
).
thenReturn
(
true
);
const
String
xcodePath
=
'/Applications/Xcode8.0.app/Contents/Developer'
;
when
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
xcodePath
,
''
));
testWithoutContext
(
'xcodeVersionSatisfactory is true when major version exceeds minimum'
,
()
{
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
11
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
2
);
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
10
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
2
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isTrue
);
},
overrides:
<
Type
,
Generator
>{
XcodeProjectInterpreter:
()
=>
mockXcodeProjectInterpreter
,
Platform:
()
=>
mockPlatform
,
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
'eulaSigned is false when clang is not installed'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcrun'
,
'clang'
]))
.
thenThrow
(
const
ProcessException
(
'/usr/bin/xcrun'
,
<
String
>[
'clang'
]));
expect
(
xcode
.
eulaSigned
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
'eulaSigned is false when clang output indicates EULA not yet accepted'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcrun'
,
'clang'
]))
.
thenReturn
(
ProcessResult
(
1
,
1
,
''
,
'Xcode EULA has not been accepted.
\n
Launch Xcode and accept the license.'
));
expect
(
xcode
.
eulaSigned
,
isFalse
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
'eulaSigned is true when clang output indicates EULA has been accepted'
,
()
{
when
(
mockProcessManager
.
runSync
(<
String
>[
'/usr/bin/xcrun'
,
'clang'
]))
.
thenReturn
(
ProcessResult
(
1
,
1
,
''
,
'clang: error: no input files'
));
expect
(
xcode
.
eulaSigned
,
isTrue
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
'SDK name'
,
()
{
expect
(
getNameForSdk
(
SdkType
.
iPhone
),
'iphoneos'
);
expect
(
getNameForSdk
(
SdkType
.
iPhoneSimulator
),
'iphonesimulator'
);
expect
(
getNameForSdk
(
SdkType
.
macOS
),
'macosx'
);
});
expect
(
xcode
.
isVersionSatisfactory
,
isTrue
);
});
testWithoutContext
(
'xcodeVersionSatisfactory is true when minor version exceeds minimum'
,
()
{
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
10
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
3
);
expect
(
xcode
.
isVersionSatisfactory
,
isTrue
);
});
testWithoutContext
(
'isInstalledAndMeetsVersionCheck is false when not macOS'
,
()
{
when
(
platform
.
isMacOS
).
thenReturn
(
false
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isFalse
);
});
testWithoutContext
(
'isInstalledAndMeetsVersionCheck is false when not installed'
,
()
{
when
(
platform
.
isMacOS
).
thenReturn
(
true
);
const
String
xcodePath
=
'/Applications/Xcode8.0.app/Contents/Developer'
;
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
xcodePath
,
''
));
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
false
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isFalse
);
});
testWithoutContext
(
'isInstalledAndMeetsVersionCheck is false when no xcode-select'
,
()
{
when
(
platform
.
isMacOS
).
thenReturn
(
true
);
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenReturn
(
ProcessResult
(
1
,
127
,
''
,
'ERROR'
));
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
10
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
2
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isFalse
);
});
testWithoutContext
(
'isInstalledAndMeetsVersionCheck is false when version not satisfied'
,
()
{
when
(
platform
.
isMacOS
).
thenReturn
(
true
);
const
String
xcodePath
=
'/Applications/Xcode8.0.app/Contents/Developer'
;
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
xcodePath
,
''
));
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
9
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
0
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isFalse
);
});
testWithoutContext
(
'isInstalledAndMeetsVersionCheck is true when macOS and installed and version is satisfied'
,
()
{
when
(
platform
.
isMacOS
).
thenReturn
(
true
);
const
String
xcodePath
=
'/Applications/Xcode8.0.app/Contents/Developer'
;
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcode-select'
,
'--print-path'
]))
.
thenReturn
(
ProcessResult
(
1
,
0
,
xcodePath
,
''
));
when
(
mockXcodeProjectInterpreter
.
isInstalled
).
thenReturn
(
true
);
when
(
mockXcodeProjectInterpreter
.
majorVersion
).
thenReturn
(
10
);
when
(
mockXcodeProjectInterpreter
.
minorVersion
).
thenReturn
(
2
);
expect
(
xcode
.
isInstalledAndMeetsVersionCheck
,
isTrue
);
});
testWithoutContext
(
'eulaSigned is false when clang is not installed'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcrun'
,
'clang'
]))
.
thenThrow
(
const
ProcessException
(
'/usr/bin/xcrun'
,
<
String
>[
'clang'
]));
expect
(
xcode
.
eulaSigned
,
isFalse
);
});
testWithoutContext
(
'eulaSigned is false when clang output indicates EULA not yet accepted'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcrun'
,
'clang'
]))
.
thenReturn
(
ProcessResult
(
1
,
1
,
''
,
'Xcode EULA has not been accepted.
\n
Launch Xcode and accept the license.'
));
expect
(
xcode
.
eulaSigned
,
isFalse
);
});
testWithoutContext
(
'eulaSigned is true when clang output indicates EULA has been accepted'
,
()
{
when
(
processManager
.
runSync
(<
String
>[
'/usr/bin/xcrun'
,
'clang'
]))
.
thenReturn
(
ProcessResult
(
1
,
1
,
''
,
'clang: error: no input files'
));
expect
(
xcode
.
eulaSigned
,
isTrue
);
});
testWithoutContext
(
'SDK name'
,
()
{
expect
(
getNameForSdk
(
SdkType
.
iPhone
),
'iphoneos'
);
expect
(
getNameForSdk
(
SdkType
.
iPhoneSimulator
),
'iphonesimulator'
);
expect
(
getNameForSdk
(
SdkType
.
macOS
),
'macosx'
);
});
}
class
MockLogger
extends
Mock
implements
Logger
{}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment