Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / ocmock / OCMock / OCPartialMockObject.m
1 //---------------------------------------------------------------------------------------
2 //  $Id$
3 //  Copyright (c) 2009 by Mulle Kybernetik. See License file for details.
4 //---------------------------------------------------------------------------------------
5
6 #import <objc/runtime.h>
7 #import "OCPartialMockRecorder.h"
8 #import "OCPartialMockObject.h"
9
10
11 @interface OCPartialMockObject (Private)
12 - (void)forwardInvocationForRealObject:(NSInvocation *)anInvocation;
13 @end 
14
15
16 NSString *OCMRealMethodAliasPrefix = @"ocmock_replaced_";
17
18 @implementation OCPartialMockObject
19
20
21 #pragma mark  Mock table
22
23 static NSMutableDictionary *mockTable;
24
25 + (void)initialize
26 {
27         if(self == [OCPartialMockObject class])
28                 mockTable = [[NSMutableDictionary alloc] init];
29 }
30
31 + (void)rememberPartialMock:(OCPartialMockObject *)mock forObject:(id)anObject
32 {
33         [mockTable setObject:[NSValue valueWithNonretainedObject:mock] forKey:[NSValue valueWithNonretainedObject:anObject]];
34 }
35
36 + (void)forgetPartialMockForObject:(id)anObject
37 {
38         [mockTable removeObjectForKey:[NSValue valueWithNonretainedObject:anObject]];
39 }
40
41 + (OCPartialMockObject *)existingPartialMockForObject:(id)anObject
42 {
43         OCPartialMockObject *mock = [[mockTable objectForKey:[NSValue valueWithNonretainedObject:anObject]] nonretainedObjectValue];
44         if(mock == nil)
45                 [NSException raise:NSInternalInconsistencyException format:@"No partial mock for object %p", anObject];
46         return mock;
47 }
48
49
50
51 #pragma mark  Initialisers, description, accessors, etc.
52
53 - (id)initWithObject:(NSObject *)anObject
54 {
55         [super initWithClass:[anObject class]];
56         realObject = [anObject retain];
57         [[self class] rememberPartialMock:self forObject:anObject];
58         [self setupSubclassForObject:realObject];
59         return self;
60 }
61
62 - (void)dealloc
63 {
64         if(realObject != nil)
65                 [self stop];
66         [super dealloc];
67 }
68
69 - (NSString *)description
70 {
71         return [NSString stringWithFormat:@"OCPartialMockObject[%@]", NSStringFromClass(mockedClass)];
72 }
73
74 - (NSObject *)realObject
75 {
76         return realObject;
77 }
78
79 - (void)stop
80 {
81         object_setClass(realObject, [self mockedClass]);
82         [realObject release];
83         [[self class] forgetPartialMockForObject:realObject];
84         realObject = nil;
85 }
86
87
88 #pragma mark  Subclass management
89
90 - (void)setupSubclassForObject:(id)anObject
91 {
92         Class realClass = [anObject class];
93         double timestamp = [NSDate timeIntervalSinceReferenceDate];
94         const char *className = [[NSString stringWithFormat:@"%@-%p-%f", realClass, anObject, timestamp] UTF8String];
95         Class subclass = objc_allocateClassPair(realClass, className, 0);
96         objc_registerClassPair(subclass);
97         object_setClass(anObject, subclass);
98         
99         Method forwardInvocationMethod = class_getInstanceMethod([self class], @selector(forwardInvocationForRealObject:));
100         IMP forwardInvocationImp = method_getImplementation(forwardInvocationMethod);
101         const char *forwardInvocationTypes = method_getTypeEncoding(forwardInvocationMethod);
102         class_addMethod(subclass, @selector(forwardInvocation:), forwardInvocationImp, forwardInvocationTypes);
103 }
104
105 - (void)setupForwarderForSelector:(SEL)selector
106 {
107         Class subclass = [[self realObject] class];
108         Method originalMethod = class_getInstanceMethod([subclass superclass], selector);
109         IMP originalImp = method_getImplementation(originalMethod);
110
111         IMP forwarderImp = [subclass instanceMethodForSelector:@selector(aMethodThatMustNotExist)];
112         class_addMethod(subclass, method_getName(originalMethod), forwarderImp, method_getTypeEncoding(originalMethod)); 
113
114         SEL aliasSelector = NSSelectorFromString([OCMRealMethodAliasPrefix stringByAppendingString:NSStringFromSelector(selector)]);
115         class_addMethod(subclass, aliasSelector, originalImp, method_getTypeEncoding(originalMethod));
116 }
117
118 - (void)forwardInvocationForRealObject:(NSInvocation *)anInvocation
119 {
120         // in here "self" is a reference to the real object, not the mock
121         OCPartialMockObject *mock = [OCPartialMockObject existingPartialMockForObject:self];
122         if([mock handleInvocation:anInvocation] == NO)
123                 [NSException raise:NSInternalInconsistencyException format:@"Ended up in subclass forwarder for %@ with unstubbed method %@",
124                  [self class], NSStringFromSelector([anInvocation selector])];
125 }
126
127
128
129 #pragma mark  Overrides
130
131 - (id)getNewRecorder
132 {
133         return [[[OCPartialMockRecorder alloc] initWithSignatureResolver:self] autorelease];
134 }
135
136 - (void)handleUnRecordedInvocation:(NSInvocation *)anInvocation
137 {
138         [anInvocation invokeWithTarget:realObject];
139 }
140
141
142 @end