diff --git a/Modules/Sources/WordPressKitObjC/TaxonomyServiceRemoteREST.m b/Modules/Sources/WordPressKitObjC/TaxonomyServiceRemoteREST.m index ffa31b668971..9ddf96e5d0b5 100644 --- a/Modules/Sources/WordPressKitObjC/TaxonomyServiceRemoteREST.m +++ b/Modules/Sources/WordPressKitObjC/TaxonomyServiceRemoteREST.m @@ -287,7 +287,7 @@ - (void)updateTaxonomyWithType:(NSString *)typeIdentifier { return [jsonArray wp_map:^id(NSDictionary *jsonCategory) { return [self remoteCategoryWithJSONDictionary:jsonCategory]; - }]; + }] ?: @[]; } - (RemotePostCategory *)remoteCategoryWithJSONDictionary:(NSDictionary *)jsonCategory @@ -303,7 +303,7 @@ - (RemotePostCategory *)remoteCategoryWithJSONDictionary:(NSDictionary *)jsonCat { return [jsonArray wp_map:^id(NSDictionary *jsonTag) { return [self remoteTagWithJSONDictionary:jsonTag]; - }]; + }] ?: @[]; } - (RemotePostTag *)remoteTagWithJSONDictionary:(NSDictionary *)jsonTag diff --git a/Tests/WordPressKitTests/WordPressKitTests/Tests/TaxonomyServiceRemoteRESTTests.m b/Tests/WordPressKitTests/WordPressKitTests/Tests/TaxonomyServiceRemoteRESTTests.m index a026dd6178ca..dabbe6a6b240 100644 --- a/Tests/WordPressKitTests/WordPressKitTests/Tests/TaxonomyServiceRemoteRESTTests.m +++ b/Tests/WordPressKitTests/WordPressKitTests/Tests/TaxonomyServiceRemoteRESTTests.m @@ -200,6 +200,32 @@ - (void)testThatSearchCategoriesWithNameWorks failure:^(NSError * __unused error) {}]; } +/// A response missing the `categories` key must yield an empty array, not `nil` +/// (a `nil` `NSArray` traps when bridged to a non-optional Swift array). +- (void)testThatGetCategoriesWithMissingCategoriesKeyReturnsEmptyArray +{ + NSString *url = [self GETtaxonomyURLWithType:@"categories"]; + + id api = self.service.wordPressComRESTAPI; + NSDictionary *json = @{ @"found": @0 }; + NSHTTPURLResponse *response = OCMStrictClassMock([NSHTTPURLResponse class]); + OCMStub([api get:[OCMArg isEqual:url] + parameters:[OCMArg any] + success:([OCMArg invokeBlockWithArgs:json, response, nil]) + failure:[OCMArg isNotNil]]); + + XCTestExpectation *gotEmptyArray = [self expectationWithDescription:@"categories should be empty"]; + id success = ^(NSArray * _Nonnull categories) { + XCTAssertNotNil(categories); + XCTAssertEqualObjects(categories, @[]); + [gotEmptyArray fulfill]; + }; + [self.service getCategoriesWithSuccess:success + failure:^(NSError * __unused error) { XCTFail(@"should not fail"); }]; + + [self waitForExpectations:@[gotEmptyArray] timeout:0.1]; +} + #pragma mark - Tags - (void)testThatCreateTagWorks @@ -315,4 +341,30 @@ - (void)testThatSearchTagsWithNameWorks failure:^(NSError * __unused error) {}]; } +/// A response missing the `tags` key must yield an empty array, not `nil` +/// (a `nil` `NSArray` traps when bridged to a non-optional Swift array). +- (void)testThatGetTagsWithMissingTagsKeyReturnsEmptyArray +{ + NSString *url = [self GETtaxonomyURLWithType:@"tags"]; + + id api = self.service.wordPressComRESTAPI; + NSDictionary *json = @{ @"found": @0 }; + NSHTTPURLResponse *response = OCMStrictClassMock([NSHTTPURLResponse class]); + OCMStub([api get:[OCMArg isEqual:url] + parameters:[OCMArg any] + success:([OCMArg invokeBlockWithArgs:json, response, nil]) + failure:[OCMArg isNotNil]]); + + XCTestExpectation *gotEmptyArray = [self expectationWithDescription:@"tags should be empty"]; + id success = ^(NSArray * _Nonnull tags) { + XCTAssertNotNil(tags); + XCTAssertEqualObjects(tags, @[]); + [gotEmptyArray fulfill]; + }; + [self.service getTagsWithSuccess:success + failure:^(NSError * __unused error) { XCTFail(@"should not fail"); }]; + + [self waitForExpectations:@[gotEmptyArray] timeout:0.1]; +} + @end