Fix object-to-pointer comparisons on Leopard
authorWincent Colaiuta <win@wincent.com>
Mon, 23 Jul 2007 19:42:09 +0000 (21:42 +0200)
committerWincent Colaiuta <win@wincent.com>
Mon, 23 Jul 2007 19:42:09 +0000 (21:42 +0200)
The behaviour of the @encode directive has changed on Leopard and this breaks
a number of the comparisons that previously worked in Tiger. For example,
comparisons between object pointers and nil, or even between nil and nil,
were broken.

This commit adds some special cases for these types of comparisons which
now perform simple pointer equality tests instead of failing. I also removed
one test which failed on Tiger (when nil was encoded as a numeric scalar) but
no longer fails on Leopard.

Signed-off-by: Wincent Colaiuta <win@wincent.com>
NSValue+WOTest.m
Tests/WOTestSelfTests.m

index c024f5f9ebd4998a25be7134c388453feffe7cdd..a48d8fc8253541cb89efd04866c97f3f0039fee9 100644 (file)
             // can only compare objects with objects
             id selfObject   = [self nonretainedObjectValue];
             id otherObject  = [otherValue nonretainedObjectValue];
+
+            // avoid the message send if pointers are equal
+            // this also allows two nil object pointers to be considered equal, as they should
+            if (selfObject == otherObject)
+                return YES;
+
             @try {
                 if (selfObject && otherObject && [NSObject WOTest_object:selfObject respondsToSelector:@selector(isEqual:)]) 
                     return [selfObject isEqual:otherObject];
             // will raise exception (comparing numeric scalar with object)
             return ([self WOTest_compare:otherValue] == NSOrderedSame);
         }
+        else if ([otherValue WOTest_isPointerToVoid])
+            // encodings changed on Leopard such that comparisons such as WO_TEST_EQ(foo, nil) no longer worked;
+            // in this case foo is encoded as type "@" (object) and nil as "^v" (pointer to void)
+            // so we end up here and just compare pointers numerically
+            return ((void *)[self nonretainedObjectValue] == [otherValue pointerValue]);
     }
     else if ([self WOTest_isNumericScalar])
     {
     }
     else if ([self WOTest_isPointerToVoid])
     {
-        // check for special case: comparing with nil
-        typeof(nil) nilId = nil;
-        NSValue *nilValue = [NSValue valueWithBytes:&nilId objCType:@encode(typeof(nil))];
-        
-        if ((strcmp([otherValue objCType], @encode(typeof(nil))) == 0) && ([otherValue WOTest_compare:nilValue] == NSOrderedSame))
-            // other value is nil (or at least looks like nil)
-            return ((id)[self pointerValue] == nil);    
+        if ([otherValue WOTest_isObject])
+            // special case for pointer-to-void vs object comparisons (necessary on Leopard)
+            return ([self pointerValue] == (void *)[otherValue nonretainedObjectValue]);
+        else if ([otherValue WOTest_isPointerToVoid])
+            // this special case already necessary on Leopard, otherwise nil-to-nil comparison fails
+            return ([self pointerValue] == [otherValue pointerValue]);
         
-        // will raise exception (comparing pointer to void with other)
+        // fall through to standard case
         return ([self WOTest_compare:otherValue] == NSOrderedSame);
     }
     else if (([self WOTest_isCharArray] || [self WOTest_isCharacterString] || [self WOTest_isConstantCharacterString]) && 
index 9beb1477fb731735ea30d653681dfd4bbb3f2723..4a5b691b70f2a04c8222146a3c05e28d4a989fcf 100644 (file)
@@ -1033,11 +1033,8 @@ NSMutableArray *WOEmptyInstanceMethodInvocations;
         ([[NSValue valueWithBytes:&dastardlyScalar 
                          objCType:@encode(int)] WOTest_testIsEqualToValue:[NSValue valueWithNonretainedObject:@"foo"]]);
     
-    // can only compare an object to a numeric scalar is if the scalar is nil
     typeof(nil) nilVar = nil;
     NSValue *nilValue = [NSValue valueWithBytes:&nilVar objCType:@encode(typeof(nil))];
-    WO_TEST_TRUE([nilValue WOTest_isNumericScalar]);
-    
     NSString *objectString = @"foo";
     NSValue *nonVoidValue = [NSValue valueWithBytes:&objectString objCType:@encode(typeof(objectString))];
     WO_TEST_TRUE([nonVoidValue WOTest_isObject]);