Skip to content

Commit b8746e5

Browse files
committed
Merge branch 'dmaclach-realNil'
2 parents 461c694 + 7932a18 commit b8746e5

File tree

8 files changed

+171
-23
lines changed

8 files changed

+171
-23
lines changed

Source/OCMock.xcodeproj/project.pbxproj

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@
279279
817EB15C1BD765130047E85A /* OCMBlockArgCaller.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA2891034E7B73AA3511D17 /* OCMBlockArgCaller.h */; };
280280
817EB15D1BD765130047E85A /* OCMArgAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA2833B48908EAD36444671 /* OCMArgAction.h */; };
281281
817EB1661BD7674D0047E85A /* OCMFunctionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 03F370CA1BAA1DE800CAD3E8 /* OCMFunctionsPrivate.h */; };
282+
8B11D4B72448E2E900247BE2 /* OCMCPlusPlus98Tests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8B11D4B62448E2E900247BE2 /* OCMCPlusPlus98Tests.mm */; settings = {COMPILER_FLAGS = "-std=gnu++98"; }; };
283+
8B11D4B82448E2F400247BE2 /* OCMCPlusPlus98Tests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8B11D4B62448E2E900247BE2 /* OCMCPlusPlus98Tests.mm */; settings = {COMPILER_FLAGS = "-std=gnu++98"; }; };
284+
8B11D4BA2448E53600247BE2 /* OCMCPlusPlus11Tests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8B11D4B92448E53600247BE2 /* OCMCPlusPlus11Tests.mm */; settings = {COMPILER_FLAGS = "-std=gnu++11"; }; };
285+
8B11D4BB2448E53600247BE2 /* OCMCPlusPlus11Tests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8B11D4B92448E53600247BE2 /* OCMCPlusPlus11Tests.mm */; settings = {COMPILER_FLAGS = "-std=gnu++11"; }; };
282286
8BF73E53246CA75E00B9A52C /* OCMNoEscapeBlockTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BF73E52246CA75E00B9A52C /* OCMNoEscapeBlockTests.m */; settings = {COMPILER_FLAGS = "-Xclang -fexperimental-optimized-noescape"; }; };
283287
8BF73E54246CA75E00B9A52C /* OCMNoEscapeBlockTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BF73E52246CA75E00B9A52C /* OCMNoEscapeBlockTests.m */; settings = {COMPILER_FLAGS = "-Xclang -fexperimental-optimized-noescape"; }; };
284288
8DE97C5522B43EE60098C63F /* OCMockObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 03B3159E146333BF0052CD09 /* OCMockObject.m */; };
@@ -547,7 +551,7 @@
547551
2FA28006D043CBDBBAEF6E3F /* OCMMacroState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMMacroState.h; sourceTree = "<group>"; };
548552
2FA280987F4EA8A4D79000D0 /* OCMMacroState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCMMacroState.m; sourceTree = "<group>"; };
549553
2FA280EB5E8CDEEAE76861F7 /* OCMNonRetainingObjectReturnValueProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCMNonRetainingObjectReturnValueProvider.m; sourceTree = "<group>"; };
550-
2FA2813F93050582D83E1499 /* OCMockObjectRuntimeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCMockObjectRuntimeTests.m; sourceTree = "<group>"; };
554+
2FA2813F93050582D83E1499 /* OCMockObjectRuntimeTests.m */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.objc; fileEncoding = 4; path = OCMockObjectRuntimeTests.m; sourceTree = "<group>"; };
551555
2FA2822E19948FC997965267 /* OCMockObjectTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCMockObjectTests.m; sourceTree = "<group>"; };
552556
2FA2833B48908EAD36444671 /* OCMArgAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMArgAction.h; sourceTree = "<group>"; };
553557
2FA283D58AA7569D8A5B0C57 /* OCMBlockArgCaller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCMBlockArgCaller.m; sourceTree = "<group>"; };
@@ -571,6 +575,8 @@
571575
3CFBDD751BB3DB200050D9C5 /* TestClassWithCustomReferenceCounting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestClassWithCustomReferenceCounting.h; sourceTree = "<group>"; };
572576
3CFBDD761BB3DB200050D9C5 /* TestClassWithCustomReferenceCounting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestClassWithCustomReferenceCounting.m; sourceTree = "<group>"; };
573577
817EB1621BD765130047E85A /* OCMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OCMock.framework; sourceTree = BUILT_PRODUCTS_DIR; };
578+
8B11D4B62448E2E900247BE2 /* OCMCPlusPlus98Tests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OCMCPlusPlus98Tests.mm; sourceTree = "<group>"; };
579+
8B11D4B92448E53600247BE2 /* OCMCPlusPlus11Tests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OCMCPlusPlus11Tests.mm; sourceTree = "<group>"; };
574580
8BF73E52246CA75E00B9A52C /* OCMNoEscapeBlockTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCMNoEscapeBlockTests.m; sourceTree = "<group>"; };
575581
8DE97CA022B43EE60098C63F /* OCMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OCMock.framework; sourceTree = BUILT_PRODUCTS_DIR; };
576582
A02926811CA0725A00594AAF /* TestObjects.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = TestObjects.xcdatamodel; sourceTree = "<group>"; };
@@ -751,6 +757,8 @@
751757
037ECD5318FAD84100AF0E4C /* OCMInvocationMatcherTests.m */,
752758
031E50571BB4A56300E257C3 /* OCMBoxedReturnValueProviderTests.m */,
753759
03B316211463350E0052CD09 /* OCMConstraintTests.m */,
760+
8B11D4B62448E2E900247BE2 /* OCMCPlusPlus98Tests.mm */,
761+
8B11D4B92448E53600247BE2 /* OCMCPlusPlus11Tests.mm */,
754762
2FA28EDBF243639C57F88A1B /* OCMArgTests.m */,
755763
036865631D3571A8005E6BEE /* OCMQuantifierTests.m */,
756764
03B316291463350E0052CD09 /* OCObserverMockObjectTests.m */,
@@ -1501,9 +1509,11 @@
15011509
03565A4818F05721003AE91E /* OCMStubRecorderTests.m in Sources */,
15021510
03565A4518F05721003AE91E /* OCMockObjectForwardingTargetTests.m in Sources */,
15031511
2FA28FA53C57236B6DD64E82 /* OCMockObjectRuntimeTests.m in Sources */,
1512+
8B11D4BA2448E53600247BE2 /* OCMCPlusPlus11Tests.mm in Sources */,
15041513
2FA2839F33289795284C32FB /* OCMockObjectTests.m in Sources */,
15051514
038599F723807B06002B3ABE /* OCMockObjectInternalTests.m in Sources */,
15061515
8BF73E53246CA75E00B9A52C /* OCMNoEscapeBlockTests.m in Sources */,
1516+
8B11D4B72448E2E900247BE2 /* OCMCPlusPlus98Tests.mm in Sources */,
15071517
2FA28AB33F01A7D980F2C705 /* OCMockObjectDynamicPropertyMockingTests.m in Sources */,
15081518
031E50581BB4A56300E257C3 /* OCMBoxedReturnValueProviderTests.m in Sources */,
15091519
);
@@ -1614,9 +1624,11 @@
16141624
03C9CA1D18F05A75006DF94D /* OCMockObjectProtocolMocksTests.m in Sources */,
16151625
03E98D5118F310EE00522D42 /* OCMockObjectMacroTests.m in Sources */,
16161626
A06930951CA1BFC900513023 /* TestObjects.xcdatamodeld in Sources */,
1627+
8B11D4BB2448E53600247BE2 /* OCMCPlusPlus11Tests.mm in Sources */,
16171628
2FA28295E1F58F40A77D7448 /* OCMockObjectRuntimeTests.m in Sources */,
16181629
038599F823807B06002B3ABE /* OCMockObjectInternalTests.m in Sources */,
16191630
8BF73E54246CA75E00B9A52C /* OCMNoEscapeBlockTests.m in Sources */,
1631+
8B11D4B82448E2F400247BE2 /* OCMCPlusPlus98Tests.mm in Sources */,
16201632
2FA28246CD449A01717B1CEC /* OCMockObjectTests.m in Sources */,
16211633
2FA28F12AAD384A8CB16094B /* OCMockObjectDynamicPropertyMockingTests.m in Sources */,
16221634
);

Source/OCMock/OCMBoxedReturnValueProvider.m

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#import "OCMFunctionsPrivate.h"
1919
#import "NSValue+OCMAdditions.h"
2020

21+
2122
@implementation OCMBoxedReturnValueProvider
2223

2324
- (void)handleInvocation:(NSInvocation *)anInvocation
@@ -26,10 +27,11 @@ - (void)handleInvocation:(NSInvocation *)anInvocation
2627
NSUInteger returnTypeSize = [[anInvocation methodSignature] methodReturnLength];
2728
char valueBuffer[returnTypeSize];
2829
NSValue *returnValueAsNSValue = (NSValue *)returnValue;
30+
[returnValueAsNSValue getValue:valueBuffer];
2931

30-
if([self isMethodReturnType:returnType compatibleWithValueType:[returnValueAsNSValue objCType]])
32+
if([self isMethodReturnType:returnType compatibleWithValueType:[returnValueAsNSValue objCType]
33+
value:valueBuffer valueSize:returnTypeSize])
3134
{
32-
[returnValueAsNSValue getValue:valueBuffer];
3335
[anInvocation setReturnValue:valueBuffer];
3436
}
3537
else if([returnValueAsNSValue getBytes:valueBuffer objCType:returnType])
@@ -43,16 +45,15 @@ - (void)handleInvocation:(NSInvocation *)anInvocation
4345
}
4446
}
4547

46-
47-
- (BOOL)isMethodReturnType:(const char *)returnType compatibleWithValueType:(const char *)valueType
48+
- (BOOL)isMethodReturnType:(const char *)returnType compatibleWithValueType:(const char *)valueType value:(const void *)value valueSize:(size_t)valueSize
4849
{
4950
/* Same types are obviously compatible */
5051
if(strcmp(returnType, valueType) == 0)
5152
return YES;
5253

53-
/* Allow void* for methods that return id, mainly to be able to handle nil */
54-
if(strcmp(returnType, @encode(id)) == 0 && strcmp(valueType, @encode(void *)) == 0)
55-
return YES;
54+
/* Special treatment for nil and Nil */
55+
if(strcmp(returnType, @encode(id)) == 0 || strcmp(returnType, @encode(Class)) == 0)
56+
return OCMIsNilValue(valueType, value, valueSize);
5657

5758
return OCMEqualTypesAllowingOpaqueStructs(returnType, valueType);
5859
}

Source/OCMock/OCMFunctions.m

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,24 @@ BOOL OCMEqualTypesAllowingOpaqueStructs(const char *type1, const char *type2)
296296
}
297297
}
298298

299+
BOOL OCMIsNilValue(const char *objectCType, const void *value, size_t valueSize)
300+
{
301+
// First, check value itself
302+
for(size_t i = 0; i < valueSize; i++)
303+
if(((const char *)value)[i] != 0)
304+
return NO;
305+
306+
// Depending on the compilation settings of the file where the return value gets recorded,
307+
// nil and Nil get potentially different encodings. Check all known encodings.
308+
if((strcmp(objectCType, @encode(void *)) == 0) || // Standard Objective-C
309+
(strcmp(objectCType, @encode(int)) == 0) || // 32 bit C++ (before nullptr)
310+
(strcmp(objectCType, @encode(long long)) == 0) || // 64 bit C++ (before nullptr)
311+
(strcmp(objectCType, @encode(char *)) == 0)) // C++ with nullptr
312+
return YES;
313+
314+
return NO;
315+
}
316+
299317

300318
BOOL OCMIsAppleBaseClass(Class cls)
301319
{

Source/OCMock/OCMFunctionsPrivate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ BOOL OCMIsObjectType(const char *objCType);
2727
const char *OCMTypeWithoutQualifiers(const char *objCType);
2828
BOOL OCMEqualTypesAllowingOpaqueStructs(const char *type1, const char *type2);
2929
CFNumberType OCMNumberTypeForObjCType(const char *objcType);
30+
BOOL OCMIsNilValue(const char *objectCType, const void *value, size_t valueSize);
3031

3132
BOOL OCMIsAppleBaseClass(Class cls);
3233
BOOL OCMIsApplePrivateMethod(Class cls, SEL sel);

Source/OCMockTests/OCMBoxedReturnValueProviderTests.m

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
#import "OCMBoxedReturnValueProvider.h"
1919

2020
@interface OCMBoxedReturnValueProvider(Private)
21-
- (BOOL)isMethodReturnType:(const char *)returnType compatibleWithValueType:(const char *)valueType;
21+
- (BOOL)isMethodReturnType:(const char *)returnType compatibleWithValueType:(const char *)valueType value:(const char*)value valueSize:(size_t)valueSize;
2222
@end
2323

24+
2425
@interface OCMBoxedReturnValueProviderTests : XCTestCase
2526

2627
@end
@@ -53,12 +54,12 @@ - (void)testCorrectEqualityForCppProperty
5354
"r^{GURL}";
5455

5556
OCMBoxedReturnValueProvider *boxed = [OCMBoxedReturnValueProvider new];
56-
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type2]);
57-
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type3]);
58-
XCTAssertTrue([boxed isMethodReturnType:type2 compatibleWithValueType:type1]);
59-
XCTAssertTrue([boxed isMethodReturnType:type2 compatibleWithValueType:type3]);
60-
XCTAssertTrue([boxed isMethodReturnType:type3 compatibleWithValueType:type1]);
61-
XCTAssertTrue([boxed isMethodReturnType:type3 compatibleWithValueType:type2]);
57+
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type2 value:NULL valueSize:0]);
58+
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type3 value:NULL valueSize:0]);
59+
XCTAssertTrue([boxed isMethodReturnType:type2 compatibleWithValueType:type1 value:NULL valueSize:0]);
60+
XCTAssertTrue([boxed isMethodReturnType:type2 compatibleWithValueType:type3 value:NULL valueSize:0]);
61+
XCTAssertTrue([boxed isMethodReturnType:type3 compatibleWithValueType:type1 value:NULL valueSize:0]);
62+
XCTAssertTrue([boxed isMethodReturnType:type3 compatibleWithValueType:type2 value:NULL valueSize:0]);
6263
}
6364

6465

@@ -78,7 +79,7 @@ - (void)testCorrectEqualityForCppReturnTypesWithVtables
7879
"ar> >={__rep=(?={__long=QQ*}{__short=(?=Cc)[23c]}{__raw=[3Q]})}}}}";
7980

8081
OCMBoxedReturnValueProvider *boxed = [OCMBoxedReturnValueProvider new];
81-
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type2]);
82+
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type2 value:NULL valueSize:0]);
8283
}
8384

8485

@@ -89,8 +90,7 @@ - (void)testCorrectEqualityForStructureWithUnknownName
8990
const char *type2 = "{CLLocationCoordinate2D=dd}";
9091

9192
OCMBoxedReturnValueProvider *boxed = [OCMBoxedReturnValueProvider new];
92-
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type2]);
93-
93+
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type2 value:NULL valueSize:0]);
9494
}
9595

9696

@@ -115,8 +115,7 @@ - (void)testCorrectEqualityForStructureWithoutName
115115
"pressed_pair<GURL *, std::__1::default_delete<GURL> >=^{GURL}}}}";
116116

117117
OCMBoxedReturnValueProvider *boxed = [OCMBoxedReturnValueProvider new];
118-
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type2]);
119-
118+
XCTAssertTrue([boxed isMethodReturnType:type1 compatibleWithValueType:type2 value:NULL valueSize:0]);
120119
}
121120

122121
@end
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2020 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 <XCTest/XCTest.h>
18+
#import <OCMock/OCMock.h>
19+
20+
#if !defined(__cplusplus)
21+
#error This file must be compiled with C++
22+
#endif
23+
24+
#if !__has_feature(cxx_nullptr)
25+
#error This file must be compiled with a version of C++ that supports nullptr
26+
#endif
27+
28+
@interface OCMCPlusPlus11Tests : XCTestCase
29+
@end
30+
31+
32+
@implementation OCMCPlusPlus11Tests
33+
34+
- (void)testSetsUpStubReturningNilForIdReturnType
35+
{
36+
id mock = OCMPartialMock([NSArray arrayWithObject:@"Foo"]);
37+
38+
OCMExpect([mock lastObject]).andReturn(nil);
39+
XCTAssertNil([mock lastObject], @"Should have returned stubbed value");
40+
41+
OCMExpect([mock lastObject]).andReturn(Nil);
42+
XCTAssertNil([mock lastObject], @"Should have returned stubbed value");
43+
}
44+
45+
@end
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2020 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 <XCTest/XCTest.h>
18+
#import <OCMock/OCMock.h>
19+
20+
#if !defined(__cplusplus)
21+
#error This file must be compiled with C++
22+
#endif
23+
24+
#if __has_feature(cxx_nullptr)
25+
#error This file must be compiled with a version of C++ (98) that doesn't support nullptr
26+
#endif
27+
28+
@interface OCMCPlusPlus98Tests : XCTestCase
29+
@end
30+
31+
32+
@implementation OCMCPlusPlus98Tests
33+
34+
- (void)testSetsUpStubReturningNilForIdReturnType
35+
{
36+
id mock = OCMPartialMock([NSArray arrayWithObject:@"Foo"]);
37+
38+
OCMExpect([mock lastObject]).andReturn(nil);
39+
XCTAssertNil([mock lastObject], @"Should have returned stubbed value");
40+
41+
OCMExpect([mock lastObject]).andReturn(Nil);
42+
XCTAssertNil([mock lastObject], @"Should have returned stubbed value");
43+
}
44+
45+
@end

Source/OCMockTests/OCMockObjectMacroTests.m

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ - (NSDecimalNumber*)method {
5050

5151
@end
5252

53+
@interface TestClassWithClassReturnMethod : NSObject
54+
55+
- (Class)method;
56+
57+
@end
58+
59+
@implementation TestClassWithClassReturnMethod
60+
61+
- (Class)method
62+
{
63+
return [self class];
64+
}
65+
66+
@end
67+
68+
5369

5470
// implemented in OCMockObjectClassMethodMockingTests
5571

@@ -177,11 +193,22 @@ - (void)testSetsUpStubsWithStructureReturnValues
177193

178194
- (void)testSetsUpStubReturningNilForIdReturnType
179195
{
180-
id mock = OCMClassMock([NSString class]);
196+
id mock = OCMPartialMock([NSArray arrayWithObject:@"Foo"]);
197+
198+
OCMStub([mock lastObject]).andReturn(nil);
199+
XCTAssertNil([mock lastObject], @"Should have returned stubbed value");
200+
}
201+
202+
- (void)testSetsUpStubReturningNilForClassReturnType
203+
{
204+
id mock = OCMPartialMock([[TestClassWithClassReturnMethod alloc] init]);
181205

182-
OCMStub([mock lowercaseString]).andReturn(nil);
206+
OCMStub([mock method]).andReturn(Nil);
207+
XCTAssertNil([mock method], @"Should have returned stubbed value");
183208

184-
XCTAssertNil([mock lowercaseString], @"Should have returned stubbed value");
209+
// sometimes nil is used where Nil should be used
210+
OCMStub([mock method]).andReturn(nil);
211+
XCTAssertNil([mock method], @"Should have returned stubbed value");
185212
}
186213

187214
- (void)testSetsUpExceptionThrowing

0 commit comments

Comments
 (0)