Framework/ROADWebService/ROADWebserviceTest/Classes/RFDownloader+FakeRequest.m (188 lines of code) (raw):

// // RFDownloader+FakeRequest.m // ROADWebService // // Copyright (c) 2014 EPAM Systems, Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // Redistributions in binary form must reproduce the above copyright notice, this // list of conditions and the following disclaimer in the documentation and/or // other materials provided with the distribution. // Neither the name of the EPAM Systems, Inc. nor the names of its contributors // may be used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // See the NOTICE file and the LICENSE file distributed with this work // for additional information regarding copyright ownership and licensing #import "RFDownloader+FakeRequest.h" #import "RFSerializableTestObject.h" #import "RFAttachmentTestObject.h" #import "NSURLRequest+RFURLTest.h" @interface RFDownloader (Private) @end @implementation RFDownloader (FakeRequest) - (void)fakeStart { SEL downloaderFinishSelector = sel_registerName("cacheAndFinishWithResult:response:error:"); NSMethodSignature * downloaderFinishMethodSignature = [RFDownloader instanceMethodSignatureForSelector:downloaderFinishSelector]; NSInvocation * downloaderFinishMethodInvocation = [NSInvocation invocationWithMethodSignature:downloaderFinishMethodSignature]; [downloaderFinishMethodInvocation setTarget:self]; [downloaderFinishMethodInvocation setSelector:downloaderFinishSelector]; NSData *resultData = [[NSData alloc] init]; NSURLResponse *response; NSError *error; if ([self.request isRelatedToTest:@"test.multipart.data"]) { response = [self checkMultipartData] ? [self successResponse] : [self failureResponse]; } else if ([self.request isRelatedToTest:@"test.method.without.blocks"] || [self.request isRelatedToTest:@"test.simple.call"]) { response = [self successResponse]; } else if ([self.request isRelatedToTest:@"test.serializer"]) { response = [self checkXMLSerializedRequestData] ? [self successResponse] : [self failureResponse]; if ([self.request.HTTPMethod isEqual:@"GET"]) { NSString *unescapedString = [[self.request.URL query] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; resultData = [unescapedString dataUsingEncoding:NSWindowsCP1251StringEncoding]; } else { resultData = self.request.HTTPBody; } } else if ([self.request isRelatedToTest:@"test.cache.pragma"]) { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{@"Pragma" : @"no-cache"}]; resultData = [RFDownloader generateDateBasedData]; } else if ([self.request isRelatedToTest:@"test.cache.cache-control.no-cache"] || [self.request isRelatedToTest:@"http://test.cache.max-age.attr"]) { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{@"Cache-Control" : @"must-revalidate, max-age=0, no-cache"}]; resultData = [RFDownloader generateDateBasedData]; } else if ([self.request isRelatedToTest:@"test.cache.no.cache.headers"]) { response = [self successResponse]; resultData = [RFDownloader generateDateBasedData]; } else if ([self.request isRelatedToTest:@"test.expires.header"]) { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{@"Expires" : [RFDownloader httpDatePlusFiveMinute]}]; resultData = [RFDownloader generateDateBasedData]; } else if ([self.request isRelatedToTest:@"test.max-age.header"]) { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{@"Cache-Control" : @"max-age=300"}]; resultData = [RFDownloader generateDateBasedData]; } else if ([self.request isRelatedToTest:@"test.cache.last.modified"]) { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{@"Last-Modified" : [RFDownloader httpDatePlusFiveMinute]}]; resultData = [RFDownloader generateDateBasedData]; } else if ([self.request isRelatedToTest:@"test.cache.etag"]) { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{@"ETag" : [[NSString alloc] initWithData:[RFDownloader generateDateBasedData] encoding:NSUTF8StringEncoding]}]; resultData = [RFDownloader generateDateBasedData]; } else if ([self.request isRelatedToTest:@"test.cache.same.last.modified"]) { if ([(self.request.allHTTPHeaderFields)[@"If-Modified-Since"] isEqualToString:@"Sat, 29 Oct 1994 19:43:31 GMT"]) { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:304 HTTPVersion:@"HTTP/1.1" headerFields:nil]; } else { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{@"Last-Modified" : @"Sat, 29 Oct 1994 19:43:31 GMT"}]; resultData = [RFDownloader generateDateBasedData]; } } else if ([self.request isRelatedToTest:@"test.cache.same.etag"]) { if ([(self.request.allHTTPHeaderFields)[@"If-None-Match"] isEqualToString:@"4a7sd47ads5789a6sd"]) { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:304 HTTPVersion:@"HTTP/1.1" headerFields:nil]; } else { response = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{@"ETag" : @"4a7sd47ads5789a6sd"}]; resultData = [RFDownloader generateDateBasedData]; } } else if ([self.request isRelatedToTest:@"test.body.existence/"]) { if ([self.request.HTTPBody length] > 0) { response = [self successResponse]; } else { response = [self failureResponse]; error = [NSError errorWithDomain:@"1" code:1 userInfo:nil]; } } else if ([self.request isRelatedToTest:@"test.cache.identifier"]) { response = [self successResponse]; resultData = [RFDownloader generateDateBasedData]; } else if ([self.request isRelatedToTest:@"test.cache.offline.max-age"]) { if ([[self.request.allHTTPHeaderFields objectForKey:@"no-connection"] isEqualToString:@"YES"]) { response = nil; resultData = nil; } else { response = [self successResponse]; resultData = [RFDownloader generateDateBasedData]; } } else if ([self.request isRelatedToTest:@"test.headerfields.dictionary"]) { response = [self successResponse]; resultData = [NSJSONSerialization dataWithJSONObject:@{@"test": @"dictionary"} options:NSJSONWritingPrettyPrinted error:nil]; } else if ([self.request isRelatedToTest:@"test.headerfields.object"]) { response = [self successResponse]; RFAttachmentTestObject* testObject = [[RFAttachmentTestObject alloc] init]; testObject.name = @"header fields attachment"; NSString * testString = [RFAttributedCoder encodeRootObject:testObject]; resultData = [testString dataUsingEncoding:NSUTF8StringEncoding]; } else if ([self.request isRelatedToTest:@"test.headerfields.array"]) { response = [self successResponse]; resultData = [NSJSONSerialization dataWithJSONObject:@[@"test", @"array"] options:NSJSONWritingPrettyPrinted error:nil]; } else if ([self.request isRelatedToTest:@"test.headerfields.nobody"]) { response = [self successResponse]; resultData = nil; } else { // Not processed URL [self fakeStart]; return; } NSLog(@"Faking start of downloading at url: %@", self.request.URL); [downloaderFinishMethodInvocation setArgument:&resultData atIndex:2]; [downloaderFinishMethodInvocation setArgument:&response atIndex:3]; [downloaderFinishMethodInvocation setArgument:&error atIndex:4]; [downloaderFinishMethodInvocation invoke]; } #pragma mark - Checks - (BOOL)checkMultipartData { NSString *result = [[NSString alloc] initWithData:self.request.HTTPBody encoding:NSUTF8StringEncoding]; NSError *error = NULL; NSString *contentType = (self.request.allHTTPHeaderFields)[@"Content-Type"]; NSRange rangeBoundary = [contentType rangeOfString:@"boundary="]; NSRange rangeWithoutBoundary = NSMakeRange(0, rangeBoundary.location + rangeBoundary.length); NSString *boundary = [contentType stringByReplacingCharactersInRange:rangeWithoutBoundary withString:@""]; NSString *fullBoundary = [NSString stringWithFormat:@"\r\n--%@\r\n", boundary]; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:fullBoundary options:NSRegularExpressionCaseInsensitive error:&error]; NSUInteger numberOfMatches = [regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])]; BOOL isOkMultipartData = NO; // Number of boundaries have to be odd or for one attachment it has to be 2 if (numberOfMatches >= 2 && (numberOfMatches == 2 || numberOfMatches % 2 == 1)) { isOkMultipartData = YES; } else { NSLog(@"Number of matches exceed the limit - %lu", (unsigned long)numberOfMatches); NSLog(@"result - %@", result); NSLog(@"%@", self.request.allHTTPHeaderFields); } return isOkMultipartData; } - (BOOL)checkXMLSerializedRequestData { BOOL result = NO; NSString *body = [[NSString alloc] initWithData:self.request.HTTPBody encoding:NSUTF8StringEncoding]; RFAttributedXMLCoder *coder = [[RFAttributedXMLCoder alloc] init]; NSString *testBody = [coder encodeRootObject:[RFSerializableTestObject testObject]]; if ([testBody isEqualToString:body]) { result = YES; } return result; } - (NSHTTPURLResponse *)successResponse { return [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{}]; } - (NSHTTPURLResponse *)failureResponse { return [[NSHTTPURLResponse alloc] initWithURL:self.request.URL statusCode:400 HTTPVersion:@"HTTP/1.1" headerFields:@{}]; } + (NSData *)generateDateBasedData { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateFormat = @"yyyy/MM/dd HH:mm:ss.SSS ZZZ"; return [[dateFormatter stringFromDate:[NSDate date]] dataUsingEncoding:NSUTF8StringEncoding]; } + (NSString *)httpDatePlusFiveMinute { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss zzz"; NSTimeZone *gmt = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; [dateFormatter setTimeZone:gmt]; NSString *timeStamp = [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow:300]]; return timeStamp; } @end