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

Side by Side Diff: third_party/ocmock/OCMock/OCMFunctions.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 unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2014-2015 Erik Doernenburg and contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may
5 * not use these files except in compliance with the License. You may obtain
6 * a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17 #import <objc/runtime.h>
18 #import "OCMFunctions.h"
19 #import "OCMLocation.h"
20 #import "OCClassMockObject.h"
21 #import "OCPartialMockObject.h"
22
23 #pragma mark Known private API
24
25 @interface NSException (OCMKnownExceptionMethods)
26 + (NSException*)failureInFile:(NSString*)file
27 atLine:(int)line
28 withDescription:(NSString*)formatString, ...;
29 @end
30
31 @interface NSObject (OCMKnownTestCaseMethods)
32 - (void)recordFailureWithDescription:(NSString*)description
33 inFile:(NSString*)file
34 atLine:(NSUInteger)line
35 expected:(BOOL)expected;
36 - (void)failWithException:(NSException*)exception;
37 @end
38
39 #pragma mark Functions related to ObjC type system
40
41 BOOL OCMIsObjectType(const char* objCType) {
42 objCType = OCMTypeWithoutQualifiers(objCType);
43
44 if (strcmp(objCType, @encode(id)) == 0 ||
45 strcmp(objCType, @encode(Class)) == 0)
46 return YES;
47
48 // if the returnType is a typedef to an object, it has the form
49 // ^{OriginClass=#}
50 NSString* regexString = @"^\\^\\{(.*)=#.*\\}";
51 NSRegularExpression* regex =
52 [NSRegularExpression regularExpressionWithPattern:regexString
53 options:0
54 error:NULL];
55 NSString* type =
56 [NSString stringWithCString:objCType encoding:NSASCIIStringEncoding];
57 if ([regex numberOfMatchesInString:type
58 options:0
59 range:NSMakeRange(0, type.length)] > 0)
60 return YES;
61
62 // if the return type is a block we treat it like an object
63 // TODO: if the runtime were to encode the block's argument and/or return
64 // types, this test would not be sufficient
65 if (strcmp(objCType, @encode(void (^)())) == 0)
66 return YES;
67
68 return NO;
69 }
70
71 const char* OCMTypeWithoutQualifiers(const char* objCType) {
72 while (strchr("rnNoORV", objCType[0]) != NULL)
73 objCType += 1;
74 return objCType;
75 }
76
77 /*
78 * Sometimes an external type is an opaque struct (which will have an @encode of
79 * "{structName}"
80 * or "{structName=}") but the actual method return type, or property type, will
81 * know the contents
82 * of the struct (so will have an objcType of say "{structName=iiSS}". This
83 * function will determine
84 * those are equal provided they have the same structure name, otherwise
85 * everything else will be
86 * compared textually. This can happen particularly for pointers to such
87 * structures, which still
88 * encode what is being pointed to.
89 *
90 * For some types some runtime functions throw exceptions, which is why we wrap
91 * this in an
92 * exception handler just below.
93 */
94 static BOOL OCMEqualTypesAllowingOpaqueStructsInternal(const char* type1,
95 const char* type2) {
96 type1 = OCMTypeWithoutQualifiers(type1);
97 type2 = OCMTypeWithoutQualifiers(type2);
98
99 switch (type1[0]) {
100 case '{':
101 case '(': {
102 if (type2[0] != type1[0])
103 return NO;
104 char endChar = type1[0] == '{' ? '}' : ')';
105
106 const char* type1End = strchr(type1, endChar);
107 const char* type2End = strchr(type2, endChar);
108 const char* type1Equals = strchr(type1, '=');
109 const char* type2Equals = strchr(type2, '=');
110
111 /* Opaque types either don't have an equals sign (just the name and the
112 * end brace), or
113 * empty content after the equals sign.
114 * We want that to compare the same as a type of the same name but with
115 * the content.
116 */
117 BOOL type1Opaque = (type1Equals == NULL || (type1End < type1Equals) ||
118 type1Equals[1] == endChar);
119 BOOL type2Opaque = (type2Equals == NULL || (type2End < type2Equals) ||
120 type2Equals[1] == endChar);
121 const char* type1NameEnd =
122 (type1Equals == NULL || (type1End < type1Equals)) ? type1End
123 : type1Equals;
124 const char* type2NameEnd =
125 (type2Equals == NULL || (type2End < type2Equals)) ? type2End
126 : type2Equals;
127 intptr_t type1NameLen = type1NameEnd - type1;
128 intptr_t type2NameLen = type2NameEnd - type2;
129
130 /* If the names are not equal, return NO */
131 if (type1NameLen != type2NameLen || strncmp(type1, type2, type1NameLen))
132 return NO;
133
134 /* If the same name, and at least one is opaque, that is close enough. */
135 if (type1Opaque || type2Opaque)
136 return YES;
137
138 /* Otherwise, compare all the elements. Use NSGetSizeAndAlignment to walk
139 * through the struct elements. */
140 type1 = type1Equals + 1;
141 type2 = type2Equals + 1;
142 while (type1[0] != endChar && type1[0] != '\0') {
143 if (!OCMEqualTypesAllowingOpaqueStructs(type1, type2))
144 return NO;
145 type1 = NSGetSizeAndAlignment(type1, NULL, NULL);
146 type2 = NSGetSizeAndAlignment(type2, NULL, NULL);
147 }
148 return YES;
149 }
150 case '^':
151 /* for a pointer, make sure the other is a pointer, then recursively
152 * compare the rest */
153 if (type2[0] != type1[0])
154 return NO;
155 return OCMEqualTypesAllowingOpaqueStructs(type1 + 1, type2 + 1);
156
157 case '\0':
158 return type2[0] == '\0';
159
160 default: {
161 // Move the type pointers past the current types, then compare that region
162 const char* afterType1 = NSGetSizeAndAlignment(type1, NULL, NULL);
163 const char* afterType2 = NSGetSizeAndAlignment(type2, NULL, NULL);
164 intptr_t type1Len = afterType1 - type1;
165 intptr_t type2Len = afterType2 - type2;
166
167 return (type1Len == type2Len && (strncmp(type1, type2, type1Len) == 0));
168 }
169 }
170 }
171
172 BOOL OCMEqualTypesAllowingOpaqueStructs(const char* type1, const char* type2) {
173 @try {
174 return OCMEqualTypesAllowingOpaqueStructsInternal(type1, type2);
175 } @catch (NSException* e) {
176 /* Probably a bitfield or something that NSGetSizeAndAlignment chokes on, oh
177 * well */
178 return NO;
179 }
180 }
181
182 #pragma mark Creating classes
183
184 Class OCMCreateSubclass(Class class, void* ref) {
185 const char* className =
186 [[NSString stringWithFormat:@"%@-%p-%u", NSStringFromClass(class), ref,
187 arc4random()] UTF8String];
188 Class subclass = objc_allocateClassPair(class, className, 0);
189 objc_registerClassPair(subclass);
190 return subclass;
191 }
192
193 #pragma mark Directly manipulating the isa pointer (look away)
194
195 void OCMSetIsa(id object, Class class) {
196 *((Class*)object) = class;
197 }
198
199 Class OCMGetIsa(id object) {
200 return *((Class*)object);
201 }
202
203 #pragma mark Alias for renaming real methods
204
205 static NSString* const OCMRealMethodAliasPrefix = @"ocmock_replaced_";
206 static const char* const OCMRealMethodAliasPrefixCString = "ocmock_replaced_";
207
208 BOOL OCMIsAliasSelector(SEL selector) {
209 return [NSStringFromSelector(selector) hasPrefix:OCMRealMethodAliasPrefix];
210 }
211
212 SEL OCMAliasForOriginalSelector(SEL selector) {
213 char aliasName[2048];
214 const char* originalName = sel_getName(selector);
215 strlcpy(aliasName, OCMRealMethodAliasPrefixCString, sizeof(aliasName));
216 strlcat(aliasName, originalName, sizeof(aliasName));
217 return sel_registerName(aliasName);
218 }
219
220 SEL OCMOriginalSelectorForAlias(SEL selector) {
221 if (!OCMIsAliasSelector(selector))
222 [NSException raise:NSInvalidArgumentException
223 format:@"Not an alias selector; found %@",
224 NSStringFromSelector(selector)];
225 NSString* string = NSStringFromSelector(selector);
226 return NSSelectorFromString(
227 [string substringFromIndex:[OCMRealMethodAliasPrefix length]]);
228 }
229
230 #pragma mark Wrappers around associative references
231
232 static NSString* const OCMClassMethodMockObjectKey =
233 @"OCMClassMethodMockObjectKey";
234
235 void OCMSetAssociatedMockForClass(OCClassMockObject* mock, Class aClass) {
236 if ((mock != nil) &&
237 (objc_getAssociatedObject(aClass, OCMClassMethodMockObjectKey) != nil))
238 [NSException raise:NSInternalInconsistencyException
239 format:@"Another mock is already associated with class %@",
240 NSStringFromClass(aClass)];
241 objc_setAssociatedObject(aClass, OCMClassMethodMockObjectKey, mock,
242 OBJC_ASSOCIATION_ASSIGN);
243 }
244
245 OCClassMockObject* OCMGetAssociatedMockForClass(Class aClass,
246 BOOL includeSuperclasses) {
247 OCClassMockObject* mock = nil;
248 do {
249 mock = objc_getAssociatedObject(aClass, OCMClassMethodMockObjectKey);
250 aClass = class_getSuperclass(aClass);
251 } while ((mock == nil) && (aClass != nil) && includeSuperclasses);
252 return mock;
253 }
254
255 static NSString* const OCMPartialMockObjectKey = @"OCMPartialMockObjectKey";
256
257 void OCMSetAssociatedMockForObject(OCClassMockObject* mock, id anObject) {
258 if ((mock != nil) &&
259 (objc_getAssociatedObject(anObject, OCMPartialMockObjectKey) != nil))
260 [NSException
261 raise:NSInternalInconsistencyException
262 format:@"Another mock is already associated with object %@", anObject];
263 objc_setAssociatedObject(anObject, OCMPartialMockObjectKey, mock,
264 OBJC_ASSOCIATION_ASSIGN);
265 }
266
267 OCPartialMockObject* OCMGetAssociatedMockForObject(id anObject) {
268 return objc_getAssociatedObject(anObject, OCMPartialMockObjectKey);
269 }
270
271 #pragma mark Functions related to IDE error reporting
272
273 void OCMReportFailure(OCMLocation* loc, NSString* description) {
274 id testCase = [loc testCase];
275 if ((testCase != nil) &&
276 [testCase respondsToSelector:@selector(recordFailureWithDescription:
277 inFile:
278 atLine:
279 expected:)]) {
280 [testCase recordFailureWithDescription:description
281 inFile:[loc file]
282 atLine:[loc line]
283 expected:NO];
284 } else if ((testCase != nil) &&
285 [testCase respondsToSelector:@selector(failWithException:)]) {
286 NSException* exception = nil;
287 if ([NSException instancesRespondToSelector:@selector(failureInFile:
288 atLine:
289 withDescription:)]) {
290 exception = [NSException failureInFile:[loc file]
291 atLine:(int)[loc line]
292 withDescription:description];
293 } else {
294 NSString* reason =
295 [NSString stringWithFormat:@"%@:%lu %@", [loc file],
296 (unsigned long)[loc line], description];
297 exception = [NSException exceptionWithName:@"OCMockTestFailure"
298 reason:reason
299 userInfo:nil];
300 }
301 [testCase failWithException:exception];
302 } else if (loc != nil) {
303 NSLog(@"%@:%lu %@", [loc file], (unsigned long)[loc line], description);
304 NSString* reason =
305 [NSString stringWithFormat:@"%@:%lu %@", [loc file],
306 (unsigned long)[loc line], description];
307 [[NSException exceptionWithName:@"OCMockTestFailure"
308 reason:reason
309 userInfo:nil] raise];
310
311 } else {
312 NSLog(@"%@", description);
313 [[NSException exceptionWithName:@"OCMockTestFailure"
314 reason:description
315 userInfo:nil] raise];
316 }
317 }
OLDNEW
« no previous file with comments | « third_party/ocmock/OCMock/OCMFunctions.h ('k') | third_party/ocmock/OCMock/OCMIndirectReturnValueProvider.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698