diff --git a/Mocktail/Mocktail.m b/Mocktail/Mocktail.m index 62f26bb..329628a 100644 --- a/Mocktail/Mocktail.m +++ b/Mocktail/Mocktail.m @@ -218,42 +218,22 @@ - (void)registerContentsOfDirectoryAtURL:(NSURL *)url; - (void)registerFileAtURL:(NSURL *)url; { - NSAssert(url, @"Expected valid URL."); - - NSError *error; - NSStringEncoding originalEncoding; - NSString *contentsOfFile = [NSString stringWithContentsOfURL:url usedEncoding:&originalEncoding error:&error]; - if (error) { - NSLog(@"Error opening %@: %@", url, error); - return; - } - - NSScanner *scanner = [NSScanner scannerWithString:contentsOfFile]; - NSString *headerMatter = nil; - [scanner scanUpToString:@"\n\n" intoString:&headerMatter]; - NSArray *lines = [headerMatter componentsSeparatedByString:@"\n"]; - if ([lines count] < 4) { - NSLog(@"Invalid amount of lines: %u", (unsigned)[lines count]); - return; - } - - MocktailResponse *response = [MocktailResponse new]; - response.mocktail = self; - response.methodRegex = [NSRegularExpression regularExpressionWithPattern:lines[0] options:NSRegularExpressionCaseInsensitive error:nil]; - response.absoluteURLRegex = [NSRegularExpression regularExpressionWithPattern:lines[1] options:NSRegularExpressionCaseInsensitive error:nil]; - response.statusCode = [lines[2] integerValue]; - NSMutableDictionary *headers = [[NSMutableDictionary alloc] init]; - for (NSString *line in [lines subarrayWithRange:NSMakeRange(3, lines.count - 3)]) { - NSArray* parts = [line componentsSeparatedByString:@":"]; - [headers setObject:[[parts lastObject] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] - forKey:[parts firstObject]]; + NSError *mocktailResponseError; + MocktailResponse *response = [MocktailResponse mocktailResponseForFileAtURL:url error:&mocktailResponseError]; + + if (mocktailResponseError) { + if (mocktailResponseError.code == MocktailResponseErrorOpeningFile) { + NSLog(@"Error opening %@: %@", url, mocktailResponseError.userInfo[kFileErrorUserDataKey]); + } else if (mocktailResponseError.code == MocktailResponseErrorNumberOfLines) { + NSLog(@"Invalid amount of lines: %u", (unsigned)[mocktailResponseError.userInfo[kNumberOfLinesErrorUserDataKey] count]); + } } - response.headers = headers; - response.fileURL = url; - response.bodyOffset = [headerMatter dataUsingEncoding:originalEncoding].length + 2; - + @synchronized (_mutableMockResponses) { - [_mutableMockResponses addObject:response]; + if (response) { + response.mocktail = self; + [_mutableMockResponses addObject:response]; + } } } diff --git a/Mocktail/MocktailResponse.h b/Mocktail/MocktailResponse.h index 37e952c..7d70b58 100644 --- a/Mocktail/MocktailResponse.h +++ b/Mocktail/MocktailResponse.h @@ -9,18 +9,31 @@ #import +extern NSString *const kMocktailResponseErrorDomain; +extern NSString *const kFileErrorUserDataKey; +extern NSString *const kNumberOfLinesErrorUserDataKey; -@class Mocktail; +typedef NS_ENUM(NSInteger, MockTailResponseError) { + MocktailResponseErrorOpeningFile, + MocktailResponseErrorNumberOfLines +}; +@class Mocktail; @interface MocktailResponse : NSObject -@property (nonatomic, strong) NSRegularExpression *methodRegex; -@property (nonatomic, strong) NSRegularExpression *absoluteURLRegex; -@property (nonatomic, strong) NSURL *fileURL; -@property (nonatomic) NSInteger bodyOffset; -@property (nonatomic, strong) NSDictionary *headers; -@property (nonatomic) NSInteger statusCode; +@property (nonatomic, strong, readonly) NSRegularExpression *methodRegex; +@property (nonatomic, strong, readonly) NSRegularExpression *absoluteURLRegex; +@property (nonatomic, strong, readonly) NSURL *fileURL; +@property (nonatomic, readonly) NSInteger bodyOffset; +@property (nonatomic, strong, readonly) NSDictionary *headers; +@property (nonatomic, readonly) NSInteger statusCode; @property (nonatomic, weak) Mocktail *mocktail; +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithFileAtURL:(NSURL *)fileURL error:(NSError **)error NS_DESIGNATED_INITIALIZER; + ++ (MocktailResponse *)mocktailResponseForFileAtURL:(NSURL *)url error:(NSError **)error; + @end diff --git a/Mocktail/MocktailResponse.m b/Mocktail/MocktailResponse.m index 7c8912d..c0fd60a 100644 --- a/Mocktail/MocktailResponse.m +++ b/Mocktail/MocktailResponse.m @@ -10,6 +10,68 @@ #import "MocktailResponse.h" +@interface MocktailResponse() + +@property (nonatomic, strong) NSRegularExpression *methodRegex; +@property (nonatomic, strong) NSRegularExpression *absoluteURLRegex; +@property (nonatomic, strong) NSURL *fileURL; +@property (nonatomic) NSInteger bodyOffset; +@property (nonatomic, strong) NSDictionary *headers; +@property (nonatomic) NSInteger statusCode; + +@end + +NSString *const kMocktailResponseErrorDomain = @"MocktailResponseError"; +NSString *const kFileErrorUserDataKey = @"fileError"; +NSString *const kNumberOfLinesErrorUserDataKey = @"lines"; +static NSUInteger const kNumLinesRequired = 4; @implementation MocktailResponse + +- (instancetype)initWithFileAtURL:(NSURL *)url error:(NSError *__autoreleasing *)error { + self = [super init]; + if (self) { + NSError *fileError; + NSStringEncoding originalEncoding; + NSString *contentsOfFile = [NSString stringWithContentsOfURL:url usedEncoding:&originalEncoding error:&fileError]; + if (fileError) { + *error = [[NSError alloc] initWithDomain:kMocktailResponseErrorDomain + code:MocktailResponseErrorOpeningFile + userInfo:@{kFileErrorUserDataKey: fileError}]; + return nil; + } + + NSScanner *scanner = [NSScanner scannerWithString:contentsOfFile]; + NSString *headerMatter = nil; + [scanner scanUpToString:@"\n\n" intoString:&headerMatter]; + NSArray *lines = [headerMatter componentsSeparatedByString:@"\n"]; + if ([lines count] < kNumLinesRequired) { + *error = [[NSError alloc] initWithDomain:kMocktailResponseErrorDomain + code:MocktailResponseErrorNumberOfLines + userInfo:@{kNumberOfLinesErrorUserDataKey: lines}]; + return nil; + } + + _methodRegex = [NSRegularExpression regularExpressionWithPattern:lines[0] options:NSRegularExpressionCaseInsensitive error:nil]; + _absoluteURLRegex = [NSRegularExpression regularExpressionWithPattern:lines[1] options:NSRegularExpressionCaseInsensitive error:nil]; + _statusCode = [lines[2] integerValue]; + NSMutableDictionary *headers = [[NSMutableDictionary alloc] init]; + for (NSString *line in [lines subarrayWithRange:NSMakeRange(3, lines.count - 3)]) { + NSArray* parts = [line componentsSeparatedByString:@":"]; + headers[[parts firstObject]] = [[parts lastObject] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + } + _headers = headers; + _fileURL = url; + _bodyOffset = [headerMatter dataUsingEncoding:originalEncoding].length + 2; + } + + return self; +} + ++ (MocktailResponse *)mocktailResponseForFileAtURL:(NSURL *)url error:(NSError *__autoreleasing *)error { + NSAssert(url, @"Expected valid URL."); + + return [[MocktailResponse alloc] initWithFileAtURL:url error:error]; +} + @end