aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar thomasvl@gmail.com <thomasvl@gmail.com@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2009-01-09 20:34:30 +0000
committerGravatar thomasvl@gmail.com <thomasvl@gmail.com@7dc7ac4e-7543-0410-b95c-c1676fc8e2a3>2009-01-09 20:34:30 +0000
commit4fd103b5de98d2f469b982677ea389e7ee7d64b3 (patch)
treed0eb379fdc78996bc2e201515d26c7521d1fc8dc
parent84d1232477f398339e48ea504c45048e9328ef9b (diff)
- turned off _debug framework support in tests since we now capture a lot more
in log validation. - Added GTM_SUPPORT_GC for controlling the inclusion of GC related code. - If you are using GTMUnitTestDevLog, it also tries to capture logs from NSAssert. - Added GTM_FOREACH_OBJECT/GTM_FOREACH_KEY that uses NSEnumerator and objectEnumerator/keyEnumerator on 10.4, but on 10.5+/iPhone uses FastEnumeration. - GTMNSWorkspace+Running gives a variety of ways of determining the attributes of running processes.
-rw-r--r--AppKit/GTMCarbonEvent.m5
-rw-r--r--AppKit/GTMCarbonEventTest.m6
-rw-r--r--AppKit/GTMGetURLHandler.m16
-rw-r--r--AppKit/GTMHotKeyTextField.m8
-rw-r--r--AppKit/GTMLinearRGBShading.m3
-rw-r--r--AppKit/GTMLoginItems.m3
-rw-r--r--AppKit/GTMLoginItemsTest.m3
-rw-r--r--AppKit/GTMNSImage+Scaling.m20
-rw-r--r--AppKit/GTMNSWorkspace+Running.h80
-rw-r--r--AppKit/GTMNSWorkspace+Running.m171
-rw-r--r--AppKit/GTMNSWorkspace+RunningTest.m78
-rw-r--r--Foundation/GTMCalculatedRange.m9
-rw-r--r--Foundation/GTMFileSystemKQueue.m2
-rw-r--r--Foundation/GTMHTTPFetcher.m6
-rw-r--r--Foundation/GTMHTTPServer.m2
-rw-r--r--Foundation/GTMLightweightProxy.m4
-rw-r--r--Foundation/GTMLogger+ASL.m3
-rw-r--r--Foundation/GTMLogger.m3
-rw-r--r--Foundation/GTMNSAppleEventDescriptor+Foundation.m32
-rw-r--r--Foundation/GTMNSAppleEventDescriptor+FoundationTest.m2
-rw-r--r--Foundation/GTMNSArray+Merge.m3
-rw-r--r--Foundation/GTMNSDictionary+URLArguments.m4
-rw-r--r--Foundation/GTMNSFileManager+Path.m7
-rw-r--r--Foundation/GTMRegex.h4
-rw-r--r--Foundation/GTMRegex.m5
-rw-r--r--Foundation/GTMSignalHandler.m2
-rw-r--r--GTM.xcodeproj/project.pbxproj12
-rw-r--r--GTMDefines.h37
-rw-r--r--ReleaseNotes.txt18
-rw-r--r--UnitTesting/GTMAppKit+UnitTesting.m14
-rw-r--r--UnitTesting/GTMNSObject+BindingUnitTesting.h3
-rw-r--r--UnitTesting/GTMNSObject+BindingUnitTesting.m6
-rw-r--r--UnitTesting/GTMNSObject+UnitTesting.m13
-rw-r--r--UnitTesting/GTMSenTestCase.m6
-rw-r--r--UnitTesting/GTMUIKit+UnitTesting.m6
-rw-r--r--UnitTesting/GTMUnitTestDevLog.m71
-rw-r--r--UnitTesting/GTMUnitTestingBindingTest.m3
-rwxr-xr-xUnitTesting/RunMacOSUnitTests.sh9
-rw-r--r--iPhone/GTMABAddressBook.m6
39 files changed, 577 insertions, 108 deletions
diff --git a/AppKit/GTMCarbonEvent.m b/AppKit/GTMCarbonEvent.m
index 270a078..16c46c8 100644
--- a/AppKit/GTMCarbonEvent.m
+++ b/AppKit/GTMCarbonEvent.m
@@ -141,6 +141,7 @@
return carbonEvent;
}
+#if GTM_SUPPORT_GC
- (void)finalize {
if (event_) {
ReleaseEvent(event_);
@@ -148,6 +149,7 @@
}
[super finalize];
}
+#endif
// releases our retained event
//
@@ -596,9 +598,8 @@ CantRegisterHotkey:
BOOL handled = [event getEventHotKeyIDParameterNamed:kEventParamDirectObject
data:&keyID];
if (handled) {
- NSEnumerator *dictEnumerator = [hotkeys_ objectEnumerator];
GTMCarbonHotKey *hotkey;
- while ((hotkey = [dictEnumerator nextObject])) {
+ GTM_FOREACH_OBJECT(hotkey, [hotkeys_ allValues]) {
if ([hotkey matchesHotKeyID:keyID]) {
EventKind kind = [event eventKind];
BOOL onKeyDown = [hotkey onKeyDown];
diff --git a/AppKit/GTMCarbonEventTest.m b/AppKit/GTMCarbonEventTest.m
index a1a8b2b..f7b4d54 100644
--- a/AppKit/GTMCarbonEventTest.m
+++ b/AppKit/GTMCarbonEventTest.m
@@ -274,7 +274,11 @@ static const UInt32 kTestParameterValue = 'bam ';
whenPressed:YES],
@"Shouldn't have created hotkey");
#if DEBUG
- // This test debug selector validation, so we only can do it in debug.
+ // This tests debug selector validation, so we only can do it in debug.
+ [GTMUnitTestDevLogDebug expectPattern:@"RecordedNSAssert in "
+ @"GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments - "
+ @"\"GTMCarbonEventDispatcherHandlerTest\" selector \"badSelector:\" is "
+ @"unimplemented or misnamed \\(.*/GTMDebugSelectorValidation.h:[0-9]*\\)"];
STAssertThrowsSpecificNamed([dispatcher registerHotKey:0x5
modifiers:keyMods
target:self
diff --git a/AppKit/GTMGetURLHandler.m b/AppKit/GTMGetURLHandler.m
index 66c02eb..dcac292 100644
--- a/AppKit/GTMGetURLHandler.m
+++ b/AppKit/GTMGetURLHandler.m
@@ -149,9 +149,8 @@ withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
// classes properly. We check here instead of at init in case some of the
// handlers are being handled by plugins or other imported code that are
// loaded after we have been initialized.
- NSEnumerator *enumerator = [urlTypes_ objectEnumerator];
NSDictionary *urlType;
- while ((urlType = [enumerator nextObject])) {
+ GTM_FOREACH_OBJECT(urlType, urlTypes_) {
NSString *className = [urlType objectForKey:kGTMBundleURLClassKey];
if ([className length]) {
Class cls = NSClassFromString(className);
@@ -215,18 +214,21 @@ withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
- (Class)getClassForScheme:(NSString *)scheme
withReplyEvent:(NSAppleEventDescriptor*)replyEvent {
- NSEnumerator *typeEnumerator = [urlTypes_ objectEnumerator];
NSDictionary *urlType;
Class cls = nil;
NSString *typeScheme = nil;
- while (!typeScheme && (urlType = [typeEnumerator nextObject])) {
+ GTM_FOREACH_OBJECT(urlType, urlTypes_) {
NSArray *schemes = [urlType objectForKey:kGTMCFBundleURLSchemesKey];
- NSEnumerator *schemeEnumerator = [schemes objectEnumerator];
- while ((typeScheme = [schemeEnumerator nextObject])) {
- if ([typeScheme caseInsensitiveCompare:scheme] == NSOrderedSame) {
+ NSString *aScheme;
+ GTM_FOREACH_OBJECT(aScheme, schemes) {
+ if ([aScheme caseInsensitiveCompare:scheme] == NSOrderedSame) {
+ typeScheme = aScheme;
break;
}
}
+ if (typeScheme) {
+ break;
+ }
}
if (typeScheme) {
NSString *class = [urlType objectForKey:kGTMBundleURLClassKey];
diff --git a/AppKit/GTMHotKeyTextField.m b/AppKit/GTMHotKeyTextField.m
index 3a604be..0f14e48 100644
--- a/AppKit/GTMHotKeyTextField.m
+++ b/AppKit/GTMHotKeyTextField.m
@@ -48,12 +48,14 @@ static CFStringRef kGTM_TISPropertyUnicodeKeyLayoutData = NULL;
@implementation GTMHotKeyTextField
+#if GTM_SUPPORT_GC
- (void)finalize {
if (boundObject_ && boundKeyPath_) {
[boundObject_ removeObserver:self forKeyPath:boundKeyPath_];
}
[super finalize];
}
+#endif
- (void)dealloc {
@@ -690,10 +692,12 @@ static CFStringRef kGTM_TISPropertyUnicodeKeyLayoutData = NULL;
sizeof(uchrChars) / sizeof(UniChar),
&uchrCharLength,
uchrChars);
- if (err != noErr) { // COV_NF_START
+ if (err != noErr) {
+ // COV_NF_START
_GTMDevLog(@"failed to translate the keycode, err=%d", err);
return nil;
- } // COV_NF_END
+ // COV_NF_END
+ }
if (uchrCharLength < 1) return nil;
keystrokeString = [NSString stringWithCharacters:uchrChars
length:uchrCharLength];
diff --git a/AppKit/GTMLinearRGBShading.m b/AppKit/GTMLinearRGBShading.m
index f0216bf..af70086 100644
--- a/AppKit/GTMLinearRGBShading.m
+++ b/AppKit/GTMLinearRGBShading.m
@@ -17,6 +17,7 @@
//
#import "GTMLinearRGBShading.h"
+#import "GTMDefines.h"
// Carbon callback function required for CoreGraphics
static void cShadeFunction(void *info, const CGFloat *inPos, CGFloat *outVals);
@@ -57,6 +58,7 @@ static void cShadeFunction(void *info, const CGFloat *inPos, CGFloat *outVals);
return self;
}
+#if GTM_SUPPORT_GC
- (void)finalize {
if (nil != function_) {
CGFunctionRelease(function_);
@@ -66,6 +68,7 @@ static void cShadeFunction(void *info, const CGFloat *inPos, CGFloat *outVals);
}
[super finalize];
}
+#endif
- (void)dealloc {
if (nil != function_) {
diff --git a/AppKit/GTMLoginItems.m b/AppKit/GTMLoginItems.m
index 1e59e70..c3dedfe 100644
--- a/AppKit/GTMLoginItems.m
+++ b/AppKit/GTMLoginItems.m
@@ -42,9 +42,8 @@ NSString * const kGTMLoginItemsHiddenKey = @"Hide";
loginItems:(NSArray *)items {
if (!value || !key || !items) return NSNotFound;
NSDictionary *item = nil;
- NSEnumerator *itemsEnum = [items objectEnumerator];
NSInteger found = -1;
- while ((item = [itemsEnum nextObject])) {
+ GTM_FOREACH_OBJECT(item, items) {
++found;
id itemValue = [item objectForKey:key];
if (itemValue && [itemValue isEqual:value]) {
diff --git a/AppKit/GTMLoginItemsTest.m b/AppKit/GTMLoginItemsTest.m
index 980f772..50b7482 100644
--- a/AppKit/GTMLoginItemsTest.m
+++ b/AppKit/GTMLoginItemsTest.m
@@ -31,8 +31,7 @@
static BOOL ItemsListHasPath(NSArray *items, NSString *path) {
NSDictionary *item = nil;
- NSEnumerator *itemsEnum = [items objectEnumerator];
- while ((item = [itemsEnum nextObject])) {
+ GTM_FOREACH_OBJECT(item, items) {
NSString *itemPath = [item objectForKey:kGTMLoginItemsPathKey];
if (itemPath && [itemPath isEqual:path]) {
return YES;
diff --git a/AppKit/GTMNSImage+Scaling.m b/AppKit/GTMNSImage+Scaling.m
index 5f31190..8283b29 100644
--- a/AppKit/GTMNSImage+Scaling.m
+++ b/AppKit/GTMNSImage+Scaling.m
@@ -36,8 +36,7 @@
CGFloat repDistance = CGFLOAT_MAX;
NSImageRep *thisRep;
- NSEnumerator *repEnum = [reps objectEnumerator];
- while ((thisRep = [repEnum nextObject])) {
+ GTM_FOREACH_OBJECT(thisRep, reps) {
CGFloat thisDistance;
thisDistance = MIN(size.width - [thisRep size].width,
size.height - [thisRep size].height);
@@ -62,8 +61,7 @@
NSArray *reps = [self representations];
NSImageRep *thisRep;
- NSEnumerator *repEnum = [reps objectEnumerator];
- while ((thisRep = [repEnum nextObject])) {
+ GTM_FOREACH_OBJECT(thisRep, reps) {
if (NSEqualSizes([thisRep size], size)) {
return thisRep;
}
@@ -155,12 +153,18 @@
}
- (void)gtm_removeRepresentationsLargerThanSize:(NSSize)size {
- NSEnumerator *e = [[self representations] reverseObjectEnumerator];
+ NSMutableArray *repsToRemove = [NSMutableArray array];
NSImageRep *thisRep;
- while((thisRep = [e nextObject]) ) {
+ // Remove them in a second loop so we don't change things will doing the
+ // initial loop.
+ GTM_FOREACH_OBJECT(thisRep, [self representations]) {
if ([thisRep size].width > size.width
- && [thisRep size].height > size.height)
- [self removeRepresentation:thisRep];
+ && [thisRep size].height > size.height) {
+ [repsToRemove addObject:thisRep];
+ }
+ }
+ GTM_FOREACH_OBJECT(thisRep, repsToRemove) {
+ [self removeRepresentation:thisRep];
}
}
diff --git a/AppKit/GTMNSWorkspace+Running.h b/AppKit/GTMNSWorkspace+Running.h
new file mode 100644
index 0000000..7e9dc6d
--- /dev/null
+++ b/AppKit/GTMNSWorkspace+Running.h
@@ -0,0 +1,80 @@
+//
+// GTMNSWorkspace+Running.h
+//
+// Copyright 2007-2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import <AppKit/AppKit.h>
+#import "GTMDefines.h"
+
+// Process Dictionary keys
+// Make sure to use numberToProcessSerialNumber: on the return values
+// of these keys to get valid PSNs on both Leopard and Tiger.
+// Numeric types come back as a NSNumber.
+GTM_EXTERN NSString *const kGTMWorkspaceRunningPSN; // long long
+GTM_EXTERN NSString *const kGTMWorkspaceRunningParentPSN; // long long
+
+GTM_EXTERN NSString *const kGTMWorkspaceRunningFlavor; // SInt32
+GTM_EXTERN NSString *const kGTMWorkspaceRunningAttributes; // SInt32
+GTM_EXTERN NSString *const kGTMWorkspaceRunningFileType; // NSString
+GTM_EXTERN NSString *const kGTMWorkspaceRunningFileCreator; // NSString
+GTM_EXTERN NSString *const kGTMWorkspaceRunningPID; // long
+GTM_EXTERN NSString *const kGTMWorkspaceRunningLSBackgroundOnly; // bool
+GTM_EXTERN NSString *const kGTMWorkspaceRunningLSUIElement; // bool
+GTM_EXTERN NSString *const kGTMWorkspaceRunningIsHidden; // bool
+GTM_EXTERN NSString *const kGTMWorkspaceRunningCheckedIn; // bool
+GTM_EXTERN NSString *const kGTMWorkspaceRunningLSUIPresentationMode; // Short
+GTM_EXTERN NSString *const kGTMWorkspaceRunningBundlePath; // NSString
+GTM_EXTERN NSString *const kGTMWorkspaceRunningBundleExecutable; // NSString
+GTM_EXTERN NSString *const kGTMWorkspaceRunningBundleName; // NSString
+GTM_EXTERN NSString *const kGTMWorkspaceRunningBundleIdentifier; // NSString
+GTM_EXTERN NSString *const kGTMWorkspaceRunningBundleVersion; // NSString
+
+// A category for getting information about other running processes
+@interface NSWorkspace (GTMWorkspaceRunningAdditions)
+
+// Returns a YES/NO if a process w/ the given identifier is running
+- (BOOL)gtm_isAppWithIdentifierRunning:(NSString *)identifier;
+
+// Returns a dictionary with info for our process.
+//See Process Dictionary Keys above for values
+- (NSDictionary *)gtm_processInfoDictionary;
+
+// Returns a dictionary with info for the active process.
+// See Process Dictionary Keys above for values
+- (NSDictionary *)gtm_processInfoDictionaryForActiveApp;
+
+// Returns a dictionary with info for the process.
+//See Process Dictionary Keys above for values
+- (NSDictionary *)gtm_processInfoDictionaryForPID:(pid_t)pid;
+
+// Returns a dictionary with info for the process.
+// See Process Dictionary Keys above for values
+- (NSDictionary *)gtm_processInfoDictionaryForPSN:(const ProcessSerialNumberPtr)psn;
+
+// Returns true if we were launched as a login item.
+- (BOOL)gtm_wasLaunchedAsLoginItem;
+
+// Returns true if we were launched by a given bundleid
+- (BOOL)gtm_wasLaunchedByProcess:(NSString*)bundleid;
+
+// Returns true if the PSN was found for the running app with bundleID
+- (BOOL)gtm_processSerialNumber:(ProcessSerialNumber*)outPSN
+ withBundleID:(NSString*)bundleID;
+
+// Converts PSNs stored in NSNumbers to real PSNs
+- (ProcessSerialNumber)gtm_numberToProcessSerialNumber:(NSNumber*)number;
+
+@end
diff --git a/AppKit/GTMNSWorkspace+Running.m b/AppKit/GTMNSWorkspace+Running.m
new file mode 100644
index 0000000..a031043
--- /dev/null
+++ b/AppKit/GTMNSWorkspace+Running.m
@@ -0,0 +1,171 @@
+//
+// GTMNSWorkspace+Running.m
+//
+// Copyright 2007-2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import "GTMNSWorkspace+Running.h"
+#import <Carbon/Carbon.h>
+#import <unistd.h>
+#import "GTMGarbageCollection.h"
+#import "GTMSystemVersion.h"
+
+NSString *const kGTMWorkspaceRunningPSN = @"PSN";
+NSString *const kGTMWorkspaceRunningFlavor = @"Flavor";
+NSString *const kGTMWorkspaceRunningAttributes = @"Attributes";
+NSString *const kGTMWorkspaceRunningParentPSN = @"ParentPSN";
+NSString *const kGTMWorkspaceRunningFileType = @"FileType";
+NSString *const kGTMWorkspaceRunningFileCreator = @"FileCreator";
+NSString *const kGTMWorkspaceRunningPID = @"pid";
+NSString *const kGTMWorkspaceRunningLSBackgroundOnly = @"LSBackgroundOnly";
+NSString *const kGTMWorkspaceRunningLSUIElement = @"LSUIElement";
+NSString *const kGTMWorkspaceRunningIsHidden = @"IsHiddenAttr";
+NSString *const kGTMWorkspaceRunningCheckedIn = @"IsCheckedInAttr";
+NSString *const kGTMWorkspaceRunningLSUIPresentationMode
+ = @"LSUIPresentationMode";
+NSString *const kGTMWorkspaceRunningBundlePath = @"BundlePath";
+NSString *const kGTMWorkspaceRunningBundleExecutable = @"CFBundleExecutable";
+NSString *const kGTMWorkspaceRunningBundleName = @"CFBundleName";
+NSString *const kGTMWorkspaceRunningBundleIdentifier = @"CFBundleIdentifier";
+NSString *const kGTMWorkspaceRunningBundleVersion = @"CFBundleVersion";
+
+@implementation NSWorkspace (GTMWorkspaceRunningAdditions)
+
+/// Returns a YES/NO if a process w/ the given identifier is running
+- (BOOL)gtm_isAppWithIdentifierRunning:(NSString *)identifier {
+ if ([identifier length] == 0) return NO;
+ NSArray *launchedApps = [self launchedApplications];
+ NSArray *buildIDs
+ = [launchedApps valueForKey:@"NSApplicationBundleIdentifier"];
+ return [buildIDs containsObject:identifier];
+}
+
+- (NSDictionary *)gtm_processInfoDictionaryForPID:(pid_t)pid {
+ NSDictionary *dict = nil;
+ ProcessSerialNumber psn;
+ if (GetProcessForPID(pid, &psn) == noErr) {
+ dict = [self gtm_processInfoDictionaryForPSN:&psn];
+ }
+ return dict;
+}
+
+- (NSDictionary *)gtm_processInfoDictionaryForPSN:(ProcessSerialNumberPtr)psn {
+ NSDictionary *dict = nil;
+ if (psn) {
+ CFDictionaryRef cfDict
+ = ProcessInformationCopyDictionary(psn,
+ kProcessDictionaryIncludeAllInformationMask);
+ dict = GTMCFAutorelease(cfDict);
+ }
+ return dict;
+}
+
+- (NSDictionary *)gtm_processInfoDictionary {
+ NSDictionary *dict = nil;
+ ProcessSerialNumber selfNumber;
+ if (MacGetCurrentProcess(&selfNumber) == noErr) {
+ dict = [self gtm_processInfoDictionaryForPSN:&selfNumber];
+ }
+ return dict;
+}
+
+- (NSDictionary *)gtm_processInfoDictionaryForActiveApp {
+ NSDictionary *processDict = nil;
+ ProcessSerialNumber psn;
+ OSStatus status = GetFrontProcess(&psn);
+ if (status == noErr) {
+ processDict = [self gtm_processInfoDictionaryForPSN:&psn];
+ }
+ return processDict;
+}
+
+- (BOOL)gtm_wasLaunchedAsLoginItem {
+ // If the launching process was 'loginwindow', we were launched as a login
+ // item
+ return [self gtm_wasLaunchedByProcess:@"com.apple.loginwindow"];
+}
+
+- (BOOL)gtm_wasLaunchedByProcess:(NSString*)bundleid {
+ BOOL wasLaunchedByProcess = NO;
+ NSDictionary *processInfo = [self gtm_processInfoDictionary];
+ if (processInfo) {
+ NSNumber *processNumber
+ = [processInfo objectForKey:kGTMWorkspaceRunningParentPSN];
+ ProcessSerialNumber parentPSN
+ = [self gtm_numberToProcessSerialNumber:processNumber];
+ NSDictionary *parentProcessInfo
+ = [self gtm_processInfoDictionaryForPSN:&parentPSN];
+ NSString *parentBundle
+ = [parentProcessInfo objectForKey:kGTMWorkspaceRunningBundleIdentifier];
+ wasLaunchedByProcess
+ = [parentBundle isEqualToString:bundleid];
+ }
+ return wasLaunchedByProcess;
+}
+
+- (BOOL)gtm_processSerialNumber:(ProcessSerialNumber*)outPSN
+ withBundleID:(NSString*)bundleID {
+ if (!outPSN || [bundleID length] == 0) {
+ return NO;
+ }
+
+ NSArray *apps = [self launchedApplications];
+
+ NSEnumerator *enumerator = [apps objectEnumerator];
+ NSDictionary *dict;
+
+ while ((dict = [enumerator nextObject])) {
+ NSString *nextID = [dict objectForKey:@"NSApplicationBundleIdentifier"];
+
+ if ([nextID isEqualToString:bundleID]) {
+ NSNumber *psn
+ = [dict objectForKey:@"NSApplicationProcessSerialNumberLow"];
+ outPSN->lowLongOfPSN = [psn unsignedIntValue];
+
+ psn = [dict objectForKey:@"NSApplicationProcessSerialNumberHigh"];
+ outPSN->highLongOfPSN = [psn unsignedIntValue];
+
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+- (ProcessSerialNumber)gtm_numberToProcessSerialNumber:(NSNumber*)number {
+ // There is a bug in Tiger where they were packing ProcessSerialNumbers
+ // incorrectly into the longlong that they stored in the dictionary.
+ // This fixes it.
+ ProcessSerialNumber outPSN = { kNoProcess, kNoProcess};
+ if (number) {
+ long long temp = [number longLongValue];
+ UInt32 hi = (UInt32)((temp >> 32) & 0x00000000FFFFFFFFLL);
+ UInt32 lo = (UInt32)((temp >> 0) & 0x00000000FFFFFFFFLL);
+ if ([GTMSystemVersion isLeopardOrGreater]) {
+ outPSN.highLongOfPSN = hi;
+ outPSN.lowLongOfPSN = lo;
+ } else {
+#if TARGET_RT_BIG_ENDIAN
+ outPSN.highLongOfPSN = hi;
+ outPSN.lowLongOfPSN = lo;
+#else
+ outPSN.highLongOfPSN = lo;
+ outPSN.lowLongOfPSN = hi;
+#endif
+ }
+ }
+ return outPSN;
+}
+@end
diff --git a/AppKit/GTMNSWorkspace+RunningTest.m b/AppKit/GTMNSWorkspace+RunningTest.m
new file mode 100644
index 0000000..abd20a6
--- /dev/null
+++ b/AppKit/GTMNSWorkspace+RunningTest.m
@@ -0,0 +1,78 @@
+//
+// GTMNSWorkspace+RunningTest.m
+//
+// Copyright 2007-2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import "GTMSenTestCase.h"
+#import "GTMNSWorkspace+Running.h"
+#import <unistd.h>
+
+@interface GTMNSWorkspace_RunningTest : GTMTestCase
+@end
+
+@implementation GTMNSWorkspace_RunningTest
+
+- (void)testBasics {
+ NSWorkspace *ws = [NSWorkspace sharedWorkspace];
+ STAssertTrue([ws gtm_isAppWithIdentifierRunning:@"com.apple.finder"], nil);
+ STAssertFalse([ws gtm_isAppWithIdentifierRunning:@"com.google.nothing"], nil);
+
+ NSDictionary *processInfo = [ws gtm_processInfoDictionary];
+ STAssertNotNil(processInfo, nil);
+
+ BOOL wasLaunchedAsLoginItem = [ws gtm_wasLaunchedAsLoginItem];
+ STAssertFalse(wasLaunchedAsLoginItem, nil);
+
+ pid_t pid = getpid();
+ NSDictionary *processInfo2 = [ws gtm_processInfoDictionaryForPID:pid];
+ STAssertNotNil(processInfo2, nil);
+ STAssertEqualObjects(processInfo, processInfo2, nil);
+
+ ProcessSerialNumber num = { 0, 0 };
+ BOOL gotPSN = [ws gtm_processSerialNumber:&num
+ withBundleID:@"com.apple.finder"];
+ STAssertTrue(gotPSN, nil);
+ STAssertGreaterThan(num.highLongOfPSN + num.lowLongOfPSN, (UInt32)0, nil);
+ gotPSN = [ws gtm_processSerialNumber:&num
+ withBundleID:@"bad.bundle.id"];
+ STAssertFalse(gotPSN, nil);
+
+ gotPSN = [ws gtm_processSerialNumber:NULL
+ withBundleID:nil];
+ STAssertFalse(gotPSN, nil);
+
+ processInfo = [ws gtm_processInfoDictionaryForActiveApp];
+ STAssertNotNil(processInfo, nil);
+
+ NSString *const keys[] = {
+ kGTMWorkspaceRunningPSN, kGTMWorkspaceRunningParentPSN,
+ kGTMWorkspaceRunningFlavor, kGTMWorkspaceRunningAttributes,
+ kGTMWorkspaceRunningFileType, kGTMWorkspaceRunningFileCreator,
+ kGTMWorkspaceRunningPID, kGTMWorkspaceRunningLSBackgroundOnly,
+ kGTMWorkspaceRunningLSUIElement, kGTMWorkspaceRunningIsHidden,
+ kGTMWorkspaceRunningCheckedIn, kGTMWorkspaceRunningBundleIdentifier,
+ kGTMWorkspaceRunningBundleVersion, kGTMWorkspaceRunningBundleName,
+ kGTMWorkspaceRunningLSUIPresentationMode, kGTMWorkspaceRunningBundlePath,
+ kGTMWorkspaceRunningBundleExecutable
+ };
+ for (size_t i = 0; i < sizeof(keys) / sizeof(NSString *); ++i) {
+ NSString *const key = keys[i];
+ STAssertNotNil([processInfo objectForKey:key],
+ @"Couldn't get %@ from %@", key, processInfo);
+ }
+}
+
+@end
diff --git a/Foundation/GTMCalculatedRange.m b/Foundation/GTMCalculatedRange.m
index ef49d83..5ab491d 100644
--- a/Foundation/GTMCalculatedRange.m
+++ b/Foundation/GTMCalculatedRange.m
@@ -81,9 +81,8 @@ GTM_INLINE BOOL FPEqual(CGFloat a, CGFloat b) {
- (void)insertStop:(id)item atPosition:(CGFloat)position {
NSUInteger positionIndex = 0;
- NSEnumerator *theEnumerator = [storage_ objectEnumerator];
GTMCalculatedRangeStopPrivate *theStop;
- while (nil != (theStop = [theEnumerator nextObject])) {
+ GTM_FOREACH_OBJECT(theStop, storage_) {
if ([theStop position] < position) {
positionIndex += 1;
}
@@ -100,9 +99,8 @@ GTM_INLINE BOOL FPEqual(CGFloat a, CGFloat b) {
- (BOOL)removeStopAtPosition:(CGFloat)position {
NSUInteger positionIndex = 0;
BOOL foundStop = NO;
- NSEnumerator *theEnumerator = [storage_ objectEnumerator];
GTMCalculatedRangeStopPrivate *theStop;
- while (nil != (theStop = [theEnumerator nextObject])) {
+ GTM_FOREACH_OBJECT(theStop, storage_) {
if (FPEqual([theStop position], position)) {
break;
} else {
@@ -135,8 +133,7 @@ GTM_INLINE BOOL FPEqual(CGFloat a, CGFloat b) {
- (id)valueAtPosition:(CGFloat)position {
id theValue = nil;
GTMCalculatedRangeStopPrivate *theStop;
- NSEnumerator *theEnumerator = [storage_ objectEnumerator];
- while (nil != (theStop = [theEnumerator nextObject])) {
+ GTM_FOREACH_OBJECT(theStop, storage_) {
if (FPEqual([theStop position], position)) {
theValue = [theStop item];
break;
diff --git a/Foundation/GTMFileSystemKQueue.m b/Foundation/GTMFileSystemKQueue.m
index 050d68f..ebb2ec8 100644
--- a/Foundation/GTMFileSystemKQueue.m
+++ b/Foundation/GTMFileSystemKQueue.m
@@ -85,11 +85,13 @@ static CFSocketRef gRunLoopSocket = NULL;
return self;
}
+#if GTM_SUPPORT_GC
- (void)finalize {
[self unregisterWithKQueue];
[super finalize];
}
+#endif
- (void)dealloc {
[self unregisterWithKQueue];
diff --git a/Foundation/GTMHTTPFetcher.m b/Foundation/GTMHTTPFetcher.m
index 34821f2..c3be384 100644
--- a/Foundation/GTMHTTPFetcher.m
+++ b/Foundation/GTMHTTPFetcher.m
@@ -398,9 +398,8 @@ CannotBeginFetch:
// any headers in the redirect override headers in the original.
NSDictionary *redirectHeaders = [redirectRequest allHTTPHeaderFields];
if (redirectHeaders) {
- NSEnumerator *enumerator = [redirectHeaders keyEnumerator];
NSString *key;
- while (nil != (key = [enumerator nextObject])) {
+ GTM_FOREACH_KEY(key, redirectHeaders) {
NSString *value = [redirectHeaders objectForKey:key];
[newRequest setValue:value forHTTPHeaderField:key];
}
@@ -1198,10 +1197,9 @@ CannotBeginFetch:
[self removeExpiredCookiesInArray:cookieStorageArray];
- NSEnumerator *newCookieEnum = [newCookies objectEnumerator];
NSHTTPCookie *newCookie;
- while ((newCookie = [newCookieEnum nextObject]) != nil) {
+ GTM_FOREACH_OBJECT(newCookie, newCookies) {
if ([[newCookie name] length] > 0
&& [[newCookie domain] length] > 0
diff --git a/Foundation/GTMHTTPServer.m b/Foundation/GTMHTTPServer.m
index ecd649c..4ecc9f7 100644
--- a/Foundation/GTMHTTPServer.m
+++ b/Foundation/GTMHTTPServer.m
@@ -94,10 +94,12 @@ static NSString *kResponse = @"Response";
[super dealloc];
}
+#if GTM_SUPPORT_GC
- (void)finalize {
[self stop];
[super finalize];
}
+#endif
- (id)delegate {
return delegate_;
diff --git a/Foundation/GTMLightweightProxy.m b/Foundation/GTMLightweightProxy.m
index 39f5f5c..c00e44b 100644
--- a/Foundation/GTMLightweightProxy.m
+++ b/Foundation/GTMLightweightProxy.m
@@ -17,7 +17,7 @@
//
#import "GTMLightweightProxy.h"
-
+#import "GTMDefines.h"
@implementation GTMLightweightProxy
@@ -28,12 +28,14 @@
}
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+#if GTM_SUPPORT_GC
// -[NSProxy finalize] is only in 10.5 or later
- (void)finalize {
representedObject_ = nil;
[super finalize];
}
#endif
+#endif
- (void)dealloc {
// it's weak, we don't release
diff --git a/Foundation/GTMLogger+ASL.m b/Foundation/GTMLogger+ASL.m
index 2213df6..90ea7e5 100644
--- a/Foundation/GTMLogger+ASL.m
+++ b/Foundation/GTMLogger+ASL.m
@@ -17,6 +17,7 @@
//
#import "GTMLogger+ASL.h"
+#import "GTMDefines.h"
@implementation GTMLogger (GTMLoggerASLAdditions)
@@ -107,10 +108,12 @@
[super dealloc];
}
+#if GTM_SUPPORT_GC
- (void)finalize {
if (client_) asl_close(client_);
[super finalize];
}
+#endif
// We don't test this one line because we don't want to pollute actual system
// logs with test messages.
diff --git a/Foundation/GTMLogger.m b/Foundation/GTMLogger.m
index 4da1034..de941d2 100644
--- a/Foundation/GTMLogger.m
+++ b/Foundation/GTMLogger.m
@@ -291,8 +291,7 @@ static GTMLogger *gSharedLogger = nil;
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
@synchronized(self) {
id<GTMLogWriter> child = nil;
- NSEnumerator *childEnumerator = [self objectEnumerator];
- while ((child = [childEnumerator nextObject])) {
+ GTM_FOREACH_OBJECT(child, self) {
if ([child conformsToProtocol:@protocol(GTMLogWriter)])
[child logMessage:msg level:level];
}
diff --git a/Foundation/GTMNSAppleEventDescriptor+Foundation.m b/Foundation/GTMNSAppleEventDescriptor+Foundation.m
index d0c26ec..b355607 100644
--- a/Foundation/GTMNSAppleEventDescriptor+Foundation.m
+++ b/Foundation/GTMNSAppleEventDescriptor+Foundation.m
@@ -100,15 +100,22 @@ static NSMutableDictionary *gTypeMap = nil;
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
NSAppleEventDescriptor *userRecord = [self descriptorForKeyword:keyASUserRecordFields];
if (userRecord) {
- NSEnumerator *userItems = [[userRecord gtm_arrayValue] objectEnumerator];
- NSString *key;
- while ((key = [userItems nextObject])) {
- NSString *value = [userItems nextObject];
- if (!value) {
- _GTMDevLog(@"Got a key %@ with no value in %@", key, userItems);
- return nil;
+ NSArray *userItems = [userRecord gtm_arrayValue];
+ NSString *key = nil;
+ NSString *item;
+ GTM_FOREACH_OBJECT(item, userItems) {
+ if (key) {
+ // Save the pair and reset our state
+ [dictionary setObject:item forKey:key];
+ key = nil;
+ } else {
+ // Save it for the next pair
+ key = item;
}
- [dictionary setObject:value forKey:key];
+ }
+ if (key) {
+ _GTMDevLog(@"Got a key %@ with no value in %@", key, userItems);
+ return nil;
}
} else {
NSUInteger count = [self numberOfItems];
@@ -291,10 +298,9 @@ static NSMutableDictionary *gTypeMap = nil;
}
- (NSAppleEventDescriptor*)gtm_appleEventDescriptor {
- NSEnumerator* keys = [self keyEnumerator];
Class keyClass = nil;
id key = nil;
- while ((key = [keys nextObject])) {
+ GTM_FOREACH_KEY(key, self) {
if (!keyClass) {
if ([key isKindOfClass:[GTMFourCharCode class]]) {
keyClass = [GTMFourCharCode class];
@@ -314,8 +320,7 @@ static NSMutableDictionary *gTypeMap = nil;
NSAppleEventDescriptor *desc = [NSAppleEventDescriptor recordDescriptor];
if ([keyClass isEqual:[NSString class]]) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self count] * 2];
- keys = [self keyEnumerator];
- while ((key = [keys nextObject])) {
+ GTM_FOREACH_KEY(key, self) {
[array addObject:key];
[array addObject:[self objectForKey:key]];
}
@@ -325,8 +330,7 @@ static NSMutableDictionary *gTypeMap = nil;
}
[desc setDescriptor:userRecord forKeyword:keyASUserRecordFields];
} else {
- keys = [self keyEnumerator];
- while ((key = [keys nextObject])) {
+ GTM_FOREACH_KEY(key, self) {
id value = [self objectForKey:key];
NSAppleEventDescriptor *valDesc = [value gtm_appleEventDescriptor];
if (!valDesc) {
diff --git a/Foundation/GTMNSAppleEventDescriptor+FoundationTest.m b/Foundation/GTMNSAppleEventDescriptor+FoundationTest.m
index 6df19ab..f346e99 100644
--- a/Foundation/GTMNSAppleEventDescriptor+FoundationTest.m
+++ b/Foundation/GTMNSAppleEventDescriptor+FoundationTest.m
@@ -242,7 +242,7 @@
NSAppleEventDescriptor *userRecord = [array gtm_appleEventDescriptor];
STAssertNotNil(userRecord, @"");
[desc setDescriptor:userRecord forKeyword:keyASUserRecordFields];
- [GTMUnitTestDevLog expectPattern:@"Got a key bam with no value in <.*"];
+ [GTMUnitTestDevLog expectPattern:@"Got a key bam with no value in \\(.*"];
dictionary = [desc gtm_objectValue];
STAssertNil(dictionary, @"Should be nil");
}
diff --git a/Foundation/GTMNSArray+Merge.m b/Foundation/GTMNSArray+Merge.m
index da58a02..0c1582d 100644
--- a/Foundation/GTMNSArray+Merge.m
+++ b/Foundation/GTMNSArray+Merge.m
@@ -56,8 +56,7 @@
: nil;
id newItem = nil;
- NSEnumerator *itemEnum = [sortedNewArray objectEnumerator];
- while ((newItem = [itemEnum nextObject])) {
+ GTM_FOREACH_OBJECT(newItem, sortedNewArray) {
BOOL stillLooking = YES;
while (oldIndex < oldCount && stillLooking) {
// We must take care here, since Intel leaves junk in high bytes of
diff --git a/Foundation/GTMNSDictionary+URLArguments.m b/Foundation/GTMNSDictionary+URLArguments.m
index d67572c..89610e4 100644
--- a/Foundation/GTMNSDictionary+URLArguments.m
+++ b/Foundation/GTMNSDictionary+URLArguments.m
@@ -19,6 +19,7 @@
#import "GTMNSDictionary+URLArguments.h"
#import "GTMNSString+URLArguments.h"
#import "GTMMethodCheck.h"
+#import "GTMDefines.h"
@implementation NSDictionary (GTMNSDictionaryURLArgumentsAdditions)
@@ -26,9 +27,8 @@ GTM_METHOD_CHECK(NSString, gtm_stringByEscapingForURLArgument);
- (NSString *)gtm_httpArgumentsString {
NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:[self count]];
- NSEnumerator* keyEnumerator = [self keyEnumerator];
NSString* key;
- while ((key = [keyEnumerator nextObject])) {
+ GTM_FOREACH_KEY(key, self) {
[arguments addObject:[NSString stringWithFormat:@"%@=%@",
[key gtm_stringByEscapingForURLArgument],
[[[self objectForKey:key] description] gtm_stringByEscapingForURLArgument]]];
diff --git a/Foundation/GTMNSFileManager+Path.m b/Foundation/GTMNSFileManager+Path.m
index 2d71729..195cd9e 100644
--- a/Foundation/GTMNSFileManager+Path.m
+++ b/Foundation/GTMNSFileManager+Path.m
@@ -17,6 +17,7 @@
//
#import "GTMNSFileManager+Path.h"
+#import "GTMDefines.h"
@implementation NSFileManager (GMFileManagerPathAdditions)
@@ -34,10 +35,9 @@
return YES;
NSString *actualPath = @"/";
- NSEnumerator *directoryEnumerator = [[path pathComponents] objectEnumerator];
NSString *directory;
- while ((directory = [directoryEnumerator nextObject])) {
+ GTM_FOREACH_OBJECT(directory, [path pathComponents]) {
actualPath = [actualPath stringByAppendingPathComponent:directory];
if ([self fileExistsAtPath:actualPath isDirectory:&isDir] && isDir) {
@@ -84,10 +84,9 @@
NSMutableArray *paths = [NSMutableArray arrayWithCapacity:[basenames count]];
NSString *basename;
- NSEnumerator *basenamesEnumerator = [basenames objectEnumerator];
// Convert all the |basenames| to full paths.
- while ((basename = [basenamesEnumerator nextObject])) {
+ GTM_FOREACH_OBJECT(basename, basenames) {
NSString *fullPath = [directoryPath stringByAppendingPathComponent:basename];
[paths addObject:fullPath];
}
diff --git a/Foundation/GTMRegex.h b/Foundation/GTMRegex.h
index c32eee2..3ef5604 100644
--- a/Foundation/GTMRegex.h
+++ b/Foundation/GTMRegex.h
@@ -84,12 +84,10 @@ _EXTERN NSString* kGTMRegexPatternErrorErrorString _INITIALIZE_AS(@"patternError
// Example usage:
//
// NSArray *inputArrayOfStrings = ...
-// NSEnumerator *enumerator = [inputArrayOfString objectEnumerator];
-// NSString *curStr = nil;
// NSArray *matches = [NSMutableArray array];
//
// GTMRegex *regex = [GTMRegex regexWithPattern:@"foo.*bar"];
-// while ((curStr = [enumerator nextObject]) != nil) {
+// for (NSString *curStr in inputArrayOfStrings) {
// if ([regex matchesString:curStr])
// [matches addObject:curStr];
// }
diff --git a/Foundation/GTMRegex.m b/Foundation/GTMRegex.m
index 71d5050..1027224 100644
--- a/Foundation/GTMRegex.m
+++ b/Foundation/GTMRegex.m
@@ -190,6 +190,7 @@ static NSString *const kReplacementPattern =
return self;
}
+#if GTM_SUPPORT_GC
- (void)finalize {
// we used pattern_ as our flag that we initialized the regex_t
if (pattern_) {
@@ -200,6 +201,7 @@ static NSString *const kReplacementPattern =
}
[super finalize];
}
+#endif
- (void)dealloc {
// we used pattern_ as our flag that we initialized the regex_t
@@ -390,9 +392,8 @@ static NSString *const kReplacementPattern =
// no replacements, they want to eat matches, nothing to do
} else {
// spin over the split up replacement
- NSEnumerator *replacementEnumerator = [replacements objectEnumerator];
GTMRegexStringSegment *replacementSegment = nil;
- while ((replacementSegment = [replacementEnumerator nextObject]) != nil) {
+ GTM_FOREACH_OBJECT(replacementSegment, replacements) {
if (![replacementSegment isMatch]) {
// not a match, raw text to put in
[result appendString:[replacementSegment string]];
diff --git a/Foundation/GTMSignalHandler.m b/Foundation/GTMSignalHandler.m
index edfff7d..557d8be 100644
--- a/Foundation/GTMSignalHandler.m
+++ b/Foundation/GTMSignalHandler.m
@@ -86,12 +86,14 @@ static CFSocketRef gRunLoopSocket = NULL;
return self;
}
+#if GTM_SUPPORT_GC
- (void)finalize {
[self unregisterWithKQueue];
[super finalize];
}
+#endif
- (void)dealloc {
[self unregisterWithKQueue];
diff --git a/GTM.xcodeproj/project.pbxproj b/GTM.xcodeproj/project.pbxproj
index 1faf2b1..dff1850 100644
--- a/GTM.xcodeproj/project.pbxproj
+++ b/GTM.xcodeproj/project.pbxproj
@@ -135,6 +135,9 @@
8B8EC87D0EF17C270044D13F /* GTMNSFileManager+Carbon.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B8EC87B0EF17C270044D13F /* GTMNSFileManager+Carbon.h */; settings = {ATTRIBUTES = (Public, ); }; };
8B8EC87E0EF17C270044D13F /* GTMNSFileManager+Carbon.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8EC87C0EF17C270044D13F /* GTMNSFileManager+Carbon.m */; };
8B8EC8800EF17C2F0044D13F /* GTMNSFileManager+CarbonTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8EC87F0EF17C2F0044D13F /* GTMNSFileManager+CarbonTest.m */; };
+ 8BA01B5D0F144BD800926923 /* GTMNSWorkspace+Running.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA01B5B0F144BD800926923 /* GTMNSWorkspace+Running.m */; };
+ 8BA01B5E0F144BD800926923 /* GTMNSWorkspace+Running.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BA01B5C0F144BD800926923 /* GTMNSWorkspace+Running.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 8BA01B600F144BE500926923 /* GTMNSWorkspace+RunningTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BA01B5F0F144BE500926923 /* GTMNSWorkspace+RunningTest.m */; };
8BC045C20DAE899100C2D1CA /* GTMGeometryUtilsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F48FE2800D198D0E009257D2 /* GTMGeometryUtilsTest.m */; };
8BC046B90DAE8C4B00C2D1CA /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BC046B80DAE8C4B00C2D1CA /* ApplicationServices.framework */; };
8BC04CD80DB003D800C2D1CA /* GTMMethodCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B6F31F40DA3489B0052CA40 /* GTMMethodCheck.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -412,6 +415,9 @@
8B8EC87B0EF17C270044D13F /* GTMNSFileManager+Carbon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSFileManager+Carbon.h"; sourceTree = "<group>"; };
8B8EC87C0EF17C270044D13F /* GTMNSFileManager+Carbon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSFileManager+Carbon.m"; sourceTree = "<group>"; };
8B8EC87F0EF17C2F0044D13F /* GTMNSFileManager+CarbonTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSFileManager+CarbonTest.m"; sourceTree = "<group>"; };
+ 8BA01B5B0F144BD800926923 /* GTMNSWorkspace+Running.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSWorkspace+Running.m"; sourceTree = "<group>"; };
+ 8BA01B5C0F144BD800926923 /* GTMNSWorkspace+Running.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "GTMNSWorkspace+Running.h"; sourceTree = "<group>"; };
+ 8BA01B5F0F144BE500926923 /* GTMNSWorkspace+RunningTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "GTMNSWorkspace+RunningTest.m"; sourceTree = "<group>"; };
8BC046B80DAE8C4B00C2D1CA /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = "<absolute>"; };
8BC04D140DB0061300C2D1CA /* RunMacOSUnitTests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = RunMacOSUnitTests.sh; sourceTree = "<group>"; };
8BE2836B0DED0F130035B3F8 /* GTMFourCharCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMFourCharCode.m; sourceTree = "<group>"; };
@@ -772,6 +778,9 @@
7F3EB38C0E5E09C700A7A75E /* GTMNSImage+Scaling.h */,
7F3EB38D0E5E09C700A7A75E /* GTMNSImage+Scaling.m */,
7F3EB3930E5E0A2100A7A75E /* GTMNSImage+ScalingTest.m */,
+ 8BA01B5B0F144BD800926923 /* GTMNSWorkspace+Running.m */,
+ 8BA01B5C0F144BD800926923 /* GTMNSWorkspace+Running.h */,
+ 8BA01B5F0F144BE500926923 /* GTMNSWorkspace+RunningTest.m */,
F47F1C740D490E5C00925B8F /* GTMShading.h */,
F435E4840DC8F3DC0069CDE8 /* TestData */,
);
@@ -1028,6 +1037,7 @@
8B3E292F0EEB53F8000681D8 /* GTMCarbonEvent.h in Headers */,
F49FA8440EEF2AB700077669 /* GTMFileSystemKQueue.h in Headers */,
8B8EC87D0EF17C270044D13F /* GTMNSFileManager+Carbon.h in Headers */,
+ 8BA01B5E0F144BD800926923 /* GTMNSWorkspace+Running.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1426,6 +1436,7 @@
8B3E292E0EEB53F8000681D8 /* GTMCarbonEvent.m in Sources */,
F49FA8450EEF2AB700077669 /* GTMFileSystemKQueue.m in Sources */,
8B8EC87E0EF17C270044D13F /* GTMNSFileManager+Carbon.m in Sources */,
+ 8BA01B5D0F144BD800926923 /* GTMNSWorkspace+Running.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1449,6 +1460,7 @@
8B8B102A0EEB8B2900E543D0 /* GTMCarbonEventTest.m in Sources */,
8B8B10FD0EEB8BC300E543D0 /* GTMUnitTestingUtilities.m in Sources */,
8B8B11000EEB8CD000E543D0 /* GTMGetURLHandlerTest.m in Sources */,
+ 8BA01B600F144BE500926923 /* GTMNSWorkspace+RunningTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/GTMDefines.h b/GTMDefines.h
index 5242e88..b41a6c8 100644
--- a/GTMDefines.h
+++ b/GTMDefines.h
@@ -155,6 +155,26 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
#endif // _GTMCompileAssert
+// Macro to allow fast enumeration when building for 10.5 or later, and
+// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration
+// does keys, so pick the right thing, nothing is done on the FastEnumeration
+// side to be sure you're getting what you wanted.
+#ifndef GTM_FOREACH_OBJECT
+ #if defined(TARGET_OS_IPHONE) || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+ #define GTM_FOREACH_OBJECT(element, collection) \
+ for (element in collection)
+ #define GTM_FOREACH_KEY(element, collection) \
+ for (element in collection)
+ #else
+ #define GTM_FOREACH_OBJECT(element, collection) \
+ for (NSEnumerator * _ ## element ## _enum = [collection objectEnumerator]; \
+ (element = [_ ## element ## _enum nextObject]) != nil; )
+ #define GTM_FOREACH_KEY(element, collection) \
+ for (NSEnumerator * _ ## element ## _enum = [collection keyEnumerator]; \
+ (element = [_ ## element ## _enum nextObject]) != nil; )
+ #endif
+#endif
+
// ============================================================================
// ----------------------------------------------------------------------------
@@ -179,6 +199,23 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
#define GTM_MACOS_SDK 1
#endif
+// Provide a symbol to include/exclude extra code for GC support. (This mainly
+// just controls the inclusion of finalize methods).
+#ifndef GTM_SUPPORT_GC
+ #if GTM_IPHONE_SDK
+ // iPhone never needs GC
+ #define GTM_SUPPORT_GC 0
+ #else
+ // We can't find a symbol to tell if GC is supported/required, so best we
+ // do on Mac targets is include it if we're on 10.5 or later.
+ #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
+ #define GTM_SUPPORT_GC 0
+ #else
+ #define GTM_SUPPORT_GC 1
+ #endif
+ #endif
+#endif
+
// To simplify support for 64bit (and Leopard in general), we provide the type
// defines for non Leopard SDKs
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt
index cd07252..b592a31 100644
--- a/ReleaseNotes.txt
+++ b/ReleaseNotes.txt
@@ -188,6 +188,9 @@ Changes since 1.5.1
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.
+ Since we have turned this on, we have turned off using _debug frameworks
+ from the RunUnitTests.sh because it was reporting a pile of uninteresting
+ issues that were interfering with unittests.
- Added GTMFileSystemKQueue. It provides a simple wrapper for kqueuing
something in the file system and tracking changes to it.
@@ -204,6 +207,18 @@ Changes since 1.5.1
for the messages in debug builds, to make it easier to validate messages
that are only present in debug builds.
+- Added GTM_SUPPORT_GC for controlling the inclusion of GC related code.
+
+- If you are using GTMUnitTestDevLog, it also tries to capture logs from
+ NSAssert.
+
+- Added GTM_FOREACH_OBJECT/GTM_FOREACH_KEY that uses NSEnumerator and
+ objectEnumerator/keyEnumerator on 10.4, but on 10.5+/iPhone uses
+ FastEnumeration.
+
+- GTMNSWorkspace+Running gives a variety of ways of determining the attributes
+ of running processes.
+
Release 1.5.1
Changes since 1.5.0
@@ -291,8 +306,7 @@ Changes since 1.0.0
- Added RunMacOSUnitTests shell script. We run this script for starting up our
unittests because it turns on a variety of "enhancements" (such as zombies,
- scribbling etc) to encourage our unittests to fail for us. It also will run
- the unittests using the _debug frameworks if you have them.
+ scribbling etc) to encourage our unittests to fail for us.
https://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?bundleID=19915
diff --git a/UnitTesting/GTMAppKit+UnitTesting.m b/UnitTesting/GTMAppKit+UnitTesting.m
index 0e21491..23c44e3 100644
--- a/UnitTesting/GTMAppKit+UnitTesting.m
+++ b/UnitTesting/GTMAppKit+UnitTesting.m
@@ -37,10 +37,9 @@ GTM_METHOD_CHECK(NSObject, gtm_unitTestEncodeState:);
ENCODE_NSINTEGER(inCoder, [[self mainWindow] windowNumber], @"ApplicationMainWindow");
// Descend down into the windows allowing them to store their state
- NSEnumerator *windowEnum = [[self windows] objectEnumerator];
NSWindow *window = nil;
int i = 0;
- while ((window = [windowEnum nextObject])) {
+ GTM_FOREACH_OBJECT(window, [self windows]) {
if ([window isVisible]) {
// Only record visible windows because invisible windows may be closing on us
// This appears to happen differently in 64 bit vs 32 bit, and items
@@ -190,10 +189,12 @@ GTM_METHOD_CHECK(NSObject, gtm_unitTestEncodeState:);
}
}
// Descend down into the menuitems allowing them to store their state
- NSEnumerator *menuItemEnum = [[self itemArray] objectEnumerator];
NSMenuItem *menuItem = nil;
- for (int i = 0; (menuItem = [menuItemEnum nextObject]); ++i) {
- [inCoder encodeObject:menuItem forKey:[NSString stringWithFormat:@"MenuItem %d", i]];
+ int i = 0;
+ GTM_FOREACH_OBJECT(menuItem, [self itemArray]) {
+ [inCoder encodeObject:menuItem
+ forKey:[NSString stringWithFormat:@"MenuItem %d", i]];
+ ++i;
}
}
@@ -324,10 +325,9 @@ GTM_METHOD_CHECK(NSObject, gtm_unitTestEncodeState:);
[super gtm_unitTestEncodeState:inCoder];
[inCoder encodeBool:[self isHidden] forKey:@"ViewIsHidden"];
if ([self gtm_shouldEncodeStateForSubviews]) {
- NSEnumerator *subviewEnum = [[self subviews] objectEnumerator];
NSView *subview = nil;
int i = 0;
- while ((subview = [subviewEnum nextObject])) {
+ GTM_FOREACH_OBJECT(subview, [self subviews]) {
[inCoder encodeObject:subview forKey:[NSString stringWithFormat:@"ViewSubView %d", i]];
i = i + 1;
}
diff --git a/UnitTesting/GTMNSObject+BindingUnitTesting.h b/UnitTesting/GTMNSObject+BindingUnitTesting.h
index 462bb9b..55c3dfe 100644
--- a/UnitTesting/GTMNSObject+BindingUnitTesting.h
+++ b/UnitTesting/GTMNSObject+BindingUnitTesting.h
@@ -46,9 +46,8 @@ do { \
NSArray *errors = nil; \
BOOL isGood = GTMDoExposedBindingsFunctionCorrectly(a1Object, &errors); \
if (!isGood) { \
- NSEnumerator *errorEnum = [errors objectEnumerator]; \
NSString *failString; \
- while ((failString = [errorEnum nextObject])) { \
+ GTM_FOREACH_OBJECT(failString, errors) { \
if (description) { \
STFail(@"%@: %@", failString, STComposeString(description, ##__VA_ARGS__)); \
} else { \
diff --git a/UnitTesting/GTMNSObject+BindingUnitTesting.m b/UnitTesting/GTMNSObject+BindingUnitTesting.m
index 7a14ad6..d064a47 100644
--- a/UnitTesting/GTMNSObject+BindingUnitTesting.m
+++ b/UnitTesting/GTMNSObject+BindingUnitTesting.m
@@ -31,9 +31,8 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object,
NSArray *bindings = [object exposedBindings];
if ([bindings count]) {
NSArray *bindingsToIgnore = [object gtm_unitTestExposedBindingsToIgnore];
- NSEnumerator *bindingsEnum = [bindings objectEnumerator];
NSString *bindingKey;
- while ((bindingKey = [bindingsEnum nextObject])) {
+ GTM_FOREACH_OBJECT(bindingKey, bindings) {
if (![bindingsToIgnore containsObject:bindingKey]) {
Class theClass = [object valueClassForBinding:bindingKey];
if (!theClass) {
@@ -54,9 +53,8 @@ BOOL GTMDoExposedBindingsFunctionCorrectly(NSObject *object,
} // COV_NF_LINE - compiler bug
NSArray *testValues
= [object gtm_unitTestExposedBindingsTestValues:bindingKey];
- NSEnumerator *testEnum = [testValues objectEnumerator];
GTMBindingUnitTestData *testData;
- while ((testData = [testEnum nextObject])) {
+ GTM_FOREACH_OBJECT(testData, testValues) {
id valueToSet = [testData valueToSet];
[object setValue:valueToSet forKey:bindingKey];
id valueReceived = [object valueForKey:bindingKey];
diff --git a/UnitTesting/GTMNSObject+UnitTesting.m b/UnitTesting/GTMNSObject+UnitTesting.m
index bc94729..f3bfbb1 100644
--- a/UnitTesting/GTMNSObject+UnitTesting.m
+++ b/UnitTesting/GTMNSObject+UnitTesting.m
@@ -417,11 +417,14 @@ static NSString *gGTMUnitTestSaveToDirectory = nil;
// we're on an automated build system, so use the build products dir as an
// override instead of writing on the desktop.
NSDictionary *env = [[NSProcessInfo processInfo] environment];
- NSEnumerator *enumerator = [env keyEnumerator];
- NSString *key = nil;
- while (((key = [enumerator nextObject]) != nil) &&
- ![key hasSuffix:@"BUILD_NUMBER"])
- ;
+ BOOL foundBuildNumber = NO;
+ NSString *key;
+ GTM_FOREACH_KEY(key, env) {
+ if ([key hasSuffix:@"BUILD_NUMBER"]) {
+ foundBuildNumber = YES;
+ break;
+ }
+ }
if (key) {
result = [env objectForKey:@"BUILT_PRODUCTS_DIR"];
}
diff --git a/UnitTesting/GTMSenTestCase.m b/UnitTesting/GTMSenTestCase.m
index 8d45dab..dbd137a 100644
--- a/UnitTesting/GTMSenTestCase.m
+++ b/UnitTesting/GTMSenTestCase.m
@@ -314,10 +314,9 @@ static void _GTMRunLeaks(void) {
if (cExclusionsEnv) {
NSString *exclusionsEnv = [NSString stringWithUTF8String:cExclusionsEnv];
NSArray *exclusionsArray = [exclusionsEnv componentsSeparatedByString:@","];
- NSEnumerator *exclusionsEnum = [exclusionsArray objectEnumerator];
NSString *exclusion;
NSCharacterSet *wcSet = [NSCharacterSet whitespaceCharacterSet];
- while ((exclusion = [exclusionsEnum nextObject])) {
+ GTM_FOREACH_OBJECT(exclusion, exclusionsArray) {
exclusion = [exclusion stringByTrimmingCharactersInSet:wcSet];
[exclusions appendFormat:@"-exclude \"%@\" ", exclusion];
}
@@ -345,7 +344,8 @@ static __attribute__((constructor)) void _GTMInstallLeaks(void) {
if (checkLeaks) {
fprintf(stderr, "Leak Checking Enabled\n");
fflush(stderr);
- _GTMDevAssert(atexit(&_GTMRunLeaks) == 0,
+ int ret = atexit(&_GTMRunLeaks);
+ _GTMDevAssert(ret == 0,
@"Unable to install _GTMRunLeaks as an atexit handler (%d)",
errno);
}
diff --git a/UnitTesting/GTMUIKit+UnitTesting.m b/UnitTesting/GTMUIKit+UnitTesting.m
index d1cf2b2..56460be 100644
--- a/UnitTesting/GTMUIKit+UnitTesting.m
+++ b/UnitTesting/GTMUIKit+UnitTesting.m
@@ -93,13 +93,11 @@
[layer gtm_unitTestEncodeState:inCoder];
}
if ([self gtm_shouldEncodeStateForSubviews]) {
- NSEnumerator *subviewEnum = [[self subviews] objectEnumerator];
- UIView *subview = nil;
int i = 0;
- while ((subview = [subviewEnum nextObject])) {
+ for (UIView *subview in [self subviews]) {
[inCoder encodeObject:subview
forKey:[NSString stringWithFormat:@"ViewSubView %d", i]];
- i = i + 1;
+ i++;
}
}
}
diff --git a/UnitTesting/GTMUnitTestDevLog.m b/UnitTesting/GTMUnitTestDevLog.m
index 227eb11..35e29ae 100644
--- a/UnitTesting/GTMUnitTestDevLog.m
+++ b/UnitTesting/GTMUnitTestDevLog.m
@@ -38,7 +38,7 @@ static void GTMDevLogDebugAssert(OSType componentSignature,
length:StrLength(outputMsg)
encoding:NSMacOSRomanStringEncoding]
autorelease];
- _GTMDevLog(outLog);
+ _GTMDevLog(@"%@", outLog); // Don't want any percents in outLog honored
}
static inline void GTMInstallDebugAssertOutputHandler(void) {
InstallDebugAssertOutputHandler(GTMDevLogDebugAssert);
@@ -51,6 +51,57 @@ static inline void GTMInstallDebugAssertOutputHandler(void) {};
static inline void GTMUninstallDebugAssertOutputHandler(void) {};
#endif // GTM_IPHONE_SDK
+@interface GTMUnttestDevLogAssertionHandler : NSAssertionHandler
+@end
+
+@implementation GTMUnttestDevLogAssertionHandler
+- (void)handleFailureInMethod:(SEL)selector
+ object:(id)object
+ file:(NSString *)fileName
+ lineNumber:(NSInteger)line
+ description:(NSString *)format, ... {
+ va_list argList;
+ va_start(argList, format);
+ NSString *descStr
+ = [[[NSString alloc] initWithFormat:format arguments:argList] autorelease];
+ va_end(argList);
+
+ // You need a format that will be useful in logs, but won't trip up Xcode or
+ // any other build systems parsing of the output.
+ NSString *outLog
+ = [NSString stringWithFormat:@"RecordedNSAssert in %@ - %@ (%@:%ld)",
+ NSStringFromSelector(selector),
+ descStr,
+ fileName, (long)line];
+ _GTMDevLog(@"%@", outLog); // Don't want any percents in outLog honored
+ [NSException raise:NSInternalInconsistencyException
+ format:@"NSAssert raised"];
+}
+
+- (void)handleFailureInFunction:(NSString *)functionName
+ file:(NSString *)fileName
+ lineNumber:(NSInteger)line
+ description:(NSString *)format, ... {
+ va_list argList;
+ va_start(argList, format);
+ NSString *descStr
+ = [[[NSString alloc] initWithFormat:format arguments:argList] autorelease];
+ va_end(argList);
+
+ // You need a format that will be useful in logs, but won't trip up Xcode or
+ // any other build systems parsing of the output.
+ NSString *outLog
+ = [NSString stringWithFormat:@"RecordedNSAssert in %@ - %@ (%@:%ld)",
+ functionName,
+ descStr,
+ fileName, (long)line];
+ _GTMDevLog(@"%@", outLog); // Don't want any percents in outLog honored
+ [NSException raise:NSInternalInconsistencyException
+ format:@"NSAssert raised"];
+}
+
+@end
+
@implementation GTMUnitTestDevLog
// If unittests are ever being run on separate threads, this may need to be
// made a thread local variable.
@@ -70,11 +121,29 @@ static BOOL gTrackingEnabled = NO;
+ (void)enableTracking {
GTMInstallDebugAssertOutputHandler();
+
+ NSMutableDictionary *threadDictionary
+ = [[NSThread currentThread] threadDictionary];
+ if ([threadDictionary objectForKey:@"NSAssertionHandler"] != nil) {
+ NSLog(@"Warning: replacing NSAssertionHandler to capture assertions");
+ }
+
+ // Install an assertion handler to capture those.
+ GTMUnttestDevLogAssertionHandler *handler =
+ [[[GTMUnttestDevLogAssertionHandler alloc] init] autorelease];
+ [threadDictionary setObject:handler forKey:@"NSAssertionHandler"];
+
gTrackingEnabled = YES;
}
+ (void)disableTracking {
GTMUninstallDebugAssertOutputHandler();
+
+ // Clear our assertion handler back out.
+ NSMutableDictionary *threadDictionary
+ = [[NSThread currentThread] threadDictionary];
+ [threadDictionary removeObjectForKey:@"NSAssertionHandler"];
+
gTrackingEnabled = NO;
}
diff --git a/UnitTesting/GTMUnitTestingBindingTest.m b/UnitTesting/GTMUnitTestingBindingTest.m
index aabac43..19ab5b0 100644
--- a/UnitTesting/GTMUnitTestingBindingTest.m
+++ b/UnitTesting/GTMUnitTestingBindingTest.m
@@ -33,9 +33,8 @@
// Iterates through all of our subviews testing the exposed bindings
- (void)doSubviewBindingTest:(NSView*)view {
NSArray *subviews = [view subviews];
- NSEnumerator *subviewEnum = [subviews objectEnumerator];
NSView *subview;
- while ((subview = [subviewEnum nextObject])) {
+ GTM_FOREACH_OBJECT(subview, subviews) {
GTMTestExposedBindings(subview, @"testing %@", subview);
[self doSubviewBindingTest:subview];
}
diff --git a/UnitTesting/RunMacOSUnitTests.sh b/UnitTesting/RunMacOSUnitTests.sh
index f35092b..23897f0 100755
--- a/UnitTesting/RunMacOSUnitTests.sh
+++ b/UnitTesting/RunMacOSUnitTests.sh
@@ -189,15 +189,6 @@ if [ ! $GTM_DISABLE_ZOMBIES ]; then
export NSZombieEnabled=YES
fi
-# If we have debug libraries on the machine, we'll use them
-# unless a target has specifically turned them off
-if [ ! $GTM_NO_DEBUG_FRAMEWORKS ]; then
- if [ -f "/System/Library/Frameworks/CoreFoundation.framework/Versions/Current/CoreFoundation_debug" ]; then
- GTMXcodeNote ${LINENO} "Using _debug frameworks"
- export DYLD_IMAGE_SUFFIX=_debug
- fi
-fi
-
# If leaks testing is enabled, we have to go through our convoluted path
# to handle architectures that don't allow us to do leak testing.
if [ GTM_ENABLE_LEAKS ]; then
diff --git a/iPhone/GTMABAddressBook.m b/iPhone/GTMABAddressBook.m
index 05a5523..05dc27f 100644
--- a/iPhone/GTMABAddressBook.m
+++ b/iPhone/GTMABAddressBook.m
@@ -441,10 +441,8 @@ typedef struct {
NSArray *people
= GTMCFAutorelease(ABGroupCopyArrayOfAllMembers([self recordRef]));
NSMutableArray *gtmPeople = [NSMutableArray arrayWithCapacity:[people count]];
- NSEnumerator *enumerator = [people objectEnumerator];
- ABRecordRef person;
- while ((person = [enumerator nextObject])) {
- [gtmPeople addObject:[GTMABPerson recordWithRecord:person]];
+ for (id person in people) {
+ [gtmPeople addObject:[GTMABPerson recordWithRecord:(ABRecordRef)person]];
}
return gtmPeople;
}