Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: testing/iossim/iossim.mm

Issue 10805004: Add iossim testing tool for running iOS unit tests. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Set correct revision for class-dump in DEPS Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« testing/iossim/iossim.gyp ('K') | « testing/iossim/iossim.gyp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium 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 <Foundation/Foundation.h>
6 #include <asl.h>
7 #include <libgen.h>
8 #include <stdarg.h>
9 #include <stdio.h>
10
11 // An executable (iossim) that runs an app in the iOS Simulator.
12 // Run 'iossim -h' for usage information.
13 //
14 // For best results, the iOS Simulator application should not be running when
15 // iossim is invoked.
16 //
17 // Headers for the iPhoneSimulatorRemoteClient framework used in this tool are
18 // generated by class-dump, via GYP.
19 // (class-dump is available at http://www.codethecode.com/projects/class-dump/)
20 //
21 // However, there are some forward declarations required to get things to
22 // compile. Also, the DTiPhoneSimulatorSessionDelegate protocol is referenced
23 // by the iPhoneSimulatorRemoteClient framework, but not defined in the object
24 // file, so it must be defined here before we import the generated
stuartmorgan 2012/07/20 07:45:44 s/we import/importing/
lliabraa 2012/07/26 19:14:11 Done.
25 // iPhoneSimulatorRemoteClient.h file.
26
27 @class DTiPhoneSimulatorSession;
28 @class DTiPhoneSimulatorSessionConfig;
29 @class DTiPhoneSimulatorSystemRoot;
30 @class DTiPhoneSimulatorApplicationSpecifier;
stuartmorgan 2012/07/20 07:45:44 Move this up to the top so it's alphabetical.
lliabraa 2012/07/26 19:14:11 Done.
31 @protocol DTiPhoneSimulatorSessionDelegate
stuartmorgan 2012/07/20 07:45:44 Add a blank line before this.
lliabraa 2012/07/26 19:14:11 Done.
32 - (void)session:(DTiPhoneSimulatorSession*)session
33 didEndWithError:(NSError*)error;
34 - (void)session:(DTiPhoneSimulatorSession*)session
35 didStart:(BOOL)started
36 withError:(NSError*)error;
37 @end
38
39 #import "iPhoneSimulatorRemoteClient.h"
40
41 // Name of environment variables that control the user's home directory in the
42 // simulator.
43 #define kUserHomeEnvVariable "CFFIXED_USER_HOME"
44 #define kHomeEnvVariable "HOME"
stuartmorgan 2012/07/20 07:45:44 Let's change these to const char* const, and the o
lliabraa 2012/07/26 19:14:11 Done.
45
46 // Device family codes for iPhone and iPad.
47 #define kIPhoneFamily 1
48 #define kIPadFamily 2
49
50 // Max number of seconds to wait for the simulator session to start.
51 // This timeout must allow time to start up iOS Simulator, install the app
52 // and perform any other black magic that is encoded in the
53 // iPhoneSimulatorRemoteClient framework to kick things off. Normal start up
54 // time is only a couple seconds but machine load, disk caches, etc., can all
55 // affect startup time in the wild so the timeout needs to be fairly generous.
56 // If this timeout occurs iossim will likely exit with non-zero status; the
57 // exception being if the app is invoked and completes execution before the
58 // session is started (this case is handled in session:didStart:withError).
59 #define kSessionStartTimeout 30 // seconds
stuartmorgan 2012/07/20 07:45:44 This one would be const NSTimeInterval I guess (si
lliabraa 2012/07/26 19:14:11 Done.
60
61 // An undocumented system log key included in messages from launchd. The value
62 // is the PID of the process the message is about (as opposed to launchd's PID).
63 #define ASL_KEY_REF_PID "RefPID"
stuartmorgan 2012/07/20 07:45:44 This one we can leave as-is for consistency with t
lliabraa 2012/07/26 19:14:11 Done.
64
65 namespace {
66
67 static const char* gToolName = "iossim";
stuartmorgan 2012/07/20 07:45:44 static is redundant.
lliabraa 2012/07/26 19:14:11 Done.
68
69 void LogError(NSString* format, ...) {
70 va_list list;
71 va_start(list, format);
72
73 NSString* str =
stuartmorgan 2012/07/20 07:45:44 s/str/message/ in these functions
lliabraa 2012/07/26 19:14:11 Done.
74 [[[NSString alloc] initWithFormat:format arguments:list] autorelease];
75
76 fprintf(stderr, "%s: ERROR: %s\n", gToolName, [str UTF8String]);
77 fflush(stderr);
78
79 va_end(list);
80 }
81
82 void LogWarning(NSString* format, ...) {
83 va_list list;
84 va_start(list, format);
85
86 NSString* str =
87 [[[NSString alloc] initWithFormat:format arguments:list] autorelease];
88
89 fprintf(stderr, "%s: WARNING: %s\n", gToolName, [str UTF8String]);
90 fflush(stderr);
91
92 va_end(list);
93 }
94
95 } // namespace
96
97 // A delegate that is called when the simulated app is started or ended in the
98 // simulator.
99 @interface SimulatorDelegate : NSObject <DTiPhoneSimulatorSessionDelegate> {
100 @private
101 NSString* stdioPath_; // weak
stuartmorgan 2012/07/20 07:45:44 Two spaces before // rather than one.
lliabraa 2012/07/26 19:14:11 Done.
102 NSThread* outputThread_;
103 BOOL appRunning_;
104 }
105 @end
106
107 // An implementation that copies the simulated app's stdio to stdout of this
108 // executable. While it would be nice to get stdout and stderr independently
109 // from the Simulator; anything from io buffering to output interleaved
stuartmorgan 2012/07/20 07:45:44 s/;/,/
lliabraa 2012/07/26 19:14:11 Done.
110 // between the two mean they will show up out of onder here. Putting them
stuartmorgan 2012/07/20 07:45:44 s/onder/order/
lliabraa 2012/07/26 19:14:11 Done.
111 // together keeps the order correct. The class should be initialized with the
112 // location of the simulated app's output file. When the simulated app starts,
113 // a thread is started which handles copying data from the simulated app's
114 // output file to the stdout of this executable.
115 @implementation SimulatorDelegate
116
117 // Specifies the file locations of the simulated app's stdout and stderr.
118 - (SimulatorDelegate*)initWithStdioPath:(NSString*)stdioPath {
119 self = [super init];
120 if (self) {
121 stdioPath_ = stdioPath;
stuartmorgan 2012/07/20 07:45:44 The only reason this doesn't eventually crash is t
lliabraa 2012/07/26 19:14:11 Done.
122 }
stuartmorgan 2012/07/20 07:45:44 No {} for the one-line condition
lliabraa 2012/07/26 19:14:11 Done.
123 return self;
124 }
125
126 // Reads data from the simulated app's output and writes it to stdout. This
127 // method blocks, so it should be called in a separate thread. The iOS
128 // Simulator takes a file path for the simulated app's stdout and stderr, but
129 // this path isn't always available (e.g. when the stdout is Xcode's build
130 // window). As a workaround, iossim creates temp file to hold output, which
stuartmorgan 2012/07/20 07:45:44 s/temp file/a temp file/
lliabraa 2012/07/26 19:14:11 Done.
131 // this method reads and copies to stdout.
132 - (void)tailOutput {
133 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
134
135 // Copy data to stdout/stderr while the app is running.
136 NSFileHandle* simio = [NSFileHandle fileHandleForReadingAtPath:stdioPath_];
137 NSFileHandle* standardOutput = [NSFileHandle fileHandleWithStandardOutput];
138 while (appRunning_) {
139 NSAutoreleasePool* innerPool = [[NSAutoreleasePool alloc] init];
140 [standardOutput writeData:[simio readDataToEndOfFile]];
141 [NSThread sleepForTimeInterval:0.1]; // seconds
stuartmorgan 2012/07/20 07:45:44 Remove the // seconds since TimeInterval is always
lliabraa 2012/07/26 19:14:11 Is this a hard convention? I don't see how it hurt
stuartmorgan 2012/07/26 19:47:05 Yes, see https://developer.apple.com/library/mac/#
lliabraa 2012/07/27 13:08:58 I meant is it a hard convention not to document un
142 [innerPool drain];
143 }
144
145 // Once the app is no longer running, copy any data that was written during
146 // the last sleep cycle.
stuartmorgan 2012/07/20 07:45:44 Could we just swap the sleep and the print in the
lliabraa 2012/07/26 19:14:11 I think it is better to leave this final read/writ
147 [standardOutput writeData:[simio readDataToEndOfFile]];
148
149 [pool drain];
150 }
151
152 - (void)session:(DTiPhoneSimulatorSession*)session
153 didStart:(BOOL)started
154 withError:(NSError*)error {
155 if (!started) {
156 // If the test executes very quickly (<30ms), the SimulatorDelegate may not
157 // get the initial session:started:withError: message indicating successful
158 // startup of the simulated app. Instead the delegate will get a
159 // session:started:withError: message after the timeout has elapsed. To
160 // account for this case, check if the simulated app's stdio file was
161 // ever created and if it exists dump it to stdout and return success.
162 NSFileManager* fileManager = [NSFileManager defaultManager];
163 if ([fileManager fileExistsAtPath:stdioPath_ isDirectory:NO]) {
164 appRunning_ = NO;
165 [self tailOutput];
166 // Note that exiting in this state leaves a process running
167 // (i.e. /.../iPhoneSimulator4.3.sdk/usr/libexec/installd -t 30) that will
168 // prevent future simulator sessions from being started for 30 seconds
169 // unless the iOS Simulator application is killed altogether.
170 [self session:session didEndWithError:nil];
171
172 // session:didEndWithError should not return (because it exits) so
173 // the execution path should never get here.
174 exit(EXIT_FAILURE);
175 }
176
177 LogError(@"Simulator failed to start: %@", [error localizedDescription]);
178 exit(EXIT_FAILURE);
179 }
180
181 // Start a thread to write contents of outputPath to stdout.
182 appRunning_ = YES;
183 outputThread_ = [[NSThread alloc] initWithTarget:self
184 selector:@selector(tailOutput)
185 object:nil];
186 [outputThread_ start];
187 }
188
189 - (void)session:(DTiPhoneSimulatorSession*)session
190 didEndWithError:(NSError*)error {
191 appRunning_ = NO;
192 // Wait for the output thread to finish copying data to stdout.
193 if (outputThread_) {
194 while (![outputThread_ isFinished]) {
195 [NSThread sleepForTimeInterval:0.1]; // seconds
stuartmorgan 2012/07/20 07:45:44 Remove the comment.
lliabraa 2012/07/26 19:14:11 See above.
196 }
197 [outputThread_ release];
198 outputThread_ = nil;
199 }
200
201 if (error) {
202 LogError(@"Simulator ended with error: %@", [error localizedDescription]);
203 exit(EXIT_FAILURE);
204 }
205
206 // Check if the simulated app exited abnormally by looking for system log
207 // messages from launchd that refer to the simulated app's PID. Limit query
208 // to messages in the last minute since PIDs are cyclical.
209 aslmsg query = asl_new(ASL_TYPE_QUERY);
210 asl_set_query(query, ASL_KEY_SENDER, "launchd",
211 ASL_QUERY_OP_EQUAL | ASL_QUERY_OP_SUBSTRING);
212 asl_set_query(query, ASL_KEY_REF_PID,
213 [[[session simulatedApplicationPID] stringValue] UTF8String],
214 ASL_QUERY_OP_EQUAL);
215 asl_set_query(query, ASL_KEY_TIME, "-1m", ASL_QUERY_OP_GREATER_EQUAL);
216
217 // Log any messages found.
218 aslresponse response = asl_search(NULL, query);
219 BOOL entryFound = NO;
220 aslmsg entry;
221 while ((entry = aslresponse_next(response)) != NULL) {
222 entryFound = YES;
223 LogWarning(@"Console message: %s", asl_get(entry, ASL_KEY_MSG));
224 }
225
226 // launchd only sends messages if the process crashed or exits with a
227 // non-zero status, so if the query returned any results iossim should exit
228 // with non-zero status.
229 if (entryFound) {
230 LogError(@"Simulated app crashed or exited with non-zero status");
231 exit(EXIT_FAILURE);
232 }
233 exit(EXIT_SUCCESS);
234 }
235 @end
236
237 namespace {
238
239 // Converts the given app path to an application spec, which requires an
240 // absolute path.
241 DTiPhoneSimulatorApplicationSpecifier* BuildAppSpec(NSString* appPath) {
242 if (![appPath isAbsolutePath]) {
243 NSString* cwd = [[NSFileManager defaultManager] currentDirectoryPath];
244 appPath = [cwd stringByAppendingPathComponent:appPath];
245 }
246 appPath = [appPath stringByStandardizingPath];
247 return [DTiPhoneSimulatorApplicationSpecifier
248 specifierWithApplicationPath:appPath];
249 }
250
251 // Returns the system root for the given SDK version. If sdkVersion is nil, the
252 // default system root is returned. Will return nil if the sdkVersion is not
253 // valid.
254 DTiPhoneSimulatorSystemRoot* BuildSystemRoot(NSString* sdkVersion) {
255 DTiPhoneSimulatorSystemRoot* systemRoot =
256 [DTiPhoneSimulatorSystemRoot defaultRoot];
257 if (sdkVersion) {
258 systemRoot = [DTiPhoneSimulatorSystemRoot rootWithSDKVersion:sdkVersion];
259 }
stuartmorgan 2012/07/20 07:45:44 No {}
lliabraa 2012/07/26 19:14:11 Done.
260 return systemRoot;
261 }
262
263 // Builds a config object for starting the specified app.
264 DTiPhoneSimulatorSessionConfig* BuildSessionConfig(
265 DTiPhoneSimulatorApplicationSpecifier* appSpec,
266 DTiPhoneSimulatorSystemRoot* systemRoot,
267 NSString* stdoutPath,
268 NSString* stderrPath,
269 NSArray* appArgs,
270 NSNumber* deviceFamily) {
271 DTiPhoneSimulatorSessionConfig* sessionConfig =
272 [[[DTiPhoneSimulatorSessionConfig alloc] init] autorelease];
273 sessionConfig.applicationToSimulateOnStart = appSpec;
274 sessionConfig.simulatedSystemRoot = systemRoot;
275 sessionConfig.localizedClientName = @"chromium";
276 sessionConfig.simulatedApplicationStdErrPath = stderrPath;
277 sessionConfig.simulatedApplicationStdOutPath = stdoutPath;
278 sessionConfig.simulatedApplicationLaunchArgs = appArgs;
279 // Note: This environment doesn't work for setting the app's user home
280 // directory via CFFIXED_USER_HOME. Instead the user home directory is set via
281 // the environment that the simuator runs in.
282 // sessionConfig.simulatedApplicationLaunchEnvironment =
283 // [NSDictionary dictionary];
stuartmorgan 2012/07/20 07:45:44 If this doesn't work, let's not leave the code her
lliabraa 2012/07/26 19:14:11 I changed this to a more generic TODO for supporti
284 sessionConfig.simulatedDeviceFamily = deviceFamily;
285 return sessionConfig;
286 }
287
288 // Builds a simulator session that will use the given delegate.
289 DTiPhoneSimulatorSession* BuildSession(SimulatorDelegate* delegate) {
290 DTiPhoneSimulatorSession* session =
291 [[[DTiPhoneSimulatorSession alloc] init] autorelease];
292 session.delegate = delegate;
293 return session;
294 }
295
296 // Creates a temporary directory with a unique name based on the provided
297 // template. The template should not contain any path separators and be suffixed
298 // with X's, which will be substituted with a unique alphanumeric string (see
299 // 'man mkdtemp' for details). The directory will be created as a subdirectory
300 // of NSTemporaryDirectory(). For example, if dirNameTemplate is 'test-XXX',
301 // this method would return something like '/path/to/tempdir/test-3n2'.
302 //
303 // Returns the absolute path of the newly-created directory, or nill if unable
304 // to create a unique directory.
305 NSString* CreateTempDirectory(NSString* dirNameTemplate) {
306 NSString* fullPathTemplate = [NSTemporaryDirectory()
307 stringByAppendingPathComponent:dirNameTemplate];
stuartmorgan 2012/07/20 07:45:44 Just indent 4 from the start of the previous line.
lliabraa 2012/07/26 19:14:11 I've changed the formatting to put the entire call
stuartmorgan 2012/07/26 19:47:05 Nope, both are fine. I tend toward what you did as
lliabraa 2012/07/27 13:08:58 Ack.
308 char* fullPath = mkdtemp(const_cast<char*>([fullPathTemplate UTF8String]));
309 if (fullPath == NULL) {
310 return nil;
311 }
stuartmorgan 2012/07/20 07:45:44 No {}
lliabraa 2012/07/26 19:14:11 Done.
312 return [NSString stringWithUTF8String:fullPath];
313 }
314
315 // Creates the necessary directory structure under the given user home directory
316 // path.
317 // Returns YES if successful, NO if unable to create the directories.
318 BOOL CreateHomeDirSubDirs(NSString* userHomePath) {
319 NSFileManager* fileManager = [NSFileManager defaultManager];
320
321 // Create user home and subdirectories.
322 NSArray* subDirsToCreate = [NSArray arrayWithObjects:
323 @"Documents",
324 @"Library/Caches",
325 nil];
326 for (NSString* subDir in subDirsToCreate) {
327 NSString* path = [userHomePath stringByAppendingPathComponent:subDir];
328 NSError* error;
329 if (![fileManager createDirectoryAtPath:path
330 withIntermediateDirectories:YES
331 attributes:nil
332 error:&error]) {
333 LogError(@"Unable to create directory: %@. Error: %@",
334 path, [error localizedDescription]);
335 return NO;
336 }
337 }
338
339 return YES;
340 }
341
342 // Creates the necessary directory structure under the given user home directory
343 // path, then sets the path in the appropriate environment variable.
344 // Returns YES if successful, NO if unable to create or initialize the given
345 // directory.
346 BOOL InitializeSimulatorUserHome(NSString* userHomePath) {
347 if (!CreateHomeDirSubDirs(userHomePath)) {
348 return NO;
349 }
stuartmorgan 2012/07/20 07:45:44 No {}
lliabraa 2012/07/26 19:14:11 Done.
350
351 // Update the environment to use the specified directory as the user home
352 // directory.
353 // Note: the third param of setenv specifies whether or not to overwrite the
354 // variable's value if it has already been set.
355 if ((setenv(kUserHomeEnvVariable, [userHomePath UTF8String], YES) == -1) ||
356 (setenv(kHomeEnvVariable, [userHomePath UTF8String], YES) == -1)) {
357 LogError(@"Unable to set %s environment variables.");
stuartmorgan 2012/07/20 07:45:44 This will crash if it's ever reached; there's no a
lliabraa 2012/07/26 19:14:11 Done.
358 return NO;
359 }
360
361 return YES;
362 }
363
364 // Prints the usage information to stderr.
365 void PrintUsage() {
366 fprintf(stderr, "Usage: iossim [-d device] [-s sdkVersion] [-u homeDir] "
367 "<appPath> [<appArgs>]\n");
368 fprintf(stderr, " where <appPath> is the path to the .app directory and "
stuartmorgan 2012/07/20 07:45:44 Why all the separate fprintf statements instead of
lliabraa 2012/07/26 19:14:11 No idea. Changed to string continuations
369 "appArgs are any arguments to send the simulated app.\n");
370 fprintf(stderr, "\n");
371 fprintf(stderr, "Options:\n");
372 fprintf(stderr, " -d Specifies the device (either 'iPhone' or 'iPad')."
373 " Defaults to 'iPhone'.\n");
374 fprintf(stderr, " -s Specifies the SDK version to use (e.g '4.3')."
375 " Will use system default if not specified.\n");
376 fprintf(stderr, " -u Specifies a user home directory for the simulator."
377 " Will create a new directory if not specified.\n");
378 }
379
380 } // namespace
stuartmorgan 2012/07/20 07:45:44 One more space before //
lliabraa 2012/07/26 19:14:11 Done.
381
382
383 int main(int argc, char* const argv[]) {
384 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
385
386 char* toolName = basename(argv[0]);
387 if (toolName != NULL)
388 gToolName = toolName;
389
390 NSString* appPath = nil;
391 NSString* appName = nil;
392 NSString* sdkVersion = nil;
393 NSString* deviceName = @"iPhone";
394 NSString* simHomePath = nil;
395 NSMutableArray* appArgs = [NSMutableArray array];
396
397 // Parse the optional arguments
398 int c;
399 while ((c = getopt(argc, argv, "hs:d:u:")) != -1) {
400 switch (c) {
401 case 's':
402 sdkVersion = [NSString stringWithUTF8String:optarg];
403 break;
404 case 'd':
405 deviceName = [NSString stringWithUTF8String:optarg];
406 break;
407 case 'u':
408 simHomePath = [NSString stringWithUTF8String:optarg];
stuartmorgan 2012/07/20 07:45:44 This should be using NSFileManager's stringWithFil
lliabraa 2012/07/26 19:14:11 Done.
409 break;
410 case 'h':
411 PrintUsage();
412 exit(EXIT_SUCCESS);
413 default:
414 PrintUsage();
415 exit(EXIT_FAILURE);
416 }
417 }
418
419 // There should be at least one arg left, specifying the app path. Any
420 // additional args are passed as arguments to the app.
421 if (optind < argc) {
422 appPath = [NSString stringWithUTF8String:argv[optind++]];
stuartmorgan 2012/07/20 07:45:44 As should this.
lliabraa 2012/07/26 19:14:11 Done.
423 appName = [appPath lastPathComponent];
424 while (optind < argc) {
425 [appArgs addObject:[NSString stringWithUTF8String:argv[optind++]]];
426 }
427 } else {
428 LogError(@"Unable to parse command line arguments.");
429 PrintUsage();
430 exit(EXIT_FAILURE);
431 }
432
433 // Make sure the app path provided is legit.
434 DTiPhoneSimulatorApplicationSpecifier* appSpec = BuildAppSpec(appPath);
435 if (!appSpec) {
436 LogError(@"Invalid app path: %@", appPath);
437 exit(EXIT_FAILURE);
438 }
439
440 // Make sure the SDK path provided is legit (or nil).
441 DTiPhoneSimulatorSystemRoot* systemRoot = BuildSystemRoot(sdkVersion);
442 if (!systemRoot) {
443 LogError(@"Invalid SDK version: %@", sdkVersion);
444 exit(EXIT_FAILURE);
445 }
446
447 // Get the paths for stdout and stderr so the simulated app's output will show
448 // up in the caller's stdout/stderr.
449 NSString* outputDir = CreateTempDirectory(@"iossim-XXXXXX");
450 NSString* stdioPath = [outputDir stringByAppendingPathComponent:@"stdio.txt"];
451
452 // Make sure the device name is legit.
453 NSNumber* deviceFamily = nil;
454 if (!deviceName ||
455 [@"iPhone" caseInsensitiveCompare:deviceName] == NSOrderedSame) {
456 deviceFamily = [NSNumber numberWithInt:kIPhoneFamily];
457 } else if ([@"iPad" caseInsensitiveCompare:deviceName] == NSOrderedSame) {
458 deviceFamily = [NSNumber numberWithInt:kIPadFamily];
459 } else {
460 LogError(@"Invalid device name: %@", deviceName);
461 exit(EXIT_FAILURE);
462 }
463
464 // Set up the user home directory for the simulator
465 if (!simHomePath) {
466 NSString* dirNameTemplate =
467 [NSString stringWithFormat:@"iossim-%@-%@-XXXXXX", appName, deviceName];
468 simHomePath = CreateTempDirectory(dirNameTemplate);
469 if (!simHomePath) {
470 LogError(@"Unable to create unique directory for template %@",
471 dirNameTemplate);
stuartmorgan 2012/07/20 07:45:44 Indent 1 more
lliabraa 2012/07/26 19:14:11 Done.
472 exit(EXIT_FAILURE);
473 }
474 }
475 if (!InitializeSimulatorUserHome(simHomePath)) {
476 LogError(@"Unable to initialize home directory for simulator: %@",
477 simHomePath);
stuartmorgan 2012/07/20 07:45:44 Indent 1 more
lliabraa 2012/07/26 19:14:11 Done.
478 exit(EXIT_FAILURE);
479 }
480
481 // Create the config and simulator session.
482 DTiPhoneSimulatorSessionConfig* config = BuildSessionConfig(appSpec,
483 systemRoot,
484 stdioPath,
485 stdioPath,
486 appArgs,
487 deviceFamily);
488 SimulatorDelegate* delegate =
489 [[[SimulatorDelegate alloc] initWithStdioPath:stdioPath] autorelease];
490 DTiPhoneSimulatorSession* session = BuildSession(delegate);
491
492 // Start the simulator session.
493 NSError* error;
494 BOOL started = [session requestStartWithConfig:config
495 timeout:kSessionStartTimeout
496 error:&error];
497
498 // Spin the runtime indefinitely. When the delegate gets the message that the
499 // app has quit it will exit this program.
500 if (started) {
501 [[NSRunLoop mainRunLoop] run];
502 } else {
503 LogError(@"Simulator failed to start: %@", [error localizedDescription]);
504 }
stuartmorgan 2012/07/20 07:45:44 Remove {}s on both
lliabraa 2012/07/26 19:14:11 Done.
505
506 // Note that this code is only executed if the simulator fails to start
507 // because once the main run loop is started, only the delegate calling
508 // exit() will end the program.
509 [pool drain];
510 return EXIT_FAILURE;
511 }
OLDNEW
« testing/iossim/iossim.gyp ('K') | « testing/iossim/iossim.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698