Skip to content

Commit

Permalink
Address feedback from Olivier and a bit of refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
JinlianWang committed Aug 2, 2015
1 parent 04d8c17 commit 7fc169c
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 47 deletions.
2 changes: 2 additions & 0 deletions OHHTTPStubs/OHHTTPStubs.xcodeproj/project.pbxproj
Expand Up @@ -51,6 +51,7 @@
095B1AD91AE31396009D1B56 /* OHPathHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 095B1AD41AE30BA7009D1B56 /* OHPathHelpers.m */; };
095B1ADA1AE313E0009D1B56 /* OHPathHelpers.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 095B1AD31AE30BA7009D1B56 /* OHPathHelpers.h */; };
0DB397E35DDB6808A5496D53 /* libPods-OHHTTPStubs Mac Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F49690D948DE88BBB4A36B11 /* libPods-OHHTTPStubs Mac Tests.a */; };
1D0F8E6B1B6D89890049A7D2 /* OHHTTPStubs+Mocktail.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D664C871B6A9AC00053CD7E /* OHHTTPStubs+Mocktail.m */; };
1D664C881B6A9AC00053CD7E /* OHHTTPStubs+Mocktail.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D664C871B6A9AC00053CD7E /* OHHTTPStubs+Mocktail.m */; };
1D664C8A1B6A9BCC0053CD7E /* MocktailFolder in Resources */ = {isa = PBXBuildFile; fileRef = 1D664C891B6A9BCC0053CD7E /* MocktailFolder */; };
1D664C921B6A9EAC0053CD7E /* login.tail in Resources */ = {isa = PBXBuildFile; fileRef = 1D664C7F1B6A98080053CD7E /* login.tail */; };
Expand Down Expand Up @@ -686,6 +687,7 @@
725CD9B71A9EB6FD00F84C8B /* OHHTTPStubsResponse+JSON.m in Sources */,
725CD9B61A9EB6FA00F84C8B /* OHHTTPStubsResponse+HTTPMessage.m in Sources */,
095B1AD81AE31395009D1B56 /* OHPathHelpers.m in Sources */,
1D0F8E6B1B6D89890049A7D2 /* OHHTTPStubs+Mocktail.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
19 changes: 16 additions & 3 deletions OHHTTPStubs/Sources/OHHTTPStubs+Mocktail.h
Expand Up @@ -8,6 +8,19 @@

#import "OHHTTPStubs.h"

typedef enum : NSInteger {
kErrorPathDoesNotExist = 1,
kErrorPathIsNotFolder,
kErrorPathDoesNotRead,
kErrorFileDoesNotExist,
kErrorFileDoesNotRead,
kErrorFileFormatInvalid,
kErrorFileHeaderInvalid,
kErrorFileInternalError
} Stub_Mocktail_Error_TYPE;

extern NSString* const MocktailErrorDomain;

@interface OHHTTPStubs (Mocktail)

/**
Expand All @@ -22,7 +35,7 @@
* @return a stub descriptor that uniquely identifies the stub and can be later used to remove it with
* `removeStub:`.
*/
+(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktailNamed:(NSString *)fileName;
+(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktailNamed:(NSString *)fileName error:(NSError **)error;

/**
* Add a stub given a file URL in the format of Mocktail as defined at https://github.com/square/objc-mocktail.
Expand All @@ -36,7 +49,7 @@
* @return a stub descriptor that uniquely identifies the stub and can be later used to remove it with
* `removeStub:`.
*/
+(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktail:(NSURL *)fileURL;
+(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktail:(NSURL *)fileURL error:(NSError **)error;

/**
* Add stubs using files under a folder URL in the format of Mocktail as defined at https://github.com/square/objc-mocktail.
Expand All @@ -50,6 +63,6 @@
* @return an array of stub descriptor that uniquely identifies the stub and can be later used to remove it with
* `removeStub:`.
*/
+(NSArray *)stubRequestsUsingMocktailsAt:(NSURL*)dirURL;
+(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path error:(NSError **)error;

@end
81 changes: 53 additions & 28 deletions OHHTTPStubs/Sources/OHHTTPStubs+Mocktail.m
Expand Up @@ -8,26 +8,39 @@

#import "OHHTTPStubs+Mocktail.h"

@class OHHTTPStubsDescriptor;
NSString* const MocktailErrorDomain = @"Mocktail";

@implementation OHHTTPStubs (Mocktail)


+(NSArray *)stubRequestsUsingMocktailsAt:(NSURL *)dirURL{
+(NSArray *)stubRequestsUsingMocktailsAtPath:(NSString *)path error:(NSError **)error{
NSString *dirPath = OHPathForFile(path, [self class]);
if(!dirPath){
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorPathDoesNotExist userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Path '%@' does not exist.", path] forKey:NSLocalizedDescriptionKey]];
return nil;
}

//make sure path points to a directory
BOOL isDir = NO, exists = NO;
NSError *error = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
exists = [fileManager fileExistsAtPath:dirURL.path isDirectory:&isDir];
if(!dirURL || !exists){
NSLog(@"Error opening %@: %@", dirURL.absoluteString, error);
exists = [fileManager fileExistsAtPath:dirPath isDirectory:&isDir];
if(!exists){
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorPathDoesNotExist userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Path '%@' does not exist.", path] forKey:NSLocalizedDescriptionKey]];
return nil;
}

if(!isDir){
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorPathIsNotFolder userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Path '%@' is not a folder.", path] forKey:NSLocalizedDescriptionKey]];
return nil;
}

//read the content of the directory
NSArray *fileURLs = [fileManager contentsOfDirectoryAtURL:dirURL includingPropertiesForKeys:nil options:0 error:&error];
if (error) {
NSLog(@"Error opening %@: %@", dirURL.absoluteString, error);
NSError *bError = nil;
NSURL *dirURL = [NSURL fileURLWithPath:dirPath];
NSArray *fileURLs = [fileManager contentsOfDirectoryAtURL:dirURL includingPropertiesForKeys:nil options:0 error:&bError];

if(bError){
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorPathDoesNotRead userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Error reading path '%@'.", dirURL.absoluteString] forKey:NSLocalizedDescriptionKey]];
return nil;
}

Expand All @@ -37,31 +50,32 @@ +(NSArray *)stubRequestsUsingMocktailsAt:(NSURL *)dirURL{
if (![[fileURL absoluteString] hasSuffix:@".tail"]) {
continue;
}
id<OHHTTPStubsDescriptor> descriptor = [[self class] stubRequestsUsingMocktail:fileURL];
if(descriptor){
id<OHHTTPStubsDescriptor> descriptor = [[self class] stubRequestsUsingMocktail:fileURL error: &bError];
if(descriptor && !bError){
[descriptorArray addObject:descriptor];
}
}

return descriptorArray;
}

+(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktailNamed:(NSString *)fileName{
+(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktailNamed:(NSString *)fileName error:(NSError **)error{
NSString *path = OHPathForFile(fileName, [self class]);
if(!path || ![[NSFileManager defaultManager] fileExistsAtPath:path]){
NSLog(@"File not exists at:%@", path);
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorFileDoesNotExist userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"File '%@' does not exist.", fileName] forKey:NSLocalizedDescriptionKey]];
return nil;
} else {
return [[self class] stubRequestsUsingMocktail:[NSURL fileURLWithPath:path]];
return [[self class] stubRequestsUsingMocktail:[NSURL fileURLWithPath:path] error:error];
}
}

+(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktail:(NSURL *)fileURL{
NSError *error = nil;
+(id<OHHTTPStubsDescriptor>)stubRequestsUsingMocktail:(NSURL *)fileURL error:(NSError **)error{
NSError *bError = nil;
NSStringEncoding originalEncoding;
NSString *contentsOfFile = [NSString stringWithContentsOfURL:fileURL usedEncoding:&originalEncoding error:&error];
NSString *contentsOfFile = [NSString stringWithContentsOfURL:fileURL usedEncoding:&originalEncoding error:&bError];

if (!contentsOfFile || error) {
if (!contentsOfFile || bError) {
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorFileDoesNotRead userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"File '%@' does not read.", fileURL.absoluteString] forKey:NSLocalizedDescriptionKey]];
return nil;
}

Expand All @@ -70,23 +84,36 @@ +(NSArray *)stubRequestsUsingMocktailsAt:(NSURL *)dirURL{
[scanner scanUpToString:@"\n\n" intoString:&headerMatter];
NSArray *lines = [headerMatter componentsSeparatedByString:@"\n"];
if ([lines count] < 4) {
if (error) {
error = [NSError errorWithDomain:@"Mocktail" code:0 userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Invalid amount of lines: %u", (unsigned)[lines count]]}];
}
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorFileFormatInvalid userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"File '%@' has invalid amount of lines:%u.", fileURL.absoluteString, (unsigned)[lines count]] forKey:NSLocalizedDescriptionKey]];
return nil;
}

/*handle Mocktail format, adapted from Mocktail implementation, for more details on the file format, check out: https://github.com/square/objc-Mocktail*/
NSRegularExpression *methodRegex = [NSRegularExpression regularExpressionWithPattern:lines[0] options:NSRegularExpressionCaseInsensitive error:nil];
NSRegularExpression *methodRegex = [NSRegularExpression regularExpressionWithPattern:lines[0] options:NSRegularExpressionCaseInsensitive error:&bError];

if(bError){
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorFileFormatInvalid userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"File '%@' has invalid method regular expression pattern: %@.", fileURL.absoluteString, lines[0]] forKey:NSLocalizedDescriptionKey]];
return nil;
}

NSRegularExpression *absoluteURLRegex = [NSRegularExpression regularExpressionWithPattern:lines[1] options:NSRegularExpressionCaseInsensitive error:&bError];

NSRegularExpression *absoluteURLRegex = [NSRegularExpression regularExpressionWithPattern:lines[1] options:NSRegularExpressionCaseInsensitive error:nil];
if(bError){
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorFileFormatInvalid userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"File '%@' has invalid URL regular expression pattern: %@.", fileURL.absoluteString, lines[1]] forKey:NSLocalizedDescriptionKey]];
return nil;
}

NSInteger statusCode = [lines[2] integerValue];

NSMutableDictionary *headers = @{@"Content-Type":lines[3]}.mutableCopy;

// From line 5 to '\n\n', expect HTTP response headers.
NSRegularExpression *headerPattern = [NSRegularExpression regularExpressionWithPattern:@"^([^:]+):\\s+(.*)" options:0 error:NULL];
NSRegularExpression *headerPattern = [NSRegularExpression regularExpressionWithPattern:@"^([^:]+):\\s+(.*)" options:0 error:&bError];
if(bError){
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorFileInternalError userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Internal error while stubbing file '%@'.", fileURL.absoluteString] forKey:NSLocalizedDescriptionKey]];
return nil;
}

for (NSUInteger line = 4; line < lines.count; line ++) {
NSString *headerLine = lines[line];
NSTextCheckingResult *match = [headerPattern firstMatchInString:headerLine options:0 range:NSMakeRange(0, headerLine.length)];
Expand All @@ -96,9 +123,7 @@ +(NSArray *)stubRequestsUsingMocktailsAt:(NSURL *)dirURL{
NSString *value = [headerLine substringWithRange:[match rangeAtIndex:2]];
headers[key] = value;
} else {
if (error) {
error = [NSError errorWithDomain:@"Mocktail" code:0 userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Invalid header line: %@", headerLine]}];
}
*error = [NSError errorWithDomain:MocktailErrorDomain code:kErrorFileHeaderInvalid userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"File '%@' has invalid header: %@.", fileURL.absoluteString, headerLine] forKey:NSLocalizedDescriptionKey]];
return nil;
}
}
Expand All @@ -117,7 +142,7 @@ +(NSArray *)stubRequestsUsingMocktailsAt:(NSURL *)dirURL{
} withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) {
OHHTTPStubsResponse *response = [OHHTTPStubsResponse responseWithFileAtPath:fileURL.path
statusCode:(int)statusCode headers:headers];
response.bodyOffset = [headerMatter dataUsingEncoding:NSUTF8StringEncoding].length + 2;
[response.inputStream setProperty:[NSNumber numberWithUnsignedLongLong:([headerMatter dataUsingEncoding:NSUTF8StringEncoding].length + 2)] forKey:NSStreamFileCurrentOffsetKey];
return response;
}];
}
Expand Down
10 changes: 0 additions & 10 deletions OHHTTPStubs/Sources/OHHTTPStubs.m
Expand Up @@ -411,7 +411,6 @@ - (void)stopLoading
NSTimeInterval slotTime;
double chunkSizePerSlot;
double cumulativeChunkSize;
unsigned long long bodyOffset;
} OHHTTPStubsStreamTimingInfo;

- (void)streamDataForClient:(id<NSURLProtocolClient>)client
Expand Down Expand Up @@ -444,8 +443,6 @@ - (void)streamDataForClient:(id<NSURLProtocolClient>)client
timingInfo.chunkSizePerSlot = ((stubResponse.dataSize/stubResponse.responseTime) * timingInfo.slotTime);
}

timingInfo.bodyOffset = stubResponse.bodyOffset;

[self streamDataForClient:client
fromStream:stubResponse.inputStream
timingInfo:timingInfo
Expand Down Expand Up @@ -482,13 +479,6 @@ - (void) streamDataForClient:(id<NSURLProtocolClient>)client
timingInfo:timingInfo completion:completion];
}];
} else {
if(timingInfo.bodyOffset > 0){
//skip contenst until it reaches timeingInfo.bodyOffset
uint8_t* buffer = (uint8_t*)malloc(sizeof(uint8_t)*timingInfo.bodyOffset);
[inputStream read:buffer maxLength:timingInfo.bodyOffset];
timingInfo.bodyOffset = 0;
}

uint8_t* buffer = (uint8_t*)malloc(sizeof(uint8_t)*chunkSizeToRead);
NSInteger bytesRead = [inputStream read:buffer maxLength:chunkSizeToRead];
if (bytesRead > 0)
Expand Down
4 changes: 0 additions & 4 deletions OHHTTPStubs/Sources/OHHTTPStubsResponse.h
Expand Up @@ -84,10 +84,6 @@ OHHTTPStubsDownloadSpeedWifi;
* The size of the fake response body, in bytes.
*/
@property(nonatomic, assign) unsigned long long dataSize;
/**
* The offset of the fake response body, in bytes.
*/
@property(nonatomic, assign) unsigned long long bodyOffset;
/**
* The duration to wait before faking receiving the response headers.
*
Expand Down
8 changes: 6 additions & 2 deletions OHHTTPStubs/UnitTests/Test Suites/MocktailTests.m
Expand Up @@ -30,12 +30,16 @@ - (void)tearDown{
}

- (void)testMoctTailLoginSuccess {
[OHHTTPStubs stubRequestsUsingMocktailNamed:@"login.tail"];
NSError *error = nil;
[OHHTTPStubs stubRequestsUsingMocktailNamed:@"login.tail" error: &error];
XCTAssertNil(error, @"Error while stubbing 'login.tail':%@", [error localizedDescription]);
[self runLogin];
}

- (void)testMocktailsAtFolder{
[OHHTTPStubs stubRequestsUsingMocktailsAt:[NSURL fileURLWithPath:OHPathForFile(@"MocktailFolder", [self class])]];
NSError *error = nil;
[OHHTTPStubs stubRequestsUsingMocktailsAtPath:@"MocktailFolder" error:&error];
XCTAssertNil(error, @"Error while stubbing Mocktails at folder 'MocktailFolder': %@", [error localizedDescription]);
[self runLogin];
[self runGetCards];
}
Expand Down

0 comments on commit 7fc169c

Please sign in to comment.