1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | import 'package:flutter_tools/src/base/error_handling_io.dart'; |
6 | import 'package:flutter_tools/src/base/file_system.dart'; |
7 | import 'package:flutter_tools/src/base/io.dart'; |
8 | |
9 | import '../src/common.dart'; |
10 | import 'test_utils.dart'; |
11 | |
12 | void main() { |
13 | const customLLDBInitFileSchemeSetting = |
14 | r'customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"' ; |
15 | test( |
16 | 'Ensure lldb is added to Xcode project' , |
17 | () async { |
18 | final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync( |
19 | 'lldb_test.' , |
20 | ); |
21 | try { |
22 | final String workingDirectoryPath = workingDirectory.path; |
23 | const appName = 'lldb_test' ; |
24 | |
25 | final ProcessResult createResult = await processManager.run(<String>[ |
26 | flutterBin, |
27 | ...getLocalEngineArguments(), |
28 | 'create' , |
29 | '--org' , |
30 | 'io.flutter.devicelab' , |
31 | appName, |
32 | '--platforms=ios' , |
33 | ], workingDirectory: workingDirectory.path); |
34 | expect( |
35 | createResult.exitCode, |
36 | 0, |
37 | reason: |
38 | 'Failed to create app: \n' |
39 | 'stdout: \n ${createResult.stdout}\n' |
40 | 'stderr: \n ${createResult.stderr}\n' , |
41 | ); |
42 | |
43 | final String appDirectoryPath = fileSystem.path.join(workingDirectoryPath, appName); |
44 | |
45 | final File schemeFile = fileSystem |
46 | .directory(appDirectoryPath) |
47 | .childDirectory('ios' ) |
48 | .childDirectory('Runner.xcodeproj' ) |
49 | .childDirectory('xcshareddata' ) |
50 | .childDirectory('xcschemes' ) |
51 | .childFile('Runner.xcscheme' ); |
52 | expect(schemeFile.existsSync(), isTrue); |
53 | |
54 | // Remove customLLDBInitFile from the scheme so we can validate it |
55 | // gets re-added if missing. |
56 | expect(schemeFile.readAsStringSync(), contains(customLLDBInitFileSchemeSetting)); |
57 | schemeFile.writeAsStringSync( |
58 | schemeFile.readAsStringSync().replaceAll(customLLDBInitFileSchemeSetting, '' ), |
59 | ); |
60 | |
61 | final File lldbInitFile = fileSystem |
62 | .directory(appDirectoryPath) |
63 | .childDirectory('ios' ) |
64 | .childDirectory('Flutter' ) |
65 | .childDirectory('ephemeral' ) |
66 | .childFile('flutter_lldbinit' ); |
67 | expect(lldbInitFile.existsSync(), isTrue); |
68 | |
69 | final File lldbPythonFile = fileSystem |
70 | .directory(appDirectoryPath) |
71 | .childDirectory('ios' ) |
72 | .childDirectory('Flutter' ) |
73 | .childDirectory('ephemeral' ) |
74 | .childFile('flutter_lldb_helper.py' ); |
75 | expect(lldbPythonFile.existsSync(), isTrue); |
76 | |
77 | // Delete LLDB files so we can verify they get re-added if missing. |
78 | lldbInitFile.deleteSync(); |
79 | lldbPythonFile.deleteSync(); |
80 | |
81 | final ProcessResult buildResult = await processManager.run(<String>[ |
82 | flutterBin, |
83 | ...getLocalEngineArguments(), |
84 | 'build' , |
85 | 'ios' , |
86 | ], workingDirectory: appDirectoryPath); |
87 | expect( |
88 | buildResult.exitCode, |
89 | 0, |
90 | reason: |
91 | 'Failed to build the app: \n' |
92 | 'stdout: \n ${buildResult.stdout}\n' |
93 | 'stderr: \n ${buildResult.stderr}\n' , |
94 | ); |
95 | |
96 | expect(schemeFile.readAsStringSync(), contains(customLLDBInitFileSchemeSetting)); |
97 | expect(lldbInitFile.existsSync(), isTrue); |
98 | expect(lldbPythonFile.existsSync(), isTrue); |
99 | } finally { |
100 | ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true); |
101 | } |
102 | }, |
103 | skip: !platform.isMacOS, // [intended] Can only build on macOS. |
104 | ); |
105 | |
106 | test( |
107 | 'Ensure lldb is added to Xcode project when using flavor' , |
108 | () async { |
109 | final Directory workingDirectory = fileSystem.systemTempDirectory.createTempSync( |
110 | 'lldb_test.' , |
111 | ); |
112 | try { |
113 | final String workingDirectoryPath = workingDirectory.path; |
114 | const appName = 'lldb_test' ; |
115 | const flavor = 'vanilla' ; |
116 | |
117 | final ProcessResult createResult = await processManager.run(<String>[ |
118 | flutterBin, |
119 | ...getLocalEngineArguments(), |
120 | 'create' , |
121 | '--org' , |
122 | 'io.flutter.devicelab' , |
123 | appName, |
124 | '--platforms=ios' , |
125 | ], workingDirectory: workingDirectory.path); |
126 | expect( |
127 | createResult.exitCode, |
128 | 0, |
129 | reason: |
130 | 'Failed to create app: \n' |
131 | 'stdout: \n ${createResult.stdout}\n' |
132 | 'stderr: \n ${createResult.stderr}\n' , |
133 | ); |
134 | |
135 | final String appDirectoryPath = fileSystem.path.join(workingDirectoryPath, appName); |
136 | final File schemeFile = fileSystem |
137 | .directory(appDirectoryPath) |
138 | .childDirectory('ios' ) |
139 | .childDirectory('Runner.xcodeproj' ) |
140 | .childDirectory('xcshareddata' ) |
141 | .childDirectory('xcschemes' ) |
142 | .childFile('Runner.xcscheme' ); |
143 | expect(schemeFile.existsSync(), isTrue); |
144 | |
145 | final File pbxprojFile = fileSystem |
146 | .directory(appDirectoryPath) |
147 | .childDirectory('ios' ) |
148 | .childDirectory('Runner.xcodeproj' ) |
149 | .childFile('project.pbxproj' ); |
150 | expect(pbxprojFile.existsSync(), isTrue); |
151 | |
152 | // Create flavor |
153 | final File flavorSchemeFile = fileSystem |
154 | .directory(appDirectoryPath) |
155 | .childDirectory('ios' ) |
156 | .childDirectory('Runner.xcodeproj' ) |
157 | .childDirectory('xcshareddata' ) |
158 | .childDirectory('xcschemes' ) |
159 | .childFile(' $flavor.xcscheme' ); |
160 | flavorSchemeFile.createSync(recursive: true); |
161 | flavorSchemeFile.writeAsStringSync(schemeFile.readAsStringSync()); |
162 | |
163 | String pbxprojContents = pbxprojFile.readAsStringSync(); |
164 | pbxprojContents = pbxprojContents.replaceAll('97C147071CF9000F007C117D /* Release */,' , ''' |
165 | 97C147071CF9000F007C117D /* Release */, |
166 | 78624EC12D71262400FF7985 /* Release-vanilla */, |
167 | ''' ); |
168 | pbxprojContents = pbxprojContents.replaceAll('97C147041CF9000F007C117D /* Release */,' , ''' |
169 | 97C147041CF9000F007C117D /* Release */, |
170 | 78624EC02D71262400FF7985 /* Release-vanilla */, |
171 | ''' ); |
172 | |
173 | pbxprojContents = pbxprojContents.replaceAll( |
174 | '/* Begin XCBuildConfiguration section */' , |
175 | r''' |
176 | /* Begin XCBuildConfiguration section */ |
177 | 78624EC12D71262400FF7985 /* Release-vanilla */ = { |
178 | isa = XCBuildConfiguration; |
179 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; |
180 | buildSettings = { |
181 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
182 | CLANG_ENABLE_MODULES = YES; |
183 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; |
184 | ENABLE_BITCODE = NO; |
185 | INFOPLIST_FILE = Runner/Info.plist; |
186 | LD_RUNPATH_SEARCH_PATHS = ( |
187 | "$(inherited)", |
188 | "@executable_path/Frameworks", |
189 | ); |
190 | PRODUCT_BUNDLE_IDENTIFIER = com.example.lldb_test; |
191 | PRODUCT_NAME = "$(TARGET_NAME)"; |
192 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; |
193 | SWIFT_VERSION = 5.0; |
194 | VERSIONING_SYSTEM = "apple-generic"; |
195 | }; |
196 | name = "Release-vanilla"; |
197 | }; |
198 | 78624EC02D71262400FF7985 /* Release-vanilla */ = { |
199 | isa = XCBuildConfiguration; |
200 | buildSettings = { |
201 | ALWAYS_SEARCH_USER_PATHS = NO; |
202 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; |
203 | CLANG_ANALYZER_NONNULL = YES; |
204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; |
205 | CLANG_CXX_LIBRARY = "libc++"; |
206 | CLANG_ENABLE_MODULES = YES; |
207 | CLANG_ENABLE_OBJC_ARC = YES; |
208 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; |
209 | CLANG_WARN_BOOL_CONVERSION = YES; |
210 | CLANG_WARN_COMMA = YES; |
211 | CLANG_WARN_CONSTANT_CONVERSION = YES; |
212 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; |
213 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; |
214 | CLANG_WARN_EMPTY_BODY = YES; |
215 | CLANG_WARN_ENUM_CONVERSION = YES; |
216 | CLANG_WARN_INFINITE_RECURSION = YES; |
217 | CLANG_WARN_INT_CONVERSION = YES; |
218 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; |
219 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; |
220 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; |
221 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; |
222 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; |
223 | CLANG_WARN_STRICT_PROTOTYPES = YES; |
224 | CLANG_WARN_SUSPICIOUS_MOVE = YES; |
225 | CLANG_WARN_UNREACHABLE_CODE = YES; |
226 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; |
227 | COPY_PHASE_STRIP = NO; |
228 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; |
229 | ENABLE_NS_ASSERTIONS = NO; |
230 | ENABLE_STRICT_OBJC_MSGSEND = YES; |
231 | ENABLE_USER_SCRIPT_SANDBOXING = NO; |
232 | GCC_C_LANGUAGE_STANDARD = gnu99; |
233 | GCC_NO_COMMON_BLOCKS = YES; |
234 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; |
235 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; |
236 | GCC_WARN_UNDECLARED_SELECTOR = YES; |
237 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
238 | GCC_WARN_UNUSED_FUNCTION = YES; |
239 | GCC_WARN_UNUSED_VARIABLE = YES; |
240 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; |
241 | MTL_ENABLE_DEBUG_INFO = NO; |
242 | SDKROOT = iphoneos; |
243 | SUPPORTED_PLATFORMS = iphoneos; |
244 | SWIFT_COMPILATION_MODE = wholemodule; |
245 | SWIFT_OPTIMIZATION_LEVEL = "-O"; |
246 | TARGETED_DEVICE_FAMILY = "1,2"; |
247 | VALIDATE_PRODUCT = YES; |
248 | }; |
249 | name = "Release-vanilla"; |
250 | }; |
251 | ''' , |
252 | ); |
253 | pbxprojFile.writeAsStringSync(pbxprojContents); |
254 | |
255 | // Remove customLLDBInitFile from the flavor's scheme so we can validate |
256 | // it gets re-added later. |
257 | expect(flavorSchemeFile.readAsStringSync(), contains(customLLDBInitFileSchemeSetting)); |
258 | flavorSchemeFile.writeAsStringSync( |
259 | flavorSchemeFile.readAsStringSync().replaceAll(customLLDBInitFileSchemeSetting, '' ), |
260 | ); |
261 | |
262 | final ProcessResult buildResult = await processManager.run(<String>[ |
263 | flutterBin, |
264 | ...getLocalEngineArguments(), |
265 | 'build' , |
266 | 'ios' , |
267 | '--config-only' , |
268 | '--flavor' , |
269 | flavor, |
270 | ], workingDirectory: appDirectoryPath); |
271 | expect( |
272 | buildResult.exitCode, |
273 | 0, |
274 | reason: |
275 | 'Failed to build config for the app: \n' |
276 | 'stdout: \n ${buildResult.stdout}\n' |
277 | 'stderr: \n ${buildResult.stderr}\n' , |
278 | ); |
279 | |
280 | expect(flavorSchemeFile.readAsStringSync(), contains(customLLDBInitFileSchemeSetting)); |
281 | |
282 | final File lldbInitFile = fileSystem |
283 | .directory(appDirectoryPath) |
284 | .childDirectory('ios' ) |
285 | .childDirectory('Flutter' ) |
286 | .childDirectory('ephemeral' ) |
287 | .childFile('flutter_lldbinit' ); |
288 | expect(lldbInitFile.existsSync(), isTrue); |
289 | |
290 | final File lldbPythonFile = fileSystem |
291 | .directory(appDirectoryPath) |
292 | .childDirectory('ios' ) |
293 | .childDirectory('Flutter' ) |
294 | .childDirectory('ephemeral' ) |
295 | .childFile('flutter_lldb_helper.py' ); |
296 | expect(lldbPythonFile.existsSync(), isTrue); |
297 | } finally { |
298 | ErrorHandlingFileSystem.deleteIfExists(workingDirectory, recursive: true); |
299 | } |
300 | }, |
301 | skip: !platform.isMacOS, // [intended] Can only build on macOS. |
302 | ); |
303 | } |
304 | |