1*6777b538SAndroid Build Coastguard Worker// Copyright 2012 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker// found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker#import <Foundation/Foundation.h> 6*6777b538SAndroid Build Coastguard Worker#include <getopt.h> 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker#include <string> 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard Workernamespace { 11*6777b538SAndroid Build Coastguard Worker 12*6777b538SAndroid Build Coastguard Workervoid PrintUsage() { 13*6777b538SAndroid Build Coastguard Worker fprintf( 14*6777b538SAndroid Build Coastguard Worker stderr, 15*6777b538SAndroid Build Coastguard Worker "Usage: iossim [-d device] [-s sdk_version] <app_path> <xctest_path>\n" 16*6777b538SAndroid Build Coastguard Worker " where <app_path> is the path to the .app directory and <xctest_path> " 17*6777b538SAndroid Build Coastguard Worker "is the path to an optional xctest bundle.\n" 18*6777b538SAndroid Build Coastguard Worker "Options:\n" 19*6777b538SAndroid Build Coastguard Worker " -u Specifies the device udid to use. Will use -d, -s values to get " 20*6777b538SAndroid Build Coastguard Worker "devices if not specified.\n" 21*6777b538SAndroid Build Coastguard Worker " -d Specifies the device (must be one of the values from the iOS " 22*6777b538SAndroid Build Coastguard Worker "Simulator's Hardware -> Device menu. Defaults to 'iPhone 6s'.\n" 23*6777b538SAndroid Build Coastguard Worker " -w Wipe the device's contents and settings before running the " 24*6777b538SAndroid Build Coastguard Worker "test.\n" 25*6777b538SAndroid Build Coastguard Worker " -e Specifies an environment key=value pair that will be" 26*6777b538SAndroid Build Coastguard Worker " set in the simulated application's environment.\n" 27*6777b538SAndroid Build Coastguard Worker " -t Specifies a test or test suite that should be included in the " 28*6777b538SAndroid Build Coastguard Worker "test run. All other tests will be excluded from this run. This is " 29*6777b538SAndroid Build Coastguard Worker "incompatible with -i.\n" 30*6777b538SAndroid Build Coastguard Worker " -c Specifies command line flags to pass to application.\n" 31*6777b538SAndroid Build Coastguard Worker " -p Print the device's home directory, does not run a test.\n" 32*6777b538SAndroid Build Coastguard Worker " -s Specifies the SDK version to use (e.g '9.3'). Will use system " 33*6777b538SAndroid Build Coastguard Worker "default if not specified.\n" 34*6777b538SAndroid Build Coastguard Worker " -v Be more verbose, showing all the xcrun commands we call\n" 35*6777b538SAndroid Build Coastguard Worker " -k When to kill the iOS Simulator : before, after, both, never " 36*6777b538SAndroid Build Coastguard Worker "(default: both)\n" 37*6777b538SAndroid Build Coastguard Worker " -i Use iossim instead of xcodebuild (disables all xctest " 38*6777b538SAndroid Build Coastguard Worker "features). This is incompatible with -t.\n"); 39*6777b538SAndroid Build Coastguard Worker} 40*6777b538SAndroid Build Coastguard Worker 41*6777b538SAndroid Build Coastguard Worker// Exit status codes. 42*6777b538SAndroid Build Coastguard Workerconst int kExitSuccess = EXIT_SUCCESS; 43*6777b538SAndroid Build Coastguard Workerconst int kExitInvalidArguments = 2; 44*6777b538SAndroid Build Coastguard Worker 45*6777b538SAndroid Build Coastguard Workervoid LogError(NSString* format, ...) { 46*6777b538SAndroid Build Coastguard Worker va_list list; 47*6777b538SAndroid Build Coastguard Worker va_start(list, format); 48*6777b538SAndroid Build Coastguard Worker 49*6777b538SAndroid Build Coastguard Worker NSString* message = [[NSString alloc] initWithFormat:format arguments:list]; 50*6777b538SAndroid Build Coastguard Worker 51*6777b538SAndroid Build Coastguard Worker NSLog(@"ERROR: %@", message); 52*6777b538SAndroid Build Coastguard Worker 53*6777b538SAndroid Build Coastguard Worker va_end(list); 54*6777b538SAndroid Build Coastguard Worker} 55*6777b538SAndroid Build Coastguard Worker 56*6777b538SAndroid Build Coastguard Worker} 57*6777b538SAndroid Build Coastguard Worker 58*6777b538SAndroid Build Coastguard Workertypedef enum { 59*6777b538SAndroid Build Coastguard Worker KILL_NEVER = 0, 60*6777b538SAndroid Build Coastguard Worker KILL_BEFORE = 1 << 0, 61*6777b538SAndroid Build Coastguard Worker KILL_AFTER = 1 << 1, 62*6777b538SAndroid Build Coastguard Worker KILL_BOTH = KILL_BEFORE | KILL_AFTER, 63*6777b538SAndroid Build Coastguard Worker} SimulatorKill; 64*6777b538SAndroid Build Coastguard Worker 65*6777b538SAndroid Build Coastguard Worker// See https://stackoverflow.com/a/51895129 and 66*6777b538SAndroid Build Coastguard Worker// https://github.com/facebook/xctool/pull/159/files. 67*6777b538SAndroid Build Coastguard Worker@interface NSTask (PrivateAPI) 68*6777b538SAndroid Build Coastguard Worker- (void)setStartsNewProcessGroup:(BOOL)startsNewProcessGroup; 69*6777b538SAndroid Build Coastguard Worker@end 70*6777b538SAndroid Build Coastguard Worker 71*6777b538SAndroid Build Coastguard Worker// Wrap boiler plate calls to xcrun NSTasks. 72*6777b538SAndroid Build Coastguard Worker@interface XCRunTask : NSObject 73*6777b538SAndroid Build Coastguard Worker- (instancetype)initWithArguments:(NSArray*)arguments; 74*6777b538SAndroid Build Coastguard Worker- (void)run:(bool)verbose; 75*6777b538SAndroid Build Coastguard Worker- (void)launch:(bool)verbose; 76*6777b538SAndroid Build Coastguard Worker- (void)setStandardOutput:(id)output; 77*6777b538SAndroid Build Coastguard Worker- (void)setStandardError:(id)error; 78*6777b538SAndroid Build Coastguard Worker- (int)terminationStatus; 79*6777b538SAndroid Build Coastguard Worker@end 80*6777b538SAndroid Build Coastguard Worker 81*6777b538SAndroid Build Coastguard Worker@implementation XCRunTask { 82*6777b538SAndroid Build Coastguard Worker NSTask* __strong _task; 83*6777b538SAndroid Build Coastguard Worker} 84*6777b538SAndroid Build Coastguard Worker 85*6777b538SAndroid Build Coastguard Worker- (instancetype)initWithArguments:(NSArray*)arguments { 86*6777b538SAndroid Build Coastguard Worker self = [super init]; 87*6777b538SAndroid Build Coastguard Worker if (self) { 88*6777b538SAndroid Build Coastguard Worker _task = [[NSTask alloc] init]; 89*6777b538SAndroid Build Coastguard Worker [_task setStartsNewProcessGroup:NO]; 90*6777b538SAndroid Build Coastguard Worker _task.launchPath = @"/usr/bin/xcrun"; 91*6777b538SAndroid Build Coastguard Worker _task.arguments = arguments; 92*6777b538SAndroid Build Coastguard Worker } 93*6777b538SAndroid Build Coastguard Worker return self; 94*6777b538SAndroid Build Coastguard Worker} 95*6777b538SAndroid Build Coastguard Worker 96*6777b538SAndroid Build Coastguard Worker- (void)setStandardOutput:(id)output { 97*6777b538SAndroid Build Coastguard Worker _task.standardOutput = output; 98*6777b538SAndroid Build Coastguard Worker} 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker- (void)setStandardError:(id)error { 101*6777b538SAndroid Build Coastguard Worker _task.standardError = error; 102*6777b538SAndroid Build Coastguard Worker} 103*6777b538SAndroid Build Coastguard Worker 104*6777b538SAndroid Build Coastguard Worker- (int)terminationStatus { 105*6777b538SAndroid Build Coastguard Worker return _task.terminationStatus; 106*6777b538SAndroid Build Coastguard Worker} 107*6777b538SAndroid Build Coastguard Worker 108*6777b538SAndroid Build Coastguard Worker- (void)run:(bool)verbose { 109*6777b538SAndroid Build Coastguard Worker if (verbose) { 110*6777b538SAndroid Build Coastguard Worker NSLog(@"Running xcrun %@", [_task.arguments componentsJoinedByString:@" "]); 111*6777b538SAndroid Build Coastguard Worker } 112*6777b538SAndroid Build Coastguard Worker [_task launch]; 113*6777b538SAndroid Build Coastguard Worker [_task waitUntilExit]; 114*6777b538SAndroid Build Coastguard Worker} 115*6777b538SAndroid Build Coastguard Worker 116*6777b538SAndroid Build Coastguard Worker- (void)launch:(bool)verbose { 117*6777b538SAndroid Build Coastguard Worker if (verbose) { 118*6777b538SAndroid Build Coastguard Worker NSLog(@"Running xcrun %@", [_task.arguments componentsJoinedByString:@" "]); 119*6777b538SAndroid Build Coastguard Worker } 120*6777b538SAndroid Build Coastguard Worker [_task launch]; 121*6777b538SAndroid Build Coastguard Worker} 122*6777b538SAndroid Build Coastguard Worker 123*6777b538SAndroid Build Coastguard Worker- (void)waitUntilExit { 124*6777b538SAndroid Build Coastguard Worker [_task waitUntilExit]; 125*6777b538SAndroid Build Coastguard Worker} 126*6777b538SAndroid Build Coastguard Worker 127*6777b538SAndroid Build Coastguard Worker@end 128*6777b538SAndroid Build Coastguard Worker 129*6777b538SAndroid Build Coastguard Worker// Return array of available iOS runtime dictionaries. Unavailable (old Xcode 130*6777b538SAndroid Build Coastguard Worker// versions) or other runtimes (tvOS, watchOS) are removed. 131*6777b538SAndroid Build Coastguard WorkerNSArray* Runtimes(NSDictionary* simctl_list) { 132*6777b538SAndroid Build Coastguard Worker NSMutableArray* runtimes = [simctl_list[@"runtimes"] mutableCopy]; 133*6777b538SAndroid Build Coastguard Worker for (NSDictionary* runtime in simctl_list[@"runtimes"]) { 134*6777b538SAndroid Build Coastguard Worker BOOL available = 135*6777b538SAndroid Build Coastguard Worker [runtime[@"availability"] isEqualToString:@"(available)"] || 136*6777b538SAndroid Build Coastguard Worker runtime[@"isAvailable"]; 137*6777b538SAndroid Build Coastguard Worker 138*6777b538SAndroid Build Coastguard Worker if (![runtime[@"identifier"] 139*6777b538SAndroid Build Coastguard Worker hasPrefix:@"com.apple.CoreSimulator.SimRuntime.iOS"] || 140*6777b538SAndroid Build Coastguard Worker !available) { 141*6777b538SAndroid Build Coastguard Worker [runtimes removeObject:runtime]; 142*6777b538SAndroid Build Coastguard Worker } 143*6777b538SAndroid Build Coastguard Worker } 144*6777b538SAndroid Build Coastguard Worker return runtimes; 145*6777b538SAndroid Build Coastguard Worker} 146*6777b538SAndroid Build Coastguard Worker 147*6777b538SAndroid Build Coastguard Worker// Return array of device dictionaries. 148*6777b538SAndroid Build Coastguard WorkerNSArray* Devices(NSDictionary* simctl_list) { 149*6777b538SAndroid Build Coastguard Worker NSMutableArray* devicetypes = [simctl_list[@"devicetypes"] mutableCopy]; 150*6777b538SAndroid Build Coastguard Worker for (NSDictionary* devicetype in simctl_list[@"devicetypes"]) { 151*6777b538SAndroid Build Coastguard Worker if (![devicetype[@"identifier"] 152*6777b538SAndroid Build Coastguard Worker hasPrefix:@"com.apple.CoreSimulator.SimDeviceType.iPad"] && 153*6777b538SAndroid Build Coastguard Worker ![devicetype[@"identifier"] 154*6777b538SAndroid Build Coastguard Worker hasPrefix:@"com.apple.CoreSimulator.SimDeviceType.iPhone"]) { 155*6777b538SAndroid Build Coastguard Worker [devicetypes removeObject:devicetype]; 156*6777b538SAndroid Build Coastguard Worker } 157*6777b538SAndroid Build Coastguard Worker } 158*6777b538SAndroid Build Coastguard Worker return devicetypes; 159*6777b538SAndroid Build Coastguard Worker} 160*6777b538SAndroid Build Coastguard Worker 161*6777b538SAndroid Build Coastguard Worker// Get list of devices, runtimes, etc from sim_ctl. 162*6777b538SAndroid Build Coastguard WorkerNSDictionary* GetSimulatorList(bool verbose) { 163*6777b538SAndroid Build Coastguard Worker XCRunTask* task = 164*6777b538SAndroid Build Coastguard Worker [[XCRunTask alloc] initWithArguments:@[ @"simctl", @"list", @"-j" ]]; 165*6777b538SAndroid Build Coastguard Worker NSPipe* out = [NSPipe pipe]; 166*6777b538SAndroid Build Coastguard Worker task.standardOutput = out; 167*6777b538SAndroid Build Coastguard Worker 168*6777b538SAndroid Build Coastguard Worker // In the rest of the this file we read from the pipe after -waitUntilExit 169*6777b538SAndroid Build Coastguard Worker // (We normally wrap -launch and -waitUntilExit in one -run method). However, 170*6777b538SAndroid Build Coastguard Worker // on some swarming slaves this led to a hang on simctl's pipe. Since the 171*6777b538SAndroid Build Coastguard Worker // output of simctl is so instant, reading it before exit seems to work, and 172*6777b538SAndroid Build Coastguard Worker // seems to avoid the hang. 173*6777b538SAndroid Build Coastguard Worker [task launch:verbose]; 174*6777b538SAndroid Build Coastguard Worker NSData* data = [out.fileHandleForReading readDataToEndOfFile]; 175*6777b538SAndroid Build Coastguard Worker [task waitUntilExit]; 176*6777b538SAndroid Build Coastguard Worker 177*6777b538SAndroid Build Coastguard Worker NSError* error = nil; 178*6777b538SAndroid Build Coastguard Worker return [NSJSONSerialization JSONObjectWithData:data 179*6777b538SAndroid Build Coastguard Worker options:kNilOptions 180*6777b538SAndroid Build Coastguard Worker error:&error]; 181*6777b538SAndroid Build Coastguard Worker} 182*6777b538SAndroid Build Coastguard Worker 183*6777b538SAndroid Build Coastguard Worker// List supported runtimes and devices. 184*6777b538SAndroid Build Coastguard Workervoid PrintSupportedDevices(NSDictionary* simctl_list) { 185*6777b538SAndroid Build Coastguard Worker printf("\niOS devices:\n"); 186*6777b538SAndroid Build Coastguard Worker for (NSDictionary* type in Devices(simctl_list)) { 187*6777b538SAndroid Build Coastguard Worker printf("%s\n", [type[@"name"] UTF8String]); 188*6777b538SAndroid Build Coastguard Worker } 189*6777b538SAndroid Build Coastguard Worker printf("\nruntimes:\n"); 190*6777b538SAndroid Build Coastguard Worker for (NSDictionary* runtime in Runtimes(simctl_list)) { 191*6777b538SAndroid Build Coastguard Worker printf("%s\n", [runtime[@"version"] UTF8String]); 192*6777b538SAndroid Build Coastguard Worker } 193*6777b538SAndroid Build Coastguard Worker} 194*6777b538SAndroid Build Coastguard Worker 195*6777b538SAndroid Build Coastguard Worker// Expand path to absolute path. 196*6777b538SAndroid Build Coastguard WorkerNSString* ResolvePath(NSString* path) { 197*6777b538SAndroid Build Coastguard Worker path = path.stringByExpandingTildeInPath; 198*6777b538SAndroid Build Coastguard Worker path = path.stringByStandardizingPath; 199*6777b538SAndroid Build Coastguard Worker const char* cpath = path.UTF8String; 200*6777b538SAndroid Build Coastguard Worker char* resolved_name = nullptr; 201*6777b538SAndroid Build Coastguard Worker char* abs_path = realpath(cpath, resolved_name); 202*6777b538SAndroid Build Coastguard Worker if (abs_path == nullptr) { 203*6777b538SAndroid Build Coastguard Worker return nil; 204*6777b538SAndroid Build Coastguard Worker } 205*6777b538SAndroid Build Coastguard Worker return @(abs_path); 206*6777b538SAndroid Build Coastguard Worker} 207*6777b538SAndroid Build Coastguard Worker 208*6777b538SAndroid Build Coastguard Worker// Search |simctl_list| for a udid matching |device_name| and |sdk_version|. 209*6777b538SAndroid Build Coastguard WorkerNSString* GetDeviceBySDKAndName(NSDictionary* simctl_list, 210*6777b538SAndroid Build Coastguard Worker NSString* device_name, 211*6777b538SAndroid Build Coastguard Worker NSString* sdk_version) { 212*6777b538SAndroid Build Coastguard Worker NSString* sdk = nil; 213*6777b538SAndroid Build Coastguard Worker NSString* name = nil; 214*6777b538SAndroid Build Coastguard Worker // Get runtime identifier based on version property to handle 215*6777b538SAndroid Build Coastguard Worker // cases when version and identifier are not the same, 216*6777b538SAndroid Build Coastguard Worker // e.g. below identifer is *13-2 but version is 13.2.2 217*6777b538SAndroid Build Coastguard Worker // { 218*6777b538SAndroid Build Coastguard Worker // "version" : "13.2.2", 219*6777b538SAndroid Build Coastguard Worker // "bundlePath" : "path" 220*6777b538SAndroid Build Coastguard Worker // "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-13-2", 221*6777b538SAndroid Build Coastguard Worker // "buildversion" : "17K90" 222*6777b538SAndroid Build Coastguard Worker // } 223*6777b538SAndroid Build Coastguard Worker for (NSDictionary* runtime in Runtimes(simctl_list)) { 224*6777b538SAndroid Build Coastguard Worker if ([runtime[@"version"] isEqualToString:sdk_version]) { 225*6777b538SAndroid Build Coastguard Worker sdk = runtime[@"identifier"]; 226*6777b538SAndroid Build Coastguard Worker name = runtime[@"name"]; 227*6777b538SAndroid Build Coastguard Worker break; 228*6777b538SAndroid Build Coastguard Worker } 229*6777b538SAndroid Build Coastguard Worker } 230*6777b538SAndroid Build Coastguard Worker if (sdk == nil) { 231*6777b538SAndroid Build Coastguard Worker printf("\nDid not find Runtime with specified version.\n"); 232*6777b538SAndroid Build Coastguard Worker PrintSupportedDevices(simctl_list); 233*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 234*6777b538SAndroid Build Coastguard Worker } 235*6777b538SAndroid Build Coastguard Worker NSArray* devices = [simctl_list[@"devices"] objectForKey:sdk]; 236*6777b538SAndroid Build Coastguard Worker if (devices == nil || devices.count == 0) { 237*6777b538SAndroid Build Coastguard Worker // Specific for XCode 10.1 and lower, 238*6777b538SAndroid Build Coastguard Worker // where name from 'runtimes' uses as a key in 'devices'. 239*6777b538SAndroid Build Coastguard Worker devices = [simctl_list[@"devices"] objectForKey:name]; 240*6777b538SAndroid Build Coastguard Worker } 241*6777b538SAndroid Build Coastguard Worker for (NSDictionary* device in devices) { 242*6777b538SAndroid Build Coastguard Worker if ([device[@"name"] isEqualToString:device_name]) { 243*6777b538SAndroid Build Coastguard Worker return device[@"udid"]; 244*6777b538SAndroid Build Coastguard Worker } 245*6777b538SAndroid Build Coastguard Worker } 246*6777b538SAndroid Build Coastguard Worker return nil; 247*6777b538SAndroid Build Coastguard Worker} 248*6777b538SAndroid Build Coastguard Worker 249*6777b538SAndroid Build Coastguard Worker// Create and return a device udid of |device| and |sdk_version|. 250*6777b538SAndroid Build Coastguard WorkerNSString* CreateDeviceBySDKAndName(NSString* device, 251*6777b538SAndroid Build Coastguard Worker NSString* sdk_version, 252*6777b538SAndroid Build Coastguard Worker bool verbose) { 253*6777b538SAndroid Build Coastguard Worker NSString* sdk = [@"iOS" stringByAppendingString:sdk_version]; 254*6777b538SAndroid Build Coastguard Worker XCRunTask* create = [[XCRunTask alloc] 255*6777b538SAndroid Build Coastguard Worker initWithArguments:@[ @"simctl", @"create", device, device, sdk ]]; 256*6777b538SAndroid Build Coastguard Worker [create run:verbose]; 257*6777b538SAndroid Build Coastguard Worker 258*6777b538SAndroid Build Coastguard Worker NSDictionary* simctl_list = GetSimulatorList(verbose); 259*6777b538SAndroid Build Coastguard Worker return GetDeviceBySDKAndName(simctl_list, device, sdk_version); 260*6777b538SAndroid Build Coastguard Worker} 261*6777b538SAndroid Build Coastguard Worker 262*6777b538SAndroid Build Coastguard Workerbool FindDeviceByUDID(NSDictionary* simctl_list, NSString* udid) { 263*6777b538SAndroid Build Coastguard Worker NSDictionary* devices_table = simctl_list[@"devices"]; 264*6777b538SAndroid Build Coastguard Worker for (id runtimes in devices_table) { 265*6777b538SAndroid Build Coastguard Worker NSArray* devices = devices_table[runtimes]; 266*6777b538SAndroid Build Coastguard Worker for (NSDictionary* device in devices) { 267*6777b538SAndroid Build Coastguard Worker if ([device[@"udid"] isEqualToString:udid]) { 268*6777b538SAndroid Build Coastguard Worker return true; 269*6777b538SAndroid Build Coastguard Worker } 270*6777b538SAndroid Build Coastguard Worker } 271*6777b538SAndroid Build Coastguard Worker } 272*6777b538SAndroid Build Coastguard Worker return false; 273*6777b538SAndroid Build Coastguard Worker} 274*6777b538SAndroid Build Coastguard Worker 275*6777b538SAndroid Build Coastguard Worker// Prints the HOME environment variable for a device. Used by the bots to 276*6777b538SAndroid Build Coastguard Worker// package up all the test data. 277*6777b538SAndroid Build Coastguard Workervoid PrintDeviceHome(NSString* udid, bool verbose) { 278*6777b538SAndroid Build Coastguard Worker XCRunTask* task = [[XCRunTask alloc] 279*6777b538SAndroid Build Coastguard Worker initWithArguments:@[ @"simctl", @"getenv", udid, @"HOME" ]]; 280*6777b538SAndroid Build Coastguard Worker [task run:verbose]; 281*6777b538SAndroid Build Coastguard Worker} 282*6777b538SAndroid Build Coastguard Worker 283*6777b538SAndroid Build Coastguard Worker// Erase a device, used by the bots before a clean test run. 284*6777b538SAndroid Build Coastguard Workervoid WipeDevice(NSString* udid, bool verbose) { 285*6777b538SAndroid Build Coastguard Worker XCRunTask* shutdown = 286*6777b538SAndroid Build Coastguard Worker [[XCRunTask alloc] initWithArguments:@[ @"simctl", @"shutdown", udid ]]; 287*6777b538SAndroid Build Coastguard Worker shutdown.standardOutput = nil; 288*6777b538SAndroid Build Coastguard Worker shutdown.standardError = nil; 289*6777b538SAndroid Build Coastguard Worker [shutdown run:verbose]; 290*6777b538SAndroid Build Coastguard Worker 291*6777b538SAndroid Build Coastguard Worker XCRunTask* erase = 292*6777b538SAndroid Build Coastguard Worker [[XCRunTask alloc] initWithArguments:@[ @"simctl", @"erase", udid ]]; 293*6777b538SAndroid Build Coastguard Worker [erase run:verbose]; 294*6777b538SAndroid Build Coastguard Worker} 295*6777b538SAndroid Build Coastguard Worker 296*6777b538SAndroid Build Coastguard Workervoid KillSimulator(bool verbose) { 297*6777b538SAndroid Build Coastguard Worker XCRunTask* task = 298*6777b538SAndroid Build Coastguard Worker [[XCRunTask alloc] initWithArguments:@[ @"killall", @"Simulator" ]]; 299*6777b538SAndroid Build Coastguard Worker task.standardOutput = nil; 300*6777b538SAndroid Build Coastguard Worker task.standardError = nil; 301*6777b538SAndroid Build Coastguard Worker [task run:verbose]; 302*6777b538SAndroid Build Coastguard Worker} 303*6777b538SAndroid Build Coastguard Worker 304*6777b538SAndroid Build Coastguard WorkerNSString* GetBundleIdentifierFromPath(NSString* app_path) { 305*6777b538SAndroid Build Coastguard Worker NSFileManager* file_manager = [NSFileManager defaultManager]; 306*6777b538SAndroid Build Coastguard Worker NSString* info_plist_path = 307*6777b538SAndroid Build Coastguard Worker [app_path stringByAppendingPathComponent:@"Info.plist"]; 308*6777b538SAndroid Build Coastguard Worker if (![file_manager fileExistsAtPath:info_plist_path]) { 309*6777b538SAndroid Build Coastguard Worker return nil; 310*6777b538SAndroid Build Coastguard Worker } 311*6777b538SAndroid Build Coastguard Worker 312*6777b538SAndroid Build Coastguard Worker NSDictionary* info_dictionary = 313*6777b538SAndroid Build Coastguard Worker [NSDictionary dictionaryWithContentsOfFile:info_plist_path]; 314*6777b538SAndroid Build Coastguard Worker NSString* bundle_identifier = info_dictionary[@"CFBundleIdentifier"]; 315*6777b538SAndroid Build Coastguard Worker return bundle_identifier; 316*6777b538SAndroid Build Coastguard Worker} 317*6777b538SAndroid Build Coastguard Worker 318*6777b538SAndroid Build Coastguard Workerint RunSimCtl(NSArray* arguments, bool verbose) { 319*6777b538SAndroid Build Coastguard Worker XCRunTask* task = [[XCRunTask alloc] 320*6777b538SAndroid Build Coastguard Worker initWithArguments:[@[ @"simctl" ] 321*6777b538SAndroid Build Coastguard Worker arrayByAddingObjectsFromArray:arguments]]; 322*6777b538SAndroid Build Coastguard Worker [task run:verbose]; 323*6777b538SAndroid Build Coastguard Worker int ret = [task terminationStatus]; 324*6777b538SAndroid Build Coastguard Worker if (ret) { 325*6777b538SAndroid Build Coastguard Worker NSLog(@"Warning: the following command failed: xcrun simctl %@", 326*6777b538SAndroid Build Coastguard Worker [arguments componentsJoinedByString:@" "]); 327*6777b538SAndroid Build Coastguard Worker } 328*6777b538SAndroid Build Coastguard Worker return ret; 329*6777b538SAndroid Build Coastguard Worker} 330*6777b538SAndroid Build Coastguard Worker 331*6777b538SAndroid Build Coastguard Workervoid PrepareWebTests(NSString* udid, NSString* app_path, bool verbose) { 332*6777b538SAndroid Build Coastguard Worker NSString* bundle_identifier = GetBundleIdentifierFromPath(app_path); 333*6777b538SAndroid Build Coastguard Worker 334*6777b538SAndroid Build Coastguard Worker RunSimCtl(@[ @"uninstall", udid, bundle_identifier ], verbose); 335*6777b538SAndroid Build Coastguard Worker RunSimCtl(@[ @"install", udid, app_path ], verbose); 336*6777b538SAndroid Build Coastguard Worker} 337*6777b538SAndroid Build Coastguard Worker 338*6777b538SAndroid Build Coastguard Workerint RunWebTest(NSString* app_path, 339*6777b538SAndroid Build Coastguard Worker NSString* udid, 340*6777b538SAndroid Build Coastguard Worker NSMutableArray* cmd_args, 341*6777b538SAndroid Build Coastguard Worker bool verbose) { 342*6777b538SAndroid Build Coastguard Worker NSMutableArray* arguments = [NSMutableArray array]; 343*6777b538SAndroid Build Coastguard Worker [arguments addObject:@"simctl"]; 344*6777b538SAndroid Build Coastguard Worker [arguments addObject:@"launch"]; 345*6777b538SAndroid Build Coastguard Worker [arguments addObject:@"--console"]; 346*6777b538SAndroid Build Coastguard Worker [arguments addObject:@"--terminate-running-process"]; 347*6777b538SAndroid Build Coastguard Worker [arguments addObject:udid]; 348*6777b538SAndroid Build Coastguard Worker [arguments addObject:GetBundleIdentifierFromPath(app_path)]; 349*6777b538SAndroid Build Coastguard Worker if (cmd_args.count == 1) { 350*6777b538SAndroid Build Coastguard Worker for (NSString* arg in [cmd_args[0] componentsSeparatedByString:@" "]) { 351*6777b538SAndroid Build Coastguard Worker [arguments addObject:arg]; 352*6777b538SAndroid Build Coastguard Worker } 353*6777b538SAndroid Build Coastguard Worker } 354*6777b538SAndroid Build Coastguard Worker [arguments addObject:@"-"]; 355*6777b538SAndroid Build Coastguard Worker XCRunTask* task = [[XCRunTask alloc] initWithArguments:arguments]; 356*6777b538SAndroid Build Coastguard Worker 357*6777b538SAndroid Build Coastguard Worker // The following stderr message causes a lot of test faiures on the web 358*6777b538SAndroid Build Coastguard Worker // tests. Strip the message here. 359*6777b538SAndroid Build Coastguard Worker NSArray* ignore_strings = @[ @"Class SwapLayerEAGL" ]; 360*6777b538SAndroid Build Coastguard Worker NSPipe* stderr_pipe = [NSPipe pipe]; 361*6777b538SAndroid Build Coastguard Worker stderr_pipe.fileHandleForReading.readabilityHandler = 362*6777b538SAndroid Build Coastguard Worker ^(NSFileHandle* handle) { 363*6777b538SAndroid Build Coastguard Worker NSString* log = [[NSString alloc] initWithData:handle.availableData 364*6777b538SAndroid Build Coastguard Worker encoding:NSUTF8StringEncoding]; 365*6777b538SAndroid Build Coastguard Worker for (NSString* ignore_string in ignore_strings) { 366*6777b538SAndroid Build Coastguard Worker if ([log rangeOfString:ignore_string].location != NSNotFound) { 367*6777b538SAndroid Build Coastguard Worker return; 368*6777b538SAndroid Build Coastguard Worker } 369*6777b538SAndroid Build Coastguard Worker } 370*6777b538SAndroid Build Coastguard Worker fprintf(stderr, "%s", log.UTF8String); 371*6777b538SAndroid Build Coastguard Worker }; 372*6777b538SAndroid Build Coastguard Worker task.standardError = stderr_pipe; 373*6777b538SAndroid Build Coastguard Worker 374*6777b538SAndroid Build Coastguard Worker [task run:verbose]; 375*6777b538SAndroid Build Coastguard Worker return [task terminationStatus]; 376*6777b538SAndroid Build Coastguard Worker} 377*6777b538SAndroid Build Coastguard Worker 378*6777b538SAndroid Build Coastguard Workerbool isSimDeviceBooted(NSDictionary* simctl_list, NSString* udid) { 379*6777b538SAndroid Build Coastguard Worker for (NSString* sdk in simctl_list[@"devices"]) { 380*6777b538SAndroid Build Coastguard Worker for (NSDictionary* device in simctl_list[@"devices"][sdk]) { 381*6777b538SAndroid Build Coastguard Worker if ([device[@"udid"] isEqualToString:udid]) { 382*6777b538SAndroid Build Coastguard Worker if ([device[@"state"] isEqualToString:@"Booted"]) { 383*6777b538SAndroid Build Coastguard Worker return true; 384*6777b538SAndroid Build Coastguard Worker } 385*6777b538SAndroid Build Coastguard Worker } 386*6777b538SAndroid Build Coastguard Worker } 387*6777b538SAndroid Build Coastguard Worker } 388*6777b538SAndroid Build Coastguard Worker return false; 389*6777b538SAndroid Build Coastguard Worker} 390*6777b538SAndroid Build Coastguard Worker 391*6777b538SAndroid Build Coastguard Workerint SimpleRunApplication(NSString* app_path, 392*6777b538SAndroid Build Coastguard Worker NSString* udid, 393*6777b538SAndroid Build Coastguard Worker NSMutableArray* cmd_args, 394*6777b538SAndroid Build Coastguard Worker bool verbose) { 395*6777b538SAndroid Build Coastguard Worker NSString* bundle_id = GetBundleIdentifierFromPath(app_path); 396*6777b538SAndroid Build Coastguard Worker 397*6777b538SAndroid Build Coastguard Worker RunSimCtl(@[ @"uninstall", udid, bundle_id ], verbose); 398*6777b538SAndroid Build Coastguard Worker RunSimCtl(@[ @"install", udid, app_path ], verbose); 399*6777b538SAndroid Build Coastguard Worker 400*6777b538SAndroid Build Coastguard Worker NSArray* command = [@[ 401*6777b538SAndroid Build Coastguard Worker @"launch", @"--console", @"--terminate-running-process", udid, bundle_id 402*6777b538SAndroid Build Coastguard Worker ] arrayByAddingObjectsFromArray:cmd_args]; 403*6777b538SAndroid Build Coastguard Worker return RunSimCtl(command, verbose); 404*6777b538SAndroid Build Coastguard Worker} 405*6777b538SAndroid Build Coastguard Worker 406*6777b538SAndroid Build Coastguard Workerint RunApplication(NSString* app_path, 407*6777b538SAndroid Build Coastguard Worker NSString* xctest_path, 408*6777b538SAndroid Build Coastguard Worker NSString* udid, 409*6777b538SAndroid Build Coastguard Worker NSMutableDictionary* app_env, 410*6777b538SAndroid Build Coastguard Worker NSMutableArray* cmd_args, 411*6777b538SAndroid Build Coastguard Worker NSMutableArray* tests_filter, 412*6777b538SAndroid Build Coastguard Worker bool verbose) { 413*6777b538SAndroid Build Coastguard Worker NSString* filename = 414*6777b538SAndroid Build Coastguard Worker [NSUUID.UUID.UUIDString stringByAppendingString:@".xctestrun"]; 415*6777b538SAndroid Build Coastguard Worker NSString* tempFilePath = 416*6777b538SAndroid Build Coastguard Worker [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; 417*6777b538SAndroid Build Coastguard Worker [NSFileManager.defaultManager createFileAtPath:tempFilePath 418*6777b538SAndroid Build Coastguard Worker contents:nil 419*6777b538SAndroid Build Coastguard Worker attributes:nil]; 420*6777b538SAndroid Build Coastguard Worker 421*6777b538SAndroid Build Coastguard Worker NSMutableDictionary* xctestrun = [NSMutableDictionary dictionary]; 422*6777b538SAndroid Build Coastguard Worker NSMutableDictionary* testTargetName = [NSMutableDictionary dictionary]; 423*6777b538SAndroid Build Coastguard Worker 424*6777b538SAndroid Build Coastguard Worker NSMutableDictionary* testingEnvironmentVariables = 425*6777b538SAndroid Build Coastguard Worker [NSMutableDictionary dictionary]; 426*6777b538SAndroid Build Coastguard Worker testingEnvironmentVariables[@"IDEiPhoneInternalTestBundleName"] = 427*6777b538SAndroid Build Coastguard Worker app_path.lastPathComponent; 428*6777b538SAndroid Build Coastguard Worker 429*6777b538SAndroid Build Coastguard Worker testingEnvironmentVariables[@"DYLD_FRAMEWORK_PATH"] = 430*6777b538SAndroid Build Coastguard Worker @"__TESTROOT__/Debug-iphonesimulator:__PLATFORMS__/" 431*6777b538SAndroid Build Coastguard Worker @"iPhoneSimulator.platform/Developer/Library/Frameworks"; 432*6777b538SAndroid Build Coastguard Worker testingEnvironmentVariables[@"DYLD_LIBRARY_PATH"] = 433*6777b538SAndroid Build Coastguard Worker @"__TESTROOT__/Debug-iphonesimulator:__PLATFORMS__/" 434*6777b538SAndroid Build Coastguard Worker @"iPhoneSimulator.platform/Developer/Library"; 435*6777b538SAndroid Build Coastguard Worker 436*6777b538SAndroid Build Coastguard Worker if (xctest_path) { 437*6777b538SAndroid Build Coastguard Worker testTargetName[@"TestBundlePath"] = xctest_path; 438*6777b538SAndroid Build Coastguard Worker testingEnvironmentVariables[@"DYLD_INSERT_LIBRARIES"] = 439*6777b538SAndroid Build Coastguard Worker @"__PLATFORMS__/iPhoneSimulator.platform/Developer/" 440*6777b538SAndroid Build Coastguard Worker @"usr/lib/libXCTestBundleInject.dylib"; 441*6777b538SAndroid Build Coastguard Worker testingEnvironmentVariables[@"XCInjectBundleInto"] = 442*6777b538SAndroid Build Coastguard Worker [NSString stringWithFormat:@"__TESTHOST__/%@", 443*6777b538SAndroid Build Coastguard Worker app_path.lastPathComponent 444*6777b538SAndroid Build Coastguard Worker .stringByDeletingPathExtension]; 445*6777b538SAndroid Build Coastguard Worker } else { 446*6777b538SAndroid Build Coastguard Worker testTargetName[@"TestBundlePath"] = app_path; 447*6777b538SAndroid Build Coastguard Worker } 448*6777b538SAndroid Build Coastguard Worker testTargetName[@"TestHostPath"] = app_path; 449*6777b538SAndroid Build Coastguard Worker 450*6777b538SAndroid Build Coastguard Worker if (app_env.count) { 451*6777b538SAndroid Build Coastguard Worker testTargetName[@"EnvironmentVariables"] = app_env; 452*6777b538SAndroid Build Coastguard Worker } 453*6777b538SAndroid Build Coastguard Worker 454*6777b538SAndroid Build Coastguard Worker if (cmd_args.count > 0) { 455*6777b538SAndroid Build Coastguard Worker testTargetName[@"CommandLineArguments"] = cmd_args; 456*6777b538SAndroid Build Coastguard Worker } 457*6777b538SAndroid Build Coastguard Worker 458*6777b538SAndroid Build Coastguard Worker if (tests_filter.count > 0) { 459*6777b538SAndroid Build Coastguard Worker testTargetName[@"OnlyTestIdentifiers"] = tests_filter; 460*6777b538SAndroid Build Coastguard Worker } 461*6777b538SAndroid Build Coastguard Worker 462*6777b538SAndroid Build Coastguard Worker testTargetName[@"TestingEnvironmentVariables"] = testingEnvironmentVariables; 463*6777b538SAndroid Build Coastguard Worker xctestrun[@"TestTargetName"] = testTargetName; 464*6777b538SAndroid Build Coastguard Worker 465*6777b538SAndroid Build Coastguard Worker NSData* data = [NSPropertyListSerialization 466*6777b538SAndroid Build Coastguard Worker dataWithPropertyList:xctestrun 467*6777b538SAndroid Build Coastguard Worker format:NSPropertyListXMLFormat_v1_0 468*6777b538SAndroid Build Coastguard Worker options:0 469*6777b538SAndroid Build Coastguard Worker error:nil]; 470*6777b538SAndroid Build Coastguard Worker [data writeToFile:tempFilePath atomically:YES]; 471*6777b538SAndroid Build Coastguard Worker 472*6777b538SAndroid Build Coastguard Worker XCRunTask* task = [[XCRunTask alloc] initWithArguments:@[ 473*6777b538SAndroid Build Coastguard Worker @"xcodebuild", @"-xctestrun", tempFilePath, @"-destination", 474*6777b538SAndroid Build Coastguard Worker [@"platform=iOS Simulator,id=" stringByAppendingString:udid], 475*6777b538SAndroid Build Coastguard Worker @"test-without-building" 476*6777b538SAndroid Build Coastguard Worker ]]; 477*6777b538SAndroid Build Coastguard Worker 478*6777b538SAndroid Build Coastguard Worker if (!xctest_path) { 479*6777b538SAndroid Build Coastguard Worker // The following stderr messages are meaningless on iossim when not running 480*6777b538SAndroid Build Coastguard Worker // xctests and can be safely stripped. 481*6777b538SAndroid Build Coastguard Worker NSArray* ignore_strings = @[ 482*6777b538SAndroid Build Coastguard Worker @"IDETestOperationsObserverErrorDomain", @"** TEST EXECUTE FAILED **" 483*6777b538SAndroid Build Coastguard Worker ]; 484*6777b538SAndroid Build Coastguard Worker NSPipe* stderr_pipe = [NSPipe pipe]; 485*6777b538SAndroid Build Coastguard Worker stderr_pipe.fileHandleForReading.readabilityHandler = 486*6777b538SAndroid Build Coastguard Worker ^(NSFileHandle* handle) { 487*6777b538SAndroid Build Coastguard Worker NSString* log = [[NSString alloc] initWithData:handle.availableData 488*6777b538SAndroid Build Coastguard Worker encoding:NSUTF8StringEncoding]; 489*6777b538SAndroid Build Coastguard Worker for (NSString* ignore_string in ignore_strings) { 490*6777b538SAndroid Build Coastguard Worker if ([log rangeOfString:ignore_string].location != NSNotFound) { 491*6777b538SAndroid Build Coastguard Worker return; 492*6777b538SAndroid Build Coastguard Worker } 493*6777b538SAndroid Build Coastguard Worker } 494*6777b538SAndroid Build Coastguard Worker printf("%s", log.UTF8String); 495*6777b538SAndroid Build Coastguard Worker }; 496*6777b538SAndroid Build Coastguard Worker task.standardError = stderr_pipe; 497*6777b538SAndroid Build Coastguard Worker } 498*6777b538SAndroid Build Coastguard Worker [task run:verbose]; 499*6777b538SAndroid Build Coastguard Worker return [task terminationStatus]; 500*6777b538SAndroid Build Coastguard Worker} 501*6777b538SAndroid Build Coastguard Worker 502*6777b538SAndroid Build Coastguard Workerint main(int argc, char* const argv[]) { 503*6777b538SAndroid Build Coastguard Worker NSString* app_path = nil; 504*6777b538SAndroid Build Coastguard Worker NSString* xctest_path = nil; 505*6777b538SAndroid Build Coastguard Worker NSString* udid = nil; 506*6777b538SAndroid Build Coastguard Worker NSString* device_name = @"iPhone 6s"; 507*6777b538SAndroid Build Coastguard Worker bool wants_wipe = false; 508*6777b538SAndroid Build Coastguard Worker bool wants_print_home = false; 509*6777b538SAndroid Build Coastguard Worker bool wants_print_supported_devices = false; 510*6777b538SAndroid Build Coastguard Worker bool run_web_test = false; 511*6777b538SAndroid Build Coastguard Worker bool prepare_web_test = false; 512*6777b538SAndroid Build Coastguard Worker NSString* sdk_version = nil; 513*6777b538SAndroid Build Coastguard Worker NSMutableDictionary* app_env = [NSMutableDictionary dictionary]; 514*6777b538SAndroid Build Coastguard Worker NSMutableArray* cmd_args = [NSMutableArray array]; 515*6777b538SAndroid Build Coastguard Worker NSMutableArray* tests_filter = [NSMutableArray array]; 516*6777b538SAndroid Build Coastguard Worker bool verbose_commands = false; 517*6777b538SAndroid Build Coastguard Worker SimulatorKill kill_simulator = KILL_BOTH; 518*6777b538SAndroid Build Coastguard Worker bool wants_simple_iossim = false; 519*6777b538SAndroid Build Coastguard Worker 520*6777b538SAndroid Build Coastguard Worker int c; 521*6777b538SAndroid Build Coastguard Worker while ((c = getopt(argc, argv, "hs:d:u:t:e:c:pwlvk:i")) != -1) { 522*6777b538SAndroid Build Coastguard Worker switch (c) { 523*6777b538SAndroid Build Coastguard Worker case 's': 524*6777b538SAndroid Build Coastguard Worker sdk_version = @(optarg); 525*6777b538SAndroid Build Coastguard Worker break; 526*6777b538SAndroid Build Coastguard Worker case 'd': 527*6777b538SAndroid Build Coastguard Worker device_name = @(optarg); 528*6777b538SAndroid Build Coastguard Worker break; 529*6777b538SAndroid Build Coastguard Worker case 'u': 530*6777b538SAndroid Build Coastguard Worker udid = @(optarg); 531*6777b538SAndroid Build Coastguard Worker break; 532*6777b538SAndroid Build Coastguard Worker case 'w': 533*6777b538SAndroid Build Coastguard Worker wants_wipe = true; 534*6777b538SAndroid Build Coastguard Worker break; 535*6777b538SAndroid Build Coastguard Worker case 'c': { 536*6777b538SAndroid Build Coastguard Worker NSString* cmd_arg = @(optarg); 537*6777b538SAndroid Build Coastguard Worker [cmd_args addObject:cmd_arg]; 538*6777b538SAndroid Build Coastguard Worker } break; 539*6777b538SAndroid Build Coastguard Worker case 't': { 540*6777b538SAndroid Build Coastguard Worker NSString* test = @(optarg); 541*6777b538SAndroid Build Coastguard Worker [tests_filter addObject:test]; 542*6777b538SAndroid Build Coastguard Worker } break; 543*6777b538SAndroid Build Coastguard Worker case 'e': { 544*6777b538SAndroid Build Coastguard Worker NSString* envLine = @(optarg); 545*6777b538SAndroid Build Coastguard Worker NSRange range = [envLine rangeOfString:@"="]; 546*6777b538SAndroid Build Coastguard Worker if (range.location == NSNotFound) { 547*6777b538SAndroid Build Coastguard Worker LogError(@"Invalid key=value argument for -e."); 548*6777b538SAndroid Build Coastguard Worker PrintUsage(); 549*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 550*6777b538SAndroid Build Coastguard Worker } 551*6777b538SAndroid Build Coastguard Worker NSString* key = [envLine substringToIndex:range.location]; 552*6777b538SAndroid Build Coastguard Worker NSString* value = [envLine substringFromIndex:(range.location + 1)]; 553*6777b538SAndroid Build Coastguard Worker [app_env setObject:value forKey:key]; 554*6777b538SAndroid Build Coastguard Worker } break; 555*6777b538SAndroid Build Coastguard Worker case 'p': 556*6777b538SAndroid Build Coastguard Worker wants_print_home = true; 557*6777b538SAndroid Build Coastguard Worker break; 558*6777b538SAndroid Build Coastguard Worker case 'l': 559*6777b538SAndroid Build Coastguard Worker wants_print_supported_devices = true; 560*6777b538SAndroid Build Coastguard Worker break; 561*6777b538SAndroid Build Coastguard Worker case 'v': 562*6777b538SAndroid Build Coastguard Worker verbose_commands = true; 563*6777b538SAndroid Build Coastguard Worker break; 564*6777b538SAndroid Build Coastguard Worker case 'k': { 565*6777b538SAndroid Build Coastguard Worker NSString* cmd_arg = @(optarg); 566*6777b538SAndroid Build Coastguard Worker if ([cmd_arg isEqualToString:@"before"]) { 567*6777b538SAndroid Build Coastguard Worker kill_simulator = KILL_BEFORE; 568*6777b538SAndroid Build Coastguard Worker } else if ([cmd_arg isEqualToString:@"after"]) { 569*6777b538SAndroid Build Coastguard Worker kill_simulator = KILL_AFTER; 570*6777b538SAndroid Build Coastguard Worker } else if ([cmd_arg isEqualToString:@"both"]) { 571*6777b538SAndroid Build Coastguard Worker kill_simulator = KILL_BOTH; 572*6777b538SAndroid Build Coastguard Worker } else if ([cmd_arg isEqualToString:@"never"]) { 573*6777b538SAndroid Build Coastguard Worker kill_simulator = KILL_NEVER; 574*6777b538SAndroid Build Coastguard Worker } else { 575*6777b538SAndroid Build Coastguard Worker PrintUsage(); 576*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 577*6777b538SAndroid Build Coastguard Worker } 578*6777b538SAndroid Build Coastguard Worker } break; 579*6777b538SAndroid Build Coastguard Worker case 'i': 580*6777b538SAndroid Build Coastguard Worker wants_simple_iossim = true; 581*6777b538SAndroid Build Coastguard Worker break; 582*6777b538SAndroid Build Coastguard Worker case 'h': 583*6777b538SAndroid Build Coastguard Worker PrintUsage(); 584*6777b538SAndroid Build Coastguard Worker exit(kExitSuccess); 585*6777b538SAndroid Build Coastguard Worker default: 586*6777b538SAndroid Build Coastguard Worker PrintUsage(); 587*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 588*6777b538SAndroid Build Coastguard Worker } 589*6777b538SAndroid Build Coastguard Worker } 590*6777b538SAndroid Build Coastguard Worker 591*6777b538SAndroid Build Coastguard Worker if (wants_simple_iossim && [tests_filter count]) { 592*6777b538SAndroid Build Coastguard Worker LogError(@"Cannot specify tests with -t when using -i."); 593*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 594*6777b538SAndroid Build Coastguard Worker } 595*6777b538SAndroid Build Coastguard Worker 596*6777b538SAndroid Build Coastguard Worker NSDictionary* simctl_list = GetSimulatorList(verbose_commands); 597*6777b538SAndroid Build Coastguard Worker 598*6777b538SAndroid Build Coastguard Worker if (wants_print_supported_devices) { 599*6777b538SAndroid Build Coastguard Worker PrintSupportedDevices(simctl_list); 600*6777b538SAndroid Build Coastguard Worker exit(kExitSuccess); 601*6777b538SAndroid Build Coastguard Worker } 602*6777b538SAndroid Build Coastguard Worker 603*6777b538SAndroid Build Coastguard Worker if (!sdk_version) { 604*6777b538SAndroid Build Coastguard Worker float sdk = 0; 605*6777b538SAndroid Build Coastguard Worker for (NSDictionary* runtime in Runtimes(simctl_list)) { 606*6777b538SAndroid Build Coastguard Worker sdk = fmax(sdk, [runtime[@"version"] floatValue]); 607*6777b538SAndroid Build Coastguard Worker } 608*6777b538SAndroid Build Coastguard Worker sdk_version = [NSString stringWithFormat:@"%0.1f", sdk]; 609*6777b538SAndroid Build Coastguard Worker } 610*6777b538SAndroid Build Coastguard Worker 611*6777b538SAndroid Build Coastguard Worker NSRange range; 612*6777b538SAndroid Build Coastguard Worker for (NSString* cmd_arg in cmd_args) { 613*6777b538SAndroid Build Coastguard Worker range = [cmd_arg rangeOfString:@"--run-web-tests"]; 614*6777b538SAndroid Build Coastguard Worker if (range.location != NSNotFound) { 615*6777b538SAndroid Build Coastguard Worker run_web_test = true; 616*6777b538SAndroid Build Coastguard Worker break; 617*6777b538SAndroid Build Coastguard Worker } 618*6777b538SAndroid Build Coastguard Worker } 619*6777b538SAndroid Build Coastguard Worker 620*6777b538SAndroid Build Coastguard Worker for (NSString* cmd_arg in cmd_args) { 621*6777b538SAndroid Build Coastguard Worker range = [cmd_arg rangeOfString:@"--prepare-web-tests"]; 622*6777b538SAndroid Build Coastguard Worker if (range.location != NSNotFound) { 623*6777b538SAndroid Build Coastguard Worker prepare_web_test = true; 624*6777b538SAndroid Build Coastguard Worker break; 625*6777b538SAndroid Build Coastguard Worker } 626*6777b538SAndroid Build Coastguard Worker } 627*6777b538SAndroid Build Coastguard Worker 628*6777b538SAndroid Build Coastguard Worker if (udid == nil) { 629*6777b538SAndroid Build Coastguard Worker udid = GetDeviceBySDKAndName(simctl_list, device_name, sdk_version); 630*6777b538SAndroid Build Coastguard Worker if (udid == nil) { 631*6777b538SAndroid Build Coastguard Worker udid = 632*6777b538SAndroid Build Coastguard Worker CreateDeviceBySDKAndName(device_name, sdk_version, verbose_commands); 633*6777b538SAndroid Build Coastguard Worker if (udid == nil) { 634*6777b538SAndroid Build Coastguard Worker LogError(@"Unable to find a device %@ with SDK %@.", device_name, 635*6777b538SAndroid Build Coastguard Worker sdk_version); 636*6777b538SAndroid Build Coastguard Worker PrintSupportedDevices(simctl_list); 637*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 638*6777b538SAndroid Build Coastguard Worker } 639*6777b538SAndroid Build Coastguard Worker } 640*6777b538SAndroid Build Coastguard Worker } else { 641*6777b538SAndroid Build Coastguard Worker if (!FindDeviceByUDID(simctl_list, udid)) { 642*6777b538SAndroid Build Coastguard Worker LogError( 643*6777b538SAndroid Build Coastguard Worker @"Unable to find a device with udid %@. Use 'xcrun simctl list' to " 644*6777b538SAndroid Build Coastguard Worker @"see valid device udids.", 645*6777b538SAndroid Build Coastguard Worker udid); 646*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 647*6777b538SAndroid Build Coastguard Worker } 648*6777b538SAndroid Build Coastguard Worker } 649*6777b538SAndroid Build Coastguard Worker 650*6777b538SAndroid Build Coastguard Worker if (wants_print_home) { 651*6777b538SAndroid Build Coastguard Worker PrintDeviceHome(udid, verbose_commands); 652*6777b538SAndroid Build Coastguard Worker exit(kExitSuccess); 653*6777b538SAndroid Build Coastguard Worker } 654*6777b538SAndroid Build Coastguard Worker 655*6777b538SAndroid Build Coastguard Worker if (kill_simulator & KILL_BEFORE) { 656*6777b538SAndroid Build Coastguard Worker KillSimulator(verbose_commands); 657*6777b538SAndroid Build Coastguard Worker } 658*6777b538SAndroid Build Coastguard Worker 659*6777b538SAndroid Build Coastguard Worker if (wants_wipe) { 660*6777b538SAndroid Build Coastguard Worker WipeDevice(udid, verbose_commands); 661*6777b538SAndroid Build Coastguard Worker printf("Device wiped.\n"); 662*6777b538SAndroid Build Coastguard Worker exit(kExitSuccess); 663*6777b538SAndroid Build Coastguard Worker } 664*6777b538SAndroid Build Coastguard Worker 665*6777b538SAndroid Build Coastguard Worker // There should be at least one arg left, specifying the app path. Any 666*6777b538SAndroid Build Coastguard Worker // additional args are passed as arguments to the app. 667*6777b538SAndroid Build Coastguard Worker if (optind < argc) { 668*6777b538SAndroid Build Coastguard Worker NSString* unresolved_app_path = [NSFileManager.defaultManager 669*6777b538SAndroid Build Coastguard Worker stringWithFileSystemRepresentation:argv[optind] 670*6777b538SAndroid Build Coastguard Worker length:strlen(argv[optind])]; 671*6777b538SAndroid Build Coastguard Worker app_path = ResolvePath(unresolved_app_path); 672*6777b538SAndroid Build Coastguard Worker if (!app_path) { 673*6777b538SAndroid Build Coastguard Worker LogError(@"Unable to resolve app_path %@", unresolved_app_path); 674*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 675*6777b538SAndroid Build Coastguard Worker } 676*6777b538SAndroid Build Coastguard Worker 677*6777b538SAndroid Build Coastguard Worker if (++optind < argc) { 678*6777b538SAndroid Build Coastguard Worker if (wants_simple_iossim) { 679*6777b538SAndroid Build Coastguard Worker fprintf(stderr, "Warning: xctest_path ignored when using -i"); 680*6777b538SAndroid Build Coastguard Worker } else { 681*6777b538SAndroid Build Coastguard Worker NSString* unresolved_xctest_path = [NSFileManager.defaultManager 682*6777b538SAndroid Build Coastguard Worker stringWithFileSystemRepresentation:argv[optind] 683*6777b538SAndroid Build Coastguard Worker length:strlen(argv[optind])]; 684*6777b538SAndroid Build Coastguard Worker xctest_path = ResolvePath(unresolved_xctest_path); 685*6777b538SAndroid Build Coastguard Worker if (!xctest_path) { 686*6777b538SAndroid Build Coastguard Worker LogError(@"Unable to resolve xctest_path %@", unresolved_xctest_path); 687*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 688*6777b538SAndroid Build Coastguard Worker } 689*6777b538SAndroid Build Coastguard Worker } 690*6777b538SAndroid Build Coastguard Worker } 691*6777b538SAndroid Build Coastguard Worker } else { 692*6777b538SAndroid Build Coastguard Worker LogError(@"Unable to parse command line arguments."); 693*6777b538SAndroid Build Coastguard Worker PrintUsage(); 694*6777b538SAndroid Build Coastguard Worker exit(kExitInvalidArguments); 695*6777b538SAndroid Build Coastguard Worker } 696*6777b538SAndroid Build Coastguard Worker 697*6777b538SAndroid Build Coastguard Worker if ((prepare_web_test || run_web_test || wants_simple_iossim) && 698*6777b538SAndroid Build Coastguard Worker !isSimDeviceBooted(simctl_list, udid)) { 699*6777b538SAndroid Build Coastguard Worker RunSimCtl(@[ @"boot", udid ], verbose_commands); 700*6777b538SAndroid Build Coastguard Worker } 701*6777b538SAndroid Build Coastguard Worker 702*6777b538SAndroid Build Coastguard Worker int return_code = -1; 703*6777b538SAndroid Build Coastguard Worker if (prepare_web_test) { 704*6777b538SAndroid Build Coastguard Worker PrepareWebTests(udid, app_path, verbose_commands); 705*6777b538SAndroid Build Coastguard Worker return_code = kExitSuccess; 706*6777b538SAndroid Build Coastguard Worker } else if (run_web_test) { 707*6777b538SAndroid Build Coastguard Worker return_code = RunWebTest(app_path, udid, cmd_args, verbose_commands); 708*6777b538SAndroid Build Coastguard Worker } else if (wants_simple_iossim) { 709*6777b538SAndroid Build Coastguard Worker return_code = 710*6777b538SAndroid Build Coastguard Worker SimpleRunApplication(app_path, udid, cmd_args, verbose_commands); 711*6777b538SAndroid Build Coastguard Worker } else { 712*6777b538SAndroid Build Coastguard Worker return_code = RunApplication(app_path, xctest_path, udid, app_env, cmd_args, 713*6777b538SAndroid Build Coastguard Worker tests_filter, verbose_commands); 714*6777b538SAndroid Build Coastguard Worker } 715*6777b538SAndroid Build Coastguard Worker 716*6777b538SAndroid Build Coastguard Worker if (kill_simulator & KILL_AFTER) { 717*6777b538SAndroid Build Coastguard Worker KillSimulator(verbose_commands); 718*6777b538SAndroid Build Coastguard Worker } 719*6777b538SAndroid Build Coastguard Worker 720*6777b538SAndroid Build Coastguard Worker return return_code; 721*6777b538SAndroid Build Coastguard Worker} 722