Add tests for CDVFileTransfer.

Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/commit/dea6eb24
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/tree/dea6eb24
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/diff/dea6eb24

Branch: refs/heads/master
Commit: dea6eb24d6fdf37c0fa30b7194f91b4c100b0f49
Parents: e642925
Author: Andrew Grieve <[email protected]>
Authored: Tue Jul 10 23:32:10 2012 -0400
Committer: Shazron Abdullah <[email protected]>
Committed: Wed Jul 11 14:23:01 2012 -0700

----------------------------------------------------------------------
 CordovaLib/Classes/CDVFileTransfer.h              |    5 +-
 CordovaLib/Classes/CDVFileTransfer.m              |   43 +++--
 CordovaLib/CordovaLibTests/CDVFileTransferTests.m |  171 ++++++++++++++++
 3 files changed, 200 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/dea6eb24/CordovaLib/Classes/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFileTransfer.h 
b/CordovaLib/Classes/CDVFileTransfer.h
index 4289074..54a37b3 100644
--- a/CordovaLib/Classes/CDVFileTransfer.h
+++ b/CordovaLib/Classes/CDVFileTransfer.h
@@ -34,6 +34,9 @@ enum CDVFileTransferDirection {
 };
 typedef int CDVFileTransferDirection;
 
+// Magic value within the options dict used to set a cookie.
+extern NSString* const kOptionsKeyCookie;
+
 @interface CDVFileTransfer : CDVPlugin {
     
 }
@@ -43,7 +46,7 @@ typedef int CDVFileTransferDirection;
 - (NSString*) escapePathComponentForUrlString:(NSString*)urlString;
 
 // Visible for testing.
-- (NSURLRequest*) requestForUpload:(NSArray*)arguments 
withDict:(NSDictionary*)options;
+- (NSURLRequest*) requestForUpload:(NSArray*)arguments 
withDict:(NSDictionary*)options fileData:(NSData*)fileData;
 -(NSMutableDictionary*) createFileTransferError:(int)code 
AndSource:(NSString*)source AndTarget:(NSString*)target;
 
 -(NSMutableDictionary*) createFileTransferError:(int)code 

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/dea6eb24/CordovaLib/Classes/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFileTransfer.m 
b/CordovaLib/Classes/CDVFileTransfer.m
index fb3a723..b7c16d0 100644
--- a/CordovaLib/Classes/CDVFileTransfer.m
+++ b/CordovaLib/Classes/CDVFileTransfer.m
@@ -22,13 +22,16 @@
 #include <CFNetwork/CFNetwork.h>
 
 @interface CDVFileTransfer ()
-- (CDVFileTransferDelegate*) delegateForUpload:(NSArray*)arguments;
+// Creates a delegate to handle an upload.
+- (CDVFileTransferDelegate*)delegateForUpload:(NSArray*)arguments;
+// Creates an NSData* for the file for the given upload arguments.
+- (NSData*)fileDataForUploadArguments:(NSArray*)arguments;
 @end
 
 // Buffer size to use for streaming uploads.
 static const NSUInteger kStreamBufferSize = 32768;
 // Magic value within the options dict used to set a cookie.
-static NSString* kOptionsKeyCookie = @"__cookie";
+NSString* const kOptionsKeyCookie = @"__cookie";
 
 // Writes the given data to the stream in a blocking way.
 // If successful, returns bytesToWrite.
@@ -79,7 +82,7 @@ static CFIndex WriteDataToStream(NSData* data, 
CFWriteStreamRef stream) {
     return [urlString stringByAppendingString:pathComponent];
 }
 
-- (NSURLRequest*) requestForUpload:(NSArray*)arguments 
withDict:(NSDictionary*)options {
+- (NSURLRequest*) requestForUpload:(NSArray*)arguments 
withDict:(NSDictionary*)options fileData:(NSData*)fileData {
     NSString* callbackId = [arguments objectAtIndex:0];
     
     // arguments order from js: [filePath, server, fileKey, fileName, 
mimeType, params, debug, chunkedMode]
@@ -101,27 +104,17 @@ static CFIndex WriteDataToStream(NSData* data, 
CFWriteStreamRef stream) {
         chunkedMode = NO;
     }
 
-    // Extract the path part out of a file: URL.
-    NSString* filePath = [target hasPrefix:@"/"] ? [[target copy] autorelease] 
: [[NSURL URLWithString:target] path];
-    
     CDVPluginResult* result = nil;
     CDVFileTransferError errorCode = 0;
 
     
     NSURL *url = [NSURL URLWithString:[self 
escapePathComponentForUrlString:server]];
-    NSData *fileData = nil;
     
     if (!url) {
         errorCode = INVALID_URL_ERR;
         NSLog(@"File Transfer Error: Invalid server URL %@", server);
-    } else {
-        NSError *err = nil;
-        // Memory map the file so that it can be read efficiently even if it 
is large.
-        fileData = [NSData dataWithContentsOfFile:filePath 
options:NSDataReadingMappedIfSafe error:&err];
-        if (!fileData) {
-            errorCode = FILE_NOT_FOUND_ERR;
-            NSLog(@"File Transfer Error: Could not read file data %@", 
filePath);
-        }
+    } else if (!fileData) {
+        errorCode = FILE_NOT_FOUND_ERR;
     }
     
     if(errorCode > 0) {
@@ -208,10 +201,8 @@ static CFIndex WriteDataToStream(NSData* data, 
CFWriteStreamRef stream) {
     DLog(@"fileData length: %d", [fileData length]);
        NSData *postBodyAfterFile = [[NSString 
stringWithFormat:@"\r\n--%@--\r\n", boundary] 
dataUsingEncoding:NSUTF8StringEncoding];
 
-    
     NSUInteger totalPayloadLength = [postBodyBeforeFile length] + [fileData 
length] + [postBodyAfterFile length];
     [req setValue:[[NSNumber numberWithInteger:totalPayloadLength] 
stringValue] forHTTPHeaderField:@"Content-Length"];
-
        
     
     if (chunkedMode) {
@@ -258,8 +249,24 @@ static CFIndex WriteDataToStream(NSData* data, 
CFWriteStreamRef stream) {
     return delegate;
 }
 
+- (NSData*) fileDataForUploadArguments:(NSArray*)arguments {
+    NSString* target = (NSString*)[arguments objectAtIndex:1];
+    NSError *err = nil;
+    // Extract the path part out of a file: URL.
+    NSString* filePath = [target hasPrefix:@"/"] ? [[target copy] autorelease] 
: [[NSURL URLWithString:target] path];
+
+    // Memory map the file so that it can be read efficiently even if it is 
large.
+    NSData* fileData = [NSData dataWithContentsOfFile:filePath 
options:NSDataReadingMappedIfSafe error:&err];
+    if (err != nil) {
+        NSLog(@"Error opening file %@: %@", target, err);
+    }
+    return fileData;
+}
+
 - (void) upload:(NSArray*)arguments withDict:(NSDictionary*)options {
-    NSURLRequest* req = [self requestForUpload:arguments withDict:options];
+    // fileData and req are split into helper functions to ease the unit 
testing of delegateForUpload.
+    NSData* fileData = [self fileDataForUploadArguments:arguments];
+    NSURLRequest* req = [self requestForUpload:arguments withDict:options 
fileData:fileData];
     CDVFileTransferDelegate* delegate = [self delegateForUpload:arguments];
        [NSURLConnection connectionWithRequest:req delegate:delegate];
 }

http://git-wip-us.apache.org/repos/asf/incubator-cordova-ios/blob/dea6eb24/CordovaLib/CordovaLibTests/CDVFileTransferTests.m
----------------------------------------------------------------------
diff --git a/CordovaLib/CordovaLibTests/CDVFileTransferTests.m 
b/CordovaLib/CordovaLibTests/CDVFileTransferTests.m
new file mode 100644
index 0000000..cfdfa48
--- /dev/null
+++ b/CordovaLib/CordovaLibTests/CDVFileTransferTests.m
@@ -0,0 +1,171 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you 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 <SenTestingKit/SenTestingKit.h>
+
+#import "CDV.h"
+
+static NSString* const kDummyArgCallbackId = @"cid0";
+static NSString* const kDummyArgFileKey = @"image.jpg";
+static NSString* const kDummyArgTarget = @"/path/to/image.jpg";
+static NSString* const kDummyArgServer = @"http://apache.org";;
+static NSString* const kDummyFileContents = @"0123456789";
+
+// Reads the given stream and returns the contents as an NSData.
+static NSData* readStream(NSInputStream* stream) {
+    static const NSUInteger kBufferSize = 1024;
+        
+    UInt8* buffer = malloc(kBufferSize);
+    NSMutableData* streamData = [NSMutableData data];
+    
+    [stream open];
+    for (;;) {
+        NSInteger read = [stream read:buffer maxLength:kBufferSize];
+        if (read > 0) {
+            [streamData appendBytes:buffer length:read];
+        } else {
+            break;
+        }
+    }
+    free(buffer);
+    [stream close];
+    return streamData;
+}
+
+@interface CDVFileTransferTests : SenTestCase {
+    NSMutableArray* _arguments;
+    CDVFileTransfer* _fileTransfer;
+    NSData* _dummyFileData;
+}
+@end
+
+@implementation CDVFileTransferTests
+
+- (void)setUp
+{
+    [super setUp];
+    _arguments = [[NSMutableArray alloc] initWithObjects:
+        kDummyArgCallbackId, kDummyArgTarget, kDummyArgServer, 
kDummyArgFileKey,
+        [NSNull null], [NSNull null], [NSNull null], [NSNull null], nil];
+    _dummyFileData = [[kDummyFileContents 
dataUsingEncoding:NSUTF8StringEncoding] retain];
+    _fileTransfer = [[CDVFileTransfer alloc] init];
+}
+
+- (void)tearDown
+{
+    [_arguments release];
+    _arguments = nil;
+    [_dummyFileData release];
+    _dummyFileData = nil;
+    [_fileTransfer release];
+    _fileTransfer = nil;
+    [super tearDown];
+}
+
+- (void)setFilePathArg:(NSString*)filePath {
+    [_arguments replaceObjectAtIndex:1 withObject:filePath];
+}
+
+- (void)setServerUrlArg:(NSString*)serverUrl {
+    [_arguments replaceObjectAtIndex:2 withObject:serverUrl];
+}
+
+- (void)setChunkedModeArg:(BOOL)chunk {
+    [_arguments replaceObjectAtIndex:7 withObject:[NSNumber 
numberWithBool:chunk]];
+}
+
+- (NSURLRequest*)requestForUpload {
+    return [_fileTransfer requestForUpload:_arguments withDict:nil 
fileData:_dummyFileData];
+}
+
+- (void)checkUploadRequest:(NSURLRequest*)request chunked:(BOOL)chunked {
+    STAssertTrue([@"POST" isEqualToString:[request HTTPMethod]], nil);
+    NSData* payloadData = nil;
+    if (chunked) {
+        STAssertNil([request HTTPBody], nil);
+        STAssertNotNil([request HTTPBodyStream], nil);
+        payloadData = readStream([request HTTPBodyStream]);
+    } else {
+        STAssertNotNil([request HTTPBody], nil);
+        STAssertNil([request HTTPBodyStream], nil);
+        payloadData = [request HTTPBody];
+    }
+    NSUInteger contentLength = [[request 
valueForHTTPHeaderField:@"Content-Length"] intValue];
+    STAssertEquals([payloadData length], contentLength, nil);
+}
+
+- (void)testUpload_invalidServerUrl
+{
+    [self setServerUrlArg:@"invalid url"];
+    STAssertNil([self requestForUpload], nil);
+}
+
+- (void)testUpload_missingFileData
+{
+    [_dummyFileData release];
+    _dummyFileData = nil;
+    STAssertNil([self requestForUpload], nil);
+}
+
+- (void)testUpload_serverUrlPathEscaping
+{
+    [self setServerUrlArg:@"http://apache.org/spa ce%"];
+    NSURLRequest* request = [self requestForUpload];
+    STAssertTrue([[[request URL] absoluteString] 
isEqualToString:@"http://apache.org/spa%20ce%25";], nil);
+}
+
+- (void)testUpload_nonChunked
+{
+    [self setChunkedModeArg:NO];
+    NSURLRequest* request = [self requestForUpload];
+    [self checkUploadRequest:request chunked:NO];
+}
+
+- (void)testUpload_chunked
+{
+    // As noted in the implementation, chunked upload is disabled pre 5.0.
+    if (!IsAtLeastiOSVersion(@"5.0")) {
+        return;
+    }
+    // Chunked is the default.
+    NSURLRequest* request = [self requestForUpload];
+    [self checkUploadRequest:request chunked:YES];
+}
+
+- (void)testUpload_withOptions
+{
+    [self setChunkedModeArg:NO];
+    NSDictionary* headers = [NSDictionary 
dictionaryWithObjectsAndKeys:@"val1", @"key1",
+        @"val2", @"key2", nil];
+    NSDictionary* options = [NSDictionary 
dictionaryWithObjectsAndKeys:@"cookieval", kOptionsKeyCookie,
+        headers, @"headers", @"val3", @"key3", nil];
+    NSURLRequest* request = [_fileTransfer requestForUpload:_arguments 
withDict:options fileData:_dummyFileData];
+    NSString* payload = [[[NSString alloc] initWithData:[request HTTPBody] 
encoding:NSUTF8StringEncoding] autorelease];
+    // Check that headers are properly set.
+    STAssertTrue([@"val1" isEqualToString:[request 
valueForHTTPHeaderField:@"key1"]], nil);
+    STAssertTrue([@"val2" isEqualToString:[request 
valueForHTTPHeaderField:@"key2"]], nil);
+    // Check that the cookie is set, and that it is not in the payload like 
others in the options dict.
+    STAssertTrue([@"cookieval" isEqualToString:[request 
valueForHTTPHeaderField:@"Cookie"]], nil);
+    STAssertEquals([payload rangeOfString:@"cookieval"].length, 0U, nil);
+    // Check that key3 is in the payload.
+    STAssertTrue([payload rangeOfString:@"key3"].length > 0, nil);
+    STAssertTrue([payload rangeOfString:@"val3"].length > 0, nil);
+}
+
+@end

Reply via email to