| // Copyright 2017 The Chromium 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:flutter_tools/src/base/common.dart'; |
| import 'package:flutter_tools/src/base/io.dart'; |
| import 'package:flutter_tools/src/base/platform.dart'; |
| import 'package:flutter_tools/src/cache.dart'; |
| 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 'package:mockito/mockito.dart'; |
| import 'package:process/process.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(homeDirPath, '.cocoapods', 'repos', 'master')).createSync(recursive: true); |
| } |
| |
| String podsIsInCustomDir({String cocoapodsReposDir}) { |
| cocoapodsReposDir ??= fs.path.join(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'}, |
| )).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'}, |
| )).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(<FakeCommand>[]), |
| }); |
| |
| 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(<FakeCommand>[]), |
| 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(<FakeCommand>[]), |
| }); |
| |
| 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(<FakeCommand>[]), |
| }); |
| |
| 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(<FakeCommand>[]), |
| 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(<FakeCommand>[]), |
| }); |
| }); |
| |
| 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); |
| |
| 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(<FakeCommand>[]), |
| }); |
| }); |
| |
| 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, isInstanceOf<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', |
| }, |
| )).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, isInstanceOf<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'}, |
| )); |
| }, 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', |
| }, |
| )); |
| }, 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', |
| }, |
| )); |
| }, 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', |
| }, |
| )); |
| }, 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', |
| }, |
| )); |
| }, 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', |
| }, |
| )).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, |
| }; |
| }); |
| |
| 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, ''); |