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

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

Issue 2410583002: Test update OCMock (Closed)
Patch Set: Patch in exactly 3.1.5 Created 3 years, 11 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..4dda97ab4688595308e2091b8ab54e9368214a2d 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
{
- [super init];
- mockedClass = aClass;
- return self;
+ 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,145 @@
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 +195,76 @@
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