Files
RestKit/Tests/Logic/ObjectMapping/RKPaginatorTest.m
Blake Watters 54dce20ac6 Rework paginator support for 0.20. closes #1024, #900, #759
* Renamed RKObjectPaginator to RKPaginator for simplicity
* Removed delegate on paginator in favor of simple success/failure blocks
* Added `willMapDeserializedResponseBlock` for manipulating the response body before mapping begins
* Added support for cancelling an in-progress pagination request
2012-11-18 22:44:33 -05:00

354 lines
15 KiB
Objective-C

//
// RKPaginatorTest.m
// RestKit
//
// Created by Blake Watters on 12/29/11.
// Copyright (c) 2009-2012 RestKit. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "RKTestEnvironment.h"
#import "RKPaginator.h"
#import "RKObjectMapperTestModel.h"
#import "RKURLEncodedSerialization.h"
@interface RKPaginator (Testability)
- (void)waitUntilFinished;
@end
@interface RKPaginatorTest : RKTestCase
@property (nonatomic, readonly) NSURL *paginationURL;
@property (nonatomic, readonly) RKObjectMapping *paginationMapping;
@property (nonatomic, readonly) RKResponseDescriptor *responseDescriptor;
@end
@implementation RKPaginatorTest
static NSString * const RKPaginatorTestResourcePathPattern = @"/paginate?per_page=:perPage&page=:currentPage";
- (void)setUp
{
[RKTestFactory setUp];
}
- (void)tearDown
{
[RKTestFactory tearDown];
}
- (RKResponseDescriptor *)responseDescriptor
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKObjectMapperTestModel class]];
[mapping addAttributeMappingsFromArray:@[@"name", @"age"]];
return [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:nil keyPath:@"entries" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
}
- (RKObjectMapping *)paginationMapping
{
RKObjectMapping *paginationMapping = [RKObjectMapping mappingForClass:[RKPaginator class]];
[paginationMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"current_page" toKeyPath:@"currentPage"]];
[paginationMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"per_page" toKeyPath:@"perPage"]];
[paginationMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"total_entries" toKeyPath:@"objectCount"]];
return paginationMapping;
}
- (NSURL *)paginationURL
{
return [NSURL URLWithString:RKPaginatorTestResourcePathPattern relativeToURL:[RKTestFactory baseURL]];
}
#pragma mark - Test Cases
- (void)testInitCopiesPatternURL
{
NSURL *patternURL = [NSURL URLWithString:@"http://restkit.org"];
NSURLRequest *request = [NSURLRequest requestWithURL:patternURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
expect([paginator.patternURL absoluteString]).to.equal(@"http://restkit.org");
}
- (void)testInitDoesNotHavePageCount
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
expect([paginator hasPageCount]).to.equal(NO);
}
- (void)testInitDoesNotHaveObjectCount
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
expect([paginator hasObjectCount]).to.equal(NO);
}
- (void)testThatInitWithInvalidPaginationMappingRaisesError
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
NSException *exception = nil;
@try {
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:mapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:1];
}
@catch (NSException *e) {
exception = e;
}
expect(exception).notTo.beNil();
expect([exception reason]).to.equal(@"The paginationMapping must have a target object class of `RKPaginator`");
}
- (void)testThatInitWithNilResponseDescriptorsRaisesError
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
NSException *exception = nil;
@try {
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:nil];
[paginator loadPage:1];
}
@catch (NSException *e) {
exception = e;
}
expect(exception).notTo.beNil();
expect([exception reason]).to.equal(@"Invalid parameter not satisfying: responseDescriptors");
}
- (void)testThatResourcePathPatternEvaluatesAgainstPaginator
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
id mockPaginator = [OCMockObject partialMockForObject:paginator];
NSUInteger currentPage = 1;
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
expect([paginator.URL relativeString]).to.equal(@"/paginate?per_page=25&page=1");
}
- (void)testThatURLReturnedReflectsStateOfPaginator
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
id mockPaginator = [OCMockObject partialMockForObject:paginator];
NSUInteger currentPage = 1;
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
expect([[mockPaginator URL] query]).to.equal(@"per_page=25&page=1");
}
- (void)testLoadingAPageOfObjects
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:1];
[paginator waitUntilFinished];
expect(paginator.isLoaded).to.equal(YES);
}
- (void)testLoadingPageOfObjectMapsPerPage
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:1];
[paginator waitUntilFinished];
expect(paginator.perPage).to.equal(3);
}
- (void)testLoadingPageOfObjectMapsTotalEntries
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:1];
[paginator waitUntilFinished];
expect(paginator.objectCount).to.equal(6);
}
- (void)testLoadingPageOfObjectMapsCurrentPage
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:1];
[paginator waitUntilFinished];
expect(paginator.currentPage).to.equal(1);
}
- (void)testLoadingPageOfObjectMapsEntriesToObjects
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:1];
[paginator waitUntilFinished];
expect([paginator.mappingResult array]).to.haveCountOf(3);
NSArray *expectedNames = @[ @"Blake", @"Sarah", @"Colin" ];
expect([[paginator.mappingResult array] valueForKey:@"name"]).to.equal(expectedNames);
}
- (void)testLoadingPageOfObjectHasPageCount
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:1];
[paginator waitUntilFinished];
expect([paginator hasPageCount]).to.beTruthy();
}
- (void)testLoadingPageOfObjectHasObjectCount
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:1];
[paginator waitUntilFinished];
expect([paginator hasObjectCount]).to.beTruthy();
}
- (void)testInvocationOfCompletionBlockWithSuccess
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
__block NSArray *blockObjects = nil;
[paginator setCompletionBlockWithSuccess:^(RKPaginator *paginator, NSArray *objects, NSUInteger page) {
blockObjects = objects;
} failure:nil];
[paginator loadPage:1];
[paginator waitUntilFinished];
dispatch_async(dispatch_get_main_queue(), ^{
expect(blockObjects).notTo.beNil();
});
}
- (void)testOnDidFailWithErrorBlockIsInvokedOnError
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
__block NSError *expectedError = nil;
[paginator setCompletionBlockWithSuccess:nil failure:^(RKPaginator *paginator, NSError *error) {
expectedError = error;
}];
[paginator loadPage:999];
[paginator waitUntilFinished];
dispatch_async(dispatch_get_main_queue(), ^{
expect(expectedError).notTo.beNil();
});
}
- (void)testLoadingNextPageOfObjects
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:1];
[paginator waitUntilFinished];
expect(paginator.currentPage).to.equal(1);
[paginator loadNextPage];
[paginator waitUntilFinished];
expect(paginator.currentPage).to.equal(2);
NSArray *names = @[ @"Asia", @"Roy", @"Lola" ];
expect([[paginator.mappingResult array] valueForKey:@"name"]).to.equal(names);
}
- (void)testLoadingPreviousPageOfObjects
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:2];
[paginator waitUntilFinished];
expect(paginator.currentPage).to.equal(2);
[paginator loadPreviousPage];
[paginator waitUntilFinished];
expect(paginator.currentPage).to.equal(1);
NSArray *names = @[ @"Blake", @"Sarah", @"Colin" ];
expect([[paginator.mappingResult array] valueForKey:@"name"]).to.equal(names);
}
- (void)testFailureWhenLoadingAPageOfObjects
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:@[ self.responseDescriptor ]];
[paginator loadPage:3];
[paginator waitUntilFinished];
expect(paginator.error).notTo.beNil();
}
- (void)testKnowledgeOfHasANextPage
{
RKPaginator *paginator = [RKPaginator new];
id mockPaginator = [OCMockObject partialMockForObject:paginator];
BOOL isLoaded = YES;
NSUInteger perPage = 5;
NSUInteger pageCount = 3;
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(isLoaded)] isLoaded];
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(perPage)] perPage];
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(pageCount)] pageCount];
NSUInteger currentPage = 1;
[[[mockPaginator expect] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
assertThatBool([mockPaginator hasNextPage], is(equalToBool(YES)));
currentPage = 2;
[[[mockPaginator expect] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
assertThatBool([mockPaginator hasNextPage], is(equalToBool(YES)));
currentPage = 3;
[[[mockPaginator expect] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
assertThatBool([mockPaginator hasNextPage], is(equalToBool(NO)));
}
- (void)testHasNextPageRaisesExpectionWhenNotLoaded
{
RKPaginator *paginator = [RKPaginator new];
id mockPaginator = [OCMockObject partialMockForObject:paginator];
BOOL loaded = NO;
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(loaded)] isLoaded];
STAssertThrows([mockPaginator hasNextPage], @"Expected exception due to isLoaded == NO");
}
- (void)testHasNextPageRaisesExpectionWhenPageCountIsUnknown
{
RKPaginator *paginator = [RKPaginator new];
id mockPaginator = [OCMockObject partialMockForObject:paginator];
BOOL loaded = YES;
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(loaded)] isLoaded];
BOOL hasPageCount = NO;
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(hasPageCount)] hasPageCount];
STAssertThrows([mockPaginator hasNextPage], @"Expected exception due to pageCount == NSUIntegerMax");
}
- (void)testHasPreviousPageRaisesExpectionWhenNotLoaded
{
RKPaginator *paginator = [RKPaginator new];
id mockPaginator = [OCMockObject partialMockForObject:paginator];
BOOL loaded = NO;
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(loaded)] isLoaded];
STAssertThrows([mockPaginator hasPreviousPage], @"Expected exception due to isLoaded == NO");
}
- (void)testKnowledgeOfPreviousPage
{
RKPaginator *paginator = [RKPaginator new];
id mockPaginator = [OCMockObject partialMockForObject:paginator];
BOOL isLoaded = YES;
NSUInteger perPage = 5;
NSUInteger pageCount = 3;
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(isLoaded)] isLoaded];
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(perPage)] perPage];
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(pageCount)] pageCount];
NSUInteger currentPage = 3;
[[[mockPaginator expect] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
assertThatBool([mockPaginator hasPreviousPage], is(equalToBool(YES)));
currentPage = 2;
[[[mockPaginator expect] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
assertThatBool([mockPaginator hasPreviousPage], is(equalToBool(YES)));
currentPage = 1;
[[[mockPaginator expect] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
assertThatBool([mockPaginator hasPreviousPage], is(equalToBool(NO)));
}
@end