aboutsummaryrefslogtreecommitdiff
path: root/Foundation/GTMObjC2RuntimeTest.m
diff options
context:
space:
mode:
Diffstat (limited to 'Foundation/GTMObjC2RuntimeTest.m')
-rw-r--r--Foundation/GTMObjC2RuntimeTest.m385
1 files changed, 385 insertions, 0 deletions
diff --git a/Foundation/GTMObjC2RuntimeTest.m b/Foundation/GTMObjC2RuntimeTest.m
new file mode 100644
index 0000000..2a7f354
--- /dev/null
+++ b/Foundation/GTMObjC2RuntimeTest.m
@@ -0,0 +1,385 @@
+//
+// GTMObjC2RuntimeTest.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 "GTMObjC2Runtime.h"
+#import "GTMSenTestCase.h"
+#import <string.h>
+
+@protocol GTMObjC2Runtime_TestProtocol
+@end
+
+@protocol GTMObjC2Runtime_Test2Protocol
+AT_OPTIONAL
+- (NSString*)optional;
+AT_REQUIRED
+- (NSString*)required;
+AT_OPTIONAL
++ (NSString*)class_optional;
+AT_REQUIRED
++ (NSString*)class_required;
+@end
+
+@interface GTMObjC2RuntimeTest : SenTestCase {
+ Class cls_;
+}
+@end
+
+@interface GTMObjC2Runtime_TestClass : NSObject <GTMObjC2Runtime_TestProtocol>
+- (NSString*)kwyjibo;
+
+@end
+
+@interface GTMObjC2Runtime_TestClass (GMObjC2Runtime_TestClassCategory)
+- (NSString*)eatMyShorts;
+@end
+
+@implementation GTMObjC2Runtime_TestClass
+
++ (NSString*)dontHaveACow {
+ return @"dontHaveACow";
+}
+
+- (NSString*)kwyjibo {
+ return @"kwyjibo";
+}
+@end
+
+@implementation GTMObjC2Runtime_TestClass (GMObjC2Runtime_TestClassCategory)
+- (NSString*)eatMyShorts {
+ return @"eatMyShorts";
+}
+
++ (NSString*)brokeHisBrain {
+ return @"brokeHisBrain";
+}
+
+@end
+
+@interface GTMObjC2NotificationWatcher : NSObject
+@end
+
+@implementation GTMObjC2NotificationWatcher
+- (void)startedTest:(NSNotification *)notification {
+ // Logs if we are testing on Tiger or Leopard runtime.
+ NSString *testName = [(SenTest*)[[notification object] test] name];
+ NSString *className = NSStringFromClass([GTMObjC2RuntimeTest class]);
+ if ([testName isEqualToString:className]) {
+ NSString *runtimeString;
+#ifndef OBJC2_UNAVAILABLE
+ runtimeString = @"ObjC1";
+#else
+ runtimeString = @"ObjC2";
+#endif
+ NSLog(@"Running GTMObjC2RuntimeTests using %@ runtime.", runtimeString);
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+ [nc removeObserver:self];
+ [self autorelease];
+ }
+}
+@end
+
+@implementation GTMObjC2RuntimeTest
+
++ (void)initialize {
+ // This allows us to track which runtime we are actually testing.
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+
+ // Watcher is released when it is notified.
+ GTMObjC2NotificationWatcher *watcher = [[GTMObjC2NotificationWatcher alloc] init];
+ [nc addObserver:watcher
+ selector:@selector(startedTest:)
+ name:SenTestSuiteDidStartNotification
+ object:nil];
+}
+
+- (void)setUp {
+ cls_ = [[GTMObjC2Runtime_TestClass class] retain];
+}
+
+- (void)tearDown {
+ [cls_ release];
+}
+
+- (void)test_object_getClass {
+ // Nil Checks
+ STAssertNil(object_getClass(nil), nil);
+
+ // Standard use check
+ GTMObjC2Runtime_TestClass *test = [[[cls_ alloc] init] autorelease];
+ Class cls = object_getClass(test);
+ STAssertEqualObjects(cls, cls_, nil);
+}
+
+- (void)test_class_getName {
+ // Nil Checks
+ const char *name = class_getName(nil);
+ STAssertEqualCStrings(name, "nil", nil);
+
+ // Standard use check
+ STAssertEqualCStrings(class_getName(cls_), "GTMObjC2Runtime_TestClass", nil);
+}
+
+- (void)test_class_conformsToProtocol {
+ // Nil Checks
+ STAssertFalse(class_conformsToProtocol(cls_, @protocol(NSObject)), nil);
+ STAssertFalse(class_conformsToProtocol(cls_, nil), nil);
+ // The following two tests intentionally commented out as they fail on
+ // Leopard with a crash, so we fail on Tiger intentionally as well.
+ // STAssertFalse(class_conformsToProtocol(nil, @protocol(NSObject)), nil);
+ // STAssertFalse(class_conformsToProtocol(nil, nil), nil);
+
+ // Standard use check
+ STAssertTrue(class_conformsToProtocol(cls_,
+ @protocol(GTMObjC2Runtime_TestProtocol)),
+ nil);
+}
+
+- (void)test_class_getSuperclass {
+ // Nil Checks
+ STAssertNil(class_getSuperclass(nil), nil);
+
+ // Standard use check
+ STAssertEqualObjects(class_getSuperclass(cls_), [NSObject class], nil);
+}
+
+- (void)test_class_copyMethodList {
+ // Nil Checks
+ Method *list = class_copyMethodList(nil, nil);
+ STAssertNULL(list, nil);
+
+ // Standard use check
+ list = class_copyMethodList(cls_, nil);
+ STAssertNotNULL(list, nil);
+ free(list);
+ unsigned int count = 0;
+ list = class_copyMethodList(cls_, &count);
+ STAssertNotNULL(list, nil);
+ STAssertEquals(count, 2U, nil);
+ STAssertNULL(list[count], nil);
+ free(list);
+
+ // Now test meta class
+ count = 0;
+ list = class_copyMethodList((Class)objc_getMetaClass(class_getName(cls_)),
+ &count);
+ STAssertNotNULL(list, nil);
+ STAssertEquals(count, 2U, nil);
+ STAssertNULL(list[count], nil);
+ free(list);
+}
+
+- (void)test_method_getName {
+ // Nil Checks
+ STAssertNULL(method_getName(nil), nil);
+
+ // Standard use check
+ Method *list = class_copyMethodList(cls_, nil);
+ STAssertNotNULL(list, nil);
+ const char* selName1 = sel_getName(method_getName(list[0]));
+ const char* selName2 = sel_getName(@selector(kwyjibo));
+ const char* selName3 = sel_getName(@selector(eatMyShorts));
+ BOOL isGood = ((strcmp(selName1, selName2)) == 0 || (strcmp(selName1, selName3) == 0));
+ STAssertTrue(isGood, nil);
+ free(list);
+}
+
+- (void)test_method_exchangeImplementations {
+ // nil checks
+ method_exchangeImplementations(nil, nil);
+
+ // Standard use check
+ GTMObjC2Runtime_TestClass *test = [[GTMObjC2Runtime_TestClass alloc] init];
+ STAssertNotNil(test, nil);
+
+ // Get initial values
+ NSString *val1 = [test kwyjibo];
+ STAssertNotNil(val1, nil);
+ NSString *val2 = [test eatMyShorts];
+ STAssertNotNil(val2, nil);
+ NSString *val3 = [GTMObjC2Runtime_TestClass dontHaveACow];
+ STAssertNotNil(val3, nil);
+ NSString *val4 = [GTMObjC2Runtime_TestClass brokeHisBrain];
+ STAssertNotNil(val4, nil);
+
+ // exchange the imps
+ Method *list = class_copyMethodList(cls_, nil);
+ STAssertNotNULL(list, nil);
+ method_exchangeImplementations(list[0], list[1]);
+
+ // test against initial values
+ NSString *val5 = [test kwyjibo];
+ STAssertNotNil(val5, nil);
+ NSString *val6 = [test eatMyShorts];
+ STAssertNotNil(val6, nil);
+ STAssertEqualStrings(val1, val6, nil);
+ STAssertEqualStrings(val2, val5, nil);
+
+ // Check that other methods not affected
+ STAssertEqualStrings([GTMObjC2Runtime_TestClass dontHaveACow], val3, nil);
+ STAssertEqualStrings([GTMObjC2Runtime_TestClass brokeHisBrain], val4, nil);
+
+ // exchange the imps back
+ method_exchangeImplementations(list[0], list[1]);
+
+ // and test against initial values again
+ NSString *val7 = [test kwyjibo];
+ STAssertNotNil(val7, nil);
+ NSString *val8 = [test eatMyShorts];
+ STAssertNotNil(val8, nil);
+ STAssertEqualStrings(val1, val7, nil);
+ STAssertEqualStrings(val2, val8, nil);
+
+ method_exchangeImplementations(list[0], nil);
+ method_exchangeImplementations(nil, list[0]);
+
+ val7 = [test kwyjibo];
+ STAssertNotNil(val7, nil);
+ val8 = [test eatMyShorts];
+ STAssertNotNil(val8, nil);
+ STAssertEqualStrings(val1, val7, nil);
+ STAssertEqualStrings(val2, val8, nil);
+
+ free(list);
+ [test release];
+}
+
+- (void)test_method_getImplementation {
+ // Nil Checks
+ STAssertNULL(method_getImplementation(nil), nil);
+
+ // Standard use check
+ Method *list = class_copyMethodList(cls_, nil);
+ STAssertNotNULL(list, nil);
+ STAssertNotNULL(method_getImplementation(list[0]), nil);
+ free(list);
+}
+
+- (void)test_method_setImplementation {
+ // Nil Checks
+ // This case intentionally not tested. Passing nil to method_setImplementation
+ // on Leopard crashes. It does on Tiger as well.
+ // STAssertNULL(method_setImplementation(nil, nil), nil);
+
+ // Standard use check
+ GTMObjC2Runtime_TestClass *test = [[GTMObjC2Runtime_TestClass alloc] init];
+ Method *list = class_copyMethodList(cls_, nil);
+
+ // Get initial value
+ NSString *str1 = objc_msgSend(test, method_getName(list[0]));
+ STAssertNotNil(str1, nil);
+
+ // set the imp to something else
+ IMP oldImp = method_setImplementation(list[0], method_getImplementation(list[1]));
+ STAssertNotNULL(oldImp, nil);
+
+ // make sure they are different
+ NSString *str2 = objc_msgSend(test,method_getName(list[0]));
+ STAssertNotNil(str2, nil);
+ STAssertNotEqualStrings(str1, str2, nil);
+
+ // reset the imp
+ IMP newImp = method_setImplementation(list[0], oldImp);
+ STAssertNotEquals(oldImp, newImp, nil);
+
+ // test nils
+ oldImp = method_setImplementation(list[0], nil);
+ STAssertNotNULL(oldImp, nil);
+
+ newImp = method_setImplementation(list[0], oldImp);
+ STAssertNULL(newImp, nil);
+
+ [test release];
+ free(list);
+}
+
+- (void)test_protocol_getMethodDescription {
+ // Check nil cases
+ struct objc_method_description desc = protocol_getMethodDescription(nil, nil,
+ YES, YES);
+ STAssertNULL(desc.name, nil);
+ desc = protocol_getMethodDescription(nil, @selector(optional), YES, YES);
+ STAssertNULL(desc.name, nil);
+ desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
+ nil, YES, YES);
+ STAssertNULL(desc.name, nil);
+
+ // Instance Methods
+ // Check Required case. Only OBJC2 supports required.
+ desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
+ @selector(optional), YES, YES);
+#if OBJC_API_VERSION >= 2
+ STAssertNULL(desc.name, nil);
+#else
+ STAssertNotNULL(desc.name, nil);
+#endif
+
+ // Check Required case. Only OBJC2 supports required.
+ desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
+ @selector(required), YES, YES);
+
+ STAssertNotNULL(desc.name, nil);
+
+ // Check Optional case. Only OBJC2 supports optional.
+ desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
+ @selector(optional), NO, YES);
+
+ STAssertNotNULL(desc.name, nil);
+
+ // Check Optional case. Only OBJC2 supports optional.
+ desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
+ @selector(required), NO, YES);
+#if OBJC_API_VERSION >= 2
+ STAssertNULL(desc.name, nil);
+#else
+ STAssertNotNULL(desc.name, nil);
+#endif
+
+ // Class Methods
+ // Check Required case. Only OBJC2 supports required.
+ desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
+ @selector(class_optional), YES, NO);
+#if OBJC_API_VERSION >= 2
+ STAssertNULL(desc.name, nil);
+#else
+ STAssertNotNULL(desc.name, nil);
+#endif
+
+ // Check Required case. Only OBJC2 supports required.
+ desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
+ @selector(class_required), YES, NO);
+
+ STAssertNotNULL(desc.name, nil);
+
+ // Check Optional case. Only OBJC2 supports optional.
+ desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
+ @selector(class_optional), NO, NO);
+
+ STAssertNotNULL(desc.name, nil);
+
+ // Check Optional case. Only OBJC2 supports optional.
+ desc = protocol_getMethodDescription(@protocol(GTMObjC2Runtime_Test2Protocol),
+ @selector(class_required), NO, NO);
+#if OBJC_API_VERSION >= 2
+ STAssertNULL(desc.name, nil);
+#else
+ STAssertNotNULL(desc.name, nil);
+#endif
+
+}
+
+@end