]> git.wincent.com - WOTest.git/blob - WOObjectStub.m
Code clean-up for garbage collection
[WOTest.git] / WOObjectStub.m
1 //
2 //  WOObjectStub.m
3 //  WOTest
4 //
5 //  Created by Wincent Colaiuta on 10 February 2006.
6 //
7 //  Copyright 2006-2007 Wincent Colaiuta.
8 //  This program is free software: you can redistribute it and/or modify
9 //  it under the terms of the GNU General Public License as published by
10 //  the Free Software Foundation, either version 3 of the License, or
11 //  (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU General Public License for more details.
17 //
18 //  You should have received a copy of the GNU General Public License
19 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 //
21
22 // class header
23 #import "WOObjectStub.h"
24
25 // framework headers
26
27 #import "NSInvocation+WOTest.h"
28 #import "NSObject+WOTest.h"
29
30 @implementation WOObjectStub
31
32 #pragma mark -
33 #pragma mark Creation
34
35 + (id)stubForClass:(Class)aClass withDelegate:(id)aDelegate
36 {
37     NSParameterAssert(aClass != NULL);
38     return [[self alloc] initWithClass:aClass delegate:aDelegate];
39 }
40
41 - (id)initWithClass:(Class)aClass delegate:(id)aDelegate
42 {
43     NSParameterAssert(aClass != NULL);
44     if ((self = [super init]))
45     {
46         mockedClass = aClass;
47         delegate    = aDelegate;
48     }
49     return self;
50 }
51
52 #pragma mark -
53 #pragma mark NSProxy
54
55 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
56 {
57     // avoid an infinite loop (docs warn "Be sure to avoid an infinite loop when necessary by checking that aSelector isn't the
58     // selector for this method itself and by not sending any message that might invoke this method.")
59     if (([self mockedClass] == [self class]) && (aSelector == _cmd)) return nil;
60
61     // see if method really exists in mocked class, if not forward:: will have to do something special
62     return [[self mockedClass] instanceMethodSignatureForSelector:aSelector];
63 }
64
65 #pragma mark -
66 #pragma mark NSObject protocol
67
68 - (BOOL)isEqual:(id)anObject
69 {
70     if (anObject == self) return YES;
71     @try
72     {
73         if ([NSObject WOTest_object:anObject isKindOfClass:[self class]])
74         {
75             BOOL            invocationsAreEqual     = NO;
76             BOOL            returnValuesAreEqual    = NO;
77             BOOL            exceptionsAreEqual      = NO;
78             NSInvocation    *thisInvocation         = [self invocation];
79             NSInvocation    *otherInvocation        = [anObject invocation];
80             NSValue         *thisValue              = [self returnValue];
81             NSValue         *otherValue             = [anObject returnValue];
82             id              thisException           = [self exception];
83             id              otherException          = [anObject exception];
84
85             if ([self mockedClass] != [anObject mockedClass])
86                 return NO;
87
88             if ([self acceptsAnyArguments] != [anObject acceptsAnyArguments])
89                 return NO;
90
91             if (!thisInvocation && !otherInvocation) // both nil
92                 invocationsAreEqual = YES;
93             else if (thisInvocation && otherInvocation) // both non-nil
94             {
95                 if ([self acceptsAnyArguments])
96                     invocationsAreEqual = [thisInvocation WOTest_isEqualToInvocationIgnoringArguments:otherInvocation];
97                 else
98                     invocationsAreEqual = [thisInvocation WOTest_isEqualToInvocation:otherInvocation];
99             }
100
101             if (!thisValue && !otherValue) // both nil
102                 returnValuesAreEqual = YES;
103             else if (thisValue && otherValue) // both non-nil
104                 returnValuesAreEqual = [thisValue isEqual:otherValue];
105
106             if (!thisException && !otherException) // both nil
107                 exceptionsAreEqual = YES;
108             else if (thisException && otherException) // both non-nil
109                 exceptionsAreEqual = [thisException isEqual:otherException];
110
111             if (invocationsAreEqual && returnValuesAreEqual &&
112                 exceptionsAreEqual)
113                 return YES;
114         }
115     }
116     @catch (id e) {}
117     return NO;
118 }
119
120 - (unsigned)hash
121 {
122     // hash must not rely on the object's internal state information (see docs)
123     // hash must not change while in a collection
124     return (unsigned)mockedClass;
125 }
126
127 #pragma mark -
128 #pragma mark Accessors
129
130 - (Class)mockedClass
131 {
132     return mockedClass;
133 }
134
135 @end