blob: ebfd87bb0398dc24afd162d46447185bd430ccc3 [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:platform/platform.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/cocoapods.dart';
import 'package:flutter_tools/src/plugins.dart';
import 'package:flutter_tools/src/project.dart';
import '../../src/common.dart';
import '../../src/context.dart';
typedef InvokeProcess = Future<ProcessResult> Function();
void main() {
FileSystem fs;
ProcessManager mockProcessManager;
MockXcodeProjectInterpreter mockXcodeProjectInterpreter;
FlutterProject projectUnderTest;
CocoaPods cocoaPodsUnderTest;
InvokeProcess resultOfPodVersion;
void pretendPodVersionFails() {
resultOfPodVersion = () async => exitsWithError();
}
void pretendPodVersionIs(String versionText) {
resultOfPodVersion = () async => exitsHappy(versionText);
}
void podsIsInHomeDir() {
fs.directory(fs.path.join(
globals.fsUtils.homeDirPath,
'.cocoapods',
'repos',
'master',
)).createSync(recursive: true);
}
String podsIsInCustomDir({String cocoapodsReposDir}) {
cocoapodsReposDir ??= fs.path.join(
globals.fsUtils.homeDirPath,
'cache',
'cocoapods',
'repos',
);
fs.directory(fs.path.join(cocoapodsReposDir, 'master')).createSync(recursive: true);
return cocoapodsReposDir;
}
setUp(() async {
Cache.flutterRoot = 'flutter';
fs = MemoryFileSystem();
mockProcessManager = MockProcessManager();
mockXcodeProjectInterpreter = MockXcodeProjectInterpreter();
projectUnderTest = FlutterProject.fromDirectory(fs.directory('project'));
projectUnderTest.ios.xcodeProject.createSync(recursive: true);
cocoaPodsUnderTest = CocoaPods();
pretendPodVersionIs('1.6.0');
fs.file(fs.path.join(
Cache.flutterRoot, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-ios-objc',
))
..createSync(recursive: true)
..writeAsStringSync('Objective-C iOS podfile template');
fs.file(fs.path.join(
Cache.flutterRoot, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-ios-swift',
))
..createSync(recursive: true)
..writeAsStringSync('Swift iOS podfile template');
fs.file(fs.path.join(
Cache.flutterRoot, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-macos',
))
..createSync(recursive: true)
..writeAsStringSync('macOS podfile template');
when(mockProcessManager.run(
<String>['pod', '--version'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) => resultOfPodVersion());
when(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
)).thenAnswer((_) async => exitsHappy());
when(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/macos',
environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
)).thenAnswer((_) async => exitsHappy());
});
void pretendPodIsNotInstalled() {
when(mockProcessManager.run(
<String>['which', 'pod'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) async => exitsWithError());
}
void pretendPodIsInstalled() {
when(mockProcessManager.run(
<String>['which', 'pod'],
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
)).thenAnswer((_) async => exitsHappy());
}
group('Evaluate installation', () {
testUsingContext('detects not installed, if pod exec does not exist', () async {
pretendPodIsNotInstalled();
expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.notInstalled);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('detects not installed, if pod is installed but version fails', () async {
pretendPodIsInstalled();
pretendPodVersionFails();
expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.brokenInstall);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('detects installed', () async {
pretendPodIsInstalled();
pretendPodVersionIs('0.0.1');
expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, isNot(CocoaPodsStatus.notInstalled));
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('detects unknown version', () async {
pretendPodIsInstalled();
pretendPodVersionIs('Plugin loaded.\n1.5.3');
expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.unknownVersion);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('detects below minimum version', () async {
pretendPodIsInstalled();
pretendPodVersionIs('1.5.0');
expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.belowMinimumVersion);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('detects at recommended version', () async {
pretendPodIsInstalled();
pretendPodVersionIs('1.6.0');
expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.recommended);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('detects above recommended version', () async {
pretendPodIsInstalled();
pretendPodVersionIs('1.6.1');
expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.recommended);
}, overrides: <Type, Generator>{
ProcessManager: () => mockProcessManager,
});
testUsingContext('detects initialized over 1.8.0', () async {
pretendPodIsInstalled();
pretendPodVersionIs('1.8.0');
expect(await cocoaPodsUnderTest.isCocoaPodsInitialized, isTrue);
}, overrides: <Type, Generator>{
Platform: () => FakePlatform(),
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
});
group('Setup Podfile', () {
testUsingContext('creates objective-c Podfile when not present', () async {
await cocoaPodsUnderTest.setupPodfile(projectUnderTest.ios);
expect(projectUnderTest.ios.podfile.readAsStringSync(), 'Objective-C iOS podfile template');
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('creates swift Podfile if swift', () async {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.getBuildSettings(any, any))
.thenAnswer((_) async => <String, String>{
'SWIFT_VERSION': '5.0',
});
final FlutterProject project = FlutterProject.fromPath('project');
await cocoaPodsUnderTest.setupPodfile(project.ios);
expect(projectUnderTest.ios.podfile.readAsStringSync(), 'Swift iOS podfile template');
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
});
testUsingContext('creates macOS Podfile when not present', () async {
projectUnderTest.macos.xcodeProject.createSync(recursive: true);
await cocoaPodsUnderTest.setupPodfile(projectUnderTest.macos);
expect(projectUnderTest.macos.podfile.readAsStringSync(), 'macOS podfile template');
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('does not recreate Podfile when already present', () async {
projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Existing Podfile');
final FlutterProject project = FlutterProject.fromPath('project');
await cocoaPodsUnderTest.setupPodfile(project.ios);
expect(projectUnderTest.ios.podfile.readAsStringSync(), 'Existing Podfile');
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('does not create Podfile when we cannot interpret Xcode projects', () async {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(false);
final FlutterProject project = FlutterProject.fromPath('project');
await cocoaPodsUnderTest.setupPodfile(project.ios);
expect(projectUnderTest.ios.podfile.existsSync(), false);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
});
testUsingContext('includes Pod config in xcconfig files, if not present', () async {
projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Existing Podfile');
projectUnderTest.ios.xcodeConfigFor('Debug')
..createSync(recursive: true)
..writeAsStringSync('Existing debug config');
projectUnderTest.ios.xcodeConfigFor('Release')
..createSync(recursive: true)
..writeAsStringSync('Existing release config');
final FlutterProject project = FlutterProject.fromPath('project');
await cocoaPodsUnderTest.setupPodfile(project.ios);
final String debugContents = projectUnderTest.ios.xcodeConfigFor('Debug').readAsStringSync();
expect(debugContents, contains(
'#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"\n'));
expect(debugContents, contains('Existing debug config'));
final String releaseContents = projectUnderTest.ios.xcodeConfigFor('Release').readAsStringSync();
expect(releaseContents, contains(
'#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"\n'));
expect(releaseContents, contains('Existing release config'));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
});
});
group('Update xcconfig', () {
testUsingContext('includes Pod config in xcconfig files, if the user manually added Pod dependencies without using Flutter plugins', () async {
projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Custom Podfile');
projectUnderTest.ios.podfileLock..createSync()..writeAsStringSync('Podfile.lock from user executed `pod install`');
projectUnderTest.packagesFile..createSync()..writeAsStringSync('');
projectUnderTest.ios.xcodeConfigFor('Debug')
..createSync(recursive: true)
..writeAsStringSync('Existing debug config');
projectUnderTest.ios.xcodeConfigFor('Release')
..createSync(recursive: true)
..writeAsStringSync('Existing release config');
final FlutterProject project = FlutterProject.fromPath('project');
await injectPlugins(project, checkProjects: true);
final String debugContents = projectUnderTest.ios.xcodeConfigFor('Debug').readAsStringSync();
expect(debugContents, contains(
'#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"\n'));
expect(debugContents, contains('Existing debug config'));
final String releaseContents = projectUnderTest.ios.xcodeConfigFor('Release').readAsStringSync();
expect(releaseContents, contains(
'#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"\n'));
expect(releaseContents, contains('Existing release config'));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
});
});
group('Process pods', () {
setUp(() {
podsIsInHomeDir();
});
testUsingContext('prints error, if CocoaPods is not installed', () async {
pretendPodIsNotInstalled();
projectUnderTest.ios.podfile.createSync();
final bool didInstall = await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
);
verifyNever(mockProcessManager.run(
argThat(containsAllInOrder(<String>['pod', 'install'])),
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
));
expect(testLogger.errorText, contains('not installed'));
expect(testLogger.errorText, contains('Skipping pod install'));
expect(didInstall, isFalse);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('prints warning, if Podfile is out of date', () async {
pretendPodIsInstalled();
fs.file(fs.path.join('project', 'ios', 'Podfile'))
..createSync()
..writeAsStringSync('Existing Podfile');
final Directory symlinks = projectUnderTest.ios.symlinks
..createSync(recursive: true);
symlinks.childLink('flutter').createSync('cache');
await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
);
expect(testLogger.errorText, contains('Warning: Podfile is out of date'));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws, if Podfile is missing.', () async {
pretendPodIsInstalled();
try {
await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
);
fail('ToolExit expected');
} catch(e) {
expect(e, isA<ToolExit>());
verifyNever(mockProcessManager.run(
argThat(containsAllInOrder(<String>['pod', 'install'])),
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
));
}
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws, if specs repo is outdated.', () async {
pretendPodIsInstalled();
fs.file(fs.path.join('project', 'ios', 'Podfile'))
..createSync()
..writeAsStringSync('Existing Podfile');
when(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{
'FLUTTER_FRAMEWORK_DIR': 'engine/path',
'COCOAPODS_DISABLE_STATS': 'true',
'LANG': 'en_US.UTF-8',
},
)).thenAnswer((_) async => exitsWithError(
'''
[!] Unable to satisfy the following requirements:
- `Firebase/Auth` required by `Podfile`
- `Firebase/Auth (= 4.0.0)` required by `Podfile.lock`
None of your spec sources contain a spec satisfying the dependencies: `Firebase/Auth, Firebase/Auth (= 4.0.0)`.
You have either:
* out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
* mistyped the name or version.
* not added the source repo that hosts the Podspec to your Podfile.
Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.''',
));
try {
await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
);
fail('ToolExit expected');
} catch (e) {
expect(e, isA<ToolExit>());
expect(
testLogger.errorText,
contains("CocoaPods's specs repository is too out-of-date to satisfy dependencies"),
);
}
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('run pod install, if Podfile.lock is missing', () async {
pretendPodIsInstalled();
projectUnderTest.ios.podfile
..createSync()
..writeAsStringSync('Existing Podfile');
projectUnderTest.ios.podManifestLock
..createSync(recursive: true)
..writeAsStringSync('Existing lock file.');
final bool didInstall = await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
dependenciesChanged: false,
);
expect(didInstall, isTrue);
verify(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('runs pod install, if Manifest.lock is missing', () async {
pretendPodIsInstalled();
projectUnderTest.ios.podfile
..createSync()
..writeAsStringSync('Existing Podfile');
projectUnderTest.ios.podfileLock
..createSync()
..writeAsStringSync('Existing lock file.');
final bool didInstall = await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
dependenciesChanged: false,
);
expect(didInstall, isTrue);
verify(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{
'FLUTTER_FRAMEWORK_DIR': 'engine/path',
'COCOAPODS_DISABLE_STATS': 'true',
'LANG': 'en_US.UTF-8',
},
));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('runs pod install, if Manifest.lock different from Podspec.lock', () async {
pretendPodIsInstalled();
projectUnderTest.ios.podfile
..createSync()
..writeAsStringSync('Existing Podfile');
projectUnderTest.ios.podfileLock
..createSync()
..writeAsStringSync('Existing lock file.');
projectUnderTest.ios.podManifestLock
..createSync(recursive: true)
..writeAsStringSync('Different lock file.');
final bool didInstall = await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
dependenciesChanged: false,
);
expect(didInstall, isTrue);
verify(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{
'FLUTTER_FRAMEWORK_DIR': 'engine/path',
'COCOAPODS_DISABLE_STATS': 'true',
'LANG': 'en_US.UTF-8',
},
));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('runs pod install, if flutter framework changed', () async {
pretendPodIsInstalled();
projectUnderTest.ios.podfile
..createSync()
..writeAsStringSync('Existing Podfile');
projectUnderTest.ios.podfileLock
..createSync()
..writeAsStringSync('Existing lock file.');
projectUnderTest.ios.podManifestLock
..createSync(recursive: true)
..writeAsStringSync('Existing lock file.');
final bool didInstall = await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
dependenciesChanged: true,
);
expect(didInstall, isTrue);
verify(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{
'FLUTTER_FRAMEWORK_DIR': 'engine/path',
'COCOAPODS_DISABLE_STATS': 'true',
'LANG': 'en_US.UTF-8',
},
));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('runs pod install, if Podfile.lock is older than Podfile', () async {
pretendPodIsInstalled();
projectUnderTest.ios.podfile
..createSync()
..writeAsStringSync('Existing Podfile');
projectUnderTest.ios.podfileLock
..createSync()
..writeAsStringSync('Existing lock file.');
projectUnderTest.ios.podManifestLock
..createSync(recursive: true)
..writeAsStringSync('Existing lock file.');
await Future<void>.delayed(const Duration(milliseconds: 10));
projectUnderTest.ios.podfile
..writeAsStringSync('Updated Podfile');
await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
dependenciesChanged: false,
);
verify(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{
'FLUTTER_FRAMEWORK_DIR': 'engine/path',
'COCOAPODS_DISABLE_STATS': 'true',
'LANG': 'en_US.UTF-8',
},
));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('skips pod install, if nothing changed', () async {
pretendPodIsInstalled();
projectUnderTest.ios.podfile
..createSync()
..writeAsStringSync('Existing Podfile');
projectUnderTest.ios.podfileLock
..createSync()
..writeAsStringSync('Existing lock file.');
projectUnderTest.ios.podManifestLock
..createSync(recursive: true)
..writeAsStringSync('Existing lock file.');
final bool didInstall = await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
dependenciesChanged: false,
);
expect(didInstall, isFalse);
verifyNever(mockProcessManager.run(
argThat(containsAllInOrder(<String>['pod', 'install'])),
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment'),
));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('a failed pod install deletes Pods/Manifest.lock', () async {
pretendPodIsInstalled();
projectUnderTest.ios.podfile
..createSync()
..writeAsStringSync('Existing Podfile');
projectUnderTest.ios.podfileLock
..createSync()
..writeAsStringSync('Existing lock file.');
projectUnderTest.ios.podManifestLock
..createSync(recursive: true)
..writeAsStringSync('Existing lock file.');
when(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{
'FLUTTER_FRAMEWORK_DIR': 'engine/path',
'COCOAPODS_DISABLE_STATS': 'true',
'LANG': 'en_US.UTF-8',
},
)).thenAnswer(
(_) async => exitsWithError()
);
try {
await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
dependenciesChanged: true,
);
fail('Tool throw expected when pod install fails');
} on ToolExit {
expect(projectUnderTest.ios.podManifestLock.existsSync(), isFalse);
}
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
});
group('Pods repos dir is custom', () {
String cocoapodsRepoDir;
Map<String, String> environment;
setUp(() {
cocoapodsRepoDir = podsIsInCustomDir();
environment = <String, String>{
'FLUTTER_FRAMEWORK_DIR': 'engine/path',
'COCOAPODS_DISABLE_STATS': 'true',
'CP_REPOS_DIR': cocoapodsRepoDir,
'LANG': 'en_US.UTF8',
};
});
testUsingContext('succeeds, if specs repo is in CP_REPOS_DIR.', () async {
pretendPodIsInstalled();
fs.file(fs.path.join('project', 'ios', 'Podfile'))
..createSync()
..writeAsStringSync('Existing Podfile');
when(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: environment,
)).thenAnswer((_) async => exitsHappy());
final bool success = await cocoaPodsUnderTest.processPods(
xcodeProject: projectUnderTest.ios,
engineDir: 'engine/path',
);
expect(success, true);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
Platform: () => FakePlatform(environment: environment),
});
});
}
class MockProcessManager extends Mock implements ProcessManager {}
class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter {}
ProcessResult exitsWithError([ String stdout = '' ]) => ProcessResult(1, 1, stdout, '');
ProcessResult exitsHappy([ String stdout = '' ]) => ProcessResult(1, 0, stdout, '');