Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Unified Diff: third_party/ocmock/OCMock/OCClassMockObject.m

Issue 2624143003: Update OCMock to 3.1.5 (Closed)
Patch Set: Patches in more commits Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/ocmock/OCMock/OCClassMockObject.h ('k') | third_party/ocmock/OCMock/OCMArg.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/ocmock/OCMock/OCClassMockObject.m
diff --git a/third_party/ocmock/OCMock/OCClassMockObject.m b/third_party/ocmock/OCMock/OCClassMockObject.m
index 65b8fdf02d52317d7b617a5628d49dc622e784f6..2e2bc1ec28f852ca86b9a9f3b239ac5bc0fc474b 100644
--- a/third_party/ocmock/OCMock/OCClassMockObject.m
+++ b/third_party/ocmock/OCMock/OCClassMockObject.m
@@ -1,10 +1,24 @@
-//---------------------------------------------------------------------------------------
-// $Id$
-// Copyright (c) 2005-2008 by Mulle Kybernetik. See License file for details.
-//---------------------------------------------------------------------------------------
+/*
+ * Copyright (c) 2005-2015 Erik Doernenburg and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use these files 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 <objc/runtime.h>
#import "OCClassMockObject.h"
-
+#import "NSObject+OCMAdditions.h"
+#import "OCMFunctions.h"
+#import "OCMInvocationStub.h"
@implementation OCClassMockObject
@@ -12,14 +26,22 @@
- (id)initWithClass:(Class)aClass
{
+ NSParameterAssert(aClass != nil);
[super init];
mockedClass = aClass;
+ [self prepareClassForClassMethodMocking];
return self;
}
+- (void)dealloc
+{
+ [self stopMocking];
+ [super dealloc];
+}
+
- (NSString *)description
{
- return [NSString stringWithFormat:@"OCMockObject[%@]", NSStringFromClass(mockedClass)];
+ return [NSString stringWithFormat:@"OCMockObject(%@)", NSStringFromClass(mockedClass)];
}
- (Class)mockedClass
@@ -27,12 +49,140 @@
return mockedClass;
}
+#pragma mark Extending/overriding superclass behaviour
+
+- (void)stopMocking
+{
+ if(originalMetaClass != nil)
+ [self restoreMetaClass];
+ [super stopMocking];
+}
+
+- (void)restoreMetaClass
+{
+ OCMSetAssociatedMockForClass(nil, mockedClass);
+ OCMSetIsa(mockedClass, originalMetaClass);
+ originalMetaClass = nil;
+}
+
+- (void)addStub:(OCMInvocationStub *)aStub
+{
+ [super addStub:aStub];
+ if([aStub recordedAsClassMethod])
+ [self setupForwarderForClassMethodSelector:[[aStub recordedInvocation] selector]];
+}
+
+
+#pragma mark Class method mocking
+
+- (void)prepareClassForClassMethodMocking
+{
+ /* haven't figured out how to work around runtime dependencies on NSString, so exclude it for now */
+ /* also weird: [[NSString class] isKindOfClass:[NSString class]] is false, hence the additional clause */
+ if([[mockedClass class] isKindOfClass:[NSString class]] || (mockedClass == [NSString class]))
+ return;
+
+ /* if there is another mock for this exact class, stop it */
+ id otherMock = OCMGetAssociatedMockForClass(mockedClass, NO);
+ if(otherMock != nil)
+ [otherMock restoreMetaClass];
+
+ OCMSetAssociatedMockForClass(self, mockedClass);
+
+ /* dynamically create a subclass and use its meta class as the meta class for the mocked class */
+ Class subclass = OCMCreateSubclass(mockedClass, mockedClass);
+ originalMetaClass = object_getClass(mockedClass);
+ id newMetaClass = object_getClass(subclass);
+ OCMSetIsa(mockedClass, OCMGetIsa(subclass));
+
+ /* point forwardInvocation: of the object to the implementation in the mock */
+ Method myForwardMethod = class_getInstanceMethod([self mockObjectClass], @selector(forwardInvocationForClassObject:));
+ IMP myForwardIMP = method_getImplementation(myForwardMethod);
+ class_addMethod(newMetaClass, @selector(forwardInvocation:), myForwardIMP, method_getTypeEncoding(myForwardMethod));
+
+ /* create a dummy initialize method */
+ Method myDummyInitializeMethod = class_getInstanceMethod([self mockObjectClass], @selector(initializeForClassObject));
+ const char *initializeTypes = method_getTypeEncoding(myDummyInitializeMethod);
+ IMP myDummyInitializeIMP = method_getImplementation(myDummyInitializeMethod);
+ class_addMethod(newMetaClass, @selector(initialize), myDummyInitializeIMP, initializeTypes);
+
+ /* adding forwarder for most class methods (instance methods on meta class) to allow for verify after run */
+ NSArray *methodBlackList = @[@"class", @"forwardingTargetForSelector:", @"methodSignatureForSelector:", @"forwardInvocation:", @"isBlock",
+ @"instanceMethodForwarderForSelector:", @"instanceMethodSignatureForSelector:"];
+ [NSObject enumerateMethodsInClass:originalMetaClass usingBlock:^(Class cls, SEL sel) {
+ if((cls == object_getClass([NSObject class])) || (cls == [NSObject class]) || (cls == object_getClass(cls)))
+ return;
+ NSString *className = NSStringFromClass(cls);
+ NSString *selName = NSStringFromSelector(sel);
+ if(([className hasPrefix:@"NS"] || [className hasPrefix:@"UI"]) &&
+ ([selName hasPrefix:@"_"] || [selName hasSuffix:@"_"]))
+ return;
+ if([methodBlackList containsObject:selName])
+ return;
+ @try
+ {
+ [self setupForwarderForClassMethodSelector:sel];
+ }
+ @catch(NSException *e)
+ {
+ // ignore for now
+ }
+ }];
+}
+
+- (void)setupForwarderForClassMethodSelector:(SEL)selector
+{
+ SEL aliasSelector = OCMAliasForOriginalSelector(selector);
+ if(class_getClassMethod(mockedClass, aliasSelector) != NULL)
+ return;
+
+ Method originalMethod = class_getClassMethod(mockedClass, selector);
+ IMP originalIMP = method_getImplementation(originalMethod);
+ const char *types = method_getTypeEncoding(originalMethod);
+
+ Class metaClass = object_getClass(mockedClass);
+ IMP forwarderIMP = [originalMetaClass instanceMethodForwarderForSelector:selector];
+ class_replaceMethod(metaClass, selector, forwarderIMP, types);
+ class_addMethod(metaClass, aliasSelector, originalIMP, types);
+}
+
+
+- (void)forwardInvocationForClassObject:(NSInvocation *)anInvocation
+{
+ // in here "self" is a reference to the real class, not the mock
+ OCClassMockObject *mock = OCMGetAssociatedMockForClass((Class) self, YES);
+ if(mock == nil)
+ {
+ [NSException raise:NSInternalInconsistencyException format:@"No mock for class %@", NSStringFromClass((Class)self)];
+ }
+ if([mock handleInvocation:anInvocation] == NO)
+ {
+ [anInvocation setSelector:OCMAliasForOriginalSelector([anInvocation selector])];
+ [anInvocation invoke];
+ }
+}
+
+- (void)initializeForClassObject
+{
+ // we really just want to have an implementation so that the superclass's is not called
+}
+
#pragma mark Proxy API
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
- return [mockedClass instanceMethodSignatureForSelector:aSelector];
+ return [mockedClass instanceMethodSignatureForSelector:aSelector];
+}
+
+- (Class)mockObjectClass
+{
+ return [super class];
+}
+
+- (Class)class
+{
+ return mockedClass;
}
- (BOOL)respondsToSelector:(SEL)selector
@@ -40,4 +190,88 @@
return [mockedClass instancesRespondToSelector:selector];
}
+- (BOOL)isKindOfClass:(Class)aClass
+{
+ return [mockedClass isSubclassOfClass:aClass];
+}
+
+- (BOOL)conformsToProtocol:(Protocol *)aProtocol
+{
+ return class_conformsToProtocol(mockedClass, aProtocol);
+}
+
+@end
+
+
+#pragma mark -
+
+/**
+ taken from:
+ `class-dump -f isNS /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/System/Library/Frameworks/CoreFoundation.framework`
+
+ @interface NSObject (__NSIsKinds)
+ - (_Bool)isNSValue__;
+ - (_Bool)isNSTimeZone__;
+ - (_Bool)isNSString__;
+ - (_Bool)isNSSet__;
+ - (_Bool)isNSOrderedSet__;
+ - (_Bool)isNSNumber__;
+ - (_Bool)isNSDictionary__;
+ - (_Bool)isNSDate__;
+ - (_Bool)isNSData__;
+ - (_Bool)isNSArray__;
+ */
+
+@implementation OCClassMockObject(NSIsKindsImplementation)
+
+- (BOOL)isNSValue__
+{
+ return [mockedClass isKindOfClass:[NSValue class]];
+}
+
+- (BOOL)isNSTimeZone__
+{
+ return [mockedClass isKindOfClass:[NSTimeZone class]];
+}
+
+- (BOOL)isNSSet__
+{
+ return [mockedClass isKindOfClass:[NSSet class]];
+}
+
+- (BOOL)isNSOrderedSet__
+{
+ return [mockedClass isKindOfClass:[NSOrderedSet class]];
+}
+
+- (BOOL)isNSNumber__
+{
+ return [mockedClass isKindOfClass:[NSNumber class]];
+}
+
+- (BOOL)isNSDate__
+{
+ return [mockedClass isKindOfClass:[NSDate class]];
+}
+
+- (BOOL)isNSString__
+{
+ return [mockedClass isKindOfClass:[NSString class]];
+}
+
+- (BOOL)isNSDictionary__
+{
+ return [mockedClass isKindOfClass:[NSDictionary class]];
+}
+
+- (BOOL)isNSData__
+{
+ return [mockedClass isKindOfClass:[NSData class]];
+}
+
+- (BOOL)isNSArray__
+{
+ return [mockedClass isKindOfClass:[NSArray class]];
+}
+
@end
« no previous file with comments | « third_party/ocmock/OCMock/OCClassMockObject.h ('k') | third_party/ocmock/OCMock/OCMArg.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698