mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-24 04:46:01 +08:00
* 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
This commit is contained in:
@@ -92,10 +92,13 @@ static NSURL *RKRelativeURLFromURLAndResponseDescriptors(NSURL *URL, NSArray *re
|
||||
@property (nonatomic, strong) RKManagedObjectResponseMapperOperation *responseMapperOperation;
|
||||
@property (nonatomic, strong, readwrite) NSError *error;
|
||||
@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult;
|
||||
@property (nonatomic, copy) id (^willMapDeserializedResponseBlock)(id deserializedResponseBody);
|
||||
@end
|
||||
|
||||
@implementation RKManagedObjectRequestOperation
|
||||
|
||||
@dynamic willMapDeserializedResponseBlock;
|
||||
|
||||
// Designated initializer
|
||||
- (id)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation responseDescriptors:(NSArray *)responseDescriptors
|
||||
{
|
||||
@@ -177,6 +180,7 @@ static NSURL *RKRelativeURLFromURLAndResponseDescriptors(NSURL *URL, NSArray *re
|
||||
self.responseMapperOperation.targetObjectID = self.targetObjectID;
|
||||
self.responseMapperOperation.managedObjectContext = self.privateContext;
|
||||
self.responseMapperOperation.managedObjectCache = self.managedObjectCache;
|
||||
[self.responseMapperOperation setWillMapDeserializedResponseBlock:self.willMapDeserializedResponseBlock];
|
||||
[self.responseMapperOperation setQueuePriority:[self queuePriority]];
|
||||
[[RKObjectRequestOperation responseMappingQueue] addOperation:self.responseMapperOperation];
|
||||
[self.responseMapperOperation waitUntilFinished];
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
//
|
||||
// RKObjectPaginator.h
|
||||
// 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 "RKManagedObjectStore.h"
|
||||
|
||||
//@protocol RKObjectPaginatorDelegate;
|
||||
//
|
||||
//typedef void(^RKObjectPaginatorDidLoadObjectsForPageBlock)(NSArray *objects, NSUInteger page);
|
||||
//typedef void(^RKObjectPaginatorDidFailWithErrorBlock)(NSError *error, RKObjectLoader *loader);
|
||||
//
|
||||
///**
|
||||
// Instances of RKObjectPaginator retrieve paginated collections of mappable data
|
||||
// from remote systems via HTTP. Paginators perform GET requests and use a patterned
|
||||
// URL to construct a full URL reflecting the state of the paginator. Paginators rely
|
||||
// on an instance of RKObjectMappingProvider to determine how to perform object mapping
|
||||
// on the retrieved data. Paginators can load Core Data backed models provided that an
|
||||
// instance of RKManagedObjectStore is assigned to the paginator.
|
||||
// */
|
||||
//@interface RKObjectPaginator : NSObject
|
||||
//
|
||||
///**
|
||||
// Creates and returns a RKObjectPaginator object with the a provided patternURL and mappingProvider.
|
||||
//
|
||||
// @param patternURL A RKURL containing a dynamic pattern for constructing a URL to the paginated
|
||||
// resource collection.
|
||||
// @param mappingProvider An RKObjectMappingProvider containing object mapping configurations for mapping the
|
||||
// paginated resource collection.
|
||||
// @see patternURL
|
||||
// @return A paginator object initialized with patterned URL and mapping provider.
|
||||
// */
|
||||
//+ (id)paginatorWithPatternURL:(RKURL *)patternURL mappingProvider:(RKObjectMappingProvider *)mappingProvider;
|
||||
//
|
||||
///**
|
||||
// Initializes a RKObjectPaginator object with the a provided patternURL and mappingProvider.
|
||||
//
|
||||
// @param patternURL A RKURL containing a dynamic pattern for constructing a URL to the paginated
|
||||
// resource collection.
|
||||
// @param mappingProvider An RKObjectMappingProvider containing object mapping configurations for mapping the
|
||||
// paginated resource collection.
|
||||
// @see patternURL
|
||||
// @return The receiver, initialized with patterned URL and mapping provider.
|
||||
// */
|
||||
//- (id)initWithPatternURL:(RKURL *)patternURL mappingProvider:(RKObjectMappingProvider *)mappingProvider;
|
||||
//
|
||||
///**
|
||||
// A RKURL with a path pattern for building a complete URL from
|
||||
// which to load the paginated resource collection. The patterned resource
|
||||
// path will be evaluated against the state of the paginator object itself.
|
||||
//
|
||||
// For example, given a paginated collection of data at the /articles path,
|
||||
// the path pattern may look like:
|
||||
//
|
||||
// /articles?per_page=:perPage&page_number=:currentPage
|
||||
//
|
||||
// When the pattern is evaluated against the state of the paginator, this will
|
||||
// yield a complete path that can be used to load the specified page. Given
|
||||
// a paginator configured with 100 objects per page and a current page number of 3,
|
||||
// the path portion of the pagination URL would become:
|
||||
//
|
||||
// /articles?per_page=100&page_number=3
|
||||
//
|
||||
// @see [RKURL URLByInterpolatingResourcePathWithObject:]
|
||||
// */
|
||||
//@property (nonatomic, copy) RKURL *patternURL;
|
||||
//
|
||||
///**
|
||||
// Returns a complete RKURL to the paginated resource collection by interpolating
|
||||
// the state of the paginator object against the resource
|
||||
// */
|
||||
//@property (nonatomic, readonly) RKURL *URL;
|
||||
//
|
||||
///**
|
||||
// The object that acts as the delegate of the receiving paginator.
|
||||
// */
|
||||
//@property (nonatomic, assign) id<RKObjectPaginatorDelegate> delegate;
|
||||
//
|
||||
///**
|
||||
// The block to invoke when the paginator has loaded a page of objects from the collection.
|
||||
//
|
||||
// @see [RKObjectPaginatorDelegate paginator:didLoadObjects:forPage]
|
||||
// */
|
||||
//@property (nonatomic, copy) RKObjectPaginatorDidLoadObjectsForPageBlock onDidLoadObjectsForPage;
|
||||
//
|
||||
///**
|
||||
// The block to invoke when the paginator has failed loading due to an error.
|
||||
//
|
||||
// @see [RKObjectPaginatorDelegate paginator:didFailWithError:objectLoader:]
|
||||
// */
|
||||
//@property (nonatomic, copy) RKObjectPaginatorDidFailWithErrorBlock onDidFailWithError;
|
||||
//
|
||||
///**
|
||||
// The object that acts as the configuration delegate for RKObjectLoader instances built
|
||||
// and utilized by the paginator.
|
||||
//
|
||||
// **Default**: nil
|
||||
// @see RKClient
|
||||
// @see RKObjectManager
|
||||
// */
|
||||
//@property (nonatomic, assign) id<RKConfigurationDelegate> configurationDelegate;
|
||||
//
|
||||
///** @name Object Mapping Configuration */
|
||||
//
|
||||
///**
|
||||
// The mapping provider to use when performing object mapping on the data
|
||||
// loaded from the remote system. The provider will be assigned to the RKObjectLoader
|
||||
// instance built to retrieve the paginated resource collection.
|
||||
// */
|
||||
//@property (nonatomic, retain) RKObjectMappingProvider *mappingProvider;
|
||||
//
|
||||
///**
|
||||
// An object store for accessing Core Data. Required if the objects being paginated
|
||||
// are stored into Core Data.
|
||||
// */
|
||||
//@property (nonatomic, retain) RKManagedObjectStore *managedObjectStore;
|
||||
//
|
||||
///** @name Pagination Metadata */
|
||||
//
|
||||
///**
|
||||
// The number of objects to load per page
|
||||
// */
|
||||
//@property (nonatomic, assign) NSUInteger perPage;
|
||||
//
|
||||
///**
|
||||
// A Boolean value indicating if the paginator has loaded a page of objects
|
||||
//
|
||||
// @returns YES when the paginator has loaded a page of objects
|
||||
// */
|
||||
//@property (nonatomic, readonly, getter = isLoaded) BOOL loaded;
|
||||
//
|
||||
///**
|
||||
// Returns the page number for the most recently loaded page of objects.
|
||||
//
|
||||
// @return The page number for the current page of objects.
|
||||
// @exception NSInternalInconsistencyException Raised if isLoaded is NO.
|
||||
// */
|
||||
//@property (nonatomic, readonly) NSUInteger currentPage;
|
||||
//
|
||||
///**
|
||||
// Returns the number of pages in the total resource collection.
|
||||
//
|
||||
// @return A count of the number of pages in the resource collection.
|
||||
// @exception NSInternalInconsistencyException Raised if hasPageCount is NO.
|
||||
// */
|
||||
//@property (nonatomic, readonly) NSUInteger pageCount;
|
||||
//
|
||||
///**
|
||||
// Returns the total number of objects in the collection
|
||||
//
|
||||
// @return A count of the number of objects in the resource collection.
|
||||
// @exception NSInternalInconsistencyException Raised if hasObjectCount is NO.
|
||||
// */
|
||||
//@property (nonatomic, readonly) NSUInteger objectCount;
|
||||
//
|
||||
///**
|
||||
// Returns a Boolean value indicating if the total number of pages in the collection
|
||||
// is known by the paginator.
|
||||
//
|
||||
// @return YES if the paginator knows the page count, otherwise NO
|
||||
// */
|
||||
//- (BOOL)hasPageCount;
|
||||
//
|
||||
///**
|
||||
// Returns a Boolean value indicating if the total number of objects in the collection
|
||||
// is known by the paginator.
|
||||
//
|
||||
// @return YES if the paginator knows the number of objects in the paginated collection, otherwise NO.
|
||||
// */
|
||||
//- (BOOL)hasObjectCount;
|
||||
//
|
||||
///**
|
||||
// Returns a Boolean value indicating if there is a next page in the collection.
|
||||
//
|
||||
// @return YES if there is a next page, otherwise NO.
|
||||
// @exception NSInternalInconsistencyException Raised if isLoaded or hasPageCount is NO.
|
||||
// */
|
||||
//- (BOOL)hasNextPage;
|
||||
//
|
||||
///**
|
||||
// Returns a Boolean value indicating if there is a previous page in the collection.
|
||||
//
|
||||
// @return YES if there is a previous page, otherwise NO.
|
||||
// @exception NSInternalInconsistencyException Raised if isLoaded is NO.
|
||||
// */
|
||||
//- (BOOL)hasPreviousPage;
|
||||
//
|
||||
///** @name Paginator Actions */
|
||||
//
|
||||
///**
|
||||
// Loads the next page of data by incrementing the current page, constructing an object
|
||||
// loader to fetch the data, and object mapping the results.
|
||||
// */
|
||||
//- (void)loadNextPage;
|
||||
//
|
||||
///**
|
||||
// Loads the previous page of data by decrementing the current page, constructing an object
|
||||
// loader to fetch the data, and object mapping the results.
|
||||
// */
|
||||
//- (void)loadPreviousPage;
|
||||
//
|
||||
///**
|
||||
// Loads a specific page of data by mutating the current page, constructing an object
|
||||
// loader to fetch the data, and object mapping the results.
|
||||
//
|
||||
// @param pageNumber The page of objects to load from the remote backend
|
||||
// */
|
||||
//- (void)loadPage:(NSUInteger)pageNumber;
|
||||
//
|
||||
//@end
|
||||
//
|
||||
///**
|
||||
// The RKObjectPaginatorDelegate formal protocol defines
|
||||
// RKObjectPaginator delegate methods that can be implemented by
|
||||
// objects to receive informational callbacks about paginated loading
|
||||
// of mapping objects through RestKit.
|
||||
// */
|
||||
//@protocol RKObjectPaginatorDelegate <NSObject>
|
||||
//
|
||||
///**
|
||||
// Tells the delegate the paginator has loaded a page of objects from the collection.
|
||||
//
|
||||
// @param paginator The paginator that loaded the objects.
|
||||
// @param objects An array of objects mapped from the remote JSON/XML representation.
|
||||
// @param page The page number that was loaded.
|
||||
// */
|
||||
//- (void)paginator:(RKObjectPaginator *)paginator didLoadObjects:(NSArray *)objects forPage:(NSUInteger)page;
|
||||
//
|
||||
///**
|
||||
// Tells the delegate the paginator has failed loading due to an error.
|
||||
//
|
||||
// @param paginator The paginator that failed loading due to an error.
|
||||
// @param error An NSError indicating the cause of the failure.
|
||||
// @param loader The loader request that resulted in the failure.
|
||||
// */
|
||||
//- (void)paginator:(RKObjectPaginator *)paginator didFailWithError:(NSError *)error objectLoader:(RKObjectLoader *)loader;
|
||||
//
|
||||
//@optional
|
||||
//
|
||||
///**
|
||||
// Tells the delegate that the paginator is about to begin loading a page of objects.
|
||||
//
|
||||
// @param paginator The paginator performing the load.
|
||||
// @param page The numeric page number being loaded.
|
||||
// @param loader The object loader request used to load the page.
|
||||
// */
|
||||
//- (void)paginator:(RKObjectPaginator *)paginator willLoadPage:(NSUInteger)page objectLoader:(RKObjectLoader *)loader;
|
||||
//
|
||||
///**
|
||||
// Tells the delegate the paginator has loaded the first page of objects in the collection.
|
||||
//
|
||||
// @param paginator The paginator instance that has loaded the first page.
|
||||
// */
|
||||
//- (void)paginatorDidLoadFirstPage:(RKObjectPaginator *)paginator;
|
||||
//
|
||||
///**
|
||||
// Tells the delegate the paginator has loaded the last page of objects in the collection.
|
||||
//
|
||||
// @param paginator The paginator instance that has loaded the last page.
|
||||
// */
|
||||
//- (void)paginatorDidLoadLastPage:(RKObjectPaginator *)paginator;
|
||||
//
|
||||
//@end
|
||||
@@ -1,232 +0,0 @@
|
||||
//
|
||||
// RKObjectPaginator.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 "RKObjectPaginator.h"
|
||||
//#import "RKMappingOperation.h"
|
||||
//#import "SOCKit.h"
|
||||
//#import "RKLog.h"
|
||||
//
|
||||
//static NSUInteger RKObjectPaginatorDefaultPerPage = 25;
|
||||
//
|
||||
//// Private interface
|
||||
//@interface RKObjectPaginator () <RKObjectLoaderDelegate>
|
||||
//@property (nonatomic, retain) RKObjectLoader *objectLoader;
|
||||
//@property (nonatomic, assign, readwrite) NSUInteger currentPage;
|
||||
//@property (nonatomic, assign, readwrite) NSUInteger pageCount;
|
||||
//@property (nonatomic, assign, readwrite) NSUInteger objectCount;
|
||||
//@property (nonatomic, assign, readwrite) BOOL loaded;
|
||||
//@end
|
||||
//
|
||||
//@implementation RKObjectPaginator
|
||||
//
|
||||
////////////////////////////
|
||||
//+ (id)paginatorWithPatternURL:(RKURL *)aPatternURL mappingProvider:(RKObjectMappingProvider *)aMappingProvider
|
||||
//{
|
||||
// return [[[self alloc] initWithPatternURL:aPatternURL mappingProvider:aMappingProvider] autorelease];
|
||||
//}
|
||||
//
|
||||
//- (id)initWithPatternURL:(RKURL *)aPatternURL mappingProvider:(RKObjectMappingProvider *)aMappingProvider
|
||||
//{
|
||||
// self = [super init];
|
||||
// if (self) {
|
||||
// self.patternURL = [aPatternURL copy];
|
||||
// self.mappingProvider = [aMappingProvider retain];
|
||||
// self.currentPage = NSUIntegerMax;
|
||||
// self.pageCount = NSUIntegerMax;
|
||||
// self.objectCount = NSUIntegerMax;
|
||||
// self.perPage = RKObjectPaginatorDefaultPerPage;
|
||||
// self.loaded = NO;
|
||||
// }
|
||||
//
|
||||
// return self;
|
||||
//}
|
||||
//
|
||||
//- (void)dealloc
|
||||
//{
|
||||
// _delegate = nil;
|
||||
// _configurationDelegate = nil;
|
||||
// _objectLoader.delegate = nil;
|
||||
// [_patternURL release];
|
||||
// _patternURL = nil;
|
||||
// [_mappingProvider release];
|
||||
// _mappingProvider = nil;
|
||||
// [_managedObjectStore release];
|
||||
// _managedObjectStore = nil;
|
||||
// [_objectLoader cancel];
|
||||
// _objectLoader.delegate = nil;
|
||||
// [_objectLoader release];
|
||||
// _objectLoader = nil;
|
||||
// [_onDidLoadObjectsForPage release];
|
||||
// _onDidLoadObjectsForPage = nil;
|
||||
// [_onDidFailWithError release];
|
||||
// _onDidFailWithError = nil;
|
||||
//
|
||||
// [super dealloc];
|
||||
//}
|
||||
//
|
||||
//- (RKObjectMapping *)paginationMapping
|
||||
//{
|
||||
// return [self.mappingProvider paginationMapping];
|
||||
//}
|
||||
//
|
||||
//- (RKURL *)URL
|
||||
//{
|
||||
// return [self.patternURL URLByInterpolatingResourcePathWithObject:self];
|
||||
//}
|
||||
//
|
||||
//// Private. Public consumers can rely on isLoaded
|
||||
//- (BOOL)hasCurrentPage
|
||||
//{
|
||||
// return _currentPage != NSUIntegerMax;
|
||||
//}
|
||||
//
|
||||
//- (BOOL)hasPageCount
|
||||
//{
|
||||
// return _pageCount != NSUIntegerMax;
|
||||
//}
|
||||
//
|
||||
//- (BOOL)hasObjectCount
|
||||
//{
|
||||
// return _objectCount != NSUIntegerMax;
|
||||
//}
|
||||
//
|
||||
//- (NSUInteger)currentPage
|
||||
//{
|
||||
// // Referenced during initial load, so we don't rely on isLoaded.
|
||||
// NSAssert([self hasCurrentPage], @"Current page has not been initialized.");
|
||||
// return _currentPage;
|
||||
//}
|
||||
//
|
||||
//- (NSUInteger)pageCount
|
||||
//{
|
||||
// NSAssert([self hasPageCount], @"Page count not available.");
|
||||
// return _pageCount;
|
||||
//}
|
||||
//
|
||||
//- (BOOL)hasNextPage
|
||||
//{
|
||||
// NSAssert(self.isLoaded, @"Cannot determine hasNextPage: paginator is not loaded.");
|
||||
// NSAssert([self hasPageCount], @"Cannot determine hasNextPage: page count is not known.");
|
||||
//
|
||||
// return self.currentPage < self.pageCount;
|
||||
//}
|
||||
//
|
||||
//- (BOOL)hasPreviousPage
|
||||
//{
|
||||
// NSAssert(self.isLoaded, @"Cannot determine hasPreviousPage: paginator is not loaded.");
|
||||
// return self.currentPage > 1;
|
||||
//}
|
||||
//
|
||||
//#pragma mark - RKObjectLoaderDelegate methods
|
||||
//
|
||||
//- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
|
||||
//{
|
||||
// self.objectLoader = nil;
|
||||
// self.loaded = YES;
|
||||
// RKLogInfo(@"Loaded objects: %@", objects);
|
||||
// [self.delegate paginator:self didLoadObjects:objects forPage:self.currentPage];
|
||||
//
|
||||
// if (self.onDidLoadObjectsForPage) {
|
||||
// self.onDidLoadObjectsForPage(objects, self.currentPage);
|
||||
// }
|
||||
//
|
||||
// if ([self hasPageCount] && self.currentPage == 1) {
|
||||
// if ([self.delegate respondsToSelector:@selector(paginatorDidLoadFirstPage:)]) {
|
||||
// [self.delegate paginatorDidLoadFirstPage:self];
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if ([self hasPageCount] && self.currentPage == self.pageCount) {
|
||||
// if ([self.delegate respondsToSelector:@selector(paginatorDidLoadLastPage:)]) {
|
||||
// [self.delegate paginatorDidLoadLastPage:self];
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error
|
||||
//{
|
||||
// RKLogError(@"Paginator error %@", error);
|
||||
// [self.delegate paginator:self didFailWithError:error objectLoader:self.objectLoader];
|
||||
// if (self.onDidFailWithError) {
|
||||
// self.onDidFailWithError(error, self.objectLoader);
|
||||
// }
|
||||
// self.objectLoader = nil;
|
||||
//}
|
||||
//
|
||||
//- (void)objectLoader:(RKObjectLoader *)loader willMapData:(inout id *)mappableData
|
||||
//{
|
||||
// NSError *error = nil;
|
||||
// RKMappingOperation *mappingOperation = [RKMappingOperation mappingOperationFromObject:*mappableData toObject:self withMapping:[self paginationMapping]];
|
||||
// BOOL success = [mappingOperation performMapping:&error];
|
||||
// if (!success) {
|
||||
// self.pageCount = 0;
|
||||
// self.currentPage = 0;
|
||||
// RKLogError(@"Paginator didn't map info to compute page count. Assuming no pages.");
|
||||
// } else if (self.perPage && [self hasObjectCount]) {
|
||||
// float objectCountFloat = self.objectCount;
|
||||
// self.pageCount = ceilf(objectCountFloat / self.perPage);
|
||||
// RKLogInfo(@"Paginator objectCount: %ld pageCount: %ld", (long)self.objectCount, (long)self.pageCount);
|
||||
// } else {
|
||||
// NSAssert(NO, @"Paginator perPage set is 0.");
|
||||
// RKLogError(@"Paginator perPage set is 0.");
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//#pragma mark - Action methods
|
||||
//
|
||||
//- (void)loadNextPage
|
||||
//{
|
||||
// [self loadPage:self.currentPage + 1];
|
||||
//}
|
||||
//
|
||||
//- (void)loadPreviousPage
|
||||
//{
|
||||
// [self loadPage:self.currentPage - 1];
|
||||
//}
|
||||
//
|
||||
//- (void)loadPage:(NSUInteger)pageNumber
|
||||
//{
|
||||
// NSAssert(self.mappingProvider, @"Cannot perform a load with a nil mappingProvider.");
|
||||
// NSAssert(! self.objectLoader, @"Cannot perform a load while one is already in progress.");
|
||||
// self.currentPage = pageNumber;
|
||||
//
|
||||
// if (self.managedObjectStore) {
|
||||
// RKManagedObjectLoader *managedObjectLoader = [[[RKManagedObjectLoader alloc] initWithURL:self.URL mappingProvider:self.mappingProvider] autorelease];
|
||||
// managedObjectLoader.managedObjectContext = self.managedObjectStore.persistentStoreManagedObjectContext;
|
||||
// managedObjectLoader.mainQueueManagedObjectContext = self.managedObjectStore.mainQueueManagedObjectContext;
|
||||
// self.objectLoader = managedObjectLoader;
|
||||
// } else {
|
||||
// self.objectLoader = [[[RKObjectLoader alloc] initWithURL:self.URL mappingProvider:self.mappingProvider] autorelease];
|
||||
// }
|
||||
//
|
||||
// if ([self.configurationDelegate respondsToSelector:@selector(configureObjectLoader:)]) {
|
||||
// [self.configurationDelegate configureObjectLoader:self.objectLoader];
|
||||
// }
|
||||
// self.objectLoader.method = RKRequestMethodGET;
|
||||
// self.objectLoader.delegate = self;
|
||||
//
|
||||
// if ([self.delegate respondsToSelector:@selector(paginator:willLoadPage:objectLoader:)]) {
|
||||
// [self.delegate paginator:self willLoadPage:pageNumber objectLoader:self.objectLoader];
|
||||
// }
|
||||
//
|
||||
// [self.objectLoader send];
|
||||
//}
|
||||
//
|
||||
//@end
|
||||
@@ -154,6 +154,14 @@
|
||||
*/
|
||||
@property (nonatomic, assign) dispatch_queue_t failureCallbackQueue;
|
||||
|
||||
/**
|
||||
Sets a block to be executed before the object request operation begins mapping the deserialized response body, providing an opportunity to manipulate the mappable representation input that will be passed to the response mapper.
|
||||
|
||||
@param block A block object to be executed before the deserialized response is passed to the response mapper. The block has an `id` return type and must return a dictionary or array of dictionaries corresponding to the object representations that are to be mapped. The block accepts a single argument: the deserialized response data that was loaded via HTTP.
|
||||
@warning The deserialized response body may or may not be immutable depending on the implementation details of the `RKSerialization` class that deserialized the response. If you wish to make changes to the mappable object representations, you must obtain a mutable copy of the response body input.
|
||||
*/
|
||||
- (void)setWillMapDeserializedResponseBlock:(id (^)(id deserializedResponseBody))block;
|
||||
|
||||
///-------------------------------------------
|
||||
/// @name Accessing the Response Mapping Queue
|
||||
///-------------------------------------------
|
||||
|
||||
@@ -98,6 +98,7 @@ static NSString *RKStringDescribingURLResponseWithData(NSURLResponse *response,
|
||||
@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult;
|
||||
@property (nonatomic, strong, readwrite) NSError *error;
|
||||
@property (nonatomic, strong) RKObjectResponseMapperOperation *responseMapperOperation;
|
||||
@property (nonatomic, copy) id (^willMapDeserializedResponseBlock)(id deserializedResponseBody);
|
||||
@end
|
||||
|
||||
@implementation RKObjectRequestOperation
|
||||
@@ -235,6 +236,7 @@ static NSString *RKStringDescribingURLResponseWithData(NSURLResponse *response,
|
||||
responseDescriptors:self.responseDescriptors];
|
||||
self.responseMapperOperation.targetObject = self.targetObject;
|
||||
[self.responseMapperOperation setQueuePriority:[self queuePriority]];
|
||||
[self.responseMapperOperation setWillMapDeserializedResponseBlock:self.willMapDeserializedResponseBlock];
|
||||
[[RKObjectRequestOperation responseMappingQueue] addOperation:self.responseMapperOperation];
|
||||
[self.responseMapperOperation waitUntilFinished];
|
||||
if ([self isCancelled]) return nil;
|
||||
|
||||
224
Code/Network/RKPaginator.h
Normal file
224
Code/Network/RKPaginator.h
Normal file
@@ -0,0 +1,224 @@
|
||||
//
|
||||
// RKPaginator.h
|
||||
// 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 "RKHTTPRequestOperation.h"
|
||||
#import "RKManagedObjectCaching.h"
|
||||
#import "RKObjectMapping.h"
|
||||
#import "RKMappingResult.h"
|
||||
|
||||
/**
|
||||
Instances of RKPaginator retrieve paginated collections of mappable data
|
||||
from remote systems via HTTP. Paginators perform GET requests and use a patterned
|
||||
URL to construct a full URL reflecting the state of the paginator. Paginators rely
|
||||
on an instance of RKObjectMappingProvider to determine how to perform object mapping
|
||||
on the retrieved data. Paginators can load Core Data backed models provided that an
|
||||
instance of RKManagedObjectStore is assigned to the paginator.
|
||||
*/
|
||||
@interface RKPaginator : NSObject
|
||||
|
||||
/**
|
||||
Initializes a RKPaginator object with the a provided patternURL and mappingProvider.
|
||||
|
||||
@param request A request with a URL containing a dynamic pattern specifying how paginated resources are to be acessed.
|
||||
@param paginationMapping The pagination mapping specifying how pagination metadata is to be mapped from responses.
|
||||
@param responseDescriptors An array of response descriptors describing how to map object representations loaded by object request operations dispatched by the paginator.
|
||||
@return The receiver, initialized with the request, pagination mapping, and response descriptors.
|
||||
*/
|
||||
- (id)initWithRequest:(NSURLRequest *)request
|
||||
paginationMapping:(RKObjectMapping *)paginationMapping
|
||||
responseDescriptors:(NSArray *)responseDescriptors;
|
||||
|
||||
/**
|
||||
A URL with a path pattern for building a complete URL from
|
||||
which to load the paginated resource collection. The patterned resource
|
||||
path will be evaluated against the state of the paginator object itself.
|
||||
|
||||
For example, given a paginated collection of data at the /articles path,
|
||||
the path portion of the pattern URL may look like:
|
||||
|
||||
/articles?per_page=:perPage&page_number=:currentPage
|
||||
|
||||
When the pattern is evaluated against the state of the paginator, this will
|
||||
yield a complete path that can be used to load the specified page. Given
|
||||
a paginator configured with 100 objects per page and a current page number of 3,
|
||||
the path portion of the pagination URL would become:
|
||||
|
||||
/articles?per_page=100&page_number=3
|
||||
*/
|
||||
@property (nonatomic, readonly) NSURL *patternURL;
|
||||
|
||||
/**
|
||||
Returns a complete URL to the paginated resource collection by interpolating the state of the paginator object against the patternURL.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSURL *URL;
|
||||
|
||||
/**
|
||||
An optional operation queue on which object request operations constructed by the paginator are to be enqueued for processing.
|
||||
*/
|
||||
@property (nonatomic, strong) NSOperationQueue *operationQueue;
|
||||
|
||||
///-----------------------------------
|
||||
/// @name Setting the Completion Block
|
||||
///-----------------------------------
|
||||
|
||||
/**
|
||||
Sets the completion block to be invoked when the paginator finishes loading a page of results.
|
||||
|
||||
@param success A block to be executed upon a successful load of a page of objects. The block has no return value and takes three arguments: the paginator object, an array containing the paginated objects, and an integer indicating the page that was loaded.
|
||||
@param failure A block to be exected upon a failed load. The block has no return value and takes two arguments: the paginator object and an error indicating the nature of the failure.
|
||||
*/
|
||||
- (void)setCompletionBlockWithSuccess:(void (^)(RKPaginator *paginator, NSArray *objects, NSUInteger page))success
|
||||
failure:(void (^)(RKPaginator *paginator, NSError *error))failure;
|
||||
|
||||
|
||||
///-----------------------------------
|
||||
/// @name Accessing Pagination Results
|
||||
///-----------------------------------
|
||||
|
||||
@property (nonatomic, strong, readonly) RKMappingResult *mappingResult;
|
||||
@property (nonatomic, strong, readonly) NSError *error;
|
||||
|
||||
///-----------------------------------
|
||||
/// @name Object Mapping Configuration
|
||||
///-----------------------------------
|
||||
|
||||
/**
|
||||
The object mapping defining how pagination metadata is to be mapped from a paginated response onto the paginator object.
|
||||
|
||||
@warning The `objectClass` of the given mapping must be `RKPaginator`.
|
||||
*/
|
||||
@property (nonatomic, strong) RKObjectMapping *paginationMapping;
|
||||
|
||||
///------------------------------
|
||||
/// @name Core Data Configuration
|
||||
///------------------------------
|
||||
|
||||
/**
|
||||
The managed object context in which paginated managed objects are to be persisted.
|
||||
*/
|
||||
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
|
||||
|
||||
/**
|
||||
The managed object cache used to find existing managed object instances in the persistent store.
|
||||
*/
|
||||
@property (nonatomic, strong) id<RKManagedObjectCaching> managedObjectCache;
|
||||
|
||||
/**
|
||||
An array of fetch request blocks.
|
||||
*/
|
||||
@property (nonatomic, copy) NSArray *fetchRequestBlocks;
|
||||
|
||||
///------------------------------------
|
||||
/// @name Accessing Pagination Metadata
|
||||
///------------------------------------
|
||||
|
||||
/**
|
||||
The number of objects to load per page
|
||||
*/
|
||||
@property (nonatomic, assign) NSUInteger perPage;
|
||||
|
||||
/**
|
||||
A Boolean value indicating if the paginator has loaded a page of objects
|
||||
|
||||
@returns YES when the paginator has loaded a page of objects
|
||||
*/
|
||||
@property (nonatomic, readonly, getter = isLoaded) BOOL loaded;
|
||||
|
||||
/**
|
||||
Returns the page number for the most recently loaded page of objects.
|
||||
|
||||
@return The page number for the current page of objects.
|
||||
@exception NSInternalInconsistencyException Raised if `isLoaded` is equal to `NO`.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSUInteger currentPage;
|
||||
|
||||
/**
|
||||
Returns the number of pages in the total resource collection.
|
||||
|
||||
@return A count of the number of pages in the resource collection.
|
||||
@exception NSInternalInconsistencyException Raised if hasPageCount is `NO`.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSUInteger pageCount;
|
||||
|
||||
/**
|
||||
Returns the total number of objects in the collection
|
||||
|
||||
@return A count of the number of objects in the resource collection.
|
||||
@exception NSInternalInconsistencyException Raised if hasObjectCount is `NO`.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSUInteger objectCount;
|
||||
|
||||
/**
|
||||
Returns a Boolean value indicating if the total number of pages in the collection is known by the paginator.
|
||||
|
||||
@return `YES` if the paginator knows the page count, otherwise `NO`.
|
||||
*/
|
||||
- (BOOL)hasPageCount;
|
||||
|
||||
/**
|
||||
Returns a Boolean value indicating if the total number of objects in the collection is known by the paginator.
|
||||
|
||||
@return `YES` if the paginator knows the number of objects in the paginated collection, otherwise `NO`.
|
||||
*/
|
||||
- (BOOL)hasObjectCount;
|
||||
|
||||
/**
|
||||
Returns a Boolean value indicating if there is a next page in the collection.
|
||||
|
||||
@return `YES` if there is a next page, otherwise `NO`.
|
||||
@exception NSInternalInconsistencyException Raised if isLoaded or hasPageCount is `NO`.
|
||||
*/
|
||||
- (BOOL)hasNextPage;
|
||||
|
||||
/**
|
||||
Returns a Boolean value indicating if there is a previous page in the collection.
|
||||
|
||||
@return `YES` if there is a previous page, otherwise `NO`.
|
||||
@exception NSInternalInconsistencyException Raised if isLoaded is `NO`.
|
||||
*/
|
||||
- (BOOL)hasPreviousPage;
|
||||
|
||||
///------------------------
|
||||
/// @name Paginator Actions
|
||||
///------------------------
|
||||
|
||||
/**
|
||||
Loads the next page of data by incrementing the current page, constructing an object loader to fetch the data, and object mapping the results.
|
||||
*/
|
||||
- (void)loadNextPage;
|
||||
|
||||
/**
|
||||
Loads the previous page of data by decrementing the current page, constructing an object loader to fetch the data, and object mapping the results.
|
||||
*/
|
||||
- (void)loadPreviousPage;
|
||||
|
||||
/**
|
||||
Loads a specific page of data by mutating the current page, constructing an object loader to fetch the data, and object mapping the results.
|
||||
|
||||
@param pageNumber The page of objects to load from the remote backend
|
||||
*/
|
||||
- (void)loadPage:(NSUInteger)pageNumber;
|
||||
|
||||
/**
|
||||
Cancels an in-progress pagination request.
|
||||
*/
|
||||
- (void)cancel;
|
||||
|
||||
@end
|
||||
241
Code/Network/RKPaginator.m
Normal file
241
Code/Network/RKPaginator.m
Normal file
@@ -0,0 +1,241 @@
|
||||
//
|
||||
// RKPaginator.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 "RKPaginator.h"
|
||||
#import "RKMappingOperation.h"
|
||||
#import "RKObjectRequestOperation.h"
|
||||
#import "RKManagedObjectRequestOperation.h"
|
||||
#import "SOCKit.h"
|
||||
#import "RKLog.h"
|
||||
#import "RKPathUtilities.h"
|
||||
#import "RKHTTPUtilities.h"
|
||||
|
||||
static NSUInteger RKPaginatorDefaultPerPage = 25;
|
||||
|
||||
// Private interface
|
||||
@interface RKPaginator ()
|
||||
@property (nonatomic, copy) NSURLRequest *request;
|
||||
@property (nonatomic, strong) RKObjectRequestOperation *objectRequestOperation;
|
||||
@property (nonatomic, copy) NSArray *responseDescriptors;
|
||||
@property (nonatomic, assign, readwrite) NSUInteger currentPage;
|
||||
@property (nonatomic, assign, readwrite) NSUInteger pageCount;
|
||||
@property (nonatomic, assign, readwrite) NSUInteger objectCount;
|
||||
@property (nonatomic, assign, readwrite) BOOL loaded;
|
||||
@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult;
|
||||
@property (nonatomic, strong, readwrite) NSError *error;
|
||||
|
||||
@property (nonatomic, copy) void (^successBlock)(RKPaginator *paginator, NSArray *objects, NSUInteger page);
|
||||
@property (nonatomic, copy) void (^failureBlock)(RKPaginator *paginator, NSError *error);
|
||||
@end
|
||||
|
||||
@implementation RKPaginator
|
||||
|
||||
- (id)initWithRequest:(NSURLRequest *)request
|
||||
paginationMapping:(RKObjectMapping *)paginationMapping
|
||||
responseDescriptors:(NSArray *)responseDescriptors;
|
||||
{
|
||||
NSParameterAssert(request);
|
||||
NSParameterAssert(paginationMapping);
|
||||
NSParameterAssert(responseDescriptors);
|
||||
NSAssert([paginationMapping.objectClass isSubclassOfClass:[RKPaginator class]], @"The paginationMapping must have a target object class of `RKPaginator`");
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.request = request;
|
||||
self.paginationMapping = paginationMapping;
|
||||
self.responseDescriptors = responseDescriptors;
|
||||
self.currentPage = NSNotFound;
|
||||
self.pageCount = NSNotFound;
|
||||
self.objectCount = NSNotFound;
|
||||
self.perPage = RKPaginatorDefaultPerPage;
|
||||
self.loaded = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self.objectRequestOperation cancel];
|
||||
}
|
||||
|
||||
- (NSURL *)patternURL
|
||||
{
|
||||
return self.request.URL;
|
||||
}
|
||||
|
||||
- (NSURL *)URL
|
||||
{
|
||||
NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL(self.patternURL, nil);
|
||||
NSString *interpolatedString = RKPathFromPatternWithObject(pathAndQueryString, self);
|
||||
return [NSURL URLWithString:interpolatedString relativeToURL:self.request.URL];
|
||||
}
|
||||
|
||||
- (void)setCompletionBlockWithSuccess:(void (^)(RKPaginator *paginator, NSArray *objects, NSUInteger page))success
|
||||
failure:(void (^)(RKPaginator *paginator, NSError *error))failure
|
||||
{
|
||||
self.successBlock = success;
|
||||
self.failureBlock = failure;
|
||||
}
|
||||
|
||||
// Private. Public consumers can rely on isLoaded
|
||||
- (BOOL)hasCurrentPage
|
||||
{
|
||||
return _currentPage != NSNotFound;
|
||||
}
|
||||
|
||||
- (BOOL)hasPageCount
|
||||
{
|
||||
return _pageCount != NSNotFound;
|
||||
}
|
||||
|
||||
- (BOOL)hasObjectCount
|
||||
{
|
||||
return _objectCount != NSNotFound;
|
||||
}
|
||||
|
||||
- (NSUInteger)currentPage
|
||||
{
|
||||
// Referenced during initial load, so we don't rely on isLoaded.
|
||||
NSAssert([self hasCurrentPage], @"Current page has not been initialized.");
|
||||
return _currentPage;
|
||||
}
|
||||
|
||||
- (NSUInteger)pageCount
|
||||
{
|
||||
NSAssert([self hasPageCount], @"Page count not available.");
|
||||
return _pageCount;
|
||||
}
|
||||
|
||||
- (BOOL)hasNextPage
|
||||
{
|
||||
NSAssert(self.isLoaded, @"Cannot determine hasNextPage: paginator is not loaded.");
|
||||
NSAssert([self hasPageCount], @"Cannot determine hasNextPage: page count is not known.");
|
||||
|
||||
return self.currentPage < self.pageCount;
|
||||
}
|
||||
|
||||
- (BOOL)hasPreviousPage
|
||||
{
|
||||
NSAssert(self.isLoaded, @"Cannot determine hasPreviousPage: paginator is not loaded.");
|
||||
return self.currentPage > 1;
|
||||
}
|
||||
|
||||
#pragma mark - Action methods
|
||||
|
||||
- (void)loadNextPage
|
||||
{
|
||||
[self loadPage:self.currentPage + 1];
|
||||
}
|
||||
|
||||
- (void)loadPreviousPage
|
||||
{
|
||||
[self loadPage:self.currentPage - 1];
|
||||
}
|
||||
|
||||
- (void)loadPage:(NSUInteger)pageNumber
|
||||
{
|
||||
NSAssert(self.responseDescriptors, @"Cannot perform a load with nil response descriptors.");
|
||||
NSAssert(! self.objectRequestOperation, @"Cannot perform a load while one is already in progress.");
|
||||
self.currentPage = pageNumber;
|
||||
|
||||
NSMutableURLRequest *mutableRequest = [self.request mutableCopy];
|
||||
mutableRequest.URL = self.URL;
|
||||
|
||||
if (self.managedObjectContext) {
|
||||
RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithRequest:mutableRequest responseDescriptors:self.responseDescriptors];
|
||||
managedObjectRequestOperation.managedObjectContext = self.managedObjectContext;
|
||||
managedObjectRequestOperation.managedObjectCache = self.managedObjectCache;
|
||||
managedObjectRequestOperation.fetchRequestBlocks = self.fetchRequestBlocks;
|
||||
|
||||
self.objectRequestOperation = managedObjectRequestOperation;
|
||||
} else {
|
||||
self.objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:mutableRequest responseDescriptors:self.responseDescriptors];
|
||||
}
|
||||
|
||||
// Add KVO to ensure notification of loaded state prior to execution of completion block
|
||||
[self.objectRequestOperation addObserver:self forKeyPath:@"isFinished" options:0 context:nil];
|
||||
|
||||
__weak RKPaginator *weakSelf = self;
|
||||
[self.objectRequestOperation setWillMapDeserializedResponseBlock:^id(id deserializedResponseBody) {
|
||||
NSError *error = nil;
|
||||
RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:deserializedResponseBody destinationObject:weakSelf mapping:weakSelf.paginationMapping];
|
||||
BOOL success = [mappingOperation performMapping:&error];
|
||||
if (!success) {
|
||||
weakSelf.pageCount = 0;
|
||||
weakSelf.currentPage = 0;
|
||||
RKLogError(@"Paginator didn't map info to compute page count. Assuming no pages.");
|
||||
} else if (weakSelf.perPage && [weakSelf hasObjectCount]) {
|
||||
float objectCountFloat = weakSelf.objectCount;
|
||||
weakSelf.pageCount = ceilf(objectCountFloat / weakSelf.perPage);
|
||||
RKLogInfo(@"Paginator objectCount: %ld pageCount: %ld", (long)weakSelf.objectCount, (long)weakSelf.pageCount);
|
||||
} else {
|
||||
RKLogError(@"Paginator perPage set is 0.");
|
||||
}
|
||||
|
||||
return deserializedResponseBody;
|
||||
}];
|
||||
[self.objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
|
||||
if (weakSelf.successBlock) {
|
||||
weakSelf.successBlock(weakSelf, [mappingResult array], weakSelf.currentPage);
|
||||
}
|
||||
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
|
||||
if (weakSelf.failureBlock) {
|
||||
weakSelf.failureBlock(weakSelf, error);
|
||||
}
|
||||
}];
|
||||
|
||||
if (self.operationQueue) {
|
||||
[self.operationQueue addOperation:self.objectRequestOperation];
|
||||
} else {
|
||||
[self.objectRequestOperation start];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)waitUntilFinished
|
||||
{
|
||||
[self.objectRequestOperation waitUntilFinished];
|
||||
}
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@: %p patternURL=%@ isLoaded=%@ perPage=%d currentPage=%@ pageCount=%@ objectCount=%@>",
|
||||
NSStringFromClass([self class]), self, self.patternURL, self.isLoaded ? @"YES" : @"NO", self.perPage,
|
||||
[self hasCurrentPage] ? @(self.currentPage) : @"???",
|
||||
[self hasPageCount] ? @(self.pageCount) : @"???",
|
||||
[self hasObjectCount] ? @(self.objectCount) : @"???"];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
{
|
||||
if ([keyPath isEqualToString:@"isFinished"] && [self.objectRequestOperation isFinished]) {
|
||||
self.loaded = (self.objectRequestOperation.mappingResult != nil);
|
||||
self.mappingResult = self.objectRequestOperation.mappingResult;
|
||||
self.error = self.objectRequestOperation.error;
|
||||
self.objectRequestOperation = nil;
|
||||
[object removeObserver:self forKeyPath:@"isFinished"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancel
|
||||
{
|
||||
[self.objectRequestOperation cancel];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -130,6 +130,18 @@
|
||||
*/
|
||||
@property (nonatomic, strong, readonly) NSError *error;
|
||||
|
||||
///-------------------------------------
|
||||
/// @name Manipulating the Mappable Data
|
||||
///-------------------------------------
|
||||
|
||||
/**
|
||||
Sets a block to be executed before the response mapper operation begins mapping the deserialized response body, providing an opportunity to manipulate the mappable representation input before mapping begins.
|
||||
|
||||
@param block A block object to be executed before the deserialized response is passed to the response mapper. The block has an `id` return type and must return a dictionary or array of dictionaries corresponding to the object representations that are to be mapped. The block accepts a single argument: the deserialized response data that was loaded via HTTP.
|
||||
@warning The deserialized response body may or may not be immutable depending on the implementation details of the `RKSerialization` class that deserialized the response. If you wish to make changes to the mappable object representations, you must obtain a mutable copy of the response body input.
|
||||
*/
|
||||
- (void)setWillMapDeserializedResponseBlock:(id (^)(id deserializedResponseBody))block;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
||||
@@ -79,6 +79,7 @@ static dispatch_queue_t RKResponseMapperSerializationQueue() {
|
||||
@property (nonatomic, strong, readwrite) NSError *error;
|
||||
@property (nonatomic, strong, readwrite) NSDictionary *responseMappingsDictionary;
|
||||
@property (nonatomic, strong) RKMapperOperation *mapperOperation;
|
||||
@property (nonatomic, copy) id (^willMapDeserializedResponseBlock)(id deserializedResponseBody);
|
||||
@end
|
||||
|
||||
@interface RKResponseMapperOperation (ForSubclassEyesOnly)
|
||||
@@ -113,7 +114,7 @@ static dispatch_queue_t RKResponseMapperSerializationQueue() {
|
||||
__block id object;
|
||||
dispatch_sync(RKResponseMapperSerializationQueue(), ^{
|
||||
object = [RKMIMETypeSerialization objectFromData:self.data MIMEType:MIMEType error:&underlyingError];
|
||||
});
|
||||
});
|
||||
if (! object) {
|
||||
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
|
||||
[userInfo setValue:[NSString stringWithFormat:@"Loaded an unprocessable response (%ld) with content type '%@'", (long) self.response.statusCode, MIMEType]
|
||||
@@ -201,6 +202,17 @@ static dispatch_queue_t RKResponseMapperSerializationQueue() {
|
||||
return;
|
||||
}
|
||||
if (self.isCancelled) return;
|
||||
|
||||
// Invoke the will map deserialized response block
|
||||
if (self.willMapDeserializedResponseBlock) {
|
||||
parsedBody = self.willMapDeserializedResponseBlock(parsedBody);
|
||||
if (! parsedBody) {
|
||||
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Mapping was declined due to a `willMapDeserializedResponseBlock` returning nil." };
|
||||
self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorFromMappingResult userInfo:userInfo];
|
||||
RKLogError(@"Failed to parse response data: %@", [error localizedDescription]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Object map the response
|
||||
self.mappingResult = [self performMappingWithObject:parsedBody error:&error];
|
||||
|
||||
@@ -29,7 +29,8 @@ enum {
|
||||
RKMappingErrorValidationFailure = 1005, // Generic error code for use when constructing validation errors
|
||||
RKMappingErrorUnableToDetermineMapping = 1006, // The mapping operation was unable to obtain a concrete object mapping from a given dynamic mapping
|
||||
RKMappingErrorNilDestinationObject = 1007, // The mapping operation failed due to a nil destination object.
|
||||
RKMappingErrorNilManagedObjectCache = 1008 // A managed object cache is required to satisfy the mapping, but none was given.
|
||||
RKMappingErrorNilManagedObjectCache = 1008, // A managed object cache is required to satisfy the mapping, but none was given.
|
||||
RKMappingErrorMappingDeclined = 1009 // Mapping was declined by a callback.
|
||||
};
|
||||
|
||||
extern NSString * const RKMappingErrorKeyPathErrorKey; // The key path the error is associated with
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#import "RKObjectManager.h"
|
||||
#import "RKPathUtilities.h"
|
||||
#import "RKMIMETypeSerialization.h"
|
||||
#import "RKManagedObjectStore.h"
|
||||
|
||||
// Expose MIME Type singleton and initialization routine
|
||||
@interface RKMIMETypeSerialization ()
|
||||
|
||||
@@ -337,10 +337,10 @@
|
||||
254372BD15F54C3F006E8424 /* RKObjectManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AC15F54C3F006E8424 /* RKObjectManager.h */; };
|
||||
254372BE15F54C3F006E8424 /* RKObjectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AD15F54C3F006E8424 /* RKObjectManager.m */; };
|
||||
254372BF15F54C3F006E8424 /* RKObjectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AD15F54C3F006E8424 /* RKObjectManager.m */; };
|
||||
254372C015F54C3F006E8424 /* RKObjectPaginator.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AE15F54C3F006E8424 /* RKObjectPaginator.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
254372C115F54C3F006E8424 /* RKObjectPaginator.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AE15F54C3F006E8424 /* RKObjectPaginator.h */; };
|
||||
254372C215F54C3F006E8424 /* RKObjectPaginator.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AF15F54C3F006E8424 /* RKObjectPaginator.m */; };
|
||||
254372C315F54C3F006E8424 /* RKObjectPaginator.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AF15F54C3F006E8424 /* RKObjectPaginator.m */; };
|
||||
254372C015F54C3F006E8424 /* RKPaginator.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AE15F54C3F006E8424 /* RKPaginator.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
254372C115F54C3F006E8424 /* RKPaginator.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372AE15F54C3F006E8424 /* RKPaginator.h */; };
|
||||
254372C215F54C3F006E8424 /* RKPaginator.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AF15F54C3F006E8424 /* RKPaginator.m */; };
|
||||
254372C315F54C3F006E8424 /* RKPaginator.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372AF15F54C3F006E8424 /* RKPaginator.m */; };
|
||||
254372C415F54C3F006E8424 /* RKObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B015F54C3F006E8424 /* RKObjectRequestOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
254372C515F54C3F006E8424 /* RKObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 254372B015F54C3F006E8424 /* RKObjectRequestOperation.h */; };
|
||||
254372C615F54C3F006E8424 /* RKObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 254372B115F54C3F006E8424 /* RKObjectRequestOperation.m */; };
|
||||
@@ -369,6 +369,8 @@
|
||||
25565959161FC3CD00F5BB20 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25565958161FC3CD00F5BB20 /* SystemConfiguration.framework */; };
|
||||
25565965161FDD8800F5BB20 /* RKResponseMapperOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25565964161FDD8800F5BB20 /* RKResponseMapperOperationTest.m */; };
|
||||
25565966161FDD8800F5BB20 /* RKResponseMapperOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25565964161FDD8800F5BB20 /* RKResponseMapperOperationTest.m */; };
|
||||
255F87911656B22D00914D57 /* RKPaginatorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 254A62BF14AD591C00939BEE /* RKPaginatorTest.m */; };
|
||||
255F87921656B22F00914D57 /* RKPaginatorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 254A62BF14AD591C00939BEE /* RKPaginatorTest.m */; };
|
||||
2564E40B16173F7B00C12D7D /* RKRelationshipConnectionOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2564E40A16173F7B00C12D7D /* RKRelationshipConnectionOperationTest.m */; };
|
||||
2564E40C16173F7B00C12D7D /* RKRelationshipConnectionOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2564E40A16173F7B00C12D7D /* RKRelationshipConnectionOperationTest.m */; };
|
||||
257ABAB015112DD500CCAA76 /* NSManagedObjectContext+RKAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 257ABAAE15112DD400CCAA76 /* NSManagedObjectContext+RKAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@@ -801,8 +803,8 @@
|
||||
254372AB15F54C3F006E8424 /* RKHTTPRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKHTTPRequestOperation.m; sourceTree = "<group>"; };
|
||||
254372AC15F54C3F006E8424 /* RKObjectManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectManager.h; sourceTree = "<group>"; };
|
||||
254372AD15F54C3F006E8424 /* RKObjectManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectManager.m; sourceTree = "<group>"; };
|
||||
254372AE15F54C3F006E8424 /* RKObjectPaginator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectPaginator.h; sourceTree = "<group>"; };
|
||||
254372AF15F54C3F006E8424 /* RKObjectPaginator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectPaginator.m; sourceTree = "<group>"; };
|
||||
254372AE15F54C3F006E8424 /* RKPaginator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKPaginator.h; sourceTree = "<group>"; };
|
||||
254372AF15F54C3F006E8424 /* RKPaginator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKPaginator.m; sourceTree = "<group>"; };
|
||||
254372B015F54C3F006E8424 /* RKObjectRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKObjectRequestOperation.h; sourceTree = "<group>"; };
|
||||
254372B115F54C3F006E8424 /* RKObjectRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectRequestOperation.m; sourceTree = "<group>"; };
|
||||
254372B215F54C3F006E8424 /* RKRequestDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKRequestDescriptor.h; sourceTree = "<group>"; };
|
||||
@@ -815,7 +817,7 @@
|
||||
254372D515F54CE3006E8424 /* RKManagedObjectRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectRequestOperation.m; sourceTree = "<group>"; };
|
||||
2548AC6C162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectRequestOperationTest.m; sourceTree = "<group>"; };
|
||||
2549D645162B376F003DD135 /* RKRequestDescriptorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKRequestDescriptorTest.m; sourceTree = "<group>"; };
|
||||
254A62BF14AD591C00939BEE /* RKObjectPaginatorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKObjectPaginatorTest.m; sourceTree = "<group>"; };
|
||||
254A62BF14AD591C00939BEE /* RKPaginatorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKPaginatorTest.m; sourceTree = "<group>"; };
|
||||
25565955161FC3C300F5BB20 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/CoreServices.framework; sourceTree = DEVELOPER_DIR; };
|
||||
25565958161FC3CD00F5BB20 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; };
|
||||
25565964161FDD8800F5BB20 /* RKResponseMapperOperationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKResponseMapperOperationTest.m; sourceTree = "<group>"; };
|
||||
@@ -1117,8 +1119,8 @@
|
||||
E4081DFF15FB8B4000364948 /* ObjectRequestOperations */,
|
||||
254372AC15F54C3F006E8424 /* RKObjectManager.h */,
|
||||
254372AD15F54C3F006E8424 /* RKObjectManager.m */,
|
||||
254372AE15F54C3F006E8424 /* RKObjectPaginator.h */,
|
||||
254372AF15F54C3F006E8424 /* RKObjectPaginator.m */,
|
||||
254372AE15F54C3F006E8424 /* RKPaginator.h */,
|
||||
254372AF15F54C3F006E8424 /* RKPaginator.m */,
|
||||
254372B215F54C3F006E8424 /* RKRequestDescriptor.h */,
|
||||
254372B315F54C3F006E8424 /* RKRequestDescriptor.m */,
|
||||
254372B415F54C3F006E8424 /* RKResponseDescriptor.h */,
|
||||
@@ -1456,7 +1458,7 @@
|
||||
251610241456F2330060A5C5 /* RKMappingResultTest.m */,
|
||||
251610261456F2330060A5C5 /* RKObjectParameterizationTest.m */,
|
||||
251610271456F2330060A5C5 /* RKMIMETypeSerializationTest.m */,
|
||||
254A62BF14AD591C00939BEE /* RKObjectPaginatorTest.m */,
|
||||
254A62BF14AD591C00939BEE /* RKPaginatorTest.m */,
|
||||
2519764215823BA1004FE9DD /* RKAttributeMappingTest.m */,
|
||||
2519764715824455004FE9DD /* RKRelationshipMappingTest.m */,
|
||||
2519764B158244F8004FE9DD /* RKObjectMappingTest.m */,
|
||||
@@ -1739,7 +1741,7 @@
|
||||
254372A815F54995006E8424 /* RKObjectParameterization.h in Headers */,
|
||||
254372B815F54C3F006E8424 /* RKHTTPRequestOperation.h in Headers */,
|
||||
254372BC15F54C3F006E8424 /* RKObjectManager.h in Headers */,
|
||||
254372C015F54C3F006E8424 /* RKObjectPaginator.h in Headers */,
|
||||
254372C015F54C3F006E8424 /* RKPaginator.h in Headers */,
|
||||
254372C415F54C3F006E8424 /* RKObjectRequestOperation.h in Headers */,
|
||||
254372C815F54C3F006E8424 /* RKRequestDescriptor.h in Headers */,
|
||||
254372CC15F54C3F006E8424 /* RKResponseDescriptor.h in Headers */,
|
||||
@@ -1839,7 +1841,7 @@
|
||||
2598888E15EC169E006CAE95 /* RKPropertyMapping.h in Headers */,
|
||||
254372B915F54C3F006E8424 /* RKHTTPRequestOperation.h in Headers */,
|
||||
254372BD15F54C3F006E8424 /* RKObjectManager.h in Headers */,
|
||||
254372C115F54C3F006E8424 /* RKObjectPaginator.h in Headers */,
|
||||
254372C115F54C3F006E8424 /* RKPaginator.h in Headers */,
|
||||
254372C515F54C3F006E8424 /* RKObjectRequestOperation.h in Headers */,
|
||||
254372C915F54C3F006E8424 /* RKRequestDescriptor.h in Headers */,
|
||||
254372CD15F54C3F006E8424 /* RKResponseDescriptor.h in Headers */,
|
||||
@@ -2261,7 +2263,7 @@
|
||||
254372A915F54995006E8424 /* RKObjectParameterization.m in Sources */,
|
||||
254372BA15F54C3F006E8424 /* RKHTTPRequestOperation.m in Sources */,
|
||||
254372BE15F54C3F006E8424 /* RKObjectManager.m in Sources */,
|
||||
254372C215F54C3F006E8424 /* RKObjectPaginator.m in Sources */,
|
||||
254372C215F54C3F006E8424 /* RKPaginator.m in Sources */,
|
||||
254372C615F54C3F006E8424 /* RKObjectRequestOperation.m in Sources */,
|
||||
254372CA15F54C3F006E8424 /* RKRequestDescriptor.m in Sources */,
|
||||
254372CE15F54C3F006E8424 /* RKResponseDescriptor.m in Sources */,
|
||||
@@ -2345,6 +2347,7 @@
|
||||
2549D646162B376F003DD135 /* RKRequestDescriptorTest.m in Sources */,
|
||||
2506759F162DEA25003210B0 /* RKEntityMappingTest.m in Sources */,
|
||||
2548AC6D162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m in Sources */,
|
||||
255F87911656B22D00914D57 /* RKPaginatorTest.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -2406,7 +2409,7 @@
|
||||
2598889015EC169E006CAE95 /* RKPropertyMapping.m in Sources */,
|
||||
254372BB15F54C3F006E8424 /* RKHTTPRequestOperation.m in Sources */,
|
||||
254372BF15F54C3F006E8424 /* RKObjectManager.m in Sources */,
|
||||
254372C315F54C3F006E8424 /* RKObjectPaginator.m in Sources */,
|
||||
254372C315F54C3F006E8424 /* RKPaginator.m in Sources */,
|
||||
254372C715F54C3F006E8424 /* RKObjectRequestOperation.m in Sources */,
|
||||
254372CB15F54C3F006E8424 /* RKRequestDescriptor.m in Sources */,
|
||||
254372CF15F54C3F006E8424 /* RKResponseDescriptor.m in Sources */,
|
||||
@@ -2491,6 +2494,7 @@
|
||||
2549D647162B376F003DD135 /* RKRequestDescriptorTest.m in Sources */,
|
||||
250675A1162DEA27003210B0 /* RKEntityMappingTest.m in Sources */,
|
||||
2548AC6E162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m in Sources */,
|
||||
255F87921656B22F00914D57 /* RKPaginatorTest.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -12,34 +12,6 @@
|
||||
// Models
|
||||
#import "RKObjectLoaderTestResultModel.h"
|
||||
|
||||
//
|
||||
//@interface RKTestResponseLoaderWithWillMapData : RKTestResponseLoader {
|
||||
// id _mappableData;
|
||||
//}
|
||||
//
|
||||
//@property (nonatomic, readonly) id mappableData;
|
||||
//
|
||||
//@end
|
||||
//
|
||||
//@implementation RKTestResponseLoaderWithWillMapData
|
||||
//
|
||||
//@synthesize mappableData = _mappableData;
|
||||
//
|
||||
//- (void)dealloc
|
||||
//{
|
||||
// [_mappableData release];
|
||||
// [super dealloc];
|
||||
//}
|
||||
//
|
||||
//- (void)objectLoader:(RKObjectLoader *)loader willMapData:(inout id *)mappableData
|
||||
//{
|
||||
// [*mappableData setValue:@"monkey!" forKey:@"newKey"];
|
||||
// _mappableData = [*mappableData retain];
|
||||
//}
|
||||
//
|
||||
//@end
|
||||
//
|
||||
|
||||
@interface RKTestComplexUser : NSObject
|
||||
|
||||
@property (nonatomic, retain) NSNumber *userID;
|
||||
@@ -532,14 +504,21 @@
|
||||
|
||||
#pragma mark - Will Map Data Block
|
||||
|
||||
//- (void)testShouldAllowMutationOfTheParsedDataInWillMapData
|
||||
//{
|
||||
// RKTestResponseLoaderWithWillMapData *loader = (RKTestResponseLoaderWithWillMapData *)[RKTestResponseLoaderWithWillMapData responseLoader];
|
||||
// RKObjectManager *manager = [RKTestFactory objectManager];
|
||||
// [manager loadObjectsAtResourcePath:@"/JSON/humans/1.json" delegate:loader];
|
||||
// [loader waitForResponse];
|
||||
// assertThat([loader.mappableData valueForKey:@"newKey"], is(equalTo(@"monkey!")));
|
||||
//}
|
||||
//
|
||||
- (void)testShouldAllowMutationOfTheParsedDataInWillMapData
|
||||
{
|
||||
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
|
||||
[mapping addAttributeMappingsFromArray:@[@"firstname", @"lastname", @"email"]];
|
||||
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:nil keyPath:@"user" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"/JSON/ComplexNestedUser.json" relativeToURL:[RKTestFactory baseURL]]];
|
||||
RKObjectRequestOperation *requestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
|
||||
[requestOperation setWillMapDeserializedResponseBlock:^id(id deserializedResponseBody) {
|
||||
return @{ @"user": @{ @"email": @"blake@restkit.org" } };
|
||||
}];
|
||||
[requestOperation start];
|
||||
[requestOperation waitUntilFinished];
|
||||
RKTestComplexUser *user = [requestOperation.mappingResult firstObject];
|
||||
expect(user).notTo.beNil();
|
||||
expect(user.email).to.equal(@"blake@restkit.org");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,533 +0,0 @@
|
||||
//
|
||||
// RKObjectPaginatorTest.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 "RKObjectPaginator.h"
|
||||
#import "RKObjectMapperTestModel.h"
|
||||
#import "NSURL+RKAdditions.h"
|
||||
|
||||
NSString * const RKTestPaginatorDelegateTimeoutException = @"RKTestPaginatorDelegateTimeoutException";
|
||||
|
||||
@interface RKTestPaginatorDelegate : NSObject <RKObjectPaginatorDelegate>
|
||||
|
||||
@property (nonatomic, readonly, retain) NSArray *paginatedObjects;
|
||||
@property (nonatomic, readonly, retain) NSError *paginationError;
|
||||
@property (nonatomic, readonly) NSUInteger currentPage;
|
||||
@property (nonatomic, readonly, getter = isLoading) BOOL loading;
|
||||
@property (nonatomic, assign) NSTimeInterval timeout;
|
||||
|
||||
+ (RKTestPaginatorDelegate *)paginatorDelegate;
|
||||
|
||||
- (BOOL)isLoaded;
|
||||
- (BOOL)isError;
|
||||
- (void)waitForLoad;
|
||||
|
||||
@end
|
||||
|
||||
@interface RKTestPaginatorDelegate ()
|
||||
@property (nonatomic, readwrite, retain) NSArray *paginatedObjects;
|
||||
@property (nonatomic, readwrite, retain) NSError *paginationError;
|
||||
@end
|
||||
|
||||
@implementation RKTestPaginatorDelegate
|
||||
|
||||
@synthesize paginatedObjects;
|
||||
@synthesize currentPage;
|
||||
@synthesize paginationError;
|
||||
@synthesize loading;
|
||||
@synthesize timeout;
|
||||
|
||||
+ (RKTestPaginatorDelegate *)paginatorDelegate
|
||||
{
|
||||
return [[self new] autorelease];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
currentPage = NSIntegerMax;
|
||||
timeout = 5;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[paginatedObjects release];
|
||||
[paginationError release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL)isLoaded
|
||||
{
|
||||
return currentPage != NSIntegerMax;
|
||||
}
|
||||
|
||||
- (BOOL)isError
|
||||
{
|
||||
return paginationError == nil;
|
||||
}
|
||||
|
||||
- (void)waitForLoad
|
||||
{
|
||||
loading = YES;
|
||||
self.paginatedObjects = nil;
|
||||
self.paginationError = nil;
|
||||
|
||||
NSDate *startDate = [NSDate date];
|
||||
|
||||
while (loading) {
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
|
||||
if ([[NSDate date] timeIntervalSinceDate:startDate] > self.timeout) {
|
||||
[NSException raise:@"RKTestPaginatorDelegateTimeoutException" format:@"*** Operation timed out after %f seconds...", self.timeout];
|
||||
loading = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - RKObjectPaginatorDelegate
|
||||
|
||||
- (void)paginator:(RKObjectPaginator *)paginator didLoadObjects:(NSArray *)objects forPage:(NSUInteger)page
|
||||
{
|
||||
loading = NO;
|
||||
self.paginatedObjects = objects;
|
||||
currentPage = page;
|
||||
}
|
||||
|
||||
- (void)paginator:(RKObjectPaginator *)paginator didFailWithError:(NSError *)error objectLoader:(RKObjectLoader *)loader
|
||||
{
|
||||
loading = NO;
|
||||
self.paginationError = error;
|
||||
}
|
||||
|
||||
- (void)paginator:(RKObjectPaginator *)paginator willLoadPage:(NSUInteger)page objectLoader:(RKObjectLoader *)loader
|
||||
{
|
||||
// Necessary for OCMock expectations
|
||||
}
|
||||
|
||||
- (void)paginatorDidLoadFirstPage:(RKObjectPaginator *)paginator
|
||||
{
|
||||
// Necessary for OCMock expectations
|
||||
}
|
||||
|
||||
- (void)paginatorDidLoadLastPage:(RKObjectPaginator *)paginator
|
||||
{
|
||||
// Necessary for OCMock expectations
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RKObjectPaginatorTest : RKTestCase {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RKObjectPaginatorTest
|
||||
|
||||
static NSString * const RKObjectPaginatorTestResourcePathPattern = @"/paginate?per_page=:perPage&page=:currentPage";
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[RKTestFactory setUp];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
[RKTestFactory tearDown];
|
||||
}
|
||||
|
||||
- (RKObjectMappingProvider *)paginationMappingProvider
|
||||
{
|
||||
RKObjectMapping *paginationMapping = [RKObjectMapping mappingForClass:[RKObjectPaginator 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"]];
|
||||
|
||||
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKObjectMapperTestModel class]];
|
||||
[mapping addAttributeMappingsFromArray:@[@"name", @"age"]];
|
||||
RKObjectMappingProvider *mappingProvider = [RKObjectMappingProvider mappingProvider];
|
||||
mappingProvider.paginationMapping = paginationMapping;
|
||||
[mappingProvider setObjectMapping:mapping forKeyPath:@"entries"];
|
||||
|
||||
return mappingProvider;
|
||||
}
|
||||
|
||||
- (void)testInitCopiesPatternURL
|
||||
{
|
||||
RKURL *patternURL = [RKURL URLWithBaseURLString:@"http://restkit.org"];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:nil];
|
||||
assertThat([paginator.patternURL absoluteString], is(equalTo(@"http://restkit.org")));
|
||||
}
|
||||
|
||||
- (void)testInitRetainsMappingProvider
|
||||
{
|
||||
RKURL *patternURL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
assertThat(paginator.mappingProvider, is(equalTo(mappingProvider)));
|
||||
}
|
||||
|
||||
- (void)testInitDoesNotHavePageCount
|
||||
{
|
||||
RKURL *patternURL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:nil];
|
||||
assertThatBool([paginator hasPageCount], is(equalToBool(NO)));
|
||||
}
|
||||
|
||||
- (void)testInitDoesNotHaveObjectCount
|
||||
{
|
||||
RKURL *patternURL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:nil];
|
||||
assertThatBool([paginator hasObjectCount], is(equalToBool(NO)));
|
||||
}
|
||||
|
||||
- (void)testThatLoadWithNilMappingProviderRaisesException
|
||||
{
|
||||
RKURL *patternURL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:nil];
|
||||
NSException *exception = nil;
|
||||
@try {
|
||||
[paginator loadPage:1];
|
||||
}
|
||||
@catch (NSException *e) {
|
||||
exception = e;
|
||||
}
|
||||
@finally {
|
||||
assertThat(exception, is(notNilValue()));
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testThatResourcePathPatternEvaluatesAgainstPaginator
|
||||
{
|
||||
RKURL *patternURL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:nil];
|
||||
id mockPaginator = [OCMockObject partialMockForObject:paginator];
|
||||
NSUInteger currentPage = 1;
|
||||
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
|
||||
assertThat([[paginator URL] resourcePath], is(equalTo(@"/paginate?per_page=25&page=1")));
|
||||
}
|
||||
|
||||
- (void)testThatURLReturnsReflectsStateOfPaginator
|
||||
{
|
||||
RKURL *patternURL = [RKURL URLWithBaseURLString:@"http://restkit.org" resourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:nil];
|
||||
id mockPaginator = [OCMockObject partialMockForObject:paginator];
|
||||
NSUInteger currentPage = 1;
|
||||
[[[mockPaginator stub] andReturnValue:OCMOCK_VALUE(currentPage)] currentPage];
|
||||
NSDictionary *queryParams = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"1", @"page",
|
||||
@"25", @"per_page", nil];
|
||||
assertThat([[mockPaginator URL] queryParameters], is(equalTo(queryParams)));
|
||||
}
|
||||
|
||||
- (void)testLoadingAPageOfObjects
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:1];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatBool([testDelegate isLoaded], is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
- (void)testLoadingPageOfObjectMapsPerPage
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:1];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatInteger(paginator.perPage, is(equalToInteger(3)));
|
||||
}
|
||||
|
||||
- (void)testLoadingPageOfObjectMapsTotalEntries
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:1];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatInteger(paginator.objectCount, is(equalToInteger(6)));
|
||||
}
|
||||
|
||||
- (void)testLoadingPageOfObjectMapsCurrentPage
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:1];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatInteger(paginator.currentPage, is(equalToInteger(1)));
|
||||
}
|
||||
|
||||
- (void)testLoadingPageOfObjectMapsEntriesToObjects
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:1];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatInteger([[testDelegate paginatedObjects] count], is(equalToInteger(3)));
|
||||
assertThat([[testDelegate paginatedObjects] valueForKey:@"name"], is(equalTo([NSArray arrayWithObjects:@"Blake", @"Sarah", @"Colin", nil])));
|
||||
}
|
||||
|
||||
- (void)testLoadingPageOfObjectHasPageCount
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:1];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatBool([paginator hasPageCount], is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
- (void)testLoadingPageOfObjectHasObjectCount
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:1];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatBool([paginator hasObjectCount], is(equalToBool(YES)));
|
||||
}
|
||||
|
||||
- (void)testOnDidLoadObjectsForPageBlockIsInvokedOnLoad
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
__block NSArray *blockObjects = nil;
|
||||
paginator.onDidLoadObjectsForPage = ^(NSArray *objects, NSUInteger page) {
|
||||
blockObjects = objects;
|
||||
};
|
||||
[paginator loadPage:1];
|
||||
[testDelegate waitForLoad];
|
||||
assertThat(blockObjects, is(notNilValue()));
|
||||
}
|
||||
|
||||
- (void)testDelegateIsInformedOfWillLoadPage
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:testDelegate];
|
||||
[[mockDelegate expect] paginator:paginator willLoadPage:1 objectLoader:OCMOCK_ANY];
|
||||
paginator.delegate = mockDelegate;
|
||||
[paginator loadPage:1];
|
||||
[mockDelegate waitForLoad];
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
- (void)testDelegateIsInformedOnError
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:testDelegate];
|
||||
[[[mockDelegate expect] andForwardToRealObject] paginator:paginator didFailWithError:OCMOCK_ANY objectLoader:OCMOCK_ANY];
|
||||
paginator.delegate = mockDelegate;
|
||||
[paginator loadPage:999];
|
||||
[mockDelegate waitForLoad];
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
- (void)testOnDidFailWithErrorBlockIsInvokedOnError
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
__block NSError *expectedError = nil;
|
||||
paginator.onDidFailWithError = ^(NSError *error, RKObjectLoader *loader) {
|
||||
expectedError = error;
|
||||
};
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:999];
|
||||
[testDelegate waitForLoad];
|
||||
assertThat(expectedError, is(notNilValue()));
|
||||
}
|
||||
|
||||
- (void)testDelegateIsInformedOnLoadOfFirstPage
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:testDelegate];
|
||||
[[mockDelegate expect] paginatorDidLoadFirstPage:paginator];
|
||||
paginator.delegate = mockDelegate;
|
||||
[paginator loadPage:1];
|
||||
[mockDelegate waitForLoad];
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
- (void)testDelegateIsInformedOnLoadOfLastPage
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
id mockDelegate = [OCMockObject partialMockForObject:testDelegate];
|
||||
[[mockDelegate expect] paginatorDidLoadLastPage:paginator];
|
||||
paginator.delegate = mockDelegate;
|
||||
[paginator loadPage:2];
|
||||
[mockDelegate waitForLoad];
|
||||
[mockDelegate verify];
|
||||
}
|
||||
|
||||
- (void)testLoadingNextPageOfObjects
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:1];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatInteger(paginator.currentPage, is(equalToInteger(1)));
|
||||
[paginator loadNextPage];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatInteger(paginator.currentPage, is(equalToInteger(2)));
|
||||
assertThat([[testDelegate paginatedObjects] valueForKey:@"name"], is(equalTo([NSArray arrayWithObjects:@"Asia", @"Roy", @"Lola", nil])));
|
||||
}
|
||||
|
||||
- (void)testLoadingPreviousPageOfObjects
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:2];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatInteger(paginator.currentPage, is(equalToInteger(2)));
|
||||
[paginator loadPreviousPage];
|
||||
[testDelegate waitForLoad];
|
||||
assertThatInteger(paginator.currentPage, is(equalToInteger(1)));
|
||||
assertThat([[testDelegate paginatedObjects] valueForKey:@"name"], is(equalTo([NSArray arrayWithObjects:@"Blake", @"Sarah", @"Colin", nil])));
|
||||
}
|
||||
|
||||
- (void)testFailureWhenLoadingAPageOfObjects
|
||||
{
|
||||
RKURL *patternURL = [[RKTestFactory baseURL] URLByAppendingResourcePath:RKObjectPaginatorTestResourcePathPattern];
|
||||
RKObjectMappingProvider *mappingProvider = [self paginationMappingProvider];
|
||||
RKObjectPaginator *paginator = [RKObjectPaginator paginatorWithPatternURL:patternURL mappingProvider:mappingProvider];
|
||||
RKTestPaginatorDelegate *testDelegate = [RKTestPaginatorDelegate paginatorDelegate];
|
||||
paginator.delegate = testDelegate;
|
||||
[paginator loadPage:3];
|
||||
[testDelegate waitForLoad];
|
||||
assertThat(testDelegate.paginationError, is(notNilValue()));
|
||||
}
|
||||
|
||||
- (void)testKnowledgeOfHasANextPage
|
||||
{
|
||||
RKObjectPaginator *paginator = [[RKObjectPaginator new] autorelease];
|
||||
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
|
||||
{
|
||||
RKObjectPaginator *paginator = [[RKObjectPaginator new] autorelease];
|
||||
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
|
||||
{
|
||||
RKObjectPaginator *paginator = [[RKObjectPaginator new] autorelease];
|
||||
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
|
||||
{
|
||||
RKObjectPaginator *paginator = [[RKObjectPaginator new] autorelease];
|
||||
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
|
||||
{
|
||||
RKObjectPaginator *paginator = [[RKObjectPaginator new] autorelease];
|
||||
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
|
||||
353
Tests/Logic/ObjectMapping/RKPaginatorTest.m
Normal file
353
Tests/Logic/ObjectMapping/RKPaginatorTest.m
Normal file
@@ -0,0 +1,353 @@
|
||||
//
|
||||
// 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
|
||||
Reference in New Issue
Block a user