Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions Mocktail.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -28,6 +30,8 @@
A822634616C45BC4007C81BC /* Mocktail.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Mocktail.h; sourceTree = "<group>"; };
A822634816C45BC4007C81BC /* Mocktail.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Mocktail.m; sourceTree = "<group>"; };
A87D2F2216F3B6B700B594D6 /* Mocktail_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mocktail_Private.h; sourceTree = "<group>"; };
FECA012B1729B19800ED7F14 /* MImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MImage.h; sourceTree = "<group>"; };
FECA012C1729B19800ED7F14 /* MImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MImage.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -303,7 +313,7 @@
A822634B16C45BC4007C81BC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
A822634C16C45BC4007C81BC /* Build configuration list for PBXNativeTarget "Mocktail" */ = {
isa = XCConfigurationList;
Expand All @@ -312,7 +322,7 @@
A822634E16C45BC4007C81BC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationName = Debug;
};
A87D2F2516F3C51000B594D6 /* Build configuration list for PBXLegacyTarget "Mocktail Documentation" */ = {
isa = XCConfigurationList;
Expand All @@ -321,6 +331,7 @@
A87D2F2716F3C51000B594D6 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
/* End XCConfigurationList section */
};
Expand Down
18 changes: 18 additions & 0 deletions Mocktail/MImage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// MImage.h
// Mocktail
//
// Created by Coffman, Ben on 4/23/13.
// Copyright (c) 2013 Square, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface MImage : NSObject

@property (nonatomic, strong) NSString *imageName;
@property (nonatomic, strong) NSString *imageURL;

-(id)initWithValues:(NSString *)imageName imageURL:(NSString *)imageURL;

@end
21 changes: 21 additions & 0 deletions Mocktail/MImage.m
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions Mocktail/Mocktail.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
34 changes: 25 additions & 9 deletions Mocktail/MocktailURLProtocol.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#import "MocktailURLProtocol.h"
#import "Mocktail_Private.h"
#import "MocktailResponse.h"
#import "MImage.h"



@interface MocktailURLProtocol ()
Expand Down Expand Up @@ -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];
Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down