blob: d29ee82ccb6704e77e73c35c7cb35edb7dd79ff9 [file] [log] [blame]
Ian Hickson449f4a62019-11-27 15:04:02 -08001// Copyright 2014 The Flutter Authors. All rights reserved.
xster6a494192017-07-12 18:35:08 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
xster6a494192017-07-12 18:35:08 -07005import 'package:file/file.dart';
6import 'package:file/memory.dart';
Zachary Anderson6f0ed5e2020-05-06 08:15:39 -07007import 'package:flutter_tools/src/base/logger.dart';
8import 'package:flutter_tools/src/base/platform.dart';
Jenn Magdere26c7f92020-11-18 13:33:04 -08009import 'package:flutter_tools/src/build_info.dart';
Mikkel Nygaard Ravnc2e1bc02018-02-15 22:55:36 +010010import 'package:flutter_tools/src/cache.dart';
Jenn Magderd40cc5a2021-04-13 13:52:58 -070011import 'package:flutter_tools/src/flutter_plugins.dart';
stuartmorgan81c38b22019-05-24 22:51:02 -040012import 'package:flutter_tools/src/ios/xcodeproj.dart';
13import 'package:flutter_tools/src/macos/cocoapods.dart';
Sigurd Meldgaard1e8ef602018-06-28 14:35:00 +020014import 'package:flutter_tools/src/project.dart';
Jenn Magder37f4f1f2020-11-19 13:17:57 -080015import 'package:flutter_tools/src/reporting/reporting.dart';
Jenn Magder0cf10072021-03-16 13:53:04 -070016import 'package:test/fake.dart';
xster6a494192017-07-12 18:35:08 -070017
Ian Hicksond919e692019-07-13 11:51:44 -070018import '../../src/common.dart';
19import '../../src/context.dart';
Jenn Magder5a6d2a02021-03-30 12:42:39 -070020import '../../src/fake_process_manager.dart';
xster6a494192017-07-12 18:35:08 -070021
22void main() {
Jonah Williamsdb829c12022-06-17 21:34:27 -070023 late FileSystem fileSystem;
24 late FakeProcessManager fakeProcessManager;
25 late CocoaPods cocoaPodsUnderTest;
26 late BufferLogger logger;
27 late TestUsage usage;
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +020028
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +020029 void pretendPodVersionFails() {
Jenn Magderdc303272021-01-29 14:32:33 -080030 fakeProcessManager.addCommand(
31 const FakeCommand(
32 command: <String>['pod', '--version'],
33 exitCode: 1,
34 ),
35 );
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +020036 }
37
38 void pretendPodVersionIs(String versionText) {
Jenn Magderdc303272021-01-29 14:32:33 -080039 fakeProcessManager.addCommand(
40 FakeCommand(
41 command: const <String>['pod', '--version'],
42 stdout: versionText,
43 ),
44 );
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +020045 }
xster6a494192017-07-12 18:35:08 -070046
Dan Field704814c2019-02-05 16:03:37 -080047 void podsIsInHomeDir() {
Jonah Williamse34c5912020-06-23 11:14:38 -070048 fileSystem.directory(fileSystem.path.join(
Zachary Anderson390ed1c2020-02-03 14:33:03 -080049 '.cocoapods',
50 'repos',
51 'master',
52 )).createSync(recursive: true);
Dan Field704814c2019-02-05 16:03:37 -080053 }
54
Jenn Magder8ddc27e2021-03-31 16:55:20 -070055 FlutterProject setupProjectUnderTest() {
56 // This needs to be run within testWithoutContext and not setUp since FlutterProject uses context.
57 final FlutterProject projectUnderTest = FlutterProject.fromDirectory(fileSystem.directory('project'));
58 projectUnderTest.ios.xcodeProject.createSync(recursive: true);
59 projectUnderTest.macos.xcodeProject.createSync(recursive: true);
60 return projectUnderTest;
61 }
62
Mikkel Nygaard Ravnb2800742018-08-02 14:12:25 +020063 setUp(() async {
xster6a494192017-07-12 18:35:08 -070064 Cache.flutterRoot = 'flutter';
Jonah Williamse34c5912020-06-23 11:14:38 -070065 fileSystem = MemoryFileSystem.test();
Jenn Magder56c00022021-04-15 14:19:02 -070066 fakeProcessManager = FakeProcessManager.empty();
Jenn Magder86389be2020-03-25 13:27:10 -070067 logger = BufferLogger.test();
Jonah Williamsb926c7b2021-01-28 12:41:14 -080068 usage = TestUsage();
Jenn Magder86389be2020-03-25 13:27:10 -070069 cocoaPodsUnderTest = CocoaPods(
Jonah Williamse34c5912020-06-23 11:14:38 -070070 fileSystem: fileSystem,
Jenn Magderdc303272021-01-29 14:32:33 -080071 processManager: fakeProcessManager,
Jenn Magder86389be2020-03-25 13:27:10 -070072 logger: logger,
Jenn Magder37f4f1f2020-11-19 13:17:57 -080073 platform: FakePlatform(operatingSystem: 'macos'),
Jenn Magder0cf10072021-03-16 13:53:04 -070074 xcodeProjectInterpreter: FakeXcodeProjectInterpreter(),
Jenn Magder37f4f1f2020-11-19 13:17:57 -080075 usage: usage,
Jenn Magder86389be2020-03-25 13:27:10 -070076 );
Jonah Williamse34c5912020-06-23 11:14:38 -070077 fileSystem.file(fileSystem.path.join(
Jonah Williamsdb829c12022-06-17 21:34:27 -070078 Cache.flutterRoot!, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-ios-objc',
xster6a494192017-07-12 18:35:08 -070079 ))
80 ..createSync(recursive: true)
stuartmorgan3ebebeb2019-05-31 13:19:44 -070081 ..writeAsStringSync('Objective-C iOS podfile template');
Jonah Williamse34c5912020-06-23 11:14:38 -070082 fileSystem.file(fileSystem.path.join(
Jonah Williamsdb829c12022-06-17 21:34:27 -070083 Cache.flutterRoot!, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-ios-swift',
xster6a494192017-07-12 18:35:08 -070084 ))
85 ..createSync(recursive: true)
stuartmorgan3ebebeb2019-05-31 13:19:44 -070086 ..writeAsStringSync('Swift iOS podfile template');
Jonah Williamse34c5912020-06-23 11:14:38 -070087 fileSystem.file(fileSystem.path.join(
Jonah Williamsdb829c12022-06-17 21:34:27 -070088 Cache.flutterRoot!, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-macos',
stuartmorgan3ebebeb2019-05-31 13:19:44 -070089 ))
90 ..createSync(recursive: true)
91 ..writeAsStringSync('macOS podfile template');
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +020092 });
93
Christopher Fujinod1e02732019-08-23 09:21:09 -070094 void pretendPodIsNotInstalled() {
Jenn Magderdc303272021-01-29 14:32:33 -080095 fakeProcessManager.addCommand(
96 const FakeCommand(
97 command: <String>['which', 'pod'],
98 exitCode: 1,
99 ),
100 );
Christopher Fujinod1e02732019-08-23 09:21:09 -0700101 }
102
Christopher Fujino2c846af2020-03-03 17:55:02 -0800103 void pretendPodIsBroken() {
Jenn Magderdc303272021-01-29 14:32:33 -0800104 fakeProcessManager.addCommands(<FakeCommand>[
105 // it is present
106 const FakeCommand(
107 command: <String>['which', 'pod'],
108 ),
109 // but is not working
110 const FakeCommand(
111 command: <String>['pod', '--version'],
112 exitCode: 1,
113 ),
114 ]);
Christopher Fujino2c846af2020-03-03 17:55:02 -0800115 }
116
Christopher Fujinod1e02732019-08-23 09:21:09 -0700117 void pretendPodIsInstalled() {
Jenn Magderdc303272021-01-29 14:32:33 -0800118 fakeProcessManager.addCommands(<FakeCommand>[
119 const FakeCommand(
120 command: <String>['which', 'pod'],
121 ),
122 ]);
Christopher Fujinod1e02732019-08-23 09:21:09 -0700123 }
124
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200125 group('Evaluate installation', () {
Jenn Magder86389be2020-03-25 13:27:10 -0700126 testWithoutContext('detects not installed, if pod exec does not exist', () async {
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200127 pretendPodIsNotInstalled();
128 expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.notInstalled);
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200129 });
130
Jenn Magder86389be2020-03-25 13:27:10 -0700131 testWithoutContext('detects not installed, if pod is installed but version fails', () async {
Christopher Fujinod1e02732019-08-23 09:21:09 -0700132 pretendPodIsInstalled();
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200133 pretendPodVersionFails();
Christopher Fujinod1e02732019-08-23 09:21:09 -0700134 expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.brokenInstall);
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200135 });
136
Jenn Magder86389be2020-03-25 13:27:10 -0700137 testWithoutContext('detects installed', () async {
Christopher Fujinod1e02732019-08-23 09:21:09 -0700138 pretendPodIsInstalled();
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200139 pretendPodVersionIs('0.0.1');
140 expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, isNot(CocoaPodsStatus.notInstalled));
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200141 });
142
Jenn Magder86389be2020-03-25 13:27:10 -0700143 testWithoutContext('detects unknown version', () async {
Christopher Fujinod1e02732019-08-23 09:21:09 -0700144 pretendPodIsInstalled();
KyleWong85ded442019-01-03 11:57:03 +0800145 pretendPodVersionIs('Plugin loaded.\n1.5.3');
146 expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.unknownVersion);
KyleWong85ded442019-01-03 11:57:03 +0800147 });
148
Jenn Magder86389be2020-03-25 13:27:10 -0700149 testWithoutContext('detects below minimum version', () async {
Christopher Fujinod1e02732019-08-23 09:21:09 -0700150 pretendPodIsInstalled();
Jenn Magderbf7a3262022-05-16 17:42:19 -0700151 pretendPodVersionIs('1.9.0');
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200152 expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.belowMinimumVersion);
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200153 });
154
Jenn Magder86389be2020-03-25 13:27:10 -0700155 testWithoutContext('detects below recommended version', () async {
Christopher Fujinod1e02732019-08-23 09:21:09 -0700156 pretendPodIsInstalled();
Jenn Magderbf7a3262022-05-16 17:42:19 -0700157 pretendPodVersionIs('1.10.5');
Jenn Magdera14ac4e2020-03-06 12:14:42 -0800158 expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.belowRecommendedVersion);
Jenn Magdera14ac4e2020-03-06 12:14:42 -0800159 });
160
Jenn Magder86389be2020-03-25 13:27:10 -0700161 testWithoutContext('detects at recommended version', () async {
Jenn Magdera14ac4e2020-03-06 12:14:42 -0800162 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800163 pretendPodVersionIs('1.11.0');
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200164 expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.recommended);
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200165 });
166
Jenn Magder86389be2020-03-25 13:27:10 -0700167 testWithoutContext('detects above recommended version', () async {
Christopher Fujinod1e02732019-08-23 09:21:09 -0700168 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800169 pretendPodVersionIs('1.11.1');
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200170 expect(await cocoaPodsUnderTest.evaluateCocoaPodsInstallation, CocoaPodsStatus.recommended);
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200171 });
xster6a494192017-07-12 18:35:08 -0700172 });
173
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100174 group('Setup Podfile', () {
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700175 testUsingContext('creates objective-c Podfile when not present', () async {
176 final FlutterProject projectUnderTest = setupProjectUnderTest();
Zachary Andersonb7c714e2019-08-28 10:03:53 -0700177 await cocoaPodsUnderTest.setupPodfile(projectUnderTest.ios);
Sigurd Meldgaard6a8f9042018-07-16 16:21:20 +0200178
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700179 expect(projectUnderTest.ios.podfile.readAsStringSync(), 'Objective-C iOS podfile template');
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100180 });
181
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700182 testUsingContext('creates swift Podfile if swift', () async {
183 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jenn Magder0cf10072021-03-16 13:53:04 -0700184 final FakeXcodeProjectInterpreter fakeXcodeProjectInterpreter = FakeXcodeProjectInterpreter(buildSettings: <String, String>{
185 'SWIFT_VERSION': '5.0',
186 });
187 final CocoaPods cocoaPodsUnderTest = CocoaPods(
188 fileSystem: fileSystem,
189 processManager: fakeProcessManager,
190 logger: logger,
191 platform: FakePlatform(operatingSystem: 'macos'),
192 xcodeProjectInterpreter: fakeXcodeProjectInterpreter,
193 usage: usage,
194 );
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100195
Jenn Magder0cf10072021-03-16 13:53:04 -0700196 final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project'));
Zachary Andersonb7c714e2019-08-28 10:03:53 -0700197 await cocoaPodsUnderTest.setupPodfile(project.ios);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100198
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700199 expect(projectUnderTest.ios.podfile.readAsStringSync(), 'Swift iOS podfile template');
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100200 });
201
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700202 testUsingContext('creates macOS Podfile when not present', () async {
203 final FlutterProject projectUnderTest = setupProjectUnderTest();
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700204 projectUnderTest.macos.xcodeProject.createSync(recursive: true);
Zachary Andersonb7c714e2019-08-28 10:03:53 -0700205 await cocoaPodsUnderTest.setupPodfile(projectUnderTest.macos);
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700206
207 expect(projectUnderTest.macos.podfile.readAsStringSync(), 'macOS podfile template');
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700208 });
209
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700210 testUsingContext('does not recreate Podfile when already present', () async {
211 final FlutterProject projectUnderTest = setupProjectUnderTest();
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200212 projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Existing Podfile');
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100213
Jonah Williams04182572021-02-18 12:36:04 -0800214 final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project'));
Zachary Andersonb7c714e2019-08-28 10:03:53 -0700215 await cocoaPodsUnderTest.setupPodfile(project.ios);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100216
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200217 expect(projectUnderTest.ios.podfile.readAsStringSync(), 'Existing Podfile');
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100218 });
219
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700220 testUsingContext('does not create Podfile when we cannot interpret Xcode projects', () async {
221 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jenn Magder0cf10072021-03-16 13:53:04 -0700222 final CocoaPods cocoaPodsUnderTest = CocoaPods(
223 fileSystem: fileSystem,
224 processManager: fakeProcessManager,
225 logger: logger,
226 platform: FakePlatform(operatingSystem: 'macos'),
227 xcodeProjectInterpreter: FakeXcodeProjectInterpreter(isInstalled: false),
228 usage: usage,
229 );
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100230
Jenn Magder0cf10072021-03-16 13:53:04 -0700231 final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project'));
Zachary Andersonb7c714e2019-08-28 10:03:53 -0700232 await cocoaPodsUnderTest.setupPodfile(project.ios);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100233
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200234 expect(projectUnderTest.ios.podfile.existsSync(), false);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100235 });
236
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700237 testUsingContext('includes Pod config in xcconfig files, if not present', () async {
238 final FlutterProject projectUnderTest = setupProjectUnderTest();
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200239 projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Existing Podfile');
240 projectUnderTest.ios.xcodeConfigFor('Debug')
241 ..createSync(recursive: true)
242 ..writeAsStringSync('Existing debug config');
243 projectUnderTest.ios.xcodeConfigFor('Release')
244 ..createSync(recursive: true)
245 ..writeAsStringSync('Existing release config');
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100246
Jenn Magder0cf10072021-03-16 13:53:04 -0700247 final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project'));
Zachary Andersonb7c714e2019-08-28 10:03:53 -0700248 await cocoaPodsUnderTest.setupPodfile(project.ios);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100249
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200250 final String debugContents = projectUnderTest.ios.xcodeConfigFor('Debug').readAsStringSync();
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100251 expect(debugContents, contains(
Jenn Magder68919282021-01-06 13:55:23 -0800252 '#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"\n'));
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100253 expect(debugContents, contains('Existing debug config'));
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200254 final String releaseContents = projectUnderTest.ios.xcodeConfigFor('Release').readAsStringSync();
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100255 expect(releaseContents, contains(
Jenn Magder68919282021-01-06 13:55:23 -0800256 '#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"\n'));
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100257 expect(releaseContents, contains('Existing release config'));
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100258 });
Jenn Magderba5e2372021-02-11 14:11:15 -0800259
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700260 testUsingContext('does not include Pod config in xcconfig files, if legacy non-option include present', () async {
261 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jenn Magderba5e2372021-02-11 14:11:15 -0800262 projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Existing Podfile');
263
264 const String legacyDebugInclude = '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig';
265 projectUnderTest.ios.xcodeConfigFor('Debug')
266 ..createSync(recursive: true)
267 ..writeAsStringSync(legacyDebugInclude);
268 const String legacyReleaseInclude = '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig';
269 projectUnderTest.ios.xcodeConfigFor('Release')
270 ..createSync(recursive: true)
271 ..writeAsStringSync(legacyReleaseInclude);
272
Jenn Magder0cf10072021-03-16 13:53:04 -0700273 final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project'));
Jenn Magderba5e2372021-02-11 14:11:15 -0800274 await cocoaPodsUnderTest.setupPodfile(project.ios);
275
276 final String debugContents = projectUnderTest.ios.xcodeConfigFor('Debug').readAsStringSync();
277 // Redundant contains check, but this documents what we're testing--that the optional
278 // #include? doesn't get written in addition to the previous style #include.
279 expect(debugContents, isNot(contains('#include?')));
280 expect(debugContents, equals(legacyDebugInclude));
281 final String releaseContents = projectUnderTest.ios.xcodeConfigFor('Release').readAsStringSync();
282 expect(releaseContents, isNot(contains('#include?')));
283 expect(releaseContents, equals(legacyReleaseInclude));
Jenn Magderba5e2372021-02-11 14:11:15 -0800284 });
Jenn Magderaff69e42021-10-27 12:53:05 -0700285
286 testUsingContext('does not include Pod config in xcconfig files, if flavor include present', () async {
287 final FlutterProject projectUnderTest = setupProjectUnderTest();
288 projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Existing Podfile');
289
290 const String flavorDebugInclude = '#include? "Pods/Target Support Files/Pods-Free App/Pods-Free App.debug free.xcconfig"';
291 projectUnderTest.ios.xcodeConfigFor('Debug')
292 ..createSync(recursive: true)
293 ..writeAsStringSync(flavorDebugInclude);
294 const String flavorReleaseInclude = '#include? "Pods/Target Support Files/Pods-Free App/Pods-Free App.release free.xcconfig"';
295 projectUnderTest.ios.xcodeConfigFor('Release')
296 ..createSync(recursive: true)
297 ..writeAsStringSync(flavorReleaseInclude);
298
299 final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project'));
300 await cocoaPodsUnderTest.setupPodfile(project.ios);
301
302 final String debugContents = projectUnderTest.ios.xcodeConfigFor('Debug').readAsStringSync();
303 // Redundant contains check, but this documents what we're testing--that the optional
304 // #include? doesn't get written in addition to the previous style #include.
305 expect(debugContents, isNot(contains('Pods-Runner/Pods-Runner.debug')));
306 expect(debugContents, equals(flavorDebugInclude));
307 final String releaseContents = projectUnderTest.ios.xcodeConfigFor('Release').readAsStringSync();
308 expect(releaseContents, isNot(contains('Pods-Runner/Pods-Runner.release')));
309 expect(releaseContents, equals(flavorReleaseInclude));
310 });
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100311 });
312
KyleWong60aa49e2019-01-30 12:33:16 +0800313 group('Update xcconfig', () {
314 testUsingContext('includes Pod config in xcconfig files, if the user manually added Pod dependencies without using Flutter plugins', () async {
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700315 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jenn Magder0cf10072021-03-16 13:53:04 -0700316 fileSystem.file(fileSystem.path.join('project', 'foo', '.packages'))
Jonah Williams5d61bff2020-06-24 10:23:59 -0700317 ..createSync(recursive: true)
318 ..writeAsStringSync('\n');
KyleWong60aa49e2019-01-30 12:33:16 +0800319 projectUnderTest.ios.podfile..createSync()..writeAsStringSync('Custom Podfile');
320 projectUnderTest.ios.podfileLock..createSync()..writeAsStringSync('Podfile.lock from user executed `pod install`');
321 projectUnderTest.packagesFile..createSync()..writeAsStringSync('');
322 projectUnderTest.ios.xcodeConfigFor('Debug')
323 ..createSync(recursive: true)
324 ..writeAsStringSync('Existing debug config');
325 projectUnderTest.ios.xcodeConfigFor('Release')
326 ..createSync(recursive: true)
327 ..writeAsStringSync('Existing release config');
328
Jenn Magder0cf10072021-03-16 13:53:04 -0700329 final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.directory('project'));
Jenn Magder5e17a242020-10-19 14:17:43 -0700330 await injectPlugins(project, iosPlatform: true);
KyleWong60aa49e2019-01-30 12:33:16 +0800331
332 final String debugContents = projectUnderTest.ios.xcodeConfigFor('Debug').readAsStringSync();
333 expect(debugContents, contains(
Jenn Magder68919282021-01-06 13:55:23 -0800334 '#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"\n'));
KyleWong60aa49e2019-01-30 12:33:16 +0800335 expect(debugContents, contains('Existing debug config'));
336 final String releaseContents = projectUnderTest.ios.xcodeConfigFor('Release').readAsStringSync();
337 expect(releaseContents, contains(
Jenn Magder68919282021-01-06 13:55:23 -0800338 '#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"\n'));
KyleWong60aa49e2019-01-30 12:33:16 +0800339 expect(releaseContents, contains('Existing release config'));
340 }, overrides: <Type, Generator>{
Jonah Williamse34c5912020-06-23 11:14:38 -0700341 FileSystem: () => fileSystem,
Jonah Williams4c677e42019-10-22 22:05:00 -0700342 ProcessManager: () => FakeProcessManager.any(),
KyleWong60aa49e2019-01-30 12:33:16 +0800343 });
344 });
345
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100346 group('Process pods', () {
Dan Field704814c2019-02-05 16:03:37 -0800347 setUp(() {
348 podsIsInHomeDir();
349 });
350
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700351 testUsingContext('throwsToolExit if CocoaPods is not installed', () async {
352 final FlutterProject projectUnderTest = setupProjectUnderTest();
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200353 pretendPodIsNotInstalled();
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200354 projectUnderTest.ios.podfile.createSync();
Jenn Magderdc303272021-01-29 14:32:33 -0800355 await expectLater(cocoaPodsUnderTest.processPods(
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700356 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800357 buildMode: BuildMode.debug,
Jenn Magderdc303272021-01-29 14:32:33 -0800358 ), throwsToolExit(message: 'CocoaPods not installed or not in valid state'));
Jenn Magderba764eb2021-04-06 15:54:02 -0700359 expect(fakeProcessManager, hasNoRemainingExpectations);
Jenn Magder5a6d2a02021-03-30 12:42:39 -0700360 expect(fakeProcessManager, hasNoRemainingExpectations);
Christopher Fujino2c846af2020-03-03 17:55:02 -0800361 });
362
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700363 testUsingContext('throwsToolExit if CocoaPods install is broken', () async {
364 final FlutterProject projectUnderTest = setupProjectUnderTest();
Christopher Fujino2c846af2020-03-03 17:55:02 -0800365 pretendPodIsBroken();
366 projectUnderTest.ios.podfile.createSync();
Jenn Magderdc303272021-01-29 14:32:33 -0800367 await expectLater(cocoaPodsUnderTest.processPods(
Christopher Fujino2c846af2020-03-03 17:55:02 -0800368 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800369 buildMode: BuildMode.debug,
Jenn Magderdc303272021-01-29 14:32:33 -0800370 ), throwsToolExit(message: 'CocoaPods not installed or not in valid state'));
Jenn Magderba764eb2021-04-06 15:54:02 -0700371 expect(fakeProcessManager, hasNoRemainingExpectations);
Jenn Magder5a6d2a02021-03-30 12:42:39 -0700372 expect(fakeProcessManager, hasNoRemainingExpectations);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100373 });
374
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700375 testUsingContext('exits if Podfile creates the Flutter engine symlink', () async {
376 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jonah Williamse34c5912020-06-23 11:14:38 -0700377 fileSystem.file(fileSystem.path.join('project', 'ios', 'Podfile'))
Jenn Magder357d02c2019-10-15 15:33:55 -0700378 ..createSync()
379 ..writeAsStringSync('Existing Podfile');
380
381 final Directory symlinks = projectUnderTest.ios.symlinks
382 ..createSync(recursive: true);
383 symlinks.childLink('flutter').createSync('cache');
384
Jenn Magdere26c7f92020-11-18 13:33:04 -0800385 await expectLater(cocoaPodsUnderTest.processPods(
Jenn Magder357d02c2019-10-15 15:33:55 -0700386 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800387 buildMode: BuildMode.debug,
388 ), throwsToolExit(message: 'Podfile is out of date'));
Jenn Magder5a6d2a02021-03-30 12:42:39 -0700389 expect(fakeProcessManager, hasNoRemainingExpectations);
Jenn Magder357d02c2019-10-15 15:33:55 -0700390 });
391
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700392 testUsingContext('exits if iOS Podfile parses .flutter-plugins', () async {
393 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jonah Williamse34c5912020-06-23 11:14:38 -0700394 fileSystem.file(fileSystem.path.join('project', 'ios', 'Podfile'))
Jenn Magder0093c6a2020-06-12 12:44:14 -0700395 ..createSync()
Hattomo (TomohiroHattori)08a70e72021-05-20 01:54:02 +0900396 ..writeAsStringSync("plugin_pods = parse_KV_file('../.flutter-plugins')");
Jenn Magder0093c6a2020-06-12 12:44:14 -0700397
Jenn Magdere26c7f92020-11-18 13:33:04 -0800398 await expectLater(cocoaPodsUnderTest.processPods(
Jenn Magder0093c6a2020-06-12 12:44:14 -0700399 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800400 buildMode: BuildMode.debug,
401 ), throwsToolExit(message: 'Podfile is out of date'));
Jenn Magder5a6d2a02021-03-30 12:42:39 -0700402 expect(fakeProcessManager, hasNoRemainingExpectations);
Jenn Magder0093c6a2020-06-12 12:44:14 -0700403 });
404
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700405 testUsingContext('prints warning if macOS Podfile parses .flutter-plugins', () async {
406 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jenn Magder1c18cf32020-12-17 11:48:16 -0800407 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800408 pretendPodVersionIs('100.0.0');
Jenn Magderba764eb2021-04-06 15:54:02 -0700409 fakeProcessManager.addCommands(const <FakeCommand>[
410 FakeCommand(
Jenn Magderdc303272021-01-29 14:32:33 -0800411 command: <String>['pod', 'install', '--verbose'],
412 ),
Jenn Magderba764eb2021-04-06 15:54:02 -0700413 FakeCommand(
414 command: <String>['touch', 'project/macos/Podfile.lock'],
415 ),
416 ]);
Jenn Magder1c18cf32020-12-17 11:48:16 -0800417
Jenn Magderba764eb2021-04-06 15:54:02 -0700418 projectUnderTest.macos.podfile
Jenn Magder1c18cf32020-12-17 11:48:16 -0800419 ..createSync()
Hattomo (TomohiroHattori)08a70e72021-05-20 01:54:02 +0900420 ..writeAsStringSync("plugin_pods = parse_KV_file('../.flutter-plugins')");
Jenn Magderba764eb2021-04-06 15:54:02 -0700421 projectUnderTest.macos.podfileLock
422 ..createSync()
423 ..writeAsStringSync('Existing lock file.');
Jenn Magder1c18cf32020-12-17 11:48:16 -0800424
425 await cocoaPodsUnderTest.processPods(
426 xcodeProject: projectUnderTest.macos,
427 buildMode: BuildMode.debug,
428 );
429
Greg Spencer52ae1022021-11-10 16:13:04 -0800430 expect(logger.warningText, contains('Warning: Podfile is out of date'));
431 expect(logger.warningText, contains('rm macos/Podfile'));
Jenn Magder5a6d2a02021-03-30 12:42:39 -0700432 expect(fakeProcessManager, hasNoRemainingExpectations);
Jenn Magder1c18cf32020-12-17 11:48:16 -0800433 });
434
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700435 testUsingContext('throws, if Podfile is missing.', () async {
436 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jenn Magderdc303272021-01-29 14:32:33 -0800437 await expectLater(cocoaPodsUnderTest.processPods(
438 xcodeProject: projectUnderTest.ios,
439 buildMode: BuildMode.debug,
440 ), throwsToolExit(message: 'Podfile missing'));
Jenn Magderba764eb2021-04-06 15:54:02 -0700441 expect(fakeProcessManager, hasNoRemainingExpectations);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100442 });
xstere9403812017-11-10 12:41:58 -0800443
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700444 testUsingContext('throws, if specs repo is outdated.', () async {
445 final FlutterProject projectUnderTest = setupProjectUnderTest();
Christopher Fujinod1e02732019-08-23 09:21:09 -0700446 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800447 pretendPodVersionIs('100.0.0');
Jonah Williamse34c5912020-06-23 11:14:38 -0700448 fileSystem.file(fileSystem.path.join('project', 'ios', 'Podfile'))
xstere9403812017-11-10 12:41:58 -0800449 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200450 ..writeAsStringSync('Existing Podfile');
xstere9403812017-11-10 12:41:58 -0800451
Jenn Magderdc303272021-01-29 14:32:33 -0800452 fakeProcessManager.addCommand(
453 const FakeCommand(
454 command: <String>['pod', 'install', '--verbose'],
455 workingDirectory: 'project/ios',
456 environment: <String, String>{
457 'COCOAPODS_DISABLE_STATS': 'true',
458 'LANG': 'en_US.UTF-8',
459 },
460 exitCode: 1,
Ian Hickson6205c112023-02-17 14:27:33 -0800461 // This output is the output that a real CocoaPods install would generate.
Jenn Magderdc303272021-01-29 14:32:33 -0800462 stdout: '''
xstere9403812017-11-10 12:41:58 -0800463[!] Unable to satisfy the following requirements:
464
465- `Firebase/Auth` required by `Podfile`
466- `Firebase/Auth (= 4.0.0)` required by `Podfile.lock`
467
468None of your spec sources contain a spec satisfying the dependencies: `Firebase/Auth, Firebase/Auth (= 4.0.0)`.
469
470You have either:
471 * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
472 * mistyped the name or version.
473 * not added the source repo that hosts the Podspec to your Podfile.
474
475Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.''',
Jenn Magderdc303272021-01-29 14:32:33 -0800476 ),
477 );
478
479 await expectLater(cocoaPodsUnderTest.processPods(
480 xcodeProject: projectUnderTest.ios,
481 buildMode: BuildMode.debug,
482 ), throwsToolExit());
483 expect(
484 logger.errorText,
Ian Hickson6205c112023-02-17 14:27:33 -0800485 contains("CocoaPods's specs repository is too out-of-date to satisfy dependencies"),
Jenn Magderdc303272021-01-29 14:32:33 -0800486 );
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100487 });
xster4d2c2aa2017-12-27 07:30:31 -0800488
Jenn Magderf7bd20f2021-12-07 15:29:03 -0800489 final Map<String, String> possibleErrors = <String, String>{
490 'symbol not found': 'LoadError - dlsym(0x7fbbeb6837d0, Init_ffi_c): symbol not found - /Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle',
491 'incompatible architecture': "LoadError - (mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64')), '/usr/lib/ffi_c.bundle' (no such file) - /Library/Ruby/Gems/2.6.0/gems/ffi-1.15.4/lib/ffi_c.bundle",
Jenn Magderfe11f572022-04-14 14:34:10 -0700492 'bus error': '/Library/Ruby/Gems/2.6.0/gems/ffi-1.15.5/lib/ffi/library.rb:275: [BUG] Bus Error at 0x000000010072c000',
Jenn Magderf7bd20f2021-12-07 15:29:03 -0800493 };
494 possibleErrors.forEach((String errorName, String cocoaPodsError) {
495 testUsingContext('ffi $errorName failure on ARM macOS prompts gem install', () async {
496 final FlutterProject projectUnderTest = setupProjectUnderTest();
497 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800498 pretendPodVersionIs('100.0.0');
Jenn Magderf7bd20f2021-12-07 15:29:03 -0800499 fileSystem.file(fileSystem.path.join('project', 'ios', 'Podfile'))
500 ..createSync()
501 ..writeAsStringSync('Existing Podfile');
Jenn Magder37f4f1f2020-11-19 13:17:57 -0800502
Jenn Magderf7bd20f2021-12-07 15:29:03 -0800503 fakeProcessManager.addCommands(<FakeCommand>[
504 FakeCommand(
505 command: const <String>['pod', 'install', '--verbose'],
506 workingDirectory: 'project/ios',
507 environment: const <String, String>{
508 'COCOAPODS_DISABLE_STATS': 'true',
509 'LANG': 'en_US.UTF-8',
510 },
511 exitCode: 1,
Jenn Magderc9825d22022-04-21 15:49:08 -0700512 stderr: cocoaPodsError,
Jenn Magderf7bd20f2021-12-07 15:29:03 -0800513 ),
514 const FakeCommand(
515 command: <String>['which', 'sysctl'],
516 ),
517 const FakeCommand(
518 command: <String>['sysctl', 'hw.optional.arm64'],
519 stdout: 'hw.optional.arm64: 1',
520 ),
521 ]);
Jenn Magder37f4f1f2020-11-19 13:17:57 -0800522
Jenn Magderf7bd20f2021-12-07 15:29:03 -0800523 await expectToolExitLater(
524 cocoaPodsUnderTest.processPods(
525 xcodeProject: projectUnderTest.ios,
526 buildMode: BuildMode.debug,
527 ),
528 equals('Error running pod install'),
529 );
530 expect(
531 logger.errorText,
532 contains('set up CocoaPods for ARM macOS'),
533 );
Jenn Magder2e1c1462022-05-04 13:24:08 -0700534 expect(
535 logger.errorText,
536 contains('enable-libffi-alloc'),
537 );
Jenn Magderf7bd20f2021-12-07 15:29:03 -0800538 expect(usage.events, contains(const TestUsageEvent('pod-install-failure', 'arm-ffi')));
539 });
Jenn Magder37f4f1f2020-11-19 13:17:57 -0800540 });
541
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700542 testUsingContext('ffi failure on x86 macOS does not prompt gem install', () async {
543 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jenn Magder37f4f1f2020-11-19 13:17:57 -0800544 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800545 pretendPodVersionIs('100.0.0');
Jenn Magder37f4f1f2020-11-19 13:17:57 -0800546 fileSystem.file(fileSystem.path.join('project', 'ios', 'Podfile'))
547 ..createSync()
548 ..writeAsStringSync('Existing Podfile');
549
Jenn Magderdc303272021-01-29 14:32:33 -0800550 fakeProcessManager.addCommands(<FakeCommand>[
551 const FakeCommand(
552 command: <String>['pod', 'install', '--verbose'],
553 workingDirectory: 'project/ios',
554 environment: <String, String>{
555 'COCOAPODS_DISABLE_STATS': 'true',
556 'LANG': 'en_US.UTF-8',
557 },
558 exitCode: 1,
559 stderr: 'LoadError - dlsym(0x7fbbeb6837d0, Init_ffi_c): symbol not found - /Library/Ruby/Gems/2.6.0/gems/ffi-1.13.1/lib/ffi_c.bundle',
560 ),
561 const FakeCommand(
562 command: <String>['which', 'sysctl'],
563 ),
564 const FakeCommand(
565 command: <String>['sysctl', 'hw.optional.arm64'],
566 exitCode: 1,
567 ),
568 ]);
Jenn Magder37f4f1f2020-11-19 13:17:57 -0800569
570 // Capture Usage.test() events.
571 final StringBuffer buffer =
572 await capturedConsolePrint(() => expectToolExitLater(
573 cocoaPodsUnderTest.processPods(
574 xcodeProject: projectUnderTest.ios,
575 buildMode: BuildMode.debug,
576 ),
577 equals('Error running pod install'),
578 ));
579 expect(
580 logger.errorText,
581 isNot(contains('ARM macOS')),
582 );
583 expect(buffer.isEmpty, true);
584 });
585
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700586 testUsingContext('run pod install, if Podfile.lock is missing', () async {
587 final FlutterProject projectUnderTest = setupProjectUnderTest();
Christopher Fujinod1e02732019-08-23 09:21:09 -0700588 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800589 pretendPodVersionIs('100.0.0');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200590 projectUnderTest.ios.podfile
xster4d2c2aa2017-12-27 07:30:31 -0800591 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200592 ..writeAsStringSync('Existing Podfile');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200593 projectUnderTest.ios.podManifestLock
xster4d2c2aa2017-12-27 07:30:31 -0800594 ..createSync(recursive: true)
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200595 ..writeAsStringSync('Existing lock file.');
Jenn Magderdc303272021-01-29 14:32:33 -0800596
Jenn Magderba764eb2021-04-06 15:54:02 -0700597 fakeProcessManager.addCommands(const <FakeCommand>[
598 FakeCommand(
Jenn Magderdc303272021-01-29 14:32:33 -0800599 command: <String>['pod', 'install', '--verbose'],
600 workingDirectory: 'project/ios',
601 environment: <String, String>{'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
602 ),
Jenn Magderba764eb2021-04-06 15:54:02 -0700603 ]);
Chris Brackencdbdafa2018-05-03 19:40:16 -0700604 final bool didInstall = await cocoaPodsUnderTest.processPods(
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700605 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800606 buildMode: BuildMode.debug,
Chris Brackencdbdafa2018-05-03 19:40:16 -0700607 dependenciesChanged: false,
xster4d2c2aa2017-12-27 07:30:31 -0800608 );
Chris Brackencdbdafa2018-05-03 19:40:16 -0700609 expect(didInstall, isTrue);
Jenn Magderba764eb2021-04-06 15:54:02 -0700610 expect(fakeProcessManager, hasNoRemainingExpectations);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100611 });
xster4d2c2aa2017-12-27 07:30:31 -0800612
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700613 testUsingContext('runs iOS pod install, if Manifest.lock is missing', () async {
614 final FlutterProject projectUnderTest = setupProjectUnderTest();
Christopher Fujinod1e02732019-08-23 09:21:09 -0700615 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800616 pretendPodVersionIs('100.0.0');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200617 projectUnderTest.ios.podfile
xster4d2c2aa2017-12-27 07:30:31 -0800618 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200619 ..writeAsStringSync('Existing Podfile');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200620 projectUnderTest.ios.podfileLock
xster4d2c2aa2017-12-27 07:30:31 -0800621 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200622 ..writeAsStringSync('Existing lock file.');
Jenn Magderba764eb2021-04-06 15:54:02 -0700623 fakeProcessManager.addCommands(const <FakeCommand>[
624 FakeCommand(
Jenn Magderdc303272021-01-29 14:32:33 -0800625 command: <String>['pod', 'install', '--verbose'],
626 workingDirectory: 'project/ios',
627 environment: <String, String>{'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
628 ),
Jenn Magderba764eb2021-04-06 15:54:02 -0700629 FakeCommand(
630 command: <String>['touch', 'project/ios/Podfile.lock'],
631 ),
632 ]);
Chris Brackencdbdafa2018-05-03 19:40:16 -0700633 final bool didInstall = await cocoaPodsUnderTest.processPods(
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700634 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800635 buildMode: BuildMode.debug,
Chris Brackencdbdafa2018-05-03 19:40:16 -0700636 dependenciesChanged: false,
Mikkel Nygaard Ravnb3e49762018-02-15 22:17:12 +0100637 );
Chris Brackencdbdafa2018-05-03 19:40:16 -0700638 expect(didInstall, isTrue);
Jenn Magderba764eb2021-04-06 15:54:02 -0700639 expect(fakeProcessManager, hasNoRemainingExpectations);
Jenn Magdere26c7f92020-11-18 13:33:04 -0800640 });
641
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700642 testUsingContext('runs macOS pod install, if Manifest.lock is missing', () async {
643 final FlutterProject projectUnderTest = setupProjectUnderTest();
Jenn Magdere26c7f92020-11-18 13:33:04 -0800644 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800645 pretendPodVersionIs('100.0.0');
Jenn Magdere26c7f92020-11-18 13:33:04 -0800646 projectUnderTest.macos.podfile
647 ..createSync()
648 ..writeAsStringSync('Existing Podfile');
649 projectUnderTest.macos.podfileLock
650 ..createSync()
651 ..writeAsStringSync('Existing lock file.');
Jenn Magderba764eb2021-04-06 15:54:02 -0700652 fakeProcessManager.addCommands(const <FakeCommand>[
653 FakeCommand(
Jenn Magderdc303272021-01-29 14:32:33 -0800654 command: <String>['pod', 'install', '--verbose'],
655 workingDirectory: 'project/macos',
656 environment: <String, String>{'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
657 ),
Jenn Magderba764eb2021-04-06 15:54:02 -0700658 FakeCommand(
659 command: <String>['touch', 'project/macos/Podfile.lock'],
660 ),
661 ]);
Jenn Magdere26c7f92020-11-18 13:33:04 -0800662 final bool didInstall = await cocoaPodsUnderTest.processPods(
663 xcodeProject: projectUnderTest.macos,
664 buildMode: BuildMode.debug,
665 dependenciesChanged: false,
666 );
667 expect(didInstall, isTrue);
Jenn Magderba764eb2021-04-06 15:54:02 -0700668 expect(fakeProcessManager, hasNoRemainingExpectations);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100669 });
670
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700671 testUsingContext('runs pod install, if Manifest.lock different from Podspec.lock', () async {
672 final FlutterProject projectUnderTest = setupProjectUnderTest();
Christopher Fujinod1e02732019-08-23 09:21:09 -0700673 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800674 pretendPodVersionIs('100.0.0');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200675 projectUnderTest.ios.podfile
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100676 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200677 ..writeAsStringSync('Existing Podfile');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200678 projectUnderTest.ios.podfileLock
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100679 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200680 ..writeAsStringSync('Existing lock file.');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200681 projectUnderTest.ios.podManifestLock
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100682 ..createSync(recursive: true)
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200683 ..writeAsStringSync('Different lock file.');
Jenn Magderba764eb2021-04-06 15:54:02 -0700684 fakeProcessManager.addCommands(const <FakeCommand>[
685 FakeCommand(
Jenn Magderdc303272021-01-29 14:32:33 -0800686 command: <String>['pod', 'install', '--verbose'],
687 workingDirectory: 'project/ios',
688 environment: <String, String>{'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
689 ),
Jenn Magderba764eb2021-04-06 15:54:02 -0700690 FakeCommand(
691 command: <String>['touch', 'project/ios/Podfile.lock'],
692 ),
693 ]);
Chris Brackencdbdafa2018-05-03 19:40:16 -0700694 final bool didInstall = await cocoaPodsUnderTest.processPods(
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700695 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800696 buildMode: BuildMode.debug,
Chris Brackencdbdafa2018-05-03 19:40:16 -0700697 dependenciesChanged: false,
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100698 );
Chris Brackencdbdafa2018-05-03 19:40:16 -0700699 expect(didInstall, isTrue);
Jenn Magderba764eb2021-04-06 15:54:02 -0700700 expect(fakeProcessManager, hasNoRemainingExpectations);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100701 });
702
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700703 testUsingContext('runs pod install, if flutter framework changed', () async {
704 final FlutterProject projectUnderTest = setupProjectUnderTest();
Christopher Fujinod1e02732019-08-23 09:21:09 -0700705 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800706 pretendPodVersionIs('100.0.0');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200707 projectUnderTest.ios.podfile
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100708 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200709 ..writeAsStringSync('Existing Podfile');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200710 projectUnderTest.ios.podfileLock
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100711 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200712 ..writeAsStringSync('Existing lock file.');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200713 projectUnderTest.ios.podManifestLock
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100714 ..createSync(recursive: true)
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200715 ..writeAsStringSync('Existing lock file.');
Jenn Magderba764eb2021-04-06 15:54:02 -0700716 fakeProcessManager.addCommands(const <FakeCommand>[
717 FakeCommand(
Jenn Magderdc303272021-01-29 14:32:33 -0800718 command: <String>['pod', 'install', '--verbose'],
719 workingDirectory: 'project/ios',
720 environment: <String, String>{'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
721 ),
Jenn Magderba764eb2021-04-06 15:54:02 -0700722 FakeCommand(
723 command: <String>['touch', 'project/ios/Podfile.lock'],
724 ),
725 ]);
Chris Brackencdbdafa2018-05-03 19:40:16 -0700726 final bool didInstall = await cocoaPodsUnderTest.processPods(
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700727 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800728 buildMode: BuildMode.debug,
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100729 );
Chris Brackencdbdafa2018-05-03 19:40:16 -0700730 expect(didInstall, isTrue);
Jenn Magderba764eb2021-04-06 15:54:02 -0700731 expect(fakeProcessManager, hasNoRemainingExpectations);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100732 });
733
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700734 testUsingContext('runs pod install, if Podfile.lock is older than Podfile', () async {
735 final FlutterProject projectUnderTest = setupProjectUnderTest();
Christopher Fujinod1e02732019-08-23 09:21:09 -0700736 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800737 pretendPodVersionIs('100.0.0');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200738 projectUnderTest.ios.podfile
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200739 ..createSync()
740 ..writeAsStringSync('Existing Podfile');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200741 projectUnderTest.ios.podfileLock
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200742 ..createSync()
743 ..writeAsStringSync('Existing lock file.');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200744 projectUnderTest.ios.podManifestLock
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200745 ..createSync(recursive: true)
746 ..writeAsStringSync('Existing lock file.');
Alexandre Ardhuind927c932018-09-12 08:29:29 +0200747 await Future<void>.delayed(const Duration(milliseconds: 10));
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200748 projectUnderTest.ios.podfile
Alexandre Ardhuinc2ae6542020-03-05 08:03:26 +0100749 .writeAsStringSync('Updated Podfile');
Jenn Magderba764eb2021-04-06 15:54:02 -0700750 fakeProcessManager.addCommands(const <FakeCommand>[
751 FakeCommand(
Jenn Magderdc303272021-01-29 14:32:33 -0800752 command: <String>['pod', 'install', '--verbose'],
753 workingDirectory: 'project/ios',
754 environment: <String, String>{'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
755 ),
Jenn Magderba764eb2021-04-06 15:54:02 -0700756 FakeCommand(
757 command: <String>['touch', 'project/ios/Podfile.lock'],
758 ),
759 ]);
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200760 await cocoaPodsUnderTest.processPods(
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700761 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800762 buildMode: BuildMode.debug,
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200763 dependenciesChanged: false,
764 );
Jenn Magderba764eb2021-04-06 15:54:02 -0700765 expect(fakeProcessManager, hasNoRemainingExpectations);
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200766 });
767
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700768 testUsingContext('skips pod install, if nothing changed', () async {
769 final FlutterProject projectUnderTest = setupProjectUnderTest();
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200770 projectUnderTest.ios.podfile
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100771 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200772 ..writeAsStringSync('Existing Podfile');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200773 projectUnderTest.ios.podfileLock
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100774 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200775 ..writeAsStringSync('Existing lock file.');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200776 projectUnderTest.ios.podManifestLock
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100777 ..createSync(recursive: true)
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200778 ..writeAsStringSync('Existing lock file.');
Chris Brackencdbdafa2018-05-03 19:40:16 -0700779 final bool didInstall = await cocoaPodsUnderTest.processPods(
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700780 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800781 buildMode: BuildMode.debug,
Chris Brackencdbdafa2018-05-03 19:40:16 -0700782 dependenciesChanged: false,
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100783 );
Chris Brackencdbdafa2018-05-03 19:40:16 -0700784 expect(didInstall, isFalse);
Jenn Magderba764eb2021-04-06 15:54:02 -0700785 expect(fakeProcessManager, hasNoRemainingExpectations);
Mikkel Nygaard Ravn20004352018-02-16 10:17:28 +0100786 });
xsterf7f16852018-02-16 16:05:16 -0800787
Jenn Magder8ddc27e2021-03-31 16:55:20 -0700788 testUsingContext('a failed pod install deletes Pods/Manifest.lock', () async {
789 final FlutterProject projectUnderTest = setupProjectUnderTest();
Christopher Fujinod1e02732019-08-23 09:21:09 -0700790 pretendPodIsInstalled();
Jenn Magder320d2cf2022-02-24 12:11:21 -0800791 pretendPodVersionIs('100.0.0');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200792 projectUnderTest.ios.podfile
xsterf7f16852018-02-16 16:05:16 -0800793 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200794 ..writeAsStringSync('Existing Podfile');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200795 projectUnderTest.ios.podfileLock
xsterf7f16852018-02-16 16:05:16 -0800796 ..createSync()
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200797 ..writeAsStringSync('Existing lock file.');
Sigurd Meldgaard2d3a5c72018-07-20 08:00:30 +0200798 projectUnderTest.ios.podManifestLock
xsterf7f16852018-02-16 16:05:16 -0800799 ..createSync(recursive: true)
Mikkel Nygaard Ravn61c71712018-05-08 08:02:39 +0200800 ..writeAsStringSync('Existing lock file.');
Jenn Magderdc303272021-01-29 14:32:33 -0800801 fakeProcessManager.addCommand(
802 const FakeCommand(
803 command: <String>['pod', 'install', '--verbose'],
804 workingDirectory: 'project/ios',
805 environment: <String, String>{'COCOAPODS_DISABLE_STATS': 'true', 'LANG': 'en_US.UTF-8'},
806 exitCode: 1,
807 ),
Matan Lurey81070892018-03-19 11:45:44 -0700808 );
xsterf7f16852018-02-16 16:05:16 -0800809
Jenn Magderdc303272021-01-29 14:32:33 -0800810 await expectLater(cocoaPodsUnderTest.processPods(
stuartmorgan3ebebeb2019-05-31 13:19:44 -0700811 xcodeProject: projectUnderTest.ios,
Jenn Magdere26c7f92020-11-18 13:33:04 -0800812 buildMode: BuildMode.debug,
Jenn Magderdc303272021-01-29 14:32:33 -0800813 ), throwsToolExit(message: 'Error running pod install'));
814 expect(projectUnderTest.ios.podManifestLock.existsSync(), isFalse);
Dan Field704814c2019-02-05 16:03:37 -0800815 });
816 });
xster6a494192017-07-12 18:35:08 -0700817}
818
Jenn Magder0cf10072021-03-16 13:53:04 -0700819class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterpreter {
820 FakeXcodeProjectInterpreter({this.isInstalled = true, this.buildSettings = const <String, String>{}});
821
822 @override
823 final bool isInstalled;
824
825 @override
826 Future<Map<String, String>> getBuildSettings(
827 String projectPath, {
Jonah Williamsdb829c12022-06-17 21:34:27 -0700828 XcodeProjectBuildContext? buildContext,
Jenn Magder0cf10072021-03-16 13:53:04 -0700829 Duration timeout = const Duration(minutes: 1),
830 }) async => buildSettings;
831
832 final Map<String, String> buildSettings;
833}