diff --git a/Mocktail.xcodeproj/project.pbxproj b/Mocktail.xcodeproj/project.pbxproj index 7f864f7..bb3f250 100644 --- a/Mocktail.xcodeproj/project.pbxproj +++ b/Mocktail.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ A822634916C45BC4007C81BC /* Mocktail.m in Sources */ = {isa = PBXBuildFile; fileRef = A822634816C45BC4007C81BC /* Mocktail.m */; }; A822635016C45D9E007C81BC /* Mocktail.h in Headers */ = {isa = PBXBuildFile; fileRef = A822634616C45BC4007C81BC /* Mocktail.h */; settings = {ATTRIBUTES = (Public, ); }; }; A87D2F2316F3B6B700B594D6 /* Mocktail_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = A87D2F2216F3B6B700B594D6 /* Mocktail_Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + FECA012D1729B19800ED7F14 /* MImage.h in Headers */ = {isa = PBXBuildFile; fileRef = FECA012B1729B19800ED7F14 /* MImage.h */; }; + FECA012E1729B19800ED7F14 /* MImage.m in Sources */ = {isa = PBXBuildFile; fileRef = FECA012C1729B19800ED7F14 /* MImage.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -28,6 +30,8 @@ A822634616C45BC4007C81BC /* Mocktail.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Mocktail.h; sourceTree = ""; }; A822634816C45BC4007C81BC /* Mocktail.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Mocktail.m; sourceTree = ""; }; A87D2F2216F3B6B700B594D6 /* Mocktail_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mocktail_Private.h; sourceTree = ""; }; + FECA012B1729B19800ED7F14 /* MImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MImage.h; sourceTree = ""; }; + FECA012C1729B19800ED7F14 /* MImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MImage.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -70,6 +74,8 @@ A822634316C45BC4007C81BC /* Mocktail */ = { isa = PBXGroup; children = ( + FECA012B1729B19800ED7F14 /* MImage.h */, + FECA012C1729B19800ED7F14 /* MImage.m */, A822634616C45BC4007C81BC /* Mocktail.h */, A87D2F2216F3B6B700B594D6 /* Mocktail_Private.h */, A822634816C45BC4007C81BC /* Mocktail.m */, @@ -101,6 +107,7 @@ 39F1B1F216EE98EF00D05B96 /* MocktailResponse.h in Headers */, 39F1B1F416EE98EF00D05B96 /* MocktailURLProtocol.h in Headers */, A87D2F2316F3B6B700B594D6 /* Mocktail_Private.h in Headers */, + FECA012D1729B19800ED7F14 /* MImage.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -176,6 +183,7 @@ A822634916C45BC4007C81BC /* Mocktail.m in Sources */, 39F1B1F316EE98EF00D05B96 /* MocktailResponse.m in Sources */, 39F1B1F516EE98EF00D05B96 /* MocktailURLProtocol.m in Sources */, + FECA012E1729B19800ED7F14 /* MImage.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -265,6 +273,7 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = NO; DEBUGGING_SYMBOLS = YES; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; @@ -282,6 +291,7 @@ isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -303,7 +313,7 @@ A822634B16C45BC4007C81BC /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; A822634C16C45BC4007C81BC /* Build configuration list for PBXNativeTarget "Mocktail" */ = { isa = XCConfigurationList; @@ -312,7 +322,7 @@ A822634E16C45BC4007C81BC /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; A87D2F2516F3C51000B594D6 /* Build configuration list for PBXLegacyTarget "Mocktail Documentation" */ = { isa = XCConfigurationList; @@ -321,6 +331,7 @@ A87D2F2716F3C51000B594D6 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ }; diff --git a/Mocktail/MImage.h b/Mocktail/MImage.h new file mode 100644 index 0000000..05eab2f --- /dev/null +++ b/Mocktail/MImage.h @@ -0,0 +1,18 @@ +// +// MImage.h +// Mocktail +// +// Created by Coffman, Ben on 4/23/13. +// Copyright (c) 2013 Square, Inc. All rights reserved. +// + +#import + +@interface MImage : NSObject + +@property (nonatomic, strong) NSString *imageName; +@property (nonatomic, strong) NSString *imageURL; + +-(id)initWithValues:(NSString *)imageName imageURL:(NSString *)imageURL; + +@end diff --git a/Mocktail/MImage.m b/Mocktail/MImage.m new file mode 100644 index 0000000..a9c2c7c --- /dev/null +++ b/Mocktail/MImage.m @@ -0,0 +1,21 @@ +// +// MImage.m +// Mocktail +// +// Created by Coffman, Ben on 4/23/13. +// Copyright (c) 2013 Square, Inc. All rights reserved. +// + +#import "MImage.h" + +@implementation MImage +-(id)initWithValues:(NSString *)imageName imageURL:(NSString *)imageURL{ + if(self = [super init]){ + self.imageName = imageName; + self.imageURL = imageURL; + } + + return self; +} + +@end diff --git a/Mocktail/Mocktail.h b/Mocktail/Mocktail.h index b6062a0..8e6ec82 100644 --- a/Mocktail/Mocktail.h +++ b/Mocktail/Mocktail.h @@ -38,13 +38,13 @@ @param aKey The key to replace in `.tail` files */ -- (NSString *)objectForKeyedSubscript:(NSString *)aKey; +- (id)objectForKeyedSubscript:(NSString *)aKey; /** Sets the placeholder value for a given key @param object The placeholder value, probably a string. @param aKey The key to replace in `.tail` files */ -- (void)setObject:(NSString *)object forKeyedSubscript:(NSString *)aKey; +- (void)setObject:(id)object forKeyedSubscript:(NSString *)aKey; @end diff --git a/Mocktail/MocktailURLProtocol.m b/Mocktail/MocktailURLProtocol.m index 9a9a453..52a5c21 100644 --- a/Mocktail/MocktailURLProtocol.m +++ b/Mocktail/MocktailURLProtocol.m @@ -11,6 +11,8 @@ #import "MocktailURLProtocol.h" #import "Mocktail_Private.h" #import "MocktailResponse.h" +#import "MImage.h" + @interface MocktailURLProtocol () @@ -44,22 +46,36 @@ - (void)startLoading; MocktailResponse *response = [Mocktail mockResponseForURL:self.request.URL method:self.request.HTTPMethod]; Mocktail *mocktail = response.mocktail; NSAssert(response, @"Expected valid mock response"); - NSData *body = [NSData dataWithContentsOfURL:response.fileURL]; + __block NSData *body = [NSData dataWithContentsOfURL:response.fileURL]; body = [body subdataWithRange:NSMakeRange(response.bodyOffset, body.length - response.bodyOffset)]; // Replace placeholders with values. We transform the body data into a string for easier search and replace. NSDictionary *placeholderValues = mocktail.placeholderValues; if ([placeholderValues count] > 0) { NSMutableString *bodyString = [[NSMutableString alloc] initWithData:body encoding:NSUTF8StringEncoding]; - BOOL didReplace = NO; - for (NSString *placeholder in placeholderValues) { - NSString *value = [placeholderValues objectForKey:placeholder]; - NSString *placeholderFormat = [NSString stringWithFormat:@"{{ %@ }}", placeholder]; - - if ([bodyString replaceOccurrencesOfString:placeholderFormat withString:value options:NSLiteralSearch range:NSMakeRange(0, [bodyString length])] > 0) { - didReplace = YES; + __block BOOL didReplace = NO; + [placeholderValues enumerateKeysAndObjectsUsingBlock:^ (id key, id obj, BOOL *stop) { + if ([key hasPrefix:@"image"]) { + if([[NSBundle mainBundle] pathForResource:((MImage *)obj).imageName ofType:nil]){ + if ([[self.request.URL absoluteString] isEqual:((MImage *)obj).imageURL]) { + NSError *error; + if ([bodyString isEqual:@"{{ image }}"]){ + body = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:((MImage *)obj).imageName ofType:nil] options:NSDataReadingUncached error:&error]; + } + if (!body) { + NSLog(@"Data Error: %@", error); + } + } + } + + } else { + NSString *placeholderFormat = [NSString stringWithFormat:@"{{ %@ }}", key]; + + if ([bodyString replaceOccurrencesOfString:placeholderFormat withString:obj options:NSLiteralSearch range:NSMakeRange(0, [bodyString length])] > 0) { + didReplace = YES; + } } - } + }]; if (didReplace) { body = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; diff --git a/README.md b/README.md index ac35940..e68d7b6 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,28 @@ Here's whatcha do. **4.** There is no step 7. +## Image support + +Here's whatcha do. + +**1.** Keep track of that object you got back from calling `startWithContentsOfDirectoryAtURL:` + +**2.** Add a template tag to mock responses. Make sure it reads exactly like the below template with the word image + + {{ image }} + +**3.** Let Mocktail know which images it will mock. Make sure to start every key name with "image" Example below: + + Mocktail *mock = [Mocktail startWithContentsOfDirectoryAtURL:[[NSBundle mainBundle] resourceURL]]; + MImage *image1 = [[MImage alloc] initWithValues:@"An_Image.png" imageURL:@"http://urlOfImage/An_Image.png"]; + MImage *image2 = [[MImage alloc] initWithValues:@"Another_Image.png" imageURL:@"http://urlOfImage/Another_Image.png"]; + + mock[@"image1"] = image1; + mock[@"image2"] = image2; + +**4.** Copy images over to your app bundle, Done. + + ## Mad props While `NSURLProtocol` has been around forever, its uses aren't obvious unless you read things like [@mattt](http://github.com/mattt)'s awesome [NSHipster blog post on the subject](http://nshipster.com/nsurlprotocol/). If you don't read NSHipster, you're missing out. It's great.