aboutsummaryrefslogtreecommitdiff
path: root/UnitTesting
diff options
context:
space:
mode:
authorGravatar thomasvl@gmail.com <thomasvl@gmail.com@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2008-12-12 15:24:34 +0000
committerGravatar thomasvl@gmail.com <thomasvl@gmail.com@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2008-12-12 15:24:34 +0000
commit2e8516354aacef064d01425808da06d2cdcb4791 (patch)
tree9da4758828930280d32f18d54ece7a249df742c7 /UnitTesting
parent9f64d056dd70f2f938ac6f5adb8e75b650dc2e1a (diff)
- GTMStackTrace works on 10.5+ (and iPhone) using NSThread to build the call stack.
- Added GTM_EXTERN that makes it easier to mix and match objc and objc++ code. - Added GTMHotKeysTextField for display and editing of hot key settings. - Added GTMCarbonEvent for dealing with Carbon Events and HotKeys in a ObjC like way. - Backported the Atomic Barrier Swap functions for Objective C back to Tiger. - Added a variety of new functions to GTMUnitTestingUtilities for checking if the screensaver is in the way, waiting on user events, and generating keystrokes. - If you are using any Carbon routines that log (DebugStr, AssertMacros.h) and use GTMUnitTestDevLog, the log routines now go through _GTMDevLog so that they can be caught in GTMUnitTestDevLog and verified like any _GTMDevLog calls you may make. For an example of this in action see GTMCarbonEventTest.m. - Added GTMFileSystemKQueue. It provides a simple wrapper for kqueuing something in the file system and tracking changes to it. - RunIPhoneUnitTest.sh now cleans up the user home directory and creates a documents directory within it, used when requesting a NSDocumentDirectory. - Added GTMNSFileManager+Carbon which contains routines for path <-> Alias conversion and path <-> FSRef conversion. - Added GTMNSArray+Merge for merging one array into another with or without a custom merging function, returning a new array with the merged contents.
Diffstat (limited to 'UnitTesting')
-rw-r--r--UnitTesting/GTMIPhoneUnitTestDelegate.m10
-rw-r--r--UnitTesting/GTMNSObject+UnitTesting.h4
-rw-r--r--UnitTesting/GTMSenTestCase.h6
-rw-r--r--UnitTesting/GTMUIUnitTestingHarness/Info.plist43
-rw-r--r--UnitTesting/GTMUnitTestDevLog.m33
-rw-r--r--UnitTesting/GTMUnitTestingUtilities.h48
-rw-r--r--UnitTesting/GTMUnitTestingUtilities.m172
-rwxr-xr-xUnitTesting/RunIPhoneUnitTest.sh7
8 files changed, 291 insertions, 32 deletions
diff --git a/UnitTesting/GTMIPhoneUnitTestDelegate.m b/UnitTesting/GTMIPhoneUnitTestDelegate.m
index 7ef46fc..ab33932 100644
--- a/UnitTesting/GTMIPhoneUnitTestDelegate.m
+++ b/UnitTesting/GTMIPhoneUnitTestDelegate.m
@@ -34,11 +34,6 @@ static int MethodSort(const void *a, const void *b) {
return strcmp(nameA, nameB);
}
-@interface UIApplication (iPhoneUnitTestAdditions)
-// "Private" method that we need
-- (void)terminateWithSuccess;
-@end
-
@implementation GTMIPhoneUnitTestDelegate
// Return YES if class is subclass (1 or more generations) of SenTestCase
@@ -62,10 +57,7 @@ static int MethodSort(const void *a, const void *b) {
// Using private call to end our tests
if (!getenv("GTM_DISABLE_TERMINATION")) {
- // I call this delayed just to make sure that the stack is clean
- [application performSelector:@selector(terminateWithSuccess)
- withObject:nil
- afterDelay:0.00];
+ exit(0);
}
}
diff --git a/UnitTesting/GTMNSObject+UnitTesting.h b/UnitTesting/GTMNSObject+UnitTesting.h
index 68fab04..57b53bf 100644
--- a/UnitTesting/GTMNSObject+UnitTesting.h
+++ b/UnitTesting/GTMNSObject+UnitTesting.h
@@ -414,8 +414,8 @@ do { \
// notification so that objects who want to add data to the encoded objects unit
// test state can do so. The Coder will be in the userInfo dictionary for the
// notification under the GTMUnitTestingEncoderKey key.
-extern NSString *const GTMUnitTestingEncodedObjectNotification;
+GTM_EXTERN NSString *const GTMUnitTestingEncodedObjectNotification;
// Key for finding the encoder in the userInfo dictionary for
// GTMUnitTestingEncodedObjectNotification notifications.
-extern NSString *const GTMUnitTestingEncoderKey;
+GTM_EXTERN NSString *const GTMUnitTestingEncoderKey;
diff --git a/UnitTesting/GTMSenTestCase.h b/UnitTesting/GTMSenTestCase.h
index 99f520a..1d35591 100644
--- a/UnitTesting/GTMSenTestCase.h
+++ b/UnitTesting/GTMSenTestCase.h
@@ -990,10 +990,10 @@ do { \
- (void)failWithException:(NSException*)exception;
@end
-extern NSString *const SenTestFailureException;
+GTM_EXTERN NSString *const SenTestFailureException;
-extern NSString *const SenTestFilenameKey;
-extern NSString *const SenTestLineNumberKey;
+GTM_EXTERN NSString *const SenTestFilenameKey;
+GTM_EXTERN NSString *const SenTestLineNumberKey;
#endif // GTM_IPHONE_SDK
diff --git a/UnitTesting/GTMUIUnitTestingHarness/Info.plist b/UnitTesting/GTMUIUnitTestingHarness/Info.plist
index fe3e712..11355f7 100644
--- a/UnitTesting/GTMUIUnitTestingHarness/Info.plist
+++ b/UnitTesting/GTMUIUnitTestingHarness/Info.plist
@@ -22,6 +22,49 @@
<string>1.0</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
+ <!-- The CFBundleURLTypes are in here specifically to test
+ GTMGetURLHandler. See GTMGetURLHandlerTest for details -->
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>GTMUIUnitTestingHarnessURL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>gtmgeturlhandlertest</string>
+ </array>
+ <key>GTMBundleURLClass</key>
+ <string>GTMGetURLHandlerTest</string>
+ </dict>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>GTMGetURLHandlerBadClassURL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>gtmgeturlhandlerbadclasstest</string>
+ </array>
+ <key>GTMBundleURLClass</key>
+ <string>GTMGetURLHandlerBadClassWarning</string>
+ </dict>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>GTMGetURLHandlerMissingClassURL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>gtmgeturlhandlermissingclasstest</string>
+ </array>
+ <key>GTMBundleURLClass</key>
+ <string>GTMGetURLHandlerMissingClassWarning</string>
+ </dict>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>GTMGetURLHandlerMissingHandlerURL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>gtmgeturlhandlermissinghandlerurl</string>
+ </array>
+ </dict>
+ </array>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
diff --git a/UnitTesting/GTMUnitTestDevLog.m b/UnitTesting/GTMUnitTestDevLog.m
index 30ab13b..a0c31b3 100644
--- a/UnitTesting/GTMUnitTestDevLog.m
+++ b/UnitTesting/GTMUnitTestDevLog.m
@@ -17,9 +17,40 @@
//
#import "GTMUnitTestDevLog.h"
+
+
#import "GTMRegex.h"
#import "GTMSenTestCase.h"
+#if !GTM_IPHONE_SDK
+// Add support for grabbing messages from Carbon.
+#import <CoreServices/CoreServices.h>
+static void GTMDevLogDebugAssert(OSType componentSignature,
+ UInt32 options,
+ const char *assertionString,
+ const char *exceptionLabelString,
+ const char *errorString,
+ const char *fileName,
+ long lineNumber,
+ void *value,
+ ConstStr255Param outputMsg) {
+ NSString *outLog = [[[NSString alloc] initWithBytes:&(outputMsg[1])
+ length:StrLength(outputMsg)
+ encoding:NSMacOSRomanStringEncoding]
+ autorelease];
+ _GTMDevLog(outLog);
+}
+static inline void GTMInstallDebugAssertOutputHandler(void) {
+ InstallDebugAssertOutputHandler(GTMDevLogDebugAssert);
+}
+static inline void GTMUninstallDebugAssertOutputHandler(void) {
+ InstallDebugAssertOutputHandler(NULL);
+}
+#else // GTM_IPHONE_SDK
+static inline void GTMInstallDebugAssertOutputHandler(void) {};
+static inline void GTMUninstallDebugAssertOutputHandler(void) {};
+#endif // GTM_IPHONE_SDK
+
@implementation GTMUnitTestDevLog
// If unittests are ever being run on separate threads, this may need to be
// made a thread local variable.
@@ -38,10 +69,12 @@ static BOOL gTrackingEnabled = NO;
}
+ (void)enableTracking {
+ GTMInstallDebugAssertOutputHandler();
gTrackingEnabled = YES;
}
+ (void)disableTracking {
+ GTMUninstallDebugAssertOutputHandler();
gTrackingEnabled = NO;
}
diff --git a/UnitTesting/GTMUnitTestingUtilities.h b/UnitTesting/GTMUnitTestingUtilities.h
index eca0825..128a4c4 100644
--- a/UnitTesting/GTMUnitTestingUtilities.h
+++ b/UnitTesting/GTMUnitTestingUtilities.h
@@ -39,5 +39,53 @@
// }
+ (void)setUpForUIUnitTestsIfBeingTested;
+// Check if the screen saver is running. Some unit tests don't work when
+// the screen saver is active.
++ (BOOL)isScreenSaverActive;
+
+// Allows for posting either a keydown or a keyup with all the modifiers being
+// applied. Passing a 'g' with NSKeyDown and NSShiftKeyMask
+// generates two events (a shift key key down and a 'g' key keydown). Make sure
+// to balance this with a keyup, or things could get confused. Events get posted
+// using the CGRemoteOperation events which means that it gets posted in the
+// system event queue. Thus you can affect other applications if your app isn't
+// the active app (or in some cases, such as hotkeys, even if it is).
+// Arguments:
+// type - Event type. Currently accepts NSKeyDown and NSKeyUp
+// keyChar - character on the keyboard to type. Make sure it is lower case.
+// If you need upper case, pass in the NSShiftKeyMask in the
+// modifiers. i.e. to generate "G" pass in 'g' and NSShiftKeyMask.
+// to generate "+" pass in '=' and NSShiftKeyMask.
+// cocoaModifiers - an int made up of bit masks. Handles NSAlphaShiftKeyMask,
+// NSShiftKeyMask, NSControlKeyMask, NSAlternateKeyMask, and
+// NSCommandKeyMask
++ (void)postKeyEvent:(NSEventType)type
+ character:(CGCharCode)keyChar
+ modifiers:(UInt32)cocoaModifiers;
+
+// Syntactic sugar for posting a keydown immediately followed by a key up event
+// which is often what you really want.
+// Arguments:
+// keyChar - character on the keyboard to type. Make sure it is lower case.
+// If you need upper case, pass in the NSShiftKeyMask in the
+// modifiers. i.e. to generate "G" pass in 'g' and NSShiftKeyMask.
+// to generate "+" pass in '=' and NSShiftKeyMask.
+// cocoaModifiers - an int made up of bit masks. Handles NSAlphaShiftKeyMask,
+// NSShiftKeyMask, NSControlKeyMask, NSAlternateKeyMask, and
+// NSCommandKeyMask
++ (void)postTypeCharacterEvent:(CGCharCode)keyChar
+ modifiers:(UInt32)cocoaModifiers;
+
+// Runs the event loop in NSDefaultRunLoopMode until date. Can be useful for
+// testing user interface responses in a controlled timed event loop. For most
+// uses using:
+// [[NSRunLoop currentRunLoop] runUntilDate:date]
+// will do. The only reason you would want to use this is if you were
+// using the postKeyEvent:character:modifiers to send events and wanted to
+// receive user input.
+// Arguments:
+// date - end of execution time
++ (void)runUntilDate:(NSDate*)date;
+
@end
diff --git a/UnitTesting/GTMUnitTestingUtilities.m b/UnitTesting/GTMUnitTestingUtilities.m
index 39534f7..e72a921 100644
--- a/UnitTesting/GTMUnitTestingUtilities.m
+++ b/UnitTesting/GTMUnitTestingUtilities.m
@@ -19,16 +19,19 @@
#import "GTMUnitTestingUtilities.h"
#import <AppKit/AppKit.h>
#import "GTMDefines.h"
+#import "GTMGarbageCollection.h"
// The Users profile before we change it on them
-static CMProfileRef gCurrentColorProfile = NULL;
+static CMProfileRef gGTMCurrentColorProfile = NULL;
// Compares two color profiles
-static BOOL AreCMProfilesEqual(CMProfileRef a, CMProfileRef b);
+static BOOL GTMAreCMProfilesEqual(CMProfileRef a, CMProfileRef b);
// Stores the user's color profile away, and changes over to generic.
-static void SetColorProfileToGenericRGB();
+static void GTMSetColorProfileToGenericRGB();
// Restores the users profile.
-static void RestoreColorProfile(void);
+static void GTMRestoreColorProfile(void);
+
+static CGKeyCode GTMKeyCodeForCharCode(CGCharCode charCode);
@implementation GTMUnitTestingUtilities
@@ -81,7 +84,7 @@ static void RestoreColorProfile(void);
[defaults setFloat:.001f forKey:@"NSWindowResizeTime"];
// Switch over the screen profile to "generic rgb". This installs an
// atexit handler to return our profile back when we are done.
- SetColorProfileToGenericRGB();
+ GTMSetColorProfileToGenericRGB();
}
+ (void)setUpForUIUnitTestsIfBeingTested {
@@ -91,10 +94,98 @@ static void RestoreColorProfile(void);
}
[pool release];
}
-@end
++ (BOOL)isScreenSaverActive {
+ BOOL answer = NO;
+ ProcessSerialNumber psn;
+ if (GetFrontProcess(&psn) == noErr) {
+ CFDictionaryRef cfProcessInfo
+ = ProcessInformationCopyDictionary(&psn,
+ kProcessDictionaryIncludeAllInformationMask);
+ NSDictionary *processInfo = GTMCFAutorelease(cfProcessInfo);
+
+ NSString *bundlePath = [processInfo objectForKey:@"BundlePath"];
+ // ScreenSaverEngine is the frontmost app if the screen saver is actually
+ // running Security Agent is the frontmost app if the "enter password"
+ // dialog is showing
+ NSString *bundleName = [bundlePath lastPathComponent];
+ answer = ([bundleName isEqualToString:@"ScreenSaverEngine.app"]
+ || [bundleName isEqualToString:@"SecurityAgent.app"]);
+ }
+ return answer;
+}
+
+// Allows for posting either a keydown or a keyup with all the modifiers being
+// applied. Passing a 'g' with NSKeyDown and NSShiftKeyMask
+// generates two events (a shift key key down and a 'g' key keydown). Make sure
+// to balance this with a keyup, or things could get confused. Events get posted
+// using the CGRemoteOperation events which means that it gets posted in the
+// system event queue. Thus you can affect other applications if your app isn't
+// the active app (or in some cases, such as hotkeys, even if it is).
+// Arguments:
+// type - Event type. Currently accepts NSKeyDown and NSKeyUp
+// keyChar - character on the keyboard to type. Make sure it is lower case.
+// If you need upper case, pass in the NSShiftKeyMask in the
+// modifiers. i.e. to generate "G" pass in 'g' and NSShiftKeyMask.
+// to generate "+" pass in '=' and NSShiftKeyMask.
+// cocoaModifiers - an int made up of bit masks. Handles NSAlphaShiftKeyMask,
+// NSShiftKeyMask, NSControlKeyMask, NSAlternateKeyMask, and
+// NSCommandKeyMask
++ (void)postKeyEvent:(NSEventType)type
+ character:(CGCharCode)keyChar
+ modifiers:(UInt32)cocoaModifiers {
+ require(![self isScreenSaverActive], CantWorkWithScreenSaver);
+ require(type == NSKeyDown || type == NSKeyUp, CantDoEvent);
+ CGKeyCode code = GTMKeyCodeForCharCode(keyChar);
+ verify(code != 256);
+ CGEventRef event = CGEventCreateKeyboardEvent(NULL, code, type == NSKeyDown);
+ require(event, CantCreateEvent);
+ CGEventSetFlags(event, cocoaModifiers);
+ CGEventPost(kCGSessionEventTap, event);
+ CFRelease(event);
+CantCreateEvent:
+CantDoEvent:
+CantWorkWithScreenSaver:
+ return;
+}
+
+// Syntactic sugar for posting a keydown immediately followed by a key up event
+// which is often what you really want.
+// Arguments:
+// keyChar - character on the keyboard to type. Make sure it is lower case.
+// If you need upper case, pass in the NSShiftKeyMask in the
+// modifiers. i.e. to generate "G" pass in 'g' and NSShiftKeyMask.
+// to generate "+" pass in '=' and NSShiftKeyMask.
+// cocoaModifiers - an int made up of bit masks. Handles NSAlphaShiftKeyMask,
+// NSShiftKeyMask, NSControlKeyMask, NSAlternateKeyMask, and
+// NSCommandKeyMask
++ (void)postTypeCharacterEvent:(CGCharCode)keyChar modifiers:(UInt32)cocoaModifiers {
+ [self postKeyEvent:NSKeyDown character:keyChar modifiers:cocoaModifiers];
+ [self postKeyEvent:NSKeyUp character:keyChar modifiers:cocoaModifiers];
+}
+
+// Runs the event loop in NSDefaultRunLoopMode until date. Can be useful for
+// testing user interface responses in a controlled timed event loop. For most
+// uses using:
+// [[NSRunLoop currentRunLoop] runUntilDate:date]
+// will do. The only reason you would want to use this is if you were
+// using the postKeyEvent:character:modifiers to send events and wanted to
+// receive user input.
+// Arguments:
+// date - end of execution time
++ (void)runUntilDate:(NSDate*)date {
+ NSEvent *event;
+ while ((event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:date
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES])) {
+ [NSApp sendEvent:event];
+ }
+}
+
+@end
-BOOL AreCMProfilesEqual(CMProfileRef a, CMProfileRef b) {
+BOOL GTMAreCMProfilesEqual(CMProfileRef a, CMProfileRef b) {
BOOL equal = YES;
if (a != b) {
CMProfileMD5 aMD5;
@@ -102,17 +193,18 @@ BOOL AreCMProfilesEqual(CMProfileRef a, CMProfileRef b) {
CMError aMD5Err = CMGetProfileMD5(a, aMD5);
CMError bMD5Err = CMGetProfileMD5(b, bMD5);
equal = (!aMD5Err &&
- !bMD5Err &&
- !memcmp(aMD5, bMD5, sizeof(CMProfileMD5))) ? YES : NO;
+ !bMD5Err &&
+ !memcmp(aMD5, bMD5, sizeof(CMProfileMD5))) ? YES : NO;
}
return equal;
}
-static void RestoreColorProfile(void) {
- if (gCurrentColorProfile) {
+void GTMRestoreColorProfile(void) {
+ if (gGTMCurrentColorProfile) {
CGDirectDisplayID displayID = CGMainDisplayID();
- CMError error = CMSetProfileByAVID((UInt32)displayID, gCurrentColorProfile);
- CMCloseProfile(gCurrentColorProfile);
+ CMError error = CMSetProfileByAVID((UInt32)displayID,
+ gGTMCurrentColorProfile);
+ CMCloseProfile(gGTMCurrentColorProfile);
if (error) {
// COV_NF_START
// No way to force this case in a unittest.
@@ -123,11 +215,11 @@ static void RestoreColorProfile(void) {
} else {
_GTMDevLog(@"Color profile restored");
}
- gCurrentColorProfile = NULL;
+ gGTMCurrentColorProfile = NULL;
}
}
-void SetColorProfileToGenericRGB(void) {
+void GTMSetColorProfileToGenericRGB(void) {
NSColorSpace *genericSpace = [NSColorSpace genericRGBColorSpace];
CMProfileRef genericProfile = (CMProfileRef)[genericSpace colorSyncProfile];
CMProfileRef previousProfile;
@@ -143,7 +235,7 @@ void SetColorProfileToGenericRGB(void) {
return;
// COV_NF_END
}
- if (AreCMProfilesEqual(genericProfile, previousProfile)) {
+ if (GTMAreCMProfilesEqual(genericProfile, previousProfile)) {
CMCloseProfile(previousProfile);
return;
}
@@ -166,9 +258,53 @@ void SetColorProfileToGenericRGB(void) {
"a result. (Error: %i)", genericProfileName, error);
// COV_NF_END
} else {
- gCurrentColorProfile = previousProfile;
- atexit(RestoreColorProfile);
+ gGTMCurrentColorProfile = previousProfile;
+ atexit(GTMRestoreColorProfile);
}
CFRelease(previousProfileName);
CFRelease(genericProfileName);
}
+
+// Returns a virtual key code for a given charCode. Handles all of the
+// NS*FunctionKeys as well.
+static CGKeyCode GTMKeyCodeForCharCode(CGCharCode charCode) {
+ // character map taken from http://classicteck.com/rbarticles/mackeyboard.php
+ int characters[] = {
+ 'a', 's', 'd', 'f', 'h', 'g', 'z', 'x', 'c', 'v', 256, 'b', 'q', 'w',
+ 'e', 'r', 'y', 't', '1', '2', '3', '4', '6', '5', '=', '9', '7', '-',
+ '8', '0', ']', 'o', 'u', '[', 'i', 'p', '\n', 'l', 'j', '\'', 'k', ';',
+ '\\', ',', '/', 'n', 'm', '.', '\t', ' ', '`', '\b', 256, '\e'
+ };
+
+ // function key map taken from
+ // file:///Developer/ADC%20Reference%20Library/documentation/Cocoa/Reference/ApplicationKit/ObjC_classic/Classes/NSEvent.html
+ int functionKeys[] = {
+ // NSUpArrowFunctionKey - NSF12FunctionKey
+ 126, 125, 123, 124, 122, 120, 99, 118, 96, 97, 98, 100, 101, 109, 103, 111,
+ // NSF13FunctionKey - NSF28FunctionKey
+ 105, 107, 113, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
+ // NSF29FunctionKey - NSScrollLockFunctionKey
+ 256, 256, 256, 256, 256, 256, 256, 256, 117, 115, 256, 119, 116, 121, 256, 256,
+ // NSPauseFunctionKey - NSPrevFunctionKey
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
+ // NSNextFunctionKey - NSModeSwitchFunctionKey
+ 256, 256, 256, 256, 256, 256, 114, 1
+ };
+
+ CGKeyCode outCode = 0;
+
+ // Look in the function keys
+ if (charCode >= NSUpArrowFunctionKey && charCode <= NSModeSwitchFunctionKey) {
+ outCode = functionKeys[charCode - NSUpArrowFunctionKey];
+ } else {
+ // Look in our character map
+ for (size_t i = 0; i < (sizeof(characters) / sizeof (int)); i++) {
+ if (characters[i] == charCode) {
+ outCode = i;
+ break;
+ }
+ }
+ }
+ return outCode;
+}
+
diff --git a/UnitTesting/RunIPhoneUnitTest.sh b/UnitTesting/RunIPhoneUnitTest.sh
index 0b6fe69..bf25714 100755
--- a/UnitTesting/RunIPhoneUnitTest.sh
+++ b/UnitTesting/RunIPhoneUnitTest.sh
@@ -75,6 +75,13 @@ if [ "$PLATFORM_NAME" == "iphonesimulator" ]; then
export NSZombieEnabled=YES
fi
+ # Cleanup user home and documents directory
+ if [ -d "$CFFIXED_USER_HOME" ]; then
+ rm -rf "$CFFIXED_USER_HOME"
+ fi
+ mkdir "$CFFIXED_USER_HOME"
+ mkdir "$CFFIXED_USER_HOME/Documents"
+
# 6251475 iPhone simulator leaks @ CFHTTPCookieStore shutdown if
# CFFIXED_USER_HOME empty
GTM_LEAKS_SYMBOLS_TO_IGNORE="CFHTTPCookieStore"