123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- //
- // KWUserDefinedMatcher.m
- // Kiwi
- //
- // Created by Luke Redpath on 16/06/2011.
- // Copyright 2011 Allen Ding. All rights reserved.
- //
- #import "KWUserDefinedMatcher.h"
- @interface KWUserDefinedMatcher(){}
- @property (nonatomic, copy) NSInvocation *invocation;
- @end
- @implementation KWUserDefinedMatcher
- @synthesize selector;
- @synthesize failureMessageForShould;
- @synthesize failureMessageForShouldNot;
- @synthesize matcherBlock;
- @synthesize description;
- + (id)matcherWithSubject:(id)aSubject block:(KWUserDefinedMatcherBlock)aBlock {
- return [[self alloc] initWithSubject:aSubject block:aBlock];
- }
- - (id)initWithSubject:(id)aSubject block:(KWUserDefinedMatcherBlock)aBlock {
- self = [super initWithSubject:aSubject];
- if (self) {
- matcherBlock = [aBlock copy];
- self.description = @"match user defined matcher";
- }
- return self;
- }
- - (BOOL)evaluate {
- BOOL result;
- if (self.invocation.methodSignature.numberOfArguments == 3) {
- id argument;
- [self.invocation getArgument:&argument atIndex:2];
- result = matcherBlock(self.subject, argument);
- } else {
- result = matcherBlock(self.subject);
- }
- return result;
- }
- #pragma mark - Message forwarding
- - (BOOL)respondsToSelector:(SEL)aSelector {
- if (aSelector == self.selector) {
- return YES;
- }
- return [super respondsToSelector:aSelector];
- }
- - (void)forwardInvocation:(NSInvocation *)anInvocation {
- _invocation = anInvocation;
- }
- - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
- if (aSelector == self.selector) {
- NSString *selectorString = NSStringFromSelector(self.selector);
- /**
- * TODO: find a way of doing this that:
- * - doesn't require dummy methods (create the method signatures manually)
- * - supports an unlimited number of arguments
- */
- if ([selectorString hasSuffix:@":"]) {
- return [self methodSignatureForSelector:@selector(matcherMethodWithArgument:)];
- } else {
- return [self methodSignatureForSelector:@selector(matcherMethodWithoutArguments)];
- }
- }
- return [super methodSignatureForSelector:aSelector];
- }
- - (void)matcherMethodWithoutArguments {}
- - (void)matcherMethodWithArgument:(id)argument {}
- @end
- #pragma mark -
- @interface KWUserDefinedMatcherBuilder ()
- @property (nonatomic, strong) KWUserDefinedMatcher *matcher;
- @property (nonatomic, copy) KWUserDefinedMatcherMessageBlock failureMessageForShouldBlock;
- @property (nonatomic, copy) KWUserDefinedMatcherMessageBlock failureMessageForShouldNotBlock;
- @property (nonatomic, copy) NSString *matcherBuilderDescription;
- @end
- @implementation KWUserDefinedMatcherBuilder
- + (id)builder {
- return [self builderForSelector:nil];
- }
- + (id)builderForSelector:(SEL)aSelector {
- return [[self alloc] initWithSelector:aSelector];
- }
- - (id)initWithSelector:(SEL)aSelector {
- self = [super init];
- if (self) {
- _matcher = [[KWUserDefinedMatcher alloc] init];
- _matcher.selector = aSelector;
- }
- return self;
- }
- - (NSString *)key {
- return NSStringFromSelector(self.matcher.selector);
- }
- #pragma mark - Configuring The Matcher
- - (void)match:(KWUserDefinedMatcherBlock)block {
- self.matcher.matcherBlock = block;
- }
- - (void)failureMessageForShould:(KWUserDefinedMatcherMessageBlock)block {
- self.failureMessageForShouldBlock = block;
- }
- - (void)failureMessageForShouldNot:(KWUserDefinedMatcherMessageBlock)block {
- self.failureMessageForShouldNotBlock = block;
- }
- - (void)description:(NSString *)aDescription {
- self.matcherBuilderDescription = aDescription;
- }
- #pragma mark - Buiding The Matcher
- - (KWUserDefinedMatcher *)buildMatcherWithSubject:(id)subject {
- [self.matcher setSubject:subject];
- if (self.failureMessageForShouldBlock) {
- [self.matcher setFailureMessageForShould:self.failureMessageForShouldBlock(subject)];
- }
- if (self.failureMessageForShouldNotBlock) {
- [self.matcher setFailureMessageForShouldNot:self.failureMessageForShouldNotBlock(subject)];
- }
- if (self.matcherBuilderDescription) {
- [self.matcher setDescription:self.matcherBuilderDescription];
- }
- return self.matcher;
- }
- @end
|