Files
RestKit/Tests/Logic/ObjectMapping/RKPaginatorTest.m
2013-03-14 22:55:59 -04:00

444 lines
19 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";
static NSString * const RKPaginatorTestResourcePathPatternWithOffset = @"/paginate?limit=:perPage&offset=:offset";
- (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"]];
[paginationMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"offset" toKeyPath:@"offset"]];
return paginationMapping;
}
- (NSURL *)paginationURL
{
return [NSURL URLWithString:RKPaginatorTestResourcePathPattern relativeToURL:[RKTestFactory baseURL]];
}
- (NSURL *)paginationOffsetURL
{
return [NSURL URLWithString:RKPaginatorTestResourcePathPatternWithOffset 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)testThatURLReturnedReflectsStateOfPaginatorWithOffset
{
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationOffsetURL];
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(@"limit=25&offset=0");
}
- (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)testLoadingAPageOfObjectsWithDocumentedPaginationMapping
{
RKObjectMapping *paginationMapping = [RKObjectMapping mappingForClass:[RKPaginator class]];
[paginationMapping addAttributeMappingsFromDictionary:@{
@"per_page": @"perPage",
@"total_pages": @"pageCount",
@"total_objects": @"objectCount",
}];
NSURLRequest *request = [NSURLRequest requestWithURL:self.paginationURL];
RKPaginator *paginator = [[RKPaginator alloc] initWithRequest:request paginationMapping: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];
expect(blockObjects).willNot.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];
expect(expectedError).willNot.beNil();
}
- (void)testInvocationOfCompletionBlockWithoutWaiting
{
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];
expect(blockObjects).willNot.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)));
}
- (void)testProxyAttributes
{
RKPaginator *paginator = [RKPaginator new];
[paginator setValue:@(12345) forKey:@"pageCountNumber"];
expect(paginator.pageCount).to.equal(12345);
expect([paginator valueForKey:@"pageCountNumber"]).to.equal(12345);
[paginator setValue:@(1) forKey:@"currentPageNumber"];
expect(paginator.currentPage).to.equal(1);
expect([paginator valueForKey:@"currentPageNumber"]).to.equal(1);
[paginator setValue:@(25) forKey:@"objectCountNumber"];
expect(paginator.objectCount).to.equal(25);
expect([paginator valueForKey:@"objectCountNumber"]).to.equal(25);
[paginator setValue:@(10) forKey:@"perPageNumber"];
expect(paginator.perPage).to.equal(10);
expect([paginator valueForKey:@"perPageNumber"]).to.equal(10);
}
- (void)testPaginatorWithPaginationURLThatIncludesTrailingSlash
{
NSURL *paginationURL = [NSURL URLWithString:@"/paginate/?per_page=:perPage&page=:currentPage" relativeToURL:[RKTestFactory baseURL]];
NSURLRequest *request = [NSURLRequest requestWithURL: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];
expect(blockObjects).willNot.beNil();
expect(paginator.pageCount).to.equal(0);
expect(paginator.objectCount).to.equal(0);
}
- (void)testOffsetNumberOfNextPage
{
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.offset).to.equal(0);
[paginator loadNextPage];
[paginator waitUntilFinished];
expect(paginator.offset).to.equal(3);
}
@end