Unverified Commit 4be79199 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Swap xcodeproj_tests from MockProcessManager to FakeProcessManager (#56505)

parent 13501af6
......@@ -26,7 +26,58 @@ import '../../src/pubspec_schema.dart';
const String xcodebuild = '/usr/bin/xcodebuild';
void main() {
mocks.MockProcessManager processManager;
group('MockProcessManager', () {
mocks.MockProcessManager processManager;
XcodeProjectInterpreter xcodeProjectInterpreter;
FakePlatform platform;
BufferLogger logger;
setUp(() {
processManager = mocks.MockProcessManager();
platform = FakePlatform(operatingSystem: 'macos');
final FileSystem fileSystem = MemoryFileSystem();
fileSystem.file(xcodebuild).createSync(recursive: true);
final AnsiTerminal terminal = MockAnsiTerminal();
logger = BufferLogger.test(
terminal: terminal
);
xcodeProjectInterpreter = XcodeProjectInterpreter(
logger: logger,
fileSystem: fileSystem,
platform: platform,
processManager: processManager,
terminal: terminal,
usage: null,
);
});
// Work around https://github.com/flutter/flutter/issues/56415.
testWithoutContext('xcodebuild versionText returns null when xcodebuild is not installed', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenThrow(const ProcessException(xcodebuild, <String>['-version']));
expect(xcodeProjectInterpreter.versionText, isNull);
});
testWithoutContext('xcodebuild build settings flakes', () async {
const Duration delay = Duration(seconds: 1);
processManager.processFactory = mocks.flakyProcessFactory(
flakes: 1,
delay: delay + const Duration(seconds: 1),
);
platform.environment = const <String, String>{};
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'));
});
});
FakeProcessManager fakeProcessManager;
XcodeProjectInterpreter xcodeProjectInterpreter;
FakePlatform platform;
FileSystem fileSystem;
......@@ -34,7 +85,7 @@ void main() {
AnsiTerminal terminal;
setUp(() {
processManager = mocks.MockProcessManager();
fakeProcessManager = FakeProcessManager.list(<FakeCommand>[]);
platform = FakePlatform(operatingSystem: 'macos');
fileSystem = MemoryFileSystem();
fileSystem.file(xcodebuild).createSync(recursive: true);
......@@ -46,81 +97,89 @@ void main() {
logger: logger,
fileSystem: fileSystem,
platform: platform,
processManager: processManager,
processManager: fakeProcessManager,
terminal: terminal,
usage: null,
);
});
testWithoutContext('xcodebuild versionText returns null when xcodebuild is not installed', () {
when(processManager.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, "
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: "xcode-select: error: tool 'xcodebuild' requires Xcode, "
"but active developer directory '/Library/Developer/CommandLineTools' "
'is a command line tools instance',
'',
),
);
exitCode: 1,
));
expect(xcodeProjectInterpreter.versionText, isNull);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild versionText returns formatted version text', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenReturn(ProcessResult(1, 0, 'Xcode 8.3.3\nBuild version 8E3004b', ''));
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode 8.3.3\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.versionText, 'Xcode 8.3.3, Build version 8E3004b');
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild versionText handles Xcode version string with unexpected format', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenReturn(ProcessResult(1, 0, 'Xcode Ultra5000\nBuild version 8E3004b', ''));
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode Ultra5000\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.versionText, 'Xcode Ultra5000, Build version 8E3004b');
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild majorVersion returns major version', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenReturn(ProcessResult(1, 0, 'Xcode 11.4.1\nBuild version 11N111s', ''));
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode 11.4.1\nBuild version 11N111s',
));
expect(xcodeProjectInterpreter.majorVersion, 11);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild majorVersion is null when version has unexpected format', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenReturn(ProcessResult(1, 0, 'Xcode Ultra5000\nBuild version 8E3004b', ''));
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode Ultra5000\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.majorVersion, isNull);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild minorVersion returns minor version', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenReturn(ProcessResult(1, 0, 'Xcode 8.3.3\nBuild version 8E3004b', ''));
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode 8.3.3\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.minorVersion, 3);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild minorVersion returns 0 when minor version is unspecified', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenReturn(ProcessResult(1, 0, 'Xcode 8\nBuild version 8E3004b', ''));
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode 8\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.minorVersion, 0);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild minorVersion is null when version has unexpected format', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenReturn(ProcessResult(1, 0, 'Xcode Ultra5000\nBuild version 8E3004b', ''));
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode Ultra5000\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.minorVersion, isNull);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild isInstalled is false when not on MacOS', () {
......@@ -129,163 +188,154 @@ void main() {
logger: logger,
fileSystem: fileSystem,
platform: platform,
processManager: processManager,
processManager: fakeProcessManager,
terminal: terminal,
usage: Usage.test(),
);
fileSystem.file(xcodebuild).deleteSync();
expect(xcodeProjectInterpreter.isInstalled, isFalse);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild isInstalled is false when xcodebuild does not exist', () {
fileSystem.file(xcodebuild).deleteSync();
expect(xcodeProjectInterpreter.isInstalled, isFalse);
expect(fakeProcessManager.hasRemainingExpectations, 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, "
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: "xcode-select: error: tool 'xcodebuild' requires Xcode, "
"but active developer directory '/Library/Developer/CommandLineTools' "
'is a command line tools instance',
'',
),
);
exitCode: 1,
));
expect(xcodeProjectInterpreter.isInstalled, isFalse);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild isInstalled is false when version has unexpected format', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenReturn(ProcessResult(1, 0, 'Xcode Ultra5000\nBuild version 8E3004b', ''));
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode Ultra5000\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.isInstalled, isFalse);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild isInstalled is true when version has expected format', () {
when(processManager.runSync(<String>[xcodebuild, '-version']))
.thenReturn(ProcessResult(1, 0, 'Xcode 8.3.3\nBuild version 8E3004b', ''));
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-version'],
stdout: 'Xcode 8.3.3\nBuild version 8E3004b',
));
expect(xcodeProjectInterpreter.isInstalled, isTrue);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild build settings is empty when xcodebuild failed to get the build settings', () async {
platform.environment = Map<String, String>.unmodifiable(<String, String>{});
when(processManager.runSync(
argThat(contains(xcodebuild)),
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenReturn(ProcessResult(0, 1, '', ''));
platform.environment = const <String, String>{};
expect(await xcodeProjectInterpreter.getBuildSettings('', ''), const <String, String>{});
});
testWithoutContext('xcodebuild build settings flakes', () async {
const Duration delay = Duration(seconds: 1);
processManager.processFactory = mocks.flakyProcessFactory(
flakes: 1,
delay: delay + const Duration(seconds: 1),
);
platform.environment = Map<String, String>.unmodifiable(<String, String>{});
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[
'/usr/bin/xcodebuild',
'-project',
'/',
'-target',
'Runner',
'-showBuildSettings'
],
exitCode: 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'));
expect(await xcodeProjectInterpreter.getBuildSettings('', 'Runner'), const <String, String>{});
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild build settings contains Flutter Xcode environment variables', () async {
platform.environment = Map<String, String>.unmodifiable(<String, String>{
platform.environment = const <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>{});
};
fakeProcessManager.addCommand(FakeCommand(
command: <String>[
xcodebuild,
'-project',
fileSystem.path.separator,
'-target',
'Runner',
'-showBuildSettings',
'CODE_SIGN_STYLE=Manual',
'ARCHS=arm64'
],
));
expect(await xcodeProjectInterpreter.getBuildSettings('', 'Runner'), const <String, String>{});
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('xcodebuild clean contains Flutter Xcode environment variables', () async {
platform.environment = Map<String, String>.unmodifiable(<String, String>{
platform.environment = const <String, String>{
'FLUTTER_XCODE_CODE_SIGN_STYLE': 'Manual',
'FLUTTER_XCODE_ARCHS': 'arm64'
});
when(processManager.run(
any,
workingDirectory: anyNamed('workingDirectory')))
.thenAnswer((_) => Future<ProcessResult>.value(ProcessResult(1, 0, '', '')));
};
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[
xcodebuild,
'-workspace',
'workspace_path',
'-scheme',
'Runner',
'-quiet',
'clean',
'CODE_SIGN_STYLE=Manual',
'ARCHS=arm64'
],
));
await xcodeProjectInterpreter.cleanWorkspace('workspace_path', 'Runner');
final List<dynamic> captured = verify(processManager.run(
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(fakeProcessManager.hasRemainingExpectations, isFalse);
});
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, '', ''));
});
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-list'],
));
final XcodeProjectInterpreter xcodeProjectInterpreter = XcodeProjectInterpreter(
logger: logger,
fileSystem: fileSystem,
platform: platform,
processManager: processManager,
processManager: fakeProcessManager,
terminal: terminal,
usage: Usage.test(),
);
expect(await xcodeProjectInterpreter.getInfo(workingDirectory), isNotNull);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
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));
});
fakeProcessManager.addCommand(const FakeCommand(
command: <String>[xcodebuild, '-list'],
exitCode: 66,
stderr: stderr,
));
final XcodeProjectInterpreter xcodeProjectInterpreter = XcodeProjectInterpreter(
logger: logger,
fileSystem: fileSystem,
platform: platform,
processManager: processManager,
processManager: fakeProcessManager,
terminal: terminal,
usage: Usage.test(),
);
......@@ -293,6 +343,7 @@ void main() {
expect(
() async => await xcodeProjectInterpreter.getInfo(workingDirectory),
throwsToolExit(message: stderr));
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
testWithoutContext('Xcode project properties from default project can be parsed', () {
......@@ -427,12 +478,12 @@ Information about project "Runner":
});
testWithoutContext('environment variables as Xcode build settings', () {
platform.environment = Map<String, String>.unmodifiable(<String, String>{
platform.environment = const <String, String>{
'Ignored': 'Bogus',
'FLUTTER_NOT_XCODE': 'Bogus',
'FLUTTER_XCODE_CODE_SIGN_STYLE': 'Manual',
'FLUTTER_XCODE_ARCHS': 'arm64'
});
};
final List<String> environmentVariablesAsBuildSettings = environmentVariablesAsXcodeBuildSettings(platform);
expect(environmentVariablesAsBuildSettings, <String>['CODE_SIGN_STYLE=Manual', 'ARCHS=arm64']);
});
......@@ -440,14 +491,12 @@ Information about project "Runner":
group('updateGeneratedXcodeProperties', () {
MockLocalEngineArtifacts mockArtifacts;
MockProcessManager mockProcessManager;
FakePlatform macOS;
FileSystem fs;
setUp(() {
fs = MemoryFileSystem();
mockArtifacts = MockLocalEngineArtifacts();
mockProcessManager = MockProcessManager();
macOS = FakePlatform(operatingSystem: 'macos');
fs.file(xcodebuild).createSync(recursive: true);
});
......@@ -457,7 +506,7 @@ Information about project "Runner":
Artifacts: () => mockArtifacts,
Platform: () => macOS,
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
ProcessManager: () => FakeProcessManager.any(),
});
}
......@@ -805,7 +854,6 @@ flutter:
}
class MockLocalEngineArtifacts extends Mock implements LocalEngineArtifacts {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter {}
class MockAnsiTerminal extends Mock implements AnsiTerminal {
@override
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment