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

Side by Side Diff: third_party/ocmock/OCMock/OCMBoxedReturnValueProvider.mm

Issue 316873003: Add a workaround to compare types in mocked method (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add note in README.chromium and sync with upstream pull request Created 6 years, 6 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 // $Id$
3 // Copyright (c) 2009 by Mulle Kybernetik. See License file for details.
4 //------------------------------------------------------------------------------ ---------
5
6 #import "OCMBoxedReturnValueProvider.h"
7 #import <objc/runtime.h>
8
9 #if defined(__clang__)
10 #include <vector> // for _LIBCPP_ABI_VERSION to detect if using libc++
11 #endif
12
13 #if defined(__clang__) && defined(_LIBCPP_ABI_VERSION)
14 namespace {
15 // Default stack size to use when checking for matching opening and closing
16 // characters (<> and {}). This is used to reduce the number of allocations
17 // in AdvanceTypeDescriptionPointer function.
18 const size_t kDefaultStackSize = 32;
19
20 // Move to the next pertinent character in a type description. This skips
21 // all the field expansion that clang includes in the type description when
22 // compiling with libc++.
23 //
24 // See inner comment of -isValueTypeCompatibleWithInvocation: for more details.
25 // Returns true if the pointer was advanced, false if the type description was
26 // not correctly parsed.
27 bool AdvanceTypeDescriptionPointer(const char *&typeDescription) {
28 if (!*typeDescription)
29 return true;
30
31 ++typeDescription;
32 if (*typeDescription != '=')
33 return true;
34
35 ++typeDescription;
36 std::vector<char> stack;
37 stack.reserve(kDefaultStackSize);
38 while (*typeDescription) {
39 const char current = *typeDescription;
40 if (current == '<' || current == '{') {
41 stack.push_back(current);
42 } else if (current == '>' || current == '}') {
43 if (!stack.empty()) {
44 const char opening = stack.back();
45 if ((opening == '<' && current != '>') ||
46 (opening == '{' && current != '} ')) {
47 return false;
48 }
49 stack.pop_back();
50 } else {
51 return current == '}';
52 }
53 } else if (current == ',' && stack.empty()) {
54 return true;
55 }
56 ++typeDescription;
57 }
58 return true;
59 }
60 }
61 #endif // defined(__clang__) && defined(_LIBCPP_ABI_VERSION)
62
63 @interface OCMBoxedReturnValueProvider ()
64
65 - (BOOL)isValueTypeCompatibleWithInvocation:(NSInvocation *)anInvocation;
66
67 @end
68
69 @implementation OCMBoxedReturnValueProvider
70
71 - (BOOL)isValueTypeCompatibleWithInvocation:(NSInvocation *)anInvocation {
72 const char *returnType = [[anInvocation methodSignature] methodReturnTyp e];
73 const char *valueType = [(NSValue *)returnValue objCType];
74
75 #if defined(__aarch64__) || defined(__x86_64__)
76 // ARM64 uses 'B' for BOOLs in method signature but 'c' in NSValue. That case
77 // should match.
78 if (strcmp(returnType, "B") == 0 && strcmp(valueType, "c") == 0)
79 return YES;
80 #endif // defined(__aarch64__) || defined(__x86_64__)
81
82 #if defined(__clang__) && defined(_LIBCPP_ABI_VERSION)
83 // The type representation of the return type of the invocation, and the
84 // type representation passed to NSValue are not the same for C++ object s
85 // when compiling with libc++ with clang.
86 //
87 // In that configuration, the C++ class are expanded to list the types o f
88 // the fields, but the depth of the expansion for templated types is lar ger
89 // for the value stored in the NSValue.
90 //
91 // For example, when creating a OCMOCK_VALUE with a GURL object (from th e
92 // Chromium project), then the two types representations are:
93 //
94 // r^{GURL={basic_string<char, std::__1::char_traits<char>, std::__1::al loca
95 // tor<char> >={__compressed_pair<std::__1::basic_string<char, std::__1: :cha
96 // r_traits<char>, std::__1::allocator<char> >::__rep, std::__1::allocat or<c
97 // har> >={__rep}}}B{Parsed={Component=ii}{Component=ii}{Component=ii}{C ompo
98 // nent=ii}{Component=ii}{Component=ii}{Component=ii}{Component=ii}^{Par sed}
99 // }{scoped_ptr<GURL, base::DefaultDeleter<GURL> >={scoped_ptr_impl<GURL , ba
100 // se::DefaultDeleter<GURL> >={Data=^{GURL}}}}}
101 //
102 // r^{GURL={basic_string<char, std::__1::char_traits<char>, std::__1::al loca
103 // tor<char> >={__compressed_pair<std::__1::basic_string<char, std::__1: :cha
104 // r_traits<char>, std::__1::allocator<char> >::__rep, std::__1::allocat or<c
105 // har> >={__rep=(?={__long=II*}{__short=(?=Cc)[11c]}{__raw=[3L]})}}}B{P arse
106 // d={Component=ii}{Component=ii}{Component=ii}{Component=ii}{Component= ii}{
107 // Component=ii}{Component=ii}{Component=ii}^{Parsed}}{scoped_ptr<GURL, base
108 // ::DefaultDeleter<GURL> >={scoped_ptr_impl<GURL, base::DefaultDeleter< GURL
109 // > >={Data=^{GURL}}}}}
110 //
111 // Since those types should be considered equals, we un-expand them duri ng
112 // the comparison. For that, we remove everything following an "=" until we
113 // meet a non-matched "}" or a ",".
114
115 while (*returnType && *valueType) {
116 if (*returnType != *valueType)
117 return NO;
118
119 if (!AdvanceTypeDescriptionPointer(returnType))
120 return NO;
121
122 if (!AdvanceTypeDescriptionPointer(valueType))
123 return NO;
124 }
125
126 return !*returnType && !*valueType;
127 #else
128 return strcmp(returnType, valueType) == 0;
129 #endif // defined(__clang__) && defined(_LIBCPP_ABI_VERSION)
130 }
131
132 - (void)handleInvocation:(NSInvocation *)anInvocation
133 {
134 if (![self isValueTypeCompatibleWithInvocation:anInvocation]) {
135 const char *returnType = [[anInvocation methodSignature] methodR eturnType];
136 const char *valueType = [(NSValue *)returnValue objCType];
137 @throw [NSException exceptionWithName:NSInvalidArgumentException reason:[NSString stringWithFormat:@"Return value does not match method signatur e; signature declares '%s' but value is '%s'.", returnType, valueType] userInfo: nil];
138 }
139 void *buffer = malloc([[anInvocation methodSignature] methodReturnLength ]);
140 [returnValue getValue:buffer];
141 [anInvocation setReturnValue:buffer];
142 free(buffer);
143 }
144
145 @end
OLDNEW
« no previous file with comments | « third_party/ocmock/OCMock/OCMBoxedReturnValueProvider.m ('k') | third_party/ocmock/README.chromium » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698