diff --git a/CHANGELOG.md b/CHANGELOG.md index 868d5ff4..d8d7d5e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,17 @@ # OHHTTPStubs — CHANGELOG -## [8.0.0](https://github.com/AliSoftware/OHHTTPStubs/releases/tag/7.0.0) + + +* Fix clang static analysis warnings and use more idiomatic Objective-C error handling. + [@zeveisenberg](https://github.com/zeveisenberg) + +## [8.0.0](https://github.com/AliSoftware/OHHTTPStubs/releases/tag/8.0.0) * Update default Swift Version to 5.0 [@croig](https://github.com/CRoig) >Notes: -> * No code changes were required (except from a little missing comma which caused a compilation error). Only xcshemes and xcodeproj were changed. +> * No code changes were required (except from a little missing comma which caused a compilation error). Only xcschemes and xcodeproj were changed. ## [7.0.0](https://github.com/AliSoftware/OHHTTPStubs/releases/tag/7.0.0) diff --git a/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h b/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h index c7ef6afa..f4dc1a60 100644 --- a/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h +++ b/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.h @@ -65,7 +65,7 @@ extern NSString* const MocktailErrorDomain; * @return a stub descriptor that uniquely identifies the stub and can be later used to remove it with * `removeStub:`. */ -+(id)stubRequestsUsingMocktailNamed:(NSString *)fileName inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error; ++(nullable id)stubRequestsUsingMocktailNamed:(NSString *)fileName inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error; /** * Add a stub given a file URL in the format of Mocktail as defined at https://github.com/square/objc-mocktail. @@ -93,7 +93,7 @@ extern NSString* const MocktailErrorDomain; * @return an array of stub descriptor that uniquely identifies the stub and can be later used to remove it with * `removeStub:`. */ -+(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error; ++(nullable NSArray> *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error; @end diff --git a/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m b/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m index 9575947b..83932dd9 100644 --- a/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m +++ b/OHHTTPStubs/Sources/Mocktail/OHHTTPStubs+Mocktail.m @@ -32,7 +32,7 @@ @implementation OHHTTPStubs (Mocktail) -+(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error ++(nullable NSArray> *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error { NSURL *dirURL = [bundleOrNil?:[NSBundle bundleForClass:self.class] URLForResource:path withExtension:nil]; if (!dirURL) @@ -59,11 +59,10 @@ +(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable } // Read the content of the directory - NSError *bError = nil; NSFileManager *fileManager = [NSFileManager defaultManager]; - NSArray *fileURLs = [fileManager contentsOfDirectoryAtURL:dirURL includingPropertiesForKeys:nil options:0 error:&bError]; + NSArray *fileURLs = [fileManager contentsOfDirectoryAtURL:dirURL includingPropertiesForKeys:nil options:0 error:nil]; - if (bError) + if (!fileURLs) { if (error) { @@ -73,15 +72,15 @@ +(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable } //stub the Mocktail-formatted requests - NSMutableArray *descriptorArray = [[NSMutableArray alloc] initWithCapacity:fileURLs.count]; + NSMutableArray> *descriptorArray = [[NSMutableArray alloc] initWithCapacity:fileURLs.count]; for (NSURL *fileURL in fileURLs) { if (![fileURL.absoluteString hasSuffix:@".tail"]) { continue; } - id descriptor = [[self class] stubRequestsUsingMocktail:fileURL error: &bError]; - if (descriptor && !bError) + id descriptor = [[self class] stubRequestsUsingMocktail:fileURL error: nil]; + if (descriptor) { [descriptorArray addObject:descriptor]; } @@ -90,7 +89,7 @@ +(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable return descriptorArray; } -+(id)stubRequestsUsingMocktailNamed:(NSString *)fileName inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error ++(nullable id)stubRequestsUsingMocktailNamed:(NSString *)fileName inBundle:(nullable NSBundle*)bundleOrNil error:(NSError **)error { NSURL *responseURL = [bundleOrNil?:[NSBundle bundleForClass:self.class] URLForResource:fileName withExtension:@"tail"]; @@ -114,7 +113,7 @@ +(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable NSStringEncoding originalEncoding; NSString *contentsOfFile = [NSString stringWithContentsOfURL:fileURL usedEncoding:&originalEncoding error:&bError]; - if (!contentsOfFile || bError) + if (!contentsOfFile) { if (error) { @@ -138,9 +137,9 @@ +(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable /* Handle Mocktail format, adapted from Mocktail implementation For more details on the file format, check out: https://github.com/square/objc-Mocktail */ - NSRegularExpression *methodRegex = [NSRegularExpression regularExpressionWithPattern:lines[0] options:NSRegularExpressionCaseInsensitive error:&bError]; + NSRegularExpression *methodRegex = [NSRegularExpression regularExpressionWithPattern:lines[0] options:NSRegularExpressionCaseInsensitive error:nil]; - if (bError) + if (!methodRegex) { if (error) { @@ -149,9 +148,9 @@ +(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable return nil; } - NSRegularExpression *absoluteURLRegex = [NSRegularExpression regularExpressionWithPattern:lines[1] options:NSRegularExpressionCaseInsensitive error:&bError]; + NSRegularExpression *absoluteURLRegex = [NSRegularExpression regularExpressionWithPattern:lines[1] options:NSRegularExpressionCaseInsensitive error:nil]; - if (bError) + if (!absoluteURLRegex) { if (error) { @@ -165,8 +164,8 @@ +(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable NSMutableDictionary *headers = @{@"Content-Type":lines[3]}.mutableCopy; // From line 4 to '\n\n', expect HTTP response headers. - NSRegularExpression *headerPattern = [NSRegularExpression regularExpressionWithPattern:@"^([^:]+):\\s+(.*)" options:0 error:&bError]; - if (bError) + NSRegularExpression *headerPattern = [NSRegularExpression regularExpressionWithPattern:@"^([^:]+):\\s+(.*)" options:0 error:nil]; + if (!headerPattern) { if (error) { @@ -177,8 +176,8 @@ +(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path inBundle:(nullable // Allow bare Content-Type header on line 4 before named HTTP response headers - NSRegularExpression *bareContentTypePattern = [NSRegularExpression regularExpressionWithPattern:@"^([^:]+)+$" options:0 error:&bError]; - if (bError) + NSRegularExpression *bareContentTypePattern = [NSRegularExpression regularExpressionWithPattern:@"^([^:]+)+$" options:0 error:nil]; + if (!bareContentTypePattern) { if (error) { diff --git a/OHHTTPStubs/Sources/OHHTTPStubs.m b/OHHTTPStubs/Sources/OHHTTPStubs.m index 3a0eaf8f..12be2eb7 100644 --- a/OHHTTPStubs/Sources/OHHTTPStubs.m +++ b/OHHTTPStubs/Sources/OHHTTPStubs.m @@ -43,7 +43,7 @@ @interface OHHTTPStubsProtocol : NSURLProtocol @end @interface OHHTTPStubs() + (instancetype)sharedInstance; -@property(atomic, copy) NSMutableArray* stubDescriptors; +@property(atomic, readonly) NSMutableArray* stubDescriptors; @property(atomic, assign) BOOL enabledState; @property(atomic, copy, nullable) void (^onStubActivationBlock)(NSURLRequest*, id, OHHTTPStubsResponse*); @property(atomic, copy, nullable) void (^onStubRedirectBlock)(NSURLRequest*, NSURLRequest*, id, OHHTTPStubsResponse*); diff --git a/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m b/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m index 73e09317..cd5073c7 100644 --- a/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m +++ b/OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m @@ -66,6 +66,17 @@ - (void)testMocktailLoginSuccess [self runLogin]; } +- (void)testMocktailFailsWithInvalidInputFile +{ + NSError *error = nil; + NSBundle *bundle = [NSBundle bundleForClass:self.class]; + id descriptor = [OHHTTPStubs stubRequestsUsingMocktailNamed:@"invalid file name" inBundle:bundle error:&error]; + XCTAssertNil(descriptor, @"Invalid input failed to produce nil result"); + XCTAssertEqualObjects(error.domain, MocktailErrorDomain); + XCTAssertEqual(error.code, OHHTTPStubsMocktailErrorPathDoesNotExist); + XCTAssertEqualObjects(error.userInfo[NSLocalizedDescriptionKey], @"File 'invalid file name' does not exist."); +} + - (void)testMocktailsAtFolder { NSError *error = nil; @@ -76,6 +87,28 @@ - (void)testMocktailsAtFolder [self runGetCards]; } +- (void)testMocktailsFailWithNonexistentFolder +{ + NSError *error = nil; + NSBundle *bundle = [NSBundle bundleForClass:self.class]; + NSArray *descriptors = [OHHTTPStubs stubRequestsUsingMocktailsAtPath:@"invalid folder name" inBundle:bundle error:&error]; + XCTAssertNil(descriptors, @"Invalid input failed to produce nil result"); + XCTAssertEqualObjects(error.domain, MocktailErrorDomain); + XCTAssertEqual(error.code, OHHTTPStubsMocktailErrorPathDoesNotExist); + XCTAssertEqualObjects(error.userInfo[NSLocalizedDescriptionKey], @"Path 'invalid folder name' does not exist."); +} + +- (void)testMocktailsFailWithNonFolderFile +{ + NSError *error = nil; + NSBundle *bundle = [NSBundle bundleForClass:self.class]; + NSArray *descriptors = [OHHTTPStubs stubRequestsUsingMocktailsAtPath:@"login.tail" inBundle:bundle error:&error]; + XCTAssertNil(descriptors, @"Invalid input failed to produce nil result"); + XCTAssertEqualObjects(error.domain, MocktailErrorDomain); + XCTAssertEqual(error.code, OHHTTPStubsMocktailErrorPathIsNotFolder); + XCTAssertEqualObjects(error.userInfo[NSLocalizedDescriptionKey], @"Path 'login.tail' is not a folder."); +} + - (void)testMocktailHeaders { NSError *error = nil; @@ -167,12 +200,13 @@ - (NSHTTPURLResponse *)runGetCards XCTAssertNil(error, @"Error while getting cards."); NSArray *json = nil; - if(!error && [@"application/json" isEqual:response.MIMEType]) + NSError *jsonError = nil; + if([@"application/json" isEqualToString:response.MIMEType]) { - json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]; } - XCTAssertNotNil(json, @"The response is not a json object"); + XCTAssertNotNil(json, @"The response is not a json object: %@", jsonError); XCTAssertEqual(json.count, 2, @"The response does not contain 2 cards"); XCTAssertEqualObjects([json firstObject][@"amount"], @"$25.28", @"The first card amount does not match"); diff --git a/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m b/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m index e5e0a6a3..ca04b0ba 100644 --- a/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m +++ b/OHHTTPStubs/UnitTests/Test Suites/NSURLSessionTests.m @@ -89,7 +89,7 @@ - (void)_test_NSURLSession:(NSURLSession*)session { NSError *jsonError = nil; NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]; - XCTAssertNil(jsonError, @"Unexpected error deserializing JSON response"); + XCTAssertNotNil(jsonObject, @"Unexpected error deserializing JSON response: %@", jsonError); dataResponse = jsonObject; } [expectation fulfill];