From 731b5a4804480686f4b6f00b65f4d91977c230d5 Mon Sep 17 00:00:00 2001 From: Oleksa 'trimm' Korin Date: Sat, 16 Apr 2016 13:34:54 +0300 Subject: [PATCH 1/2] Added be evaluated for blocks --- Classes/Core/KWBlockInvocation.h | 23 ++ Classes/Core/KWBlockInvocation.m | 63 ++++ Classes/Core/KWBlockLayout.h | 100 +++++++ Classes/Core/KWBlockLayout.m | 108 +++++++ Classes/Core/KWBlockMessagePattern.h | 31 ++ Classes/Core/KWBlockMessagePattern.m | 109 +++++++ Classes/Core/KWBlockSignature.h | 13 + Classes/Core/KWBlockSignature.m | 24 ++ Classes/Core/KWMessagePattern.h | 79 ++++- Classes/Core/KWMessagePattern.m | 280 +++++++++++------- Classes/Core/KWProxyBlock.h | 31 ++ Classes/Core/KWProxyBlock.m | 177 +++++++++++ Classes/Core/KWSelectorMessagePattern.h | 25 ++ Classes/Core/KWSelectorMessagePattern.m | 124 ++++++++ Classes/Core/Kiwi.h | 6 + Classes/Core/NSInvocation+KiwiAdditions.h | 14 + Classes/Core/NSInvocation+KiwiAdditions.m | 87 ++++-- Classes/Matchers/KWBeEvaluatedMatcher.h | 34 +++ Classes/Matchers/KWBeEvaluatedMatcher.m | 179 +++++++++++ Classes/Matchers/KWMessageTrackerMatcher.h | 33 +++ Classes/Matchers/KWMessageTrackerMatcher.m | 72 +++++ Classes/Matchers/KWReceiveMatcher.h | 7 +- Classes/Matchers/KWReceiveMatcher.m | 51 +--- Classes/Stubbing/NSObject+KiwiStubAdditions.m | 60 ++-- Kiwi.xcodeproj/project.pbxproj | 139 ++++++++- Tests/KWBeEvaluatedMatcherTest.m | 269 +++++++++++++++++ Tests/KWBlockMessagePatternTest.m | 163 ++++++++++ Tests/KWMessagePatternFunctionalTests.m | 65 +++- Tests/KWProxyBlockTest.m | 173 +++++++++++ 29 files changed, 2291 insertions(+), 248 deletions(-) create mode 100644 Classes/Core/KWBlockInvocation.h create mode 100644 Classes/Core/KWBlockInvocation.m create mode 100644 Classes/Core/KWBlockLayout.h create mode 100644 Classes/Core/KWBlockLayout.m create mode 100644 Classes/Core/KWBlockMessagePattern.h create mode 100644 Classes/Core/KWBlockMessagePattern.m create mode 100644 Classes/Core/KWBlockSignature.h create mode 100644 Classes/Core/KWBlockSignature.m create mode 100644 Classes/Core/KWProxyBlock.h create mode 100644 Classes/Core/KWProxyBlock.m create mode 100644 Classes/Core/KWSelectorMessagePattern.h create mode 100644 Classes/Core/KWSelectorMessagePattern.m create mode 100644 Classes/Matchers/KWBeEvaluatedMatcher.h create mode 100644 Classes/Matchers/KWBeEvaluatedMatcher.m create mode 100644 Classes/Matchers/KWMessageTrackerMatcher.h create mode 100644 Classes/Matchers/KWMessageTrackerMatcher.m create mode 100644 Tests/KWBeEvaluatedMatcherTest.m create mode 100644 Tests/KWBlockMessagePatternTest.m create mode 100644 Tests/KWProxyBlockTest.m diff --git a/Classes/Core/KWBlockInvocation.h b/Classes/Core/KWBlockInvocation.h new file mode 100644 index 00000000..b9ef0066 --- /dev/null +++ b/Classes/Core/KWBlockInvocation.h @@ -0,0 +1,23 @@ +// +// NSBlockInvocation.h +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/27/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KiwiConfiguration.h" + +#import "NSInvocation+KiwiAdditions.h" + +@interface KWBlockInvocation : NSInvocation + +#pragma mark - Creating NSInvocation Objects + ++ (NSInvocation *)invocationWithTarget:(id)anObject; ++ (NSInvocation *)invocationWithTarget:(id)anObject messageArguments:(const void *)firstBytes, ...; ++ (NSInvocation *)invocationWithTarget:(id)anObject + firstArgument:(const void *)firstBytes + argumentList:(va_list)argumentList; + +@end diff --git a/Classes/Core/KWBlockInvocation.m b/Classes/Core/KWBlockInvocation.m new file mode 100644 index 00000000..0c428bdf --- /dev/null +++ b/Classes/Core/KWBlockInvocation.m @@ -0,0 +1,63 @@ +// +// KWBlockInvocation.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/27/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KWBlockInvocation.h" + +#import "KWObjCUtilities.h" +#import "NSMethodSignature+KiwiAdditions.h" +#import "KWProxyBlock.h" + +@implementation KWBlockInvocation + +#pragma mark - Creating NSInvocation Objects + ++ (NSInvocation *)invocationWithTarget:(id)anObject { + return [self invocationWithTarget:anObject messageArguments:nil]; +} + ++ (NSInvocation *)invocationWithTarget:(id)anObject messageArguments:(const void *)firstBytes, ... { + va_list argumentList; + va_start(argumentList, firstBytes); + + return [self invocationWithTarget:anObject selector:NULL firstArgument:firstBytes argumentList:argumentList]; +} + ++ (NSInvocation *)invocationWithTarget:(id)anObject + firstArgument:(const void *)firstBytes + argumentList:(va_list)argumentList +{ + return [self invocationWithTarget:anObject selector:NULL firstArgument:firstBytes argumentList:argumentList]; +} + ++ (NSInvocation *)invocationWithTarget:(id)anObject + selector:(SEL)aSelector + firstArgument:(const void *)firstBytes + argumentList:(va_list)argumentList +{ + if (![anObject isMemberOfClass:[KWProxyBlock class]]) { + [NSException raise:NSInvalidArgumentException format:@"%@ - target must be KWProxyBlock", anObject]; + } + + aSelector = NULL; + + return [super invocationWithTarget:anObject selector:aSelector firstArgument:firstBytes argumentList:argumentList]; +} + +#pragma mark - Argument Offset + +- (NSUInteger)argumentOffset { + return 1; +} + +#pragma mark - Properties + +- (SEL)selector { + return NULL; +} + +@end diff --git a/Classes/Core/KWBlockLayout.h b/Classes/Core/KWBlockLayout.h new file mode 100644 index 00000000..d3b92719 --- /dev/null +++ b/Classes/Core/KWBlockLayout.h @@ -0,0 +1,100 @@ +// +// KWBlockLibClosure.h +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/16/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KiwiConfiguration.h" + +// Block types and helper methods derived from +// http://opensource.apple.com//source/libclosure/libclosure-65/Block_private.h +// http://opensource.apple.com//source/libclosure/libclosure-65/runtime.c + +typedef enum { + kKWBlockDeallocating = (0x0001), // runtime + kKWBlockRefcountMask = (0xfffe), // runtime + kKWBlockNeedsFree = (1 << 24), // runtime + kKWBlockHasCopyDispose = (1 << 25), // compiler + kKWBlockHasCTOR = (1 << 26), // compiler: helpers have C++ code + kKWBlockIsGC = (1 << 27), // runtime + kKWBlockIsGlobal = (1 << 28), // compiler + kKWBlockHasStructureReturn = (1 << 29), // compiler: undefined if !kKWBlockHasSignature + kKWBlockHasSignature = (1 << 30), // compiler + kKWBlockHasExtendedLayout = (1 << 31) // compiler +} kKWBlockOptions; + +struct KWBlockDescriptor { + uintptr_t reserved; + uintptr_t size; +}; +typedef struct KWBlockDescriptor KWBlockDescriptor; + +struct KWBlockDescriptorCopyDispose { + // requires kKWBlockHasCopyDispose + void (*copy)(void *dst, const void *src); + void (*dispose)(const void *); +}; +typedef struct KWBlockDescriptorCopyDispose KWBlockDescriptorCopyDispose; + +struct KWBlockDescriptorMetadata { + // requires kKWBlockHasSignature + const char *signature; + const char *layout; // contents depend on kKWBlockHasExtendedLayout +}; +typedef struct KWBlockDescriptorMetadata KWBlockDescriptorMetadata; + +struct KWBlockLayout { + void *isa; + volatile int32_t flags; // contains ref count + int32_t reserved; + IMP imp; + KWBlockDescriptor *descriptor; +}; +typedef struct KWBlockLayout KWBlockLayout; + +FOUNDATION_EXPORT +kKWBlockOptions KWBlockLayoutGetFlags(KWBlockLayout *block); + +FOUNDATION_EXPORT +BOOL KWBlockLayoutGetOption(KWBlockLayout *block, kKWBlockOptions option); + +FOUNDATION_EXPORT +BOOL KWBlockLayoutHasCopyDispose(KWBlockLayout *block); + +FOUNDATION_EXPORT +BOOL KWBlockLayoutHasCTOR(KWBlockLayout *block); + +FOUNDATION_EXPORT +BOOL KWBlockLayoutIsGlobal(KWBlockLayout *block); + +FOUNDATION_EXPORT +BOOL KWBlockLayoutHasStructureReturn(KWBlockLayout *block); + +FOUNDATION_EXPORT +BOOL KWBlockLayoutHasSignature(KWBlockLayout *block); + +FOUNDATION_EXPORT +BOOL KWBlockLayoutHasExtendedLayout(KWBlockLayout *block); + +FOUNDATION_EXPORT +IMP KWBlockLayoutGetImp(KWBlockLayout *block); + +FOUNDATION_EXPORT +uintptr_t KWBlockLayoutGetDescriptorSize(KWBlockLayout *block); + +FOUNDATION_EXPORT +const char *KWBlockLayoutGetSignature(KWBlockLayout *block); + +FOUNDATION_EXPORT +NSMethodSignature *KWBlockLayoutGetMethodSignature(KWBlockLayout *block); + +FOUNDATION_EXPORT +KWBlockDescriptor *KWBlockLayoutGetDescriptor(KWBlockLayout *block); + +FOUNDATION_EXPORT +KWBlockDescriptorMetadata *KWBlockLayoutGetDescriptorMetadata(KWBlockLayout *block); + +FOUNDATION_EXPORT +IMP KWBlockLayoutGetForwardingImp(KWBlockLayout *block); diff --git a/Classes/Core/KWBlockLayout.m b/Classes/Core/KWBlockLayout.m new file mode 100644 index 00000000..a440ac89 --- /dev/null +++ b/Classes/Core/KWBlockLayout.m @@ -0,0 +1,108 @@ +// +// KWBlockLayout.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/16/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import + +#import "KWBlockLayout.h" +#import "KWBlockSignature.h" + +kKWBlockOptions KWBlockLayoutGetFlags(KWBlockLayout *block) { + // refcount is unneeded, as wel, as deallocating, so we filter them out from the flags + return block->flags & ~(kKWBlockRefcountMask | kKWBlockDeallocating); +} + +BOOL KWBlockLayoutGetOption(KWBlockLayout *block, kKWBlockOptions option) { + return (KWBlockLayoutGetFlags(block) & option) > 0; +} + +BOOL KWBlockLayoutHasCopyDispose(KWBlockLayout *block) { + return KWBlockLayoutGetOption(block, kKWBlockHasCopyDispose); +} + +BOOL KWBlockLayoutHasCTOR(KWBlockLayout *block) { + return KWBlockLayoutGetOption(block, kKWBlockHasCTOR); +} + +BOOL KWBlockLayoutIsGlobal(KWBlockLayout *block) { + return KWBlockLayoutGetOption(block, kKWBlockIsGlobal); +} + +BOOL KWBlockLayoutHasStructureReturn(KWBlockLayout *block) { + // block only has structure return, when it has signature + return KWBlockLayoutGetOption(block, kKWBlockHasStructureReturn) && KWBlockLayoutHasSignature(block); +} + +BOOL KWBlockLayoutHasSignature(KWBlockLayout *block) { + return KWBlockLayoutGetOption(block, kKWBlockHasSignature); +} + +BOOL KWBlockLayoutHasExtendedLayout(KWBlockLayout *block) { + return KWBlockLayoutGetOption(block, kKWBlockHasExtendedLayout); +} + +IMP KWBlockLayoutGetImp(KWBlockLayout *block) { + return block->imp; +} + +uintptr_t KWBlockLayoutGetDescriptorSize(KWBlockLayout *block) { + return KWBlockLayoutGetDescriptor(block)->size; +} + +const char *KWBlockLayoutGetSignature(KWBlockLayout *block) { + if (!KWBlockLayoutHasSignature(block)) { + return NULL; + } + + return KWBlockLayoutGetDescriptorMetadata(block)->signature; +} + +NSMethodSignature *KWBlockLayoutGetMethodSignature(KWBlockLayout *block) { + // if there is no signature, we consider block to be returning void + const char *UTF8Signature = KWBlockLayoutHasSignature(block) ? KWBlockLayoutGetSignature(block) : @encode(void); + + NSString *signature = [NSString stringWithFormat: @"%s", UTF8Signature]; + NSMethodSignature *result = [KWBlockSignature signatureWithObjCTypes:signature.UTF8String]; + + // If there are not enough arguments, we append them by adding void *, which is valid for both id and SEL + // Forwarding expects the ObjC signature return(self, _cmd) + if (result.numberOfArguments < 1) { + signature = [NSString stringWithFormat:@"%@%s", signature, @encode(void *)]; + result = [NSMethodSignature signatureWithObjCTypes:signature.UTF8String]; + } + + return result; +} + +KWBlockDescriptor *KWBlockLayoutGetDescriptor(KWBlockLayout *block) { + return block->descriptor; +} + +KWBlockDescriptorMetadata *KWBlockLayoutGetDescriptorMetadata(KWBlockLayout *block) { + // signature is only available, if the appropriate flag is set + if (!KWBlockLayoutHasSignature(block)) { + return NULL; + } + + // _Block_descriptor_3: http://opensource.apple.com//source/libclosure/libclosure-65/runtime.c + // It's layed out from descriptor pointer inside KWBlockLayout in the following way: + // - KWBlockDescriptor + // - KWBlockDescriptorCopyDispose - if kKWBlockHasCopyDispose flag is set, otherwise it's not there + // - KWBlockDescriptorMetadata + uint8_t *address = (uint8_t *)KWBlockLayoutGetDescriptor(block); + address += sizeof(KWBlockDescriptor); + if (KWBlockLayoutHasCopyDispose(block)) { + address += sizeof(KWBlockDescriptorCopyDispose); + } + + return (KWBlockDescriptorMetadata *)address; +} + +IMP KWBlockLayoutGetForwardingImp(KWBlockLayout *block) { + // explicit type casting for OBJC_OLD_DISPATCH_PROTOTYPES + return (IMP)(KWBlockLayoutHasStructureReturn(block) ? _objc_msgForward_stret : _objc_msgForward); +} diff --git a/Classes/Core/KWBlockMessagePattern.h b/Classes/Core/KWBlockMessagePattern.h new file mode 100644 index 00000000..d53bb54a --- /dev/null +++ b/Classes/Core/KWBlockMessagePattern.h @@ -0,0 +1,31 @@ +// +// KWMessagePattern.h +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/19/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KWMessagePattern.h" + +@interface KWBlockMessagePattern : KWMessagePattern + +#pragma mark - Initializing + +- (id)initWithSignature:(NSMethodSignature *)signature; +- (id)initWithSignature:(NSMethodSignature *)signature argumentFilters:(NSArray *)anArray; +- (id)initWithSignature:(NSMethodSignature *)signature + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList; + ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature; ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature argumentFilters:(NSArray *)anArray; ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList; + +#pragma mark - Properties + +@property (nonatomic, readonly) NSMethodSignature *signature; + +@end diff --git a/Classes/Core/KWBlockMessagePattern.m b/Classes/Core/KWBlockMessagePattern.m new file mode 100644 index 00000000..0de53b92 --- /dev/null +++ b/Classes/Core/KWBlockMessagePattern.m @@ -0,0 +1,109 @@ +// +// KWBlockMessagePattern.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/19/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KWBlockMessagePattern.h" + +#import "KWFormatter.h" +#import "NSMethodSignature+KiwiAdditions.h" + +@implementation KWBlockMessagePattern + +#pragma mark - Initializing + +- (id)initWithSignature:(NSMethodSignature *)signature { + return [self initWithSignature:signature argumentFilters:nil]; +} + +- (id)initWithSignature:(NSMethodSignature *)signature argumentFilters:(NSArray *)anArray { + self = [super initWithArgumentFilters:anArray]; + if (self) { + _signature = signature; + } + + return self; +} + +- (id)initWithSignature:(NSMethodSignature *)signature + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList +{ + NSUInteger argumentCount = [signature numberOfMessageArguments]; + NSArray *argumentFilters = [self argumentFiltersWithFirstArgumentFilter:firstArgumentFilter + argumentList:argumentList + argumentCount:argumentCount]; + + return [self initWithSignature:signature argumentFilters:argumentFilters]; +} + +- (id)initWithInvocation:(NSInvocation *)anInvocation { + NSArray *argumentFilters = [self argumentFiltersWithInvocation:anInvocation]; + + return [self initWithSignature:anInvocation.methodSignature argumentFilters:argumentFilters]; +} + ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature { + return [[self alloc] initWithSignature:signature]; +} + ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature argumentFilters:(NSArray *)anArray { + return [[self alloc] initWithSignature:signature argumentFilters:anArray]; +} + ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList +{ + return [[self alloc] initWithSignature:signature firstArgumentFilter:firstArgumentFilter argumentList:argumentList]; +} + +#pragma mark - Properties + +- (SEL)selector { + return NULL; +} + +#pragma mark - Comparing Message Patterns + +- (NSUInteger)hash { + return [super hash] ^ [self.signature hash]; +} + +#pragma mark - Retrieving String Representations + + +- (NSString *)stringValue { + NSMutableString *description = [NSMutableString stringWithString:@"block call( "]; + NSArray *argumentFilters = self.argumentFilters; + + NSUInteger count = [argumentFilters count]; + + for (NSUInteger i = 0; i < count; ++i) { + NSString *argumentFilterString = [KWFormatter formatObject:(self.argumentFilters)[i]]; + [description appendFormat:@"%@, ", argumentFilterString]; + } + + [description appendFormat:@")"]; + + return description; +} + +#pragma mark - Debugging + +- (NSString *)description { + return [NSString stringWithFormat:@"argumentFilters: %@", self.argumentFilters]; +} + +#pragma mark - Invocation Handling + +- (NSUInteger)argumentCountWithInvocation:(NSInvocation *)anInvocation { + NSMethodSignature *signature = [anInvocation methodSignature]; + + return [signature numberOfMessageArguments]; +} + +@end diff --git a/Classes/Core/KWBlockSignature.h b/Classes/Core/KWBlockSignature.h new file mode 100644 index 00000000..dee3f344 --- /dev/null +++ b/Classes/Core/KWBlockSignature.h @@ -0,0 +1,13 @@ +// +// KWBlockSignature.h +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/27/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import + +@interface KWBlockSignature : NSMethodSignature + +@end diff --git a/Classes/Core/KWBlockSignature.m b/Classes/Core/KWBlockSignature.m new file mode 100644 index 00000000..b55ba0df --- /dev/null +++ b/Classes/Core/KWBlockSignature.m @@ -0,0 +1,24 @@ +// +// KWBlockSignature.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/27/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KWBlockSignature.h" + +@implementation KWBlockSignature + +#pragma mark - Getting Information on Message Arguments + +- (NSUInteger)numberOfMessageArguments { + return [self numberOfArguments] - 1; +} + +- (const char *)messageArgumentTypeAtIndex:(NSUInteger)anIndex { + return [self getArgumentTypeAtIndex:anIndex + 1]; +} + + +@end diff --git a/Classes/Core/KWMessagePattern.h b/Classes/Core/KWMessagePattern.h index 81449135..18f22014 100644 --- a/Classes/Core/KWMessagePattern.h +++ b/Classes/Core/KWMessagePattern.h @@ -1,7 +1,9 @@ // -// Licensed under the terms in License.txt +// KWAbstractMessagePattern.h +// Kiwi // -// Copyright 2010 Allen Ding. All rights reserved. +// Created by Oleksa 'trimm' Korin on 4/26/16. +// Copyright © 2016 Allen Ding. All rights reserved. // #import "KiwiConfiguration.h" @@ -10,19 +12,13 @@ #pragma mark - Initializing -- (id)initWithSelector:(SEL)aSelector; -- (id)initWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray; -- (id)initWithSelector:(SEL)aSelector firstArgumentFilter:(id)firstArgumentFilter argumentList:(va_list)argumentList; - -+ (id)messagePatternWithSelector:(SEL)aSelector; -+ (id)messagePatternWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray; -+ (id)messagePatternWithSelector:(SEL)aSelector firstArgumentFilter:(id)firstArgumentFilter argumentList:(va_list)argumentList; - + (id)messagePatternFromInvocation:(NSInvocation *)anInvocation; +// this method should be overloaded by subclasses +- (id)initWithInvocation:(NSInvocation *)anInvocation; + #pragma mark - Properties -@property (nonatomic, readonly) SEL selector; @property (nonatomic, readonly) NSArray *argumentFilters; #pragma mark - Matching Invocations @@ -31,10 +27,69 @@ #pragma mark - Comparing Message Patterns -- (BOOL)isEqualToMessagePattern:(KWMessagePattern *)aMessagePattern; +- (BOOL)isEqualToMessagePattern:(id)aMessagePattern; #pragma mark - Retrieving String Representations +// this method should be overloaded by subclasses - (NSString *)stringValue; @end + +// cluster methods for KWSelectorMessagePattern +@interface KWMessagePattern (KWSelectorMessagePatternCluster) + +#pragma mark - Initializing + +- (id)initWithSelector:(SEL)aSelector NS_REPLACES_RECEIVER; +- (id)initWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray NS_REPLACES_RECEIVER; +- (id)initWithSelector:(SEL)aSelector + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList NS_REPLACES_RECEIVER; + ++ (id)messagePatternWithSelector:(SEL)aSelector; ++ (id)messagePatternWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray; ++ (id)messagePatternWithSelector:(SEL)aSelector firstArgumentFilter:(id)firstArgumentFilter argumentList:(va_list)argumentList; + +@end + +// cluster methods for KWBlockMessagePattern +@interface KWMessagePattern (KWBlockMessagePatternCluster) + +#pragma mark - Initializing + +- (id)initWithSignature:(NSMethodSignature *)signature NS_REPLACES_RECEIVER; +- (id)initWithSignature:(NSMethodSignature *)signature argumentFilters:(NSArray *)anArray NS_REPLACES_RECEIVER; +- (id)initWithSignature:(NSMethodSignature *)signature + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList NS_REPLACES_RECEIVER; + ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature; ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature argumentFilters:(NSArray *)anArray; ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList; + +@end + +// methods in this category are used for inheritance and should not be called directly +@interface KWMessagePattern (KWMessagePatternPrivate) + +#pragma mark - Initializing + +- (id)initWithArgumentFilters:(NSArray *)anArray; + +#pragma mark - Argument Filters Creation + +- (NSArray *)argumentFiltersWithInvocation:(NSInvocation *)invocation; +- (NSArray *)argumentFiltersWithFirstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList + argumentCount:(NSUInteger)count; + +#pragma mark - Invocation Handling + +// this method should be overloaded by subclasses +- (NSUInteger)argumentCountWithInvocation:(NSInvocation *)invocation; + +@end + diff --git a/Classes/Core/KWMessagePattern.m b/Classes/Core/KWMessagePattern.m index 0e4bbc4f..317cd74b 100644 --- a/Classes/Core/KWMessagePattern.m +++ b/Classes/Core/KWMessagePattern.m @@ -1,118 +1,67 @@ // -// Licensed under the terms in License.txt +// KWAbstractMessagePattern.m +// Kiwi // -// Copyright 2010 Allen Ding. All rights reserved. +// Created by Oleksa 'trimm' Korin on 4/26/16. +// Copyright © 2016 Allen Ding. All rights reserved. // #import "KWMessagePattern.h" -#import "KWAny.h" -#import "KWFormatter.h" + #import "KWNull.h" -#import "KWObjCUtilities.h" -#import "KWValue.h" #import "NSInvocation+KiwiAdditions.h" #import "NSMethodSignature+KiwiAdditions.h" +#import "KWObjCUtilities.h" +#import "KWAny.h" +#import "KWValue.h" +#import "KWFormatter.h" #import "KWGenericMatchEvaluator.h" +#import "KWBlockMessagePattern.h" +#import "KWSelectorMessagePattern.h" + @implementation KWMessagePattern #pragma mark - Initializing -- (id)initWithSelector:(SEL)aSelector { - return [self initWithSelector:aSelector argumentFilters:nil]; -} - -- (id)initWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray { +- (id)initWithArgumentFilters:(NSArray *)anArray { self = [super init]; if (self) { - selector = aSelector; - if ([anArray count] > 0) - argumentFilters = [anArray copy]; + _argumentFilters = [anArray copy]; } - + return self; } -- (id)initWithSelector:(SEL)aSelector firstArgumentFilter:(id)firstArgumentFilter argumentList:(va_list)argumentList { - NSUInteger count = KWSelectorParameterCount(aSelector); - NSMutableArray *array = [NSMutableArray arrayWithCapacity:count]; - [array addObject:(firstArgumentFilter != nil) ? firstArgumentFilter : [KWNull null]]; - - for (NSUInteger i = 1; i < count; ++i) - { - id object = va_arg(argumentList, id); - [array addObject:(object != nil) ? object : [KWNull null]]; - } - - va_end(argumentList); - return [self initWithSelector:aSelector argumentFilters:array]; -} - -+ (id)messagePatternWithSelector:(SEL)aSelector { - return [self messagePatternWithSelector:aSelector argumentFilters:nil]; -} - -+ (id)messagePatternWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray { - return [[self alloc] initWithSelector:aSelector argumentFilters:anArray]; -} - -+ (id)messagePatternWithSelector:(SEL)aSelector firstArgumentFilter:(id)firstArgumentFilter argumentList:(va_list)argumentList { - return [[self alloc] initWithSelector:aSelector firstArgumentFilter:firstArgumentFilter argumentList:argumentList]; +- (id)initWithInvocation:(NSInvocation *)anInvocation { + return [self initWithArgumentFilters:[self argumentFiltersWithInvocation:anInvocation]]; } + (id)messagePatternFromInvocation:(NSInvocation *)anInvocation { - NSMethodSignature *signature = [anInvocation methodSignature]; - NSUInteger numberOfMessageArguments = [signature numberOfMessageArguments]; - NSMutableArray *argumentFilters = nil; - - if (numberOfMessageArguments > 0) { - argumentFilters = [[NSMutableArray alloc] initWithCapacity:numberOfMessageArguments]; - - for (NSUInteger i = 0; i < numberOfMessageArguments; ++i) { - const char *type = [signature messageArgumentTypeAtIndex:i]; - void* argumentDataBuffer = malloc(KWObjCTypeLength(type)); - [anInvocation getMessageArgument:argumentDataBuffer atIndex:i]; - id object = nil; - if(*(__unsafe_unretained id*)argumentDataBuffer != [KWAny any] && !KWObjCTypeIsObject(type)) { - NSData *data = [anInvocation messageArgumentDataAtIndex:i]; - object = [KWValue valueWithBytes:[data bytes] objCType:type]; - } else { - object = *(__unsafe_unretained id*)argumentDataBuffer; - - if (object != [KWAny any] && KWObjCTypeIsBlock(type)) { - object = [object copy]; // Converting NSStackBlock to NSMallocBlock - } - } - - [argumentFilters addObject:(object != nil) ? object : [KWNull null]]; - - free(argumentDataBuffer); - } - } - - return [self messagePatternWithSelector:[anInvocation selector] argumentFilters:argumentFilters]; + return [[self alloc] initWithInvocation:anInvocation]; } #pragma mark - Properties -@synthesize selector; -@synthesize argumentFilters; +- (NSUInteger)argumentCount { + return 0; +} #pragma mark - Matching Invocations - (BOOL)argumentFiltersMatchInvocationArguments:(NSInvocation *)anInvocation { if (self.argumentFilters == nil) return YES; - + NSMethodSignature *signature = [anInvocation methodSignature]; NSUInteger numberOfArgumentFilters = [self.argumentFilters count]; - NSUInteger numberOfMessageArguments = [signature numberOfMessageArguments]; - + NSUInteger numberOfMessageArguments = [self argumentCountWithInvocation:anInvocation]; + for (NSUInteger i = 0; i < numberOfMessageArguments && i < numberOfArgumentFilters; ++i) { const char *objCType = [signature messageArgumentTypeAtIndex:i]; id __autoreleasing object = nil; - + // Extract message argument into object (wrapping values if neccesary) if (KWObjCTypeIsObject(objCType) || KWObjCTypeIsClass(objCType)) { [anInvocation getMessageArgument:&object atIndex:i]; @@ -120,14 +69,14 @@ - (BOOL)argumentFiltersMatchInvocationArguments:(NSInvocation *)anInvocation { NSData *data = [anInvocation messageArgumentDataAtIndex:i]; object = [KWValue valueWithBytes:[data bytes] objCType:objCType]; } - + // Match argument filter to object id argumentFilter = (self.argumentFilters)[i]; - + if ([argumentFilter isEqual:[KWAny any]]) { continue; } - + if ([KWGenericMatchEvaluator isGenericMatcher:argumentFilter]) { id matcher = argumentFilter; if ([object isKindOfClass:[KWValue class]] && [object isNumeric]) { @@ -150,70 +99,183 @@ - (BOOL)argumentFiltersMatchInvocationArguments:(NSInvocation *)anInvocation { return NO; } } - + return YES; } - (BOOL)matchesInvocation:(NSInvocation *)anInvocation { - return self.selector == [anInvocation selector] && [self argumentFiltersMatchInvocationArguments:anInvocation]; + return [self argumentFiltersMatchInvocationArguments:anInvocation]; } #pragma mark - Comparing Message Patterns - (NSUInteger)hash { - return [NSStringFromSelector(self.selector) hash]; + return [self.argumentFilters hash];; } - (BOOL)isEqual:(id)object { - if (![object isKindOfClass:[KWMessagePattern class]]) + if (![object isKindOfClass:[self class]]) return NO; - + return [self isEqualToMessagePattern:object]; } - (BOOL)isEqualToMessagePattern:(KWMessagePattern *)aMessagePattern { - if (self.selector != aMessagePattern.selector) - return NO; - if (self.argumentFilters == nil && aMessagePattern.argumentFilters == nil) return YES; - + return [self.argumentFilters isEqualToArray:aMessagePattern.argumentFilters]; } #pragma mark - Retrieving String Representations -- (NSString *)selectorString { - return NSStringFromSelector(self.selector); +- (NSString *)stringValue { + return nil; +} + +#pragma mark - Debugging + +- (NSString *)description { + return [NSString stringWithFormat:@"argumentFilters: %@", self.argumentFilters]; } -- (NSString *)selectorAndArgumentFiltersString { - NSMutableString *description = [[NSMutableString alloc] init]; - NSArray *components = [NSStringFromSelector(self.selector) componentsSeparatedByString:@":"]; - NSUInteger count = [components count] - 1; +#pragma mark - Argument Filters Creation - for (NSUInteger i = 0; i < count; ++i) { - NSString *selectorComponent = components[i]; - NSString *argumentFilterString = [KWFormatter formatObject:(self.argumentFilters)[i]]; - [description appendFormat:@"%@:%@ ", selectorComponent, argumentFilterString]; +- (NSArray *)argumentFiltersWithInvocation:(NSInvocation *)anInvocation { + NSMethodSignature *signature = [anInvocation methodSignature]; + NSUInteger numberOfMessageArguments = [self argumentCountWithInvocation:anInvocation]; + NSMutableArray *argumentFilters = nil; + + if (numberOfMessageArguments > 0) { + argumentFilters = [[NSMutableArray alloc] initWithCapacity:numberOfMessageArguments]; + + for (NSUInteger i = 0; i < numberOfMessageArguments; ++i) { + const char *type = [signature messageArgumentTypeAtIndex:i]; + void* argumentDataBuffer = malloc(KWObjCTypeLength(type)); + [anInvocation getMessageArgument:argumentDataBuffer atIndex:i]; + id object = nil; + if(*(__unsafe_unretained id*)argumentDataBuffer != [KWAny any] && !KWObjCTypeIsObject(type)) { + NSData *data = [anInvocation messageArgumentDataAtIndex:i]; + object = [KWValue valueWithBytes:[data bytes] objCType:type]; + } else { + object = *(__unsafe_unretained id*)argumentDataBuffer; + + if (object != [KWAny any] && KWObjCTypeIsBlock(type)) { + object = [object copy]; // Converting NSStackBlock to NSMallocBlock + } + } + + [argumentFilters addObject:(object != nil) ? object : [KWNull null]]; + + free(argumentDataBuffer); + } } + + return argumentFilters; +} - return description; +- (NSArray *)argumentFiltersWithFirstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList + argumentCount:(NSUInteger)count +{ + NSMutableArray *array = [NSMutableArray arrayWithCapacity:count]; + [array addObject:(firstArgumentFilter != nil) ? firstArgumentFilter : [KWNull null]]; + + for (NSUInteger i = 1; i < count; ++i) { + id object = va_arg(argumentList, id); + [array addObject:(object != nil) ? object : [KWNull null]]; + } + + va_end(argumentList); + + return array; } -- (NSString *)stringValue { - if (self.argumentFilters == nil) - return [self selectorString]; - else - return [self selectorAndArgumentFiltersString]; +#pragma mark - Invocation Handling + +- (NSUInteger)argumentCountWithInvocation:(NSInvocation *)invocation { + return 0; } -#pragma mark - Debugging +@end -- (NSString *)description { - return [NSString stringWithFormat:@"selector: %@\nargumentFilters: %@", - NSStringFromSelector(self.selector), - self.argumentFilters]; +// cluster methods for KWSelectorMessagePattern +@implementation KWMessagePattern (KWSelectorMessagePatternCluster) + +#pragma mark - Initializing + +- (id)initWithSelector:(SEL)aSelector { + return [[KWSelectorMessagePattern alloc] initWithSelector:aSelector]; +} + +- (id)initWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray { + return [[KWSelectorMessagePattern alloc] initWithSelector:aSelector argumentFilters:anArray]; +} + +- (id)initWithSelector:(SEL)aSelector + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList +{ + return [[KWSelectorMessagePattern alloc] initWithSelector:aSelector + firstArgumentFilter:firstArgumentFilter + argumentList:argumentList]; +} + ++ (id)messagePatternWithSelector:(SEL)aSelector { + return [KWSelectorMessagePattern messagePatternWithSelector:aSelector]; +} + ++ (id)messagePatternWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray { + return [KWSelectorMessagePattern messagePatternWithSelector:aSelector argumentFilters:anArray]; +} + ++ (id)messagePatternWithSelector:(SEL)aSelector + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList +{ + return [KWSelectorMessagePattern messagePatternWithSelector:aSelector + firstArgumentFilter:firstArgumentFilter + argumentList:argumentList]; +} + +@end + +// cluster methods for KWBlockMessagePattern +@implementation KWMessagePattern (KWBlockMessagePatternCluster) + +#pragma mark - Initializing + +- (id)initWithSignature:(NSMethodSignature *)signature { + return [[KWBlockMessagePattern alloc] initWithSignature:signature]; +} + +- (id)initWithSignature:(NSMethodSignature *)signature argumentFilters:(NSArray *)anArray { + return [[KWBlockMessagePattern alloc] initWithSignature:signature argumentFilters:anArray]; +} +- (id)initWithSignature:(NSMethodSignature *)signature + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList +{ + return [[KWBlockMessagePattern alloc] initWithSignature:signature + firstArgumentFilter:firstArgumentFilter + argumentList:argumentList]; +} + ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature { + return [KWBlockMessagePattern messagePatternWithSignature:signature]; +} + ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature argumentFilters:(NSArray *)anArray { + return [KWBlockMessagePattern messagePatternWithSignature:signature argumentFilters:anArray]; +} + ++ (id)messagePatternWithSignature:(NSMethodSignature *)signature + firstArgumentFilter:(id)firstArgumentFilter + argumentList:(va_list)argumentList +{ + return [KWBlockMessagePattern messagePatternWithSignature:signature + firstArgumentFilter:firstArgumentFilter + argumentList:argumentList]; } @end diff --git a/Classes/Core/KWProxyBlock.h b/Classes/Core/KWProxyBlock.h new file mode 100644 index 00000000..c39d3071 --- /dev/null +++ b/Classes/Core/KWProxyBlock.h @@ -0,0 +1,31 @@ +// +// KWProxyBlock.h +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/18/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import + +@interface KWProxyBlock : NSObject + +#pragma mark - Initializing + ++ (id)blockWithBlock:(id)block; + +- (id)initWithBlock:(id)block; + +#pragma mark - Properties + +@property (nonatomic, readonly) NSMethodSignature *methodSignature; + +@end + +#pragma mark - Creating Blocks + +FOUNDATION_EXPORT +KWProxyBlock *theBlockProxy(id); + +FOUNDATION_EXPORT +KWProxyBlock *lambdaProxy(id); diff --git a/Classes/Core/KWProxyBlock.m b/Classes/Core/KWProxyBlock.m new file mode 100644 index 00000000..d5cda9a8 --- /dev/null +++ b/Classes/Core/KWProxyBlock.m @@ -0,0 +1,177 @@ +// +// KWProxyBlock.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/18/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KWProxyBlock.h" + +#import "KWBlockLayout.h" +#import "KWBlockMessagePattern.h" +#import "KWMessageSpying.h" + +#import "NSObject+KiwiStubAdditions.h" +#import "NSInvocation+KiwiAdditions.h" + +@interface NSInvocation (KWPrivateInterface) + +- (void)invokeUsingIMP:(IMP)imp; + +@end + +@interface KWProxyBlock() + +#pragma mark - Properties + +@property (nonatomic, readonly, copy) id block; +@property (nonatomic, readonly, assign) KWBlockLayout *blockLayout; +@property (nonatomic, readonly, assign) KWBlockDescriptor *descriptor; + +@property (nonatomic, readonly) NSMutableSet *expectedMessagePatterns; +@property (nonatomic, readonly) NSMapTable *messageSpies; + +#pragma mark - Methods + +- (void)interposeBlock:(id)block; + +@end + +@implementation KWProxyBlock { + // we imitate the block layout for block forwarding to work + // the order of ivars is important + volatile int32_t _flags; + int32_t _reserved; + IMP _imp; + KWBlockDescriptor *_descriptor; + + // ivars related to our class, rather, than to the interposed block + id _block; +} + +@synthesize block = _block; +@synthesize descriptor = _descriptor; + +@dynamic blockLayout; +@dynamic methodSignature; + +#pragma mark - Deallocating + +- (void)dealloc { + free(_descriptor); + _descriptor = NULL; +} + +#pragma mark - Initializing + +- (id)initWithBlock:(id)block { + self = [super init]; + if (self) { + _expectedMessagePatterns = [NSMutableSet new]; + _messageSpies = [NSMapTable mapTableWithKeyOptions:NSMapTableStrongMemory valueOptions:NSMapTableStrongMemory]; + + _block = [block copy]; + [self interposeBlock:_block]; + } + + return self; +} + ++ (id)blockWithBlock:(id)aBlock { + return [[self alloc] initWithBlock:aBlock]; +} + +#pragma mark - Block Interposing + +- (void)interposeBlock:(id)interposeBlock { + KWBlockLayout *block = (__bridge KWBlockLayout *)interposeBlock; + + _flags = KWBlockLayoutGetFlags(block); + + if (_descriptor) { + free(_descriptor); + } + + uintptr_t interposeSize = KWBlockLayoutGetDescriptorSize(block); + _descriptor = calloc(1, interposeSize); + + KWBlockDescriptor *descriptor = KWBlockLayoutGetDescriptor(block); + memcpy(_descriptor, descriptor, interposeSize); + + _imp = KWBlockLayoutGetForwardingImp(block); +} + +- (id)copyWithZone:(nullable NSZone *)zone { + return self; +} + +#pragma mark - Properties + +- (KWBlockLayout *)blockLayout { + return (__bridge KWBlockLayout *)(self.block); +} + +- (NSMethodSignature *)methodSignature { + return KWBlockLayoutGetMethodSignature(self.blockLayout); +} + +#pragma mark - Forwarding + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { + return self.methodSignature; +} + +- (void)forwardInvocation:(NSInvocation *)anInvocation { + [anInvocation becomeBlockInvocation]; + + NSMapTable *spiesMap = self.messageSpies; + for (KWBlockMessagePattern *messagePattern in spiesMap) { + if ([messagePattern matchesInvocation:anInvocation]) { + NSArray *spies = [spiesMap objectForKey:messagePattern]; + + for (id spy in spies) { + [spy object:self didReceiveInvocation:anInvocation]; + } + } + } + + [anInvocation setTarget:self.block]; + [anInvocation invokeUsingIMP:KWBlockLayoutGetImp(self.blockLayout)]; +} + +- (void)addMessageSpy:(id)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern { + if (![aMessagePattern isKindOfClass:[KWBlockMessagePattern class]]) { + [super addMessageSpy:aSpy forMessagePattern:aMessagePattern]; + } + + [self.expectedMessagePatterns addObject:aMessagePattern]; + NSMutableArray *messagePatternSpies = [self.messageSpies objectForKey:aMessagePattern]; + + if (messagePatternSpies == nil) { + messagePatternSpies = [[NSMutableArray alloc] init]; + [self.messageSpies setObject:messagePatternSpies forKey:aMessagePattern]; + } + + if (![messagePatternSpies containsObject:aSpy]) + [messagePatternSpies addObject:aSpy]; +} + +- (void)removeMessageSpy:(id)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern { + if (![aMessagePattern isKindOfClass:[KWBlockMessagePattern class]]) { + [super removeMessageSpy:aSpy forMessagePattern:aMessagePattern]; + } + + NSMutableArray *messagePatternSpies = [self.messageSpies objectForKey:aMessagePattern]; + [messagePatternSpies removeObject:aSpy]; +} + +@end + +KWProxyBlock *theBlockProxy(id block) { + return [KWProxyBlock blockWithBlock:block]; +} + +KWProxyBlock *lambdaProxy(id block) { + return theBlockProxy(block); +} diff --git a/Classes/Core/KWSelectorMessagePattern.h b/Classes/Core/KWSelectorMessagePattern.h new file mode 100644 index 00000000..d274eceb --- /dev/null +++ b/Classes/Core/KWSelectorMessagePattern.h @@ -0,0 +1,25 @@ +// +// Licensed under the terms in License.txt +// +// Copyright 2010 Allen Ding. All rights reserved. +// + +#import "KWMessagePattern.h" + +@interface KWSelectorMessagePattern : KWMessagePattern + +#pragma mark - Initializing + +- (id)initWithSelector:(SEL)aSelector; +- (id)initWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray; +- (id)initWithSelector:(SEL)aSelector firstArgumentFilter:(id)firstArgumentFilter argumentList:(va_list)argumentList; + ++ (id)messagePatternWithSelector:(SEL)aSelector; ++ (id)messagePatternWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray; ++ (id)messagePatternWithSelector:(SEL)aSelector firstArgumentFilter:(id)firstArgumentFilter argumentList:(va_list)argumentList; + +#pragma mark - Properties + +@property (nonatomic, readonly) SEL selector; + +@end diff --git a/Classes/Core/KWSelectorMessagePattern.m b/Classes/Core/KWSelectorMessagePattern.m new file mode 100644 index 00000000..ff5843dc --- /dev/null +++ b/Classes/Core/KWSelectorMessagePattern.m @@ -0,0 +1,124 @@ +// +// Licensed under the terms in License.txt +// +// Copyright 2010 Allen Ding. All rights reserved. +// + +#import "KWSelectorMessagePattern.h" +#import "KWAny.h" +#import "KWFormatter.h" +#import "KWNull.h" +#import "KWObjCUtilities.h" +#import "KWValue.h" +#import "NSInvocation+KiwiAdditions.h" +#import "NSMethodSignature+KiwiAdditions.h" +#import "KWGenericMatchEvaluator.h" + +@implementation KWSelectorMessagePattern + +#pragma mark - Initializing + +- (id)initWithSelector:(SEL)aSelector { + return [self initWithSelector:aSelector argumentFilters:nil]; +} + +- (id)initWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray { + self = [super initWithArgumentFilters:anArray];; + if (self) { + _selector = aSelector; + } + + return self; +} + +- (id)initWithSelector:(SEL)aSelector firstArgumentFilter:(id)firstArgumentFilter argumentList:(va_list)argumentList { + NSUInteger count = KWSelectorParameterCount(aSelector); + + NSArray *argumentFilters = [self argumentFiltersWithFirstArgumentFilter:firstArgumentFilter + argumentList:argumentList + argumentCount:count]; + + return [self initWithSelector:aSelector argumentFilters:argumentFilters]; +} + +- (id)initWithInvocation:(NSInvocation *)anInvocation { + NSArray *argumentFilters = [self argumentFiltersWithInvocation:anInvocation]; + + return [self initWithSelector:anInvocation.selector argumentFilters:argumentFilters]; +} + ++ (id)messagePatternWithSelector:(SEL)aSelector { + return [self messagePatternWithSelector:aSelector argumentFilters:nil]; +} + ++ (id)messagePatternWithSelector:(SEL)aSelector argumentFilters:(NSArray *)anArray { + return [[self alloc] initWithSelector:aSelector argumentFilters:anArray]; +} + ++ (id)messagePatternWithSelector:(SEL)aSelector firstArgumentFilter:(id)firstArgumentFilter argumentList:(va_list)argumentList { + return [[self alloc] initWithSelector:aSelector firstArgumentFilter:firstArgumentFilter argumentList:argumentList]; +} + +#pragma mark - Matching Invocations + +- (BOOL)matchesInvocation:(NSInvocation *)anInvocation { + return self.selector == [anInvocation selector] && [super matchesInvocation:anInvocation]; +} + +#pragma mark - Comparing Message Patterns + +- (NSUInteger)hash { + return [NSStringFromSelector(self.selector) hash]; +} + +- (BOOL)isEqualToMessagePattern:(KWSelectorMessagePattern *)aMessagePattern { + if (self.selector != aMessagePattern.selector) + return NO; + + return [super isEqualToMessagePattern:aMessagePattern]; +} + +#pragma mark - Retrieving String Representations + +- (NSString *)selectorString { + return NSStringFromSelector(self.selector); +} + +- (NSString *)selectorAndArgumentFiltersString { + NSMutableString *description = [[NSMutableString alloc] init]; + NSArray *components = [NSStringFromSelector(self.selector) componentsSeparatedByString:@":"]; + NSUInteger count = [components count] - 1; + + for (NSUInteger i = 0; i < count; ++i) { + NSString *selectorComponent = components[i]; + NSString *argumentFilterString = [KWFormatter formatObject:(self.argumentFilters)[i]]; + [description appendFormat:@"%@:%@ ", selectorComponent, argumentFilterString]; + } + + return description; +} + +- (NSString *)stringValue { + if (self.argumentFilters == nil) + return [self selectorString]; + else + return [self selectorAndArgumentFiltersString]; +} + +#pragma mark - Debugging + +- (NSString *)description { + return [NSString stringWithFormat:@"selector: %@\nargumentFilters: %@", + NSStringFromSelector(self.selector), + self.argumentFilters]; +} + +#pragma mark - Invocation Handling + +- (NSUInteger)argumentCountWithInvocation:(NSInvocation *)anInvocation { + NSMethodSignature *signature = [anInvocation methodSignature]; + + return [signature numberOfMessageArguments]; +} + +@end diff --git a/Classes/Core/Kiwi.h b/Classes/Core/Kiwi.h index 03f61622..92f00f14 100644 --- a/Classes/Core/Kiwi.h +++ b/Classes/Core/Kiwi.h @@ -36,6 +36,8 @@ extern "C" { #import #import #import +#import +#import #import #import #import @@ -71,6 +73,8 @@ extern "C" { #import #import #import +#import +#import #import #import #import @@ -80,6 +84,7 @@ extern "C" { #import #import #import +#import #import #import #import @@ -94,6 +99,7 @@ extern "C" { #import #import #import +#import // Public Foundation Categories #import diff --git a/Classes/Core/NSInvocation+KiwiAdditions.h b/Classes/Core/NSInvocation+KiwiAdditions.h index d663b4c1..368fcbc7 100644 --- a/Classes/Core/NSInvocation+KiwiAdditions.h +++ b/Classes/Core/NSInvocation+KiwiAdditions.h @@ -13,6 +13,11 @@ + (NSInvocation *)invocationWithTarget:(id)anObject selector:(SEL)aSelector; + (NSInvocation *)invocationWithTarget:(id)anObject selector:(SEL)aSelector messageArguments:(const void *)firstBytes, ...; ++ (NSInvocation *)invocationWithTarget:(id)anObject + selector:(SEL)aSelector + firstArgument:(const void *)firstBytes + argumentList:(va_list)argumentList; + #pragma mark - Accessing Message Arguments // Message arguments are invocation arguments that begin after the target and selector arguments. These methods provide @@ -22,5 +27,14 @@ - (void)getMessageArgument:(void *)buffer atIndex:(NSUInteger)anIndex; - (void)setMessageArgument:(const void *)bytes atIndex:(NSUInteger)anIndex; - (void)setMessageArguments:(const void *)firstBytes, ...; +- (void)setMessageArgumentsWithFirstArgument:(const void *)firstBytes argumentList:(va_list)argumentList; + +#pragma mark - Argument Offset + +- (NSUInteger)argumentOffset; + +#pragma mark - Block Invocation + +- (void)becomeBlockInvocation; @end diff --git a/Classes/Core/NSInvocation+KiwiAdditions.m b/Classes/Core/NSInvocation+KiwiAdditions.m index 23065a2a..b6a35e86 100644 --- a/Classes/Core/NSInvocation+KiwiAdditions.m +++ b/Classes/Core/NSInvocation+KiwiAdditions.m @@ -5,10 +5,15 @@ // #import "NSInvocation+KiwiAdditions.h" + +#import + #import "KWFormatter.h" #import "KWObjCUtilities.h" #import "NSMethodSignature+KiwiAdditions.h" +#import "KWBlockInvocation.h" + @implementation NSInvocation(KiwiAdditions) #pragma mark - Creating NSInvocation Objects @@ -18,36 +23,38 @@ + (NSInvocation *)invocationWithTarget:(id)anObject selector:(SEL)aSelector { } + (NSInvocation *)invocationWithTarget:(id)anObject selector:(SEL)aSelector messageArguments:(const void *)firstBytes, ... { + va_list argumentList; + va_start(argumentList, firstBytes); + + return [self invocationWithTarget:anObject + selector:aSelector + firstArgument:firstBytes + argumentList:argumentList]; +} + ++ (NSInvocation *)invocationWithTarget:(id)anObject + selector:(SEL)aSelector + firstArgument:(const void *)firstBytes + argumentList:(va_list)argumentList +{ if (anObject == nil) { [NSException raise:NSInvalidArgumentException format:@"%@ - target must not be nil", - NSStringFromSelector(_cmd)]; + NSStringFromSelector(_cmd)]; } - + NSMethodSignature *signature = [anObject methodSignatureForSelector:aSelector]; - + if (signature == nil) { [NSException raise:NSInvalidArgumentException format:@"%@ - target returned nil for -methodSignatureForSelector", - NSStringFromSelector(_cmd)]; + NSStringFromSelector(_cmd)]; } - - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; + + NSInvocation *invocation = [self invocationWithMethodSignature:signature]; [invocation setTarget:anObject]; [invocation setSelector:aSelector]; - NSUInteger numberOfMessageArguments = [signature numberOfMessageArguments]; - - if (numberOfMessageArguments == 0) - return invocation; - - va_list argumentList; - va_start(argumentList, firstBytes); - const void *bytes = firstBytes; - - for (NSUInteger i = 0; i < numberOfMessageArguments && bytes != nil; ++i) { - [invocation setMessageArgument:bytes atIndex:i]; - bytes = va_arg(argumentList, const void *); - } - - va_end(argumentList); + + [invocation setMessageArgumentsWithFirstArgument:firstBytes argumentList:argumentList]; + return invocation; } @@ -63,29 +70,49 @@ - (NSData *)messageArgumentDataAtIndex:(NSUInteger)anIndex { } - (void)getMessageArgument:(void *)buffer atIndex:(NSUInteger)anIndex { - [self getArgument:buffer atIndex:anIndex + 2]; + [self getArgument:buffer atIndex:anIndex + self.argumentOffset]; } - (void)setMessageArgument:(const void *)bytes atIndex:(NSUInteger)anIndex { - [self setArgument:(void *)bytes atIndex:anIndex + 2]; + [self setArgument:(void *)bytes atIndex:anIndex + self.argumentOffset]; } - (void)setMessageArguments:(const void *)firstBytes, ... { - NSUInteger numberOfMessageArguments = [[self methodSignature] numberOfMessageArguments]; - - if (numberOfMessageArguments == 0) - return; - va_list argumentList; va_start(argumentList, firstBytes); - const void *bytes = firstBytes; + [self setMessageArgumentsWithFirstArgument:firstBytes argumentList:argumentList]; +} + +- (void)setMessageArgumentsWithFirstArgument:(const void *)firstBytes argumentList:(va_list)argumentList { + NSUInteger numberOfMessageArguments = [[self methodSignature] numberOfMessageArguments]; + + if (numberOfMessageArguments == 0) { + return; + va_end(argumentList); + } + + const void *bytes = firstBytes; + for (NSUInteger i = 0; i < numberOfMessageArguments && bytes != nil; ++i) { [self setMessageArgument:bytes atIndex:i]; bytes = va_arg(argumentList, const void *); } - + va_end(argumentList); } +#pragma mark - Argument Offset + +- (NSUInteger)argumentOffset { + return 2; +} + +#pragma mark - Block Invocation + +- (void)becomeBlockInvocation { + object_setClass(self, [KWBlockInvocation class]); +} + + @end diff --git a/Classes/Matchers/KWBeEvaluatedMatcher.h b/Classes/Matchers/KWBeEvaluatedMatcher.h new file mode 100644 index 00000000..2b2f4cef --- /dev/null +++ b/Classes/Matchers/KWBeEvaluatedMatcher.h @@ -0,0 +1,34 @@ +// +// KWBeEvaluatedMatcher.h +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/20/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KWMessageTrackerMatcher.h" +#import "KWMatchVerifier.h" + +@interface KWBeEvaluatedMatcher : KWMessageTrackerMatcher + +- (void)beEvaluated; +- (void)beEvaluatedWithCount:(NSUInteger)aCount; +- (void)beEvaluatedWithCountAtLeast:(NSUInteger)aCount; +- (void)beEvaluatedWithCountAtMost:(NSUInteger)aCount; + +- (void)beEvaluatedWithArguments:(id)firstArgument, ...; +- (void)beEvaluatedWithCount:(NSUInteger)aCount arguments:(id)firstArgument, ...; +- (void)beEvaluatedWithCountAtLeast:(NSUInteger)aCount arguments:(id)firstArgument, ...; +- (void)beEvaluatedWithCountAtMost:(NSUInteger)aCount arguments:(id)firstArgument, ...; + +@end + +@interface KWMatchVerifier (KWBeEvaluatedMatcherAdditions) + +// NSInvocation doesn't work with va_arg, so we have to implement it directly in match verifier +- (void)beEvaluatedWithArguments:(id)firstArgument, ...; +- (void)beEvaluatedWithCount:(NSUInteger)aCount arguments:(id)firstArgument, ...; +- (void)beEvaluatedWithCountAtLeast:(NSUInteger)aCount arguments:(id)firstArgument, ...; +- (void)beEvaluatedWithCountAtMost:(NSUInteger)aCount arguments:(id)firstArgument, ...; + +@end diff --git a/Classes/Matchers/KWBeEvaluatedMatcher.m b/Classes/Matchers/KWBeEvaluatedMatcher.m new file mode 100644 index 00000000..ad82bbd7 --- /dev/null +++ b/Classes/Matchers/KWBeEvaluatedMatcher.m @@ -0,0 +1,179 @@ +// +// KWBeEvaluatedMatcher.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/20/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KWBeEvaluatedMatcher.h" + +#import "KWBlockMessagePattern.h" +#import "KWCountType.h" +#import "KWMessageTracker.h" +#import "KWWorkarounds.h" +#import "KWProxyBlock.h" + +#define KWStartVAList(listName, argument) \ + va_list listName; \ + va_start(listName, argument); + +#define KWMessagePatternWithVAListAndSignature(list, argument, signature) \ + [KWBlockMessagePattern messagePatternWithSignature:(signature) \ + firstArgumentFilter:argument \ + argumentList:list] + +#define KWBeEvaluatedWithCount(argument, type, countValue, signature) \ + do { \ + KWStartVAList(args, argument); \ + [(id)self beEvaluatedWithMessagePattern:KWMessagePatternWithVAListAndSignature(args, argument, (signature)) \ + countType:type \ + count:countValue]; \ + } while(0) + +#define KWBeEvaluatedWithUnspecifiedCount(argument, signature) \ + do { \ + KWStartVAList(args, firstArgument) \ + id pattern = KWMessagePatternWithVAListAndSignature(args, firstArgument, (signature)); \ + [(id)self beEvaluatedWithUnspecifiedCountOfMessagePattern:pattern]; \ + } while(0) + +@implementation KWBeEvaluatedMatcher + +#pragma mark - Getting Matcher Strings + ++ (NSArray *)matcherStrings { + return @[@"beEvaluated", + @"beEvaluatedWithCount", + @"beEvaluatedWithCountAtLeast:", + @"beEvaluatedWithCountAtMost:", + @"beEvaluatedWithArguments:", + @"beEvaluatedWithCount:arguments:", + @"beEvaluatedWithCountAtLeast:arguments:", + @"beEvaluatedWithCountAtMost:arguments:", + @"beEvaluatedWithUnspecifiedCountOfMessagePattern:", + @"beEvaluatedWithMessagePattern:countType:count:"]; +} + +#pragma mark - Configuring Matchers + +- (void)beEvaluated { + id pattern = [KWBlockMessagePattern messagePatternWithSignature:[self subjectSignature]]; + [self beEvaluatedWithUnspecifiedCountOfMessagePattern:pattern]; +} + +- (void)beEvaluatedWithCount:(NSUInteger)aCount { + [self beEvaluatedWithCountType:KWCountTypeExact count:aCount]; +} + +- (void)beEvaluatedWithCountAtLeast:(NSUInteger)aCount { + [self beEvaluatedWithCountType:KWCountTypeAtLeast count:aCount]; +} + +- (void)beEvaluatedWithCountAtMost:(NSUInteger)aCount { + [self beEvaluatedWithCountType:KWCountTypeAtMost count:aCount]; +} + +- (void)beEvaluatedWithCountType:(KWCountType)aCountType count:(NSUInteger)aCount { + id pattern = [KWBlockMessagePattern messagePatternWithSignature:[self subjectSignature]]; + + [self beEvaluatedWithMessagePattern:pattern countType:aCountType count:aCount]; +} + +- (void)beEvaluatedWithUnspecifiedCountOfMessagePattern:(KWBlockMessagePattern *)messagePattern { + KWCountType countType = self.willEvaluateAgainstNegativeExpectation ? KWCountTypeAtLeast : KWCountTypeExact; + + [self beEvaluatedWithCountType:countType count:1]; +} + +- (void)beEvaluatedWithArguments:(id)firstArgument, ... { + KWBeEvaluatedWithUnspecifiedCount(firstArgument, [self subjectSignature]); +} + +#define KWBeEvaluatedWithCountType(type) \ + KWBeEvaluatedWithCount(firstArgument, type, aCount, [self subjectSignature]) + +- (void)beEvaluatedWithCount:(NSUInteger)aCount arguments:(id)firstArgument, ... { + KWBeEvaluatedWithCountType(KWCountTypeExact); +} + +- (void)beEvaluatedWithCountAtLeast:(NSUInteger)aCount arguments:(id)firstArgument, ... { + KWBeEvaluatedWithCountType(KWCountTypeAtLeast); +} + +- (void)beEvaluatedWithCountAtMost:(NSUInteger)aCount arguments:(id)firstArgument, ... { + KWBeEvaluatedWithCountType(KWCountTypeAtMost); +} + +#undef KWBeEvaluatedWithCountType + +#pragma mark - Message Pattern Receiving + +- (void)beEvaluatedWithMessagePattern:(KWBlockMessagePattern *)aMessagePattern countType:(KWCountType)aCountType count:(NSUInteger)aCount { +#if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG + @try { +#endif // #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG + + [self setMessageTrackerWithMessagePattern:aMessagePattern countType:aCountType count:aCount]; + +#if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG + } @catch(NSException *exception) { + KWSetExceptionFromAcrossInvocationBoundary(exception); + } +#endif // #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG +} + +#pragma mark - Matching + +- (BOOL)shouldBeEvaluatedAtEndOfExample { + return YES; +} + +- (BOOL)evaluate { + if (![self.subject isKindOfClass:[KWProxyBlock class]]) + [NSException raise:@"KWMatcherException" format:@"subject must be a KWProxyBlock"]; + + return [super evaluate]; +} + +- (NSMethodSignature *)subjectSignature { + return [self.subject methodSignature]; +} + +@end + +@implementation KWMatchVerifier (KWBeEvaluatedMatcherAdditions) + +#pragma mark - Verifying + +- (void)beEvaluatedWithArguments:(id)firstArgument, ... { + KWBeEvaluatedWithUnspecifiedCount(firstArgument, [self beEvaluated_subjectSignature]); +} + +#define KWBeEvaluatedWithCountType(type) \ + KWBeEvaluatedWithCount(firstArgument, type, aCount, [self beEvaluated_subjectSignature]) + +- (void)beEvaluatedWithCount:(NSUInteger)aCount arguments:(id)firstArgument, ... { + KWBeEvaluatedWithCountType(KWCountTypeExact); +} + +- (void)beEvaluatedWithCountAtLeast:(NSUInteger)aCount arguments:(id)firstArgument, ... { + KWBeEvaluatedWithCountType(KWCountTypeAtLeast); +} + +- (void)beEvaluatedWithCountAtMost:(NSUInteger)aCount arguments:(id)firstArgument, ... { + KWBeEvaluatedWithCountType(KWCountTypeAtMost); +} + +#undef KWBeEvaluatedWithCountType + +- (NSMethodSignature *)beEvaluated_subjectSignature { + return [self.subject methodSignature]; +} + +@end + +#undef KWBeEvaluatedWithUnspecifiedCount +#undef KWBeEvaluatedWithCount +#undef KWMessagePatternWithVAListAndSignature +#undef KWStartVAList diff --git a/Classes/Matchers/KWMessageTrackerMatcher.h b/Classes/Matchers/KWMessageTrackerMatcher.h new file mode 100644 index 00000000..a77431f3 --- /dev/null +++ b/Classes/Matchers/KWMessageTrackerMatcher.h @@ -0,0 +1,33 @@ +// +// KWMessageTrackerMatcher.h +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/20/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KWMatcher.h" + +#import "KWCountType.h" + +@class KWMessageTracker; +@class KWMessagePattern; + +@interface KWMessageTrackerMatcher : KWMatcher + +#pragma mark - Properties + +@property (nonatomic, readonly) KWMessageTracker *messageTracker; +@property (nonatomic, assign) BOOL willEvaluateMultipleTimes; +@property (nonatomic, assign) BOOL willEvaluateAgainstNegativeExpectation; + +@end + +// methods in this category are used for inheritance and should not be called directly +@interface KWMessageTrackerMatcher (KWKWMessageTrackerMatcherPrivate) + +- (void)setMessageTrackerWithMessagePattern:(KWMessagePattern *)aMessagePattern + countType:(KWCountType)aCountType + count:(NSUInteger)aCount; + +@end diff --git a/Classes/Matchers/KWMessageTrackerMatcher.m b/Classes/Matchers/KWMessageTrackerMatcher.m new file mode 100644 index 00000000..eb387c92 --- /dev/null +++ b/Classes/Matchers/KWMessageTrackerMatcher.m @@ -0,0 +1,72 @@ +// +// KWMessageTrackerMatcher.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/20/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import "KWMessageTrackerMatcher.h" + +#import "KWMessageTracker.h" +#import "KWMessagePattern.h" + +@interface KWMessageTrackerMatcher () + +@property (nonatomic, strong) KWMessageTracker *messageTracker; + +@end + +@implementation KWMessageTrackerMatcher + +#pragma mark - Initializing + +- (id)initWithSubject:(id)anObject { + self = [super initWithSubject:anObject]; + if (self) { + _willEvaluateMultipleTimes = NO; + } + + return self; +} + +#pragma mark - Matching + +- (BOOL)shouldBeEvaluatedAtEndOfExample { + return YES; +} + +- (BOOL)evaluate { + BOOL succeeded = [self.messageTracker succeeded]; + + if (!self.willEvaluateMultipleTimes) { + [self.messageTracker stopTracking]; + } + return succeeded; +} + +#pragma mark - Getting Failure Messages + +- (NSString *)failureMessageForShould { + return [NSString stringWithFormat:@"expected subject to receive -%@ %@, but received it %@", + [self.messageTracker.messagePattern stringValue], + [self.messageTracker expectedCountPhrase], + [self.messageTracker receivedCountPhrase]]; +} + +- (NSString *)failureMessageForShouldNot { + return [NSString stringWithFormat:@"expected subject not to receive -%@, but received it %@", + [self.messageTracker.messagePattern stringValue], + [self.messageTracker receivedCountPhrase]]; +} + +#pragma mark - Setting Message Tracker + +- (void)setMessageTrackerWithMessagePattern:(KWMessagePattern *)aMessagePattern + countType:(KWCountType)aCountType + count:(NSUInteger)aCount +{ + self.messageTracker = [KWMessageTracker messageTrackerWithSubject:self.subject messagePattern:aMessagePattern countType:aCountType count:aCount]; +} + +@end diff --git a/Classes/Matchers/KWReceiveMatcher.h b/Classes/Matchers/KWReceiveMatcher.h index 23fa7bff..b1e9e9e0 100644 --- a/Classes/Matchers/KWReceiveMatcher.h +++ b/Classes/Matchers/KWReceiveMatcher.h @@ -6,16 +6,13 @@ #import "KiwiConfiguration.h" #import "KWCountType.h" -#import "KWMatcher.h" +#import "KWMessageTrackerMatcher.h" #import "KWMatchVerifier.h" @class KWMessagePattern; @class KWMessageTracker; -@interface KWReceiveMatcher : KWMatcher - -@property (nonatomic, assign) BOOL willEvaluateMultipleTimes; -@property (nonatomic, assign) BOOL willEvaluateAgainstNegativeExpectation; +@interface KWReceiveMatcher : KWMessageTrackerMatcher #pragma mark - Configuring Matchers diff --git a/Classes/Matchers/KWReceiveMatcher.m b/Classes/Matchers/KWReceiveMatcher.m index 12fb0aef..36bfb10d 100644 --- a/Classes/Matchers/KWReceiveMatcher.m +++ b/Classes/Matchers/KWReceiveMatcher.m @@ -21,25 +21,10 @@ @interface KWReceiveMatcher() -#pragma mark - Properties - -@property (nonatomic, readwrite, strong) KWMessageTracker *messageTracker; - @end @implementation KWReceiveMatcher -#pragma mark - Initializing - -- (id)initWithSubject:(id)anObject { - self = [super initWithSubject:anObject]; - if (self) { - _willEvaluateMultipleTimes = NO; - } - - return self; -} - #pragma mark - Getting Matcher Strings + (NSArray *)matcherStrings { @@ -57,36 +42,6 @@ + (NSArray *)matcherStrings { @"receiveUnspecifiedCountOfMessagePattern:andReturn:"]; } -#pragma mark - Matching - -- (BOOL)shouldBeEvaluatedAtEndOfExample { - return YES; -} - -- (BOOL)evaluate { - BOOL succeeded = [self.messageTracker succeeded]; - - if (!self.willEvaluateMultipleTimes) { - [self.messageTracker stopTracking]; - } - return succeeded; -} - -#pragma mark - Getting Failure Messages - -- (NSString *)failureMessageForShould { - return [NSString stringWithFormat:@"expected subject to receive -%@ %@, but received it %@", - [self.messageTracker.messagePattern stringValue], - [self.messageTracker expectedCountPhrase], - [self.messageTracker receivedCountPhrase]]; -} - -- (NSString *)failureMessageForShouldNot { - return [NSString stringWithFormat:@"expected subject not to receive -%@, but received it %@", - [self.messageTracker.messagePattern stringValue], - [self.messageTracker receivedCountPhrase]]; -} - #pragma mark - Configuring Matchers - (void)receive:(SEL)aSelector { @@ -150,8 +105,8 @@ - (void)receiveMessagePattern:(KWMessagePattern *)aMessagePattern countType:(KWC @try { #endif // #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG - [self.subject stubMessagePattern:aMessagePattern andReturn:nil overrideExisting:NO]; - self.messageTracker = [KWMessageTracker messageTrackerWithSubject:self.subject messagePattern:aMessagePattern countType:aCountType count:aCount]; + [self.subject stubMessagePattern:aMessagePattern andReturn:nil overrideExisting:NO]; + [self setMessageTrackerWithMessagePattern:aMessagePattern countType:aCountType count:aCount]; #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG } @catch(NSException *exception) { @@ -166,7 +121,7 @@ - (void)receiveMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id) #endif // #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG [self.subject stubMessagePattern:aMessagePattern andReturn:aValue]; - self.messageTracker = [KWMessageTracker messageTrackerWithSubject:self.subject messagePattern:aMessagePattern countType:aCountType count:aCount]; + [self setMessageTrackerWithMessagePattern:aMessagePattern countType:aCountType count:aCount]; #if KW_TARGET_HAS_INVOCATION_EXCEPTION_BUG } @catch(NSException *exception) { diff --git a/Classes/Stubbing/NSObject+KiwiStubAdditions.m b/Classes/Stubbing/NSObject+KiwiStubAdditions.m index bf0e0358..7c6a817b 100644 --- a/Classes/Stubbing/NSObject+KiwiStubAdditions.m +++ b/Classes/Stubbing/NSObject+KiwiStubAdditions.m @@ -8,7 +8,7 @@ #import "KWCaptureSpy.h" #import "KWIntercept.h" #import "KWInvocationCapturer.h" -#import "KWMessagePattern.h" +#import "KWSelectorMessagePattern.h" #import "KWObjCUtilities.h" #import "KWStringUtilities.h" #import "KWStub.h" @@ -32,7 +32,7 @@ - (NSMethodSignature *)invocationCapturer:(KWInvocationCapturer *)anInvocationCa } - (void)invocationCapturer:(KWInvocationCapturer *)anInvocationCapturer didCaptureInvocation:(NSInvocation *)anInvocation { - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternFromInvocation:anInvocation]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternFromInvocation:anInvocation]; id value = (anInvocationCapturer.userInfo)[StubValueKey]; if (!(anInvocationCapturer.userInfo)[StubSecondValueKey]) { [self stubMessagePattern:messagePattern andReturn:value]; @@ -46,70 +46,70 @@ - (void)invocationCapturer:(KWInvocationCapturer *)anInvocationCapturer didCaptu #pragma mark - Stubbing Methods - (void)stub:(SEL)aSelector { - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector]; [self stubMessagePattern:messagePattern andReturn:nil]; } - (void)stub:(SEL)aSelector withBlock:(id (^)(NSArray *))block { - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector]; [self stubMessagePattern:messagePattern withBlock:block]; } - (void)stub:(SEL)aSelector withArguments:(id)firstArgument, ... { va_list argumentList; va_start(argumentList, firstArgument); - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList]; [self stubMessagePattern:messagePattern andReturn:nil]; } - (void)stub:(SEL)aSelector andReturn:(id)aValue { - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector]; [self stubMessagePattern:messagePattern andReturn:aValue]; } - (void)stub:(SEL)aSelector andReturn:(id)aValue withArguments:(id)firstArgument, ... { va_list argumentList; va_start(argumentList, firstArgument); - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList]; [self stubMessagePattern:messagePattern andReturn:aValue]; } - (void)stub:(SEL)aSelector andReturn:(id)aValue times:(NSNumber *)times afterThatReturn:(id)aSecondValue { - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector]; [self stubMessagePattern:messagePattern andReturn:aValue times:times afterThatReturn:aSecondValue]; } + (void)stub:(SEL)aSelector { - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector]; [self stubMessagePattern:messagePattern andReturn:nil]; } + (void)stub:(SEL)aSelector withBlock:(id (^)(NSArray *))block { - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector]; [self stubMessagePattern:messagePattern withBlock:block]; } + (void)stub:(SEL)aSelector withArguments:(id)firstArgument, ... { va_list argumentList; va_start(argumentList, firstArgument); - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList]; [self stubMessagePattern:messagePattern andReturn:nil]; } + (void)stub:(SEL)aSelector andReturn:(id)aValue { - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector]; [self stubMessagePattern:messagePattern andReturn:aValue]; } + (void)stub:(SEL)aSelector andReturn:(id)aValue withArguments:(id)firstArgument, ... { va_list argumentList; va_start(argumentList, firstArgument); - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector firstArgumentFilter:firstArgument argumentList:argumentList]; [self stubMessagePattern:messagePattern andReturn:aValue]; } + (void)stub:(SEL)aSelector andReturn:(id)aValue times:(NSNumber *)times afterThatReturn:(id)aSecondValue { - KWMessagePattern *messagePattern = [KWMessagePattern messagePatternWithSelector:aSelector]; + KWSelectorMessagePattern *messagePattern = [KWSelectorMessagePattern messagePatternWithSelector:aSelector]; [self stubMessagePattern:messagePattern andReturn:aValue times:times afterThatReturn:aSecondValue]; } @@ -127,11 +127,11 @@ - (id)stubAndReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue return [KWInvocationCapturer invocationCapturerWithDelegate:self userInfo:userInfo]; } -- (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue { +- (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern andReturn:(id)aValue { [self stubMessagePattern:aMessagePattern andReturn:aValue overrideExisting:YES]; } -- (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue overrideExisting:(BOOL)overrideExisting { +- (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern andReturn:(id)aValue overrideExisting:(BOOL)overrideExisting { if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) { [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists", NSStringFromSelector(aMessagePattern.selector)]; @@ -143,7 +143,7 @@ - (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aVa KWAssociateObjectStub(self, stub, overrideExisting); } -- (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue { +- (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue { if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) { [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists", NSStringFromSelector(aMessagePattern.selector)]; @@ -155,7 +155,7 @@ - (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aVa KWAssociateObjectStub(self, stub, YES); } -- (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block { +- (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block { if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) { [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists", NSStringFromSelector(aMessagePattern.selector)]; @@ -167,11 +167,11 @@ - (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern withBlock:(id (^) KWAssociateObjectStub(self, stub, YES); } -+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue { ++ (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern andReturn:(id)aValue { [self stubMessagePattern:aMessagePattern andReturn:aValue overrideExisting:YES]; } -+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue overrideExisting:(BOOL)override { ++ (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern andReturn:(id)aValue overrideExisting:(BOOL)override { if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) { [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists", NSStringFromSelector(aMessagePattern.selector)]; @@ -183,11 +183,11 @@ + (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aVa KWAssociateObjectStub(self, stub, override); } -+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue { ++ (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue { [self stubMessagePattern:aMessagePattern andReturn:aValue times:times afterThatReturn:aSecondValue overrideExisting:YES]; } -+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue overrideExisting:(BOOL)override { ++ (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern andReturn:(id)aValue times:(id)times afterThatReturn:(id)aSecondValue overrideExisting:(BOOL)override { if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) { [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists", NSStringFromSelector(aMessagePattern.selector)]; @@ -199,11 +199,11 @@ + (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern andReturn:(id)aVa KWAssociateObjectStub(self, stub, override); } -+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block { ++ (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block { [self stubMessagePattern:aMessagePattern withBlock:block overrideExisting:YES]; } -+ (void)stubMessagePattern:(KWMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block overrideExisting:(BOOL)override { ++ (void)stubMessagePattern:(KWSelectorMessagePattern *)aMessagePattern withBlock:(id (^)(NSArray *params))block overrideExisting:(BOOL)override { if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) { [NSException raise:@"KWStubException" format:@"cannot stub -%@ because no such method exists", NSStringFromSelector(aMessagePattern.selector)]; @@ -221,7 +221,7 @@ - (void)clearStubs { #pragma mark - Spying on Messages -- (void)addMessageSpy:(id)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern { +- (void)addMessageSpy:(id)aSpy forMessagePattern:(KWSelectorMessagePattern *)aMessagePattern { if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) { [NSException raise:@"KWSpyException" format:@"cannot add spy for -%@ because no such method exists", NSStringFromSelector(aMessagePattern.selector)]; @@ -232,17 +232,17 @@ - (void)addMessageSpy:(id)aSpy forMessagePattern:(KWMessagePatt KWAssociateMessageSpy(self, aSpy, aMessagePattern); } -- (void)removeMessageSpy:(id)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern { +- (void)removeMessageSpy:(id)aSpy forMessagePattern:(KWSelectorMessagePattern *)aMessagePattern { KWClearObjectSpy(self, aSpy, aMessagePattern); } - (KWCaptureSpy *)captureArgument:(SEL)selector atIndex:(NSUInteger)index { KWCaptureSpy *spy = [[KWCaptureSpy alloc] initWithArgumentIndex:index]; - [self addMessageSpy:spy forMessagePattern:[KWMessagePattern messagePatternWithSelector:selector]]; + [self addMessageSpy:spy forMessagePattern:[KWSelectorMessagePattern messagePatternWithSelector:selector]]; return spy; } -+ (void)addMessageSpy:(id)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern { ++ (void)addMessageSpy:(id)aSpy forMessagePattern:(KWSelectorMessagePattern *)aMessagePattern { if ([self methodSignatureForSelector:aMessagePattern.selector] == nil) { [NSException raise:@"KWSpyException" format:@"cannot add spy for -%@ because no such method exists", NSStringFromSelector(aMessagePattern.selector)]; @@ -253,13 +253,13 @@ + (void)addMessageSpy:(id)aSpy forMessagePattern:(KWMessagePatt KWAssociateMessageSpy(self, aSpy, aMessagePattern); } -+ (void)removeMessageSpy:(id)aSpy forMessagePattern:(KWMessagePattern *)aMessagePattern { ++ (void)removeMessageSpy:(id)aSpy forMessagePattern:(KWSelectorMessagePattern *)aMessagePattern { KWClearObjectSpy(self, aSpy, aMessagePattern); } + (KWCaptureSpy *)captureArgument:(SEL)selector atIndex:(NSUInteger)index { KWCaptureSpy *spy = [[KWCaptureSpy alloc] initWithArgumentIndex:index]; - [self addMessageSpy:spy forMessagePattern:[KWMessagePattern messagePatternWithSelector:selector]]; + [self addMessageSpy:spy forMessagePattern:[KWSelectorMessagePattern messagePatternWithSelector:selector]]; return spy; } diff --git a/Kiwi.xcodeproj/project.pbxproj b/Kiwi.xcodeproj/project.pbxproj index 13095624..da352cdf 100755 --- a/Kiwi.xcodeproj/project.pbxproj +++ b/Kiwi.xcodeproj/project.pbxproj @@ -24,7 +24,7 @@ 4AE02FE61AEB47E600556381 /* KWFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982C8516A802920030A0B1 /* KWFormatter.m */; }; 4AE02FE71AEB47E600556381 /* KWFutureObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982C8716A802920030A0B1 /* KWFutureObject.m */; }; 4AE02FE81AEB47E600556381 /* KWInvocationCapturer.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982C9616A802920030A0B1 /* KWInvocationCapturer.m */; }; - 4AE02FE91AEB47E600556381 /* KWMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AE33459195820DC00CDE895 /* KWMessagePattern.m */; }; + 4AE02FE91AEB47E600556381 /* KWSelectorMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AE33459195820DC00CDE895 /* KWSelectorMessagePattern.m */; }; 4AE02FEA1AEB47E600556381 /* KWMessageTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982CA616A802920030A0B1 /* KWMessageTracker.m */; }; 4AE02FEB1AEB47E600556381 /* KWNull.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982CAA16A802920030A0B1 /* KWNull.m */; }; 4AE02FEC1AEB47E600556381 /* KWObjCUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982CAC16A802920030A0B1 /* KWObjCUtilities.m */; }; @@ -113,7 +113,7 @@ 4AE030411AEB47FF00556381 /* KWFutureObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982C8616A802920030A0B1 /* KWFutureObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4AE030421AEB47FF00556381 /* KWInvocationCapturer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982C9516A802920030A0B1 /* KWInvocationCapturer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4AE030431AEB47FF00556381 /* KWLet.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A03096618448E800086F533 /* KWLet.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4AE030441AEB47FF00556381 /* KWMessagePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE33458195820DC00CDE895 /* KWMessagePattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4AE030441AEB47FF00556381 /* KWSelectorMessagePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE33458195820DC00CDE895 /* KWSelectorMessagePattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4AE030451AEB47FF00556381 /* KWMessageSpying.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982CA416A802920030A0B1 /* KWMessageSpying.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4AE030461AEB47FF00556381 /* KWMessageTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982CA516A802920030A0B1 /* KWMessageTracker.h */; }; 4AE030471AEB47FF00556381 /* KWNull.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982CA916A802920030A0B1 /* KWNull.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -288,7 +288,7 @@ CE87C4491AF195BE00310C07 /* KWFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982C8516A802920030A0B1 /* KWFormatter.m */; }; CE87C44A1AF195BE00310C07 /* KWFutureObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982C8716A802920030A0B1 /* KWFutureObject.m */; }; CE87C44B1AF195BE00310C07 /* KWInvocationCapturer.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982C9616A802920030A0B1 /* KWInvocationCapturer.m */; }; - CE87C44C1AF195BE00310C07 /* KWMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AE33459195820DC00CDE895 /* KWMessagePattern.m */; }; + CE87C44C1AF195BE00310C07 /* KWSelectorMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AE33459195820DC00CDE895 /* KWSelectorMessagePattern.m */; }; CE87C44D1AF195BE00310C07 /* KWMessageTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982CA616A802920030A0B1 /* KWMessageTracker.m */; }; CE87C44E1AF195BE00310C07 /* KWNull.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982CAA16A802920030A0B1 /* KWNull.m */; }; CE87C44F1AF195BE00310C07 /* KWObjCUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F982CAC16A802920030A0B1 /* KWObjCUtilities.m */; }; @@ -380,7 +380,7 @@ CE87C4A51AF1963B00310C07 /* KWFutureObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982C8616A802920030A0B1 /* KWFutureObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; CE87C4A61AF1963B00310C07 /* KWInvocationCapturer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982C9516A802920030A0B1 /* KWInvocationCapturer.h */; settings = {ATTRIBUTES = (Public, ); }; }; CE87C4A71AF1963B00310C07 /* KWLet.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A03096618448E800086F533 /* KWLet.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CE87C4A81AF1963B00310C07 /* KWMessagePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE33458195820DC00CDE895 /* KWMessagePattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CE87C4A81AF1963B00310C07 /* KWSelectorMessagePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE33458195820DC00CDE895 /* KWSelectorMessagePattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; CE87C4A91AF1963B00310C07 /* KWMessageSpying.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982CA416A802920030A0B1 /* KWMessageSpying.h */; settings = {ATTRIBUTES = (Public, ); }; }; CE87C4AA1AF1963B00310C07 /* KWMessageTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982CA516A802920030A0B1 /* KWMessageTracker.h */; }; CE87C4AB1AF1963B00310C07 /* KWNull.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F982CA916A802920030A0B1 /* KWNull.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -515,6 +515,44 @@ CE87C52E1AF1994200310C07 /* KWStringUtilitiesTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F5FC83B511B100B100BF98A2 /* KWStringUtilitiesTest.m */; }; CE87C52F1AF1994200310C07 /* KWValueTest.m in Sources */ = {isa = PBXBuildFile; fileRef = F5C6FD2311782A290068BBC8 /* KWValueTest.m */; }; CE87C5301AF1994200310C07 /* NSNumber_KiwiAdditionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA9C69F7190CA6EE002C4DC0 /* NSNumber_KiwiAdditionsTests.m */; }; + D737DEA91CC7D9A20049D07D /* KWMessageTrackerMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = D737DEA71CC7D9A20049D07D /* KWMessageTrackerMatcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D737DEAA1CC7D9A20049D07D /* KWMessageTrackerMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = D737DEA71CC7D9A20049D07D /* KWMessageTrackerMatcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D737DEAB1CC7D9A20049D07D /* KWMessageTrackerMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = D737DEA81CC7D9A20049D07D /* KWMessageTrackerMatcher.m */; }; + D737DEAC1CC7D9A20049D07D /* KWMessageTrackerMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = D737DEA81CC7D9A20049D07D /* KWMessageTrackerMatcher.m */; }; + D737DEAF1CC7DEF00049D07D /* KWBeEvaluatedMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = D737DEAD1CC7DEF00049D07D /* KWBeEvaluatedMatcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D737DEB01CC7DEF00049D07D /* KWBeEvaluatedMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = D737DEAD1CC7DEF00049D07D /* KWBeEvaluatedMatcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D737DEB11CC7DEF00049D07D /* KWBeEvaluatedMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = D737DEAE1CC7DEF00049D07D /* KWBeEvaluatedMatcher.m */; }; + D737DEB21CC7DEF00049D07D /* KWBeEvaluatedMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = D737DEAE1CC7DEF00049D07D /* KWBeEvaluatedMatcher.m */; }; + D73A29951CC90571007BEAFB /* KWBeEvaluatedMatcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D73A29941CC90571007BEAFB /* KWBeEvaluatedMatcherTest.m */; }; + D73A29961CC90571007BEAFB /* KWBeEvaluatedMatcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D73A29941CC90571007BEAFB /* KWBeEvaluatedMatcherTest.m */; }; + D73BE5C61CCFB8BC0080CC79 /* KWMessagePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = D73BE5C41CCFB8BC0080CC79 /* KWMessagePattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D73BE5C71CCFB8BC0080CC79 /* KWMessagePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = D73BE5C41CCFB8BC0080CC79 /* KWMessagePattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D73BE5C81CCFB8BC0080CC79 /* KWMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = D73BE5C51CCFB8BC0080CC79 /* KWMessagePattern.m */; }; + D73BE5C91CCFB8BC0080CC79 /* KWMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = D73BE5C51CCFB8BC0080CC79 /* KWMessagePattern.m */; }; + D73BE5CB1CCFF4280080CC79 /* KWBlockMessagePatternTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D73BE5CA1CCFF4280080CC79 /* KWBlockMessagePatternTest.m */; }; + D73BE5CC1CCFF4280080CC79 /* KWBlockMessagePatternTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D73BE5CA1CCFF4280080CC79 /* KWBlockMessagePatternTest.m */; }; + D766D4911CD01526005F47AF /* KWBlockSignature.h in Headers */ = {isa = PBXBuildFile; fileRef = D766D48F1CD01526005F47AF /* KWBlockSignature.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D766D4921CD01526005F47AF /* KWBlockSignature.h in Headers */ = {isa = PBXBuildFile; fileRef = D766D48F1CD01526005F47AF /* KWBlockSignature.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D766D4931CD01526005F47AF /* KWBlockSignature.m in Sources */ = {isa = PBXBuildFile; fileRef = D766D4901CD01526005F47AF /* KWBlockSignature.m */; }; + D766D4941CD01526005F47AF /* KWBlockSignature.m in Sources */ = {isa = PBXBuildFile; fileRef = D766D4901CD01526005F47AF /* KWBlockSignature.m */; }; + D766D4971CD016F7005F47AF /* KWBlockInvocation.h in Headers */ = {isa = PBXBuildFile; fileRef = D766D4951CD016F7005F47AF /* KWBlockInvocation.h */; }; + D766D4981CD016F7005F47AF /* KWBlockInvocation.h in Headers */ = {isa = PBXBuildFile; fileRef = D766D4951CD016F7005F47AF /* KWBlockInvocation.h */; }; + D766D4991CD016F7005F47AF /* KWBlockInvocation.m in Sources */ = {isa = PBXBuildFile; fileRef = D766D4961CD016F7005F47AF /* KWBlockInvocation.m */; }; + D766D49A1CD016F7005F47AF /* KWBlockInvocation.m in Sources */ = {isa = PBXBuildFile; fileRef = D766D4961CD016F7005F47AF /* KWBlockInvocation.m */; }; + D775FDB41CC246590081F88E /* KWBlockLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = D775FDB21CC246590081F88E /* KWBlockLayout.m */; }; + D775FDB51CC246590081F88E /* KWBlockLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = D775FDB21CC246590081F88E /* KWBlockLayout.m */; }; + D775FDB61CC246590081F88E /* KWBlockLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = D775FDB31CC246590081F88E /* KWBlockLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D775FDB71CC246590081F88E /* KWBlockLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = D775FDB31CC246590081F88E /* KWBlockLayout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D7A2CE771CC67D9C00AB351F /* KWBlockMessagePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = D7A2CE751CC67D9C00AB351F /* KWBlockMessagePattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D7A2CE781CC67D9C00AB351F /* KWBlockMessagePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = D7A2CE751CC67D9C00AB351F /* KWBlockMessagePattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D7A2CE791CC67D9C00AB351F /* KWBlockMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = D7A2CE761CC67D9C00AB351F /* KWBlockMessagePattern.m */; }; + D7A2CE7A1CC67D9C00AB351F /* KWBlockMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = D7A2CE761CC67D9C00AB351F /* KWBlockMessagePattern.m */; }; + D7C3D13F1CC4DDA000A0E0AD /* KWProxyBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = D7C3D13D1CC4DDA000A0E0AD /* KWProxyBlock.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D7C3D1401CC4DDA000A0E0AD /* KWProxyBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = D7C3D13D1CC4DDA000A0E0AD /* KWProxyBlock.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D7C3D1411CC4DDA000A0E0AD /* KWProxyBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = D7C3D13E1CC4DDA000A0E0AD /* KWProxyBlock.m */; }; + D7C3D1421CC4DDA000A0E0AD /* KWProxyBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = D7C3D13E1CC4DDA000A0E0AD /* KWProxyBlock.m */; }; + D7C3D1441CC4E7C000A0E0AD /* KWProxyBlockTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D7C3D1431CC4E7C000A0E0AD /* KWProxyBlockTest.m */; }; + D7C3D1451CC4E7C000A0E0AD /* KWProxyBlockTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D7C3D1431CC4E7C000A0E0AD /* KWProxyBlockTest.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -584,8 +622,8 @@ 4AE02FC71AEB45EB00556381 /* KiwiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KiwiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 4AE02FD61AEB466D00556381 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4AE02FD81AEB46D000556381 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 4AE33458195820DC00CDE895 /* KWMessagePattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWMessagePattern.h; sourceTree = ""; }; - 4AE33459195820DC00CDE895 /* KWMessagePattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWMessagePattern.m; sourceTree = ""; }; + 4AE33458195820DC00CDE895 /* KWSelectorMessagePattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWSelectorMessagePattern.h; sourceTree = ""; }; + 4AE33459195820DC00CDE895 /* KWSelectorMessagePattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWSelectorMessagePattern.m; sourceTree = ""; }; 4BA52D0015487F0C00FC957B /* KWCaptureTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWCaptureTest.m; sourceTree = ""; }; 4E3C5DB01716C34900835B62 /* KWRegularExpressionPatternMatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWRegularExpressionPatternMatcher.h; sourceTree = ""; }; 4E3C5DB11716C34900835B62 /* KWRegularExpressionPatternMatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWRegularExpressionPatternMatcher.m; sourceTree = ""; }; @@ -803,13 +841,31 @@ CE39E6141B857CAB00736C33 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/Mac/Nimble.framework; sourceTree = ""; }; CE39E6171B857CE000736C33 /* KWObjCNimbleTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWObjCNimbleTests.m; sourceTree = ""; }; CE39E61A1B857DE300736C33 /* KWSwiftNimbleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KWSwiftNimbleTests.swift; sourceTree = ""; }; - CE54493E1B8BDCB0002994B5 /* KiwiTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KiwiTests-Bridging-Header.h"; sourceTree = ""; }; CE7EFF981B8475BD00FFE6D6 /* KWSwiftXCTestAssertionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KWSwiftXCTestAssertionTests.swift; sourceTree = ""; }; CE7EFF9B1B847AD700FFE6D6 /* KWObjCXCTestAssertionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWObjCXCTestAssertionTests.m; sourceTree = ""; }; CE80E44E1AF255BF00D2F0D6 /* KWBackgroundTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWBackgroundTask.h; sourceTree = ""; }; CE80E44F1AF255BF00D2F0D6 /* KWBackgroundTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBackgroundTask.m; sourceTree = ""; }; CE87C4231AF194E900310C07 /* Kiwi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Kiwi.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE87C42D1AF194EA00310C07 /* KiwiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KiwiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D737DEA71CC7D9A20049D07D /* KWMessageTrackerMatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWMessageTrackerMatcher.h; sourceTree = ""; }; + D737DEA81CC7D9A20049D07D /* KWMessageTrackerMatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWMessageTrackerMatcher.m; sourceTree = ""; }; + D737DEAD1CC7DEF00049D07D /* KWBeEvaluatedMatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWBeEvaluatedMatcher.h; sourceTree = ""; }; + D737DEAE1CC7DEF00049D07D /* KWBeEvaluatedMatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBeEvaluatedMatcher.m; sourceTree = ""; }; + D73A29941CC90571007BEAFB /* KWBeEvaluatedMatcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBeEvaluatedMatcherTest.m; sourceTree = ""; }; + D73BE5C41CCFB8BC0080CC79 /* KWMessagePattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWMessagePattern.h; sourceTree = ""; }; + D73BE5C51CCFB8BC0080CC79 /* KWMessagePattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWMessagePattern.m; sourceTree = ""; }; + D73BE5CA1CCFF4280080CC79 /* KWBlockMessagePatternTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBlockMessagePatternTest.m; sourceTree = ""; }; + D766D48F1CD01526005F47AF /* KWBlockSignature.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWBlockSignature.h; sourceTree = ""; }; + D766D4901CD01526005F47AF /* KWBlockSignature.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBlockSignature.m; sourceTree = ""; }; + D766D4951CD016F7005F47AF /* KWBlockInvocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWBlockInvocation.h; sourceTree = ""; }; + D766D4961CD016F7005F47AF /* KWBlockInvocation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBlockInvocation.m; sourceTree = ""; }; + D775FDB21CC246590081F88E /* KWBlockLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBlockLayout.m; sourceTree = ""; }; + D775FDB31CC246590081F88E /* KWBlockLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWBlockLayout.h; sourceTree = ""; }; + D7A2CE751CC67D9C00AB351F /* KWBlockMessagePattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWBlockMessagePattern.h; sourceTree = ""; }; + D7A2CE761CC67D9C00AB351F /* KWBlockMessagePattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBlockMessagePattern.m; sourceTree = ""; }; + D7C3D13D1CC4DDA000A0E0AD /* KWProxyBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWProxyBlock.h; sourceTree = ""; }; + D7C3D13E1CC4DDA000A0E0AD /* KWProxyBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWProxyBlock.m; sourceTree = ""; }; + D7C3D1431CC4E7C000A0E0AD /* KWProxyBlockTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWProxyBlockTest.m; sourceTree = ""; }; DA084D3F17E3804200592D5A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; DA084D4217E3804200592D5A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; DA3EAD0718A7A1D700EBBF57 /* KWSharedExampleFunctionalTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWSharedExampleFunctionalTest.m; sourceTree = ""; }; @@ -984,6 +1040,10 @@ CE80E44F1AF255BF00D2F0D6 /* KWBackgroundTask.m */, 9F982C6116A802920030A0B1 /* KWBlock.h */, 9F982C6216A802920030A0B1 /* KWBlock.m */, + D7C3D13D1CC4DDA000A0E0AD /* KWProxyBlock.h */, + D7C3D13E1CC4DDA000A0E0AD /* KWProxyBlock.m */, + D775FDB31CC246590081F88E /* KWBlockLayout.h */, + D775FDB21CC246590081F88E /* KWBlockLayout.m */, 9F982C6716A802920030A0B1 /* KWCallSite.h */, 9F982C6816A802920030A0B1 /* KWCallSite.m */, 9F982C6916A802920030A0B1 /* KWCaptureSpy.h */, @@ -1016,8 +1076,12 @@ 9F982C9D16A802920030A0B1 /* KWMatchers.h */, 9F982C9E16A802920030A0B1 /* KWMatchers.m */, 9F982C9F16A802920030A0B1 /* KWMatching.h */, - 4AE33458195820DC00CDE895 /* KWMessagePattern.h */, - 4AE33459195820DC00CDE895 /* KWMessagePattern.m */, + D73BE5C41CCFB8BC0080CC79 /* KWMessagePattern.h */, + D73BE5C51CCFB8BC0080CC79 /* KWMessagePattern.m */, + 4AE33458195820DC00CDE895 /* KWSelectorMessagePattern.h */, + 4AE33459195820DC00CDE895 /* KWSelectorMessagePattern.m */, + D7A2CE751CC67D9C00AB351F /* KWBlockMessagePattern.h */, + D7A2CE761CC67D9C00AB351F /* KWBlockMessagePattern.m */, 9F982CA416A802920030A0B1 /* KWMessageSpying.h */, 9F982CA516A802920030A0B1 /* KWMessageTracker.h */, 9F982CA616A802920030A0B1 /* KWMessageTracker.m */, @@ -1039,10 +1103,14 @@ 9F982CCA16A802920030A0B1 /* KWValue.m */, 9F982CCC16A802920030A0B1 /* KWWorkarounds.h */, 9F982CCD16A802920030A0B1 /* KWWorkarounds.m */, + D766D4951CD016F7005F47AF /* KWBlockInvocation.h */, + D766D4961CD016F7005F47AF /* KWBlockInvocation.m */, 9F982CCE16A802920030A0B1 /* NSInvocation+KiwiAdditions.h */, 9F982CCF16A802920030A0B1 /* NSInvocation+KiwiAdditions.m */, 9F982CD016A802920030A0B1 /* NSInvocation+OCMAdditions.h */, 9F982CD116A802920030A0B1 /* NSInvocation+OCMAdditions.m */, + D766D48F1CD01526005F47AF /* KWBlockSignature.h */, + D766D4901CD01526005F47AF /* KWBlockSignature.m */, 9F982CD216A802920030A0B1 /* NSMethodSignature+KiwiAdditions.h */, 9F982CD316A802920030A0B1 /* NSMethodSignature+KiwiAdditions.m */, 9F982CD416A802920030A0B1 /* NSNumber+KiwiAdditions.h */, @@ -1132,8 +1200,12 @@ 9F982C5616A802920030A0B1 /* KWNilMatcher.m */, DAA1B3AD18CF25C00015CF7A /* KWNotificationMatcher.h */, DAA1B3AE18CF25C00015CF7A /* KWNotificationMatcher.m */, + D737DEA71CC7D9A20049D07D /* KWMessageTrackerMatcher.h */, + D737DEA81CC7D9A20049D07D /* KWMessageTrackerMatcher.m */, 9F982CB416A802920030A0B1 /* KWReceiveMatcher.h */, 9F982CB516A802920030A0B1 /* KWReceiveMatcher.m */, + D737DEAD1CC7DEF00049D07D /* KWBeEvaluatedMatcher.h */, + D737DEAE1CC7DEF00049D07D /* KWBeEvaluatedMatcher.m */, 4E3C5DB01716C34900835B62 /* KWRegularExpressionPatternMatcher.h */, 4E3C5DB11716C34900835B62 /* KWRegularExpressionPatternMatcher.m */, 9F982CB916A802920030A0B1 /* KWRespondToSelectorMatcher.h */, @@ -1306,7 +1378,9 @@ F5D7C8D311643C2900758FEA /* KWDeviceInfoTest.m */, 89861D9316FE0EE5008CE99D /* KWFormatterTest.m */, F55E61CD119B74D600F30B42 /* KWMessagePatternTest.m */, + D73BE5CA1CCFF4280080CC79 /* KWBlockMessagePatternTest.m */, DAAC61CA17E75B50000165F6 /* KWObjCUtilitiesTest.m */, + D7C3D1431CC4E7C000A0E0AD /* KWProxyBlockTest.m */, F5FC83B511B100B100BF98A2 /* KWStringUtilitiesTest.m */, F5C6FD2311782A290068BBC8 /* KWValueTest.m */, DA9C69F7190CA6EE002C4DC0 /* NSNumber_KiwiAdditionsTests.m */, @@ -1337,6 +1411,7 @@ A352E9E712EDC30A0049C691 /* KWHaveValueMatcherTest.m */, F553B29D11755A00004FCA2E /* KWInequalityMatcherTest.m */, F5C36E91115C9F0700425FDA /* KWReceiveMatcherTest.m */, + D73A29941CC90571007BEAFB /* KWBeEvaluatedMatcherTest.m */, 4E3C5DB71716C68000835B62 /* KWRegularExpressionPatternMatcherTest.m */, F553B6641175D48C004FCA2E /* KWRespondToSelectorMatcherTest.m */, A385CAE713AA7EA200DCA951 /* KWUserDefinedMatcherTest.m */, @@ -1385,10 +1460,11 @@ 4AE030411AEB47FF00556381 /* KWFutureObject.h in Headers */, 4AE030421AEB47FF00556381 /* KWInvocationCapturer.h in Headers */, 4AE030431AEB47FF00556381 /* KWLet.h in Headers */, - 4AE030441AEB47FF00556381 /* KWMessagePattern.h in Headers */, + 4AE030441AEB47FF00556381 /* KWSelectorMessagePattern.h in Headers */, 4AE030451AEB47FF00556381 /* KWMessageSpying.h in Headers */, 4AE030471AEB47FF00556381 /* KWNull.h in Headers */, 4AE030481AEB47FF00556381 /* KWObjCUtilities.h in Headers */, + D7C3D1401CC4DDA000A0E0AD /* KWProxyBlock.h in Headers */, 4AE0304C1AEB480000556381 /* KWSpec.h in Headers */, 4AE0304D1AEB480000556381 /* KWStringUtilities.h in Headers */, 4AE0304E1AEB480000556381 /* KWValue.h in Headers */, @@ -1410,12 +1486,14 @@ 4AE030641AEB480200556381 /* KWBeTrueMatcher.h in Headers */, 4AE030651AEB480300556381 /* KWBeWithinMatcher.h in Headers */, 4AE030661AEB480300556381 /* KWBeZeroMatcher.h in Headers */, + D737DEB01CC7DEF00049D07D /* KWBeEvaluatedMatcher.h in Headers */, 4AE030671AEB480300556381 /* KWBlockRaiseMatcher.h in Headers */, 4AE030681AEB480300556381 /* KWChangeMatcher.h in Headers */, 4AE030691AEB480300556381 /* KWConformToProtocolMatcher.h in Headers */, 4AE0306A1AEB480300556381 /* KWContainMatcher.h in Headers */, 4AE0306B1AEB480300556381 /* KWContainStringMatcher.h in Headers */, 4AE0306C1AEB480400556381 /* KWEqualMatcher.h in Headers */, + D766D4921CD01526005F47AF /* KWBlockSignature.h in Headers */, 4AE0306D1AEB480400556381 /* KWGenericMatcher.h in Headers */, 4AE030701AEB480400556381 /* KWHaveMatcher.h in Headers */, 4AE030711AEB480400556381 /* KWHaveValueMatcher.h in Headers */, @@ -1441,9 +1519,13 @@ CE87C4F31AF1990200310C07 /* Kiwi.h in Headers */, 4AE030851AEB480800556381 /* KWRegisterMatchersNode.h in Headers */, 4AE030861AEB480800556381 /* KWSharedExample.h in Headers */, + D775FDB71CC246590081F88E /* KWBlockLayout.h in Headers */, + D73BE5C71CCFB8BC0080CC79 /* KWMessagePattern.h in Headers */, + D766D4981CD016F7005F47AF /* KWBlockInvocation.h in Headers */, 4AE030881AEB480800556381 /* KWStub.h in Headers */, 4AE0308A1AEB480900556381 /* NSObject+KiwiStubAdditions.h in Headers */, CE80E4511AF255BF00D2F0D6 /* KWBackgroundTask.h in Headers */, + D7A2CE781CC67D9C00AB351F /* KWBlockMessagePattern.h in Headers */, 4AE0308B1AEB480900556381 /* KWAsyncVerifier.h in Headers */, 4AE0303B1AEB47FE00556381 /* KWExampleDelegate.h in Headers */, 4AE0308C1AEB480900556381 /* KWExistVerifier.h in Headers */, @@ -1465,6 +1547,7 @@ 4AE030541AEB480100556381 /* NSInvocation+KiwiAdditions.h in Headers */, 4AE030561AEB480100556381 /* NSMethodSignature+KiwiAdditions.h in Headers */, 4AE030571AEB480100556381 /* NSNumber+KiwiAdditions.h in Headers */, + D737DEAA1CC7D9A20049D07D /* KWMessageTrackerMatcher.h in Headers */, 4AE0305B1AEB480100556381 /* NSValue+KiwiAdditions.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1495,12 +1578,13 @@ CE87C4D91AF1963B00310C07 /* KWRespondToSelectorMatcher.h in Headers */, CE87C4E81AF1963B00310C07 /* KWPendingNode.h in Headers */, CE87C4A71AF1963B00310C07 /* KWLet.h in Headers */, + D7C3D13F1CC4DDA000A0E0AD /* KWProxyBlock.h in Headers */, CE87C4C01AF1963B00310C07 /* KWNotificationMatcher.h in Headers */, CE87C4AB1AF1963B00310C07 /* KWNull.h in Headers */, CE87C4B41AF1963B00310C07 /* KWMatcher.h in Headers */, CE87C4B51AF1963B00310C07 /* KWMatcherFactory.h in Headers */, CE87C4B71AF1963B00310C07 /* KWMatching.h in Headers */, - CE87C4A81AF1963B00310C07 /* KWMessagePattern.h in Headers */, + CE87C4A81AF1963B00310C07 /* KWSelectorMessagePattern.h in Headers */, CE87C4B61AF1963B00310C07 /* KWMatchers.h in Headers */, CE87C4DD1AF1963B00310C07 /* KWMock.h in Headers */, CE87C4A91AF1963B00310C07 /* KWMessageSpying.h in Headers */, @@ -1516,12 +1600,14 @@ CE87C4D01AF1963B00310C07 /* KWEqualMatcher.h in Headers */, CE87C4A11AF1963B00310C07 /* KWExampleNodeVisitor.h in Headers */, CE87C4E51AF1963B00310C07 /* KWExampleNode.h in Headers */, + D737DEAF1CC7DEF00049D07D /* KWBeEvaluatedMatcher.h in Headers */, CE87C4A21AF1963B00310C07 /* KWExpectationType.h in Headers */, CE87C4F01AF1963B00310C07 /* KWExistVerifier.h in Headers */, CE87C49E1AF1963B00310C07 /* KWExample.h in Headers */, CE87C49F1AF1963B00310C07 /* KWExampleSuiteBuilder.h in Headers */, CE87C49D1AF1963B00310C07 /* KWDeviceInfo.h in Headers */, CE87C49B1AF1963B00310C07 /* KWCaptureSpy.h in Headers */, + D766D4911CD01526005F47AF /* KWBlockSignature.h in Headers */, CE87C49A1AF1963B00310C07 /* KWCallSite.h in Headers */, CE87C4CC1AF1963B00310C07 /* KWChangeMatcher.h in Headers */, CE87C4CE1AF1963B00310C07 /* KWContainMatcher.h in Headers */, @@ -1547,9 +1633,13 @@ CE87C4E01AF1963B00310C07 /* KWAfterEachNode.h in Headers */, CE87C4EF1AF1963B00310C07 /* KWAsyncVerifier.h in Headers */, CE87C4ED1AF1963B00310C07 /* KWIntercept.h in Headers */, + D775FDB61CC246590081F88E /* KWBlockLayout.h in Headers */, + D73BE5C61CCFB8BC0080CC79 /* KWMessagePattern.h in Headers */, + D766D4971CD016F7005F47AF /* KWBlockInvocation.h in Headers */, CE87C4EB1AF1963B00310C07 /* KWSharedExampleRegistry.h in Headers */, CE87C4E71AF1963B00310C07 /* KWLetNode.h in Headers */, CE80E4501AF255BF00D2F0D6 /* KWBackgroundTask.h in Headers */, + D7A2CE771CC67D9C00AB351F /* KWBlockMessagePattern.h in Headers */, CE87C4D21AF1963B00310C07 /* KWGenericMatchEvaluator.h in Headers */, CE87C4961AF1963B00310C07 /* KiwiConfiguration.h in Headers */, CE87C4A01AF1963B00310C07 /* KWExampleDelegate.h in Headers */, @@ -1571,6 +1661,7 @@ CE87C4B91AF1963B00310C07 /* NSInvocation+OCMAdditions.h in Headers */, CE87C4BA1AF1963B00310C07 /* NSMethodSignature+KiwiAdditions.h in Headers */, CE87C4BB1AF1963B00310C07 /* NSNumber+KiwiAdditions.h in Headers */, + D737DEA91CC7D9A20049D07D /* KWMessageTrackerMatcher.h in Headers */, CE87C4BF1AF1963B00310C07 /* NSValue+KiwiAdditions.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1736,10 +1827,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D766D4941CD01526005F47AF /* KWBlockSignature.m in Sources */, 4AE02FDA1AEB47E600556381 /* KWSuiteConfigurationBase.m in Sources */, 4AE02FDB1AEB47E600556381 /* KWAllTestsSuite.m in Sources */, 4AE02FDC1AEB47E600556381 /* KWSymbolicator.m in Sources */, + D737DEAC1CC7D9A20049D07D /* KWMessageTrackerMatcher.m in Sources */, 4AE02FDD1AEB47E600556381 /* KWAny.m in Sources */, + D737DEB21CC7DEF00049D07D /* KWBeEvaluatedMatcher.m in Sources */, 4AE02FDE1AEB47E600556381 /* KWBlock.m in Sources */, 4AE02FDF1AEB47E600556381 /* KWCallSite.m in Sources */, 4AE02FE01AEB47E600556381 /* KWCaptureSpy.m in Sources */, @@ -1751,10 +1845,12 @@ 4AE02FE61AEB47E600556381 /* KWFormatter.m in Sources */, 4AE02FE71AEB47E600556381 /* KWFutureObject.m in Sources */, 4AE02FE81AEB47E600556381 /* KWInvocationCapturer.m in Sources */, - 4AE02FE91AEB47E600556381 /* KWMessagePattern.m in Sources */, + 4AE02FE91AEB47E600556381 /* KWSelectorMessagePattern.m in Sources */, 4AE02FEA1AEB47E600556381 /* KWMessageTracker.m in Sources */, 4AE02FEB1AEB47E600556381 /* KWNull.m in Sources */, + D7A2CE7A1CC67D9C00AB351F /* KWBlockMessagePattern.m in Sources */, 4AE02FEC1AEB47E600556381 /* KWObjCUtilities.m in Sources */, + D766D49A1CD016F7005F47AF /* KWBlockInvocation.m in Sources */, 4AE02FED1AEB47E600556381 /* KWProbePoller.m in Sources */, CE80E4531AF255BF00D2F0D6 /* KWBackgroundTask.m in Sources */, 4AE02FEE1AEB47E600556381 /* KWSpec.m in Sources */, @@ -1783,8 +1879,10 @@ 4AE030061AEB47E600556381 /* KWBeWithinMatcher.m in Sources */, 4AE030071AEB47E600556381 /* KWBeZeroMatcher.m in Sources */, 4AE030081AEB47E600556381 /* KWBlockRaiseMatcher.m in Sources */, + D775FDB51CC246590081F88E /* KWBlockLayout.m in Sources */, 4AE030091AEB47E600556381 /* KWChangeMatcher.m in Sources */, 4AE0300A1AEB47E600556381 /* KWConformToProtocolMatcher.m in Sources */, + D7C3D1421CC4DDA000A0E0AD /* KWProxyBlock.m in Sources */, 4AE0300B1AEB47E600556381 /* KWContainMatcher.m in Sources */, 4AE0300C1AEB47E600556381 /* KWContainStringMatcher.m in Sources */, 4AE0300D1AEB47E600556381 /* KWEqualMatcher.m in Sources */, @@ -1798,6 +1896,7 @@ 4AE030151AEB47E600556381 /* KWRegularExpressionPatternMatcher.m in Sources */, 4AE030161AEB47E600556381 /* KWRespondToSelectorMatcher.m in Sources */, 4AE030CA1AEB4DCF00556381 /* NSObject+KiwiSpyAdditions.m in Sources */, + D73BE5C91CCFB8BC0080CC79 /* KWMessagePattern.m in Sources */, 4AE030171AEB47E600556381 /* KWStringContainsMatcher.m in Sources */, 4AE030181AEB47E600556381 /* KWStringPrefixMatcher.m in Sources */, 4AE030191AEB47E600556381 /* KWUserDefinedMatcher.m in Sources */, @@ -1861,6 +1960,8 @@ 4AE030A71AEB494400556381 /* KWMockTest.m in Sources */, 4AE030A81AEB494400556381 /* KWRealObjectSpyTest.m in Sources */, 4AE030A91AEB494400556381 /* KWRealObjectStubTest.m in Sources */, + D73A29961CC90571007BEAFB /* KWBeEvaluatedMatcherTest.m in Sources */, + D73BE5CC1CCFF4280080CC79 /* KWBlockMessagePatternTest.m in Sources */, 4AE030AA1AEB494400556381 /* KWStubTest.m in Sources */, 4AE030AB1AEB494400556381 /* KWCaptureTest.m in Sources */, 4AE030AC1AEB494400556381 /* KWSharedExampleRegistryTest.m in Sources */, @@ -1880,6 +1981,7 @@ 4AE030B91AEB494400556381 /* TestSpy.m in Sources */, 4AE030BA1AEB494400556381 /* TestVerifier.m in Sources */, 4AE030BB1AEB494400556381 /* KWBlockNodeTest.m in Sources */, + D7C3D1451CC4E7C000A0E0AD /* KWProxyBlockTest.m in Sources */, 4AE030BC1AEB494400556381 /* KWContextNodeTest.m in Sources */, 4AE030BD1AEB494400556381 /* KWExampleSuiteBuilderTest.m in Sources */, 4AE030BE1AEB494400556381 /* KWExampleSuiteTest.m in Sources */, @@ -1900,10 +2002,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D766D4931CD01526005F47AF /* KWBlockSignature.m in Sources */, CE87C43D1AF195BE00310C07 /* KWSuiteConfigurationBase.m in Sources */, CE87C43E1AF195BE00310C07 /* KWAllTestsSuite.m in Sources */, CE87C43F1AF195BE00310C07 /* KWSymbolicator.m in Sources */, + D737DEAB1CC7D9A20049D07D /* KWMessageTrackerMatcher.m in Sources */, CE87C4401AF195BE00310C07 /* KWAny.m in Sources */, + D737DEB11CC7DEF00049D07D /* KWBeEvaluatedMatcher.m in Sources */, CE87C4411AF195BE00310C07 /* KWBlock.m in Sources */, CE87C4421AF195BE00310C07 /* KWCallSite.m in Sources */, CE87C4431AF195BE00310C07 /* KWCaptureSpy.m in Sources */, @@ -1915,10 +2020,12 @@ CE87C4491AF195BE00310C07 /* KWFormatter.m in Sources */, CE87C44A1AF195BE00310C07 /* KWFutureObject.m in Sources */, CE87C44B1AF195BE00310C07 /* KWInvocationCapturer.m in Sources */, - CE87C44C1AF195BE00310C07 /* KWMessagePattern.m in Sources */, + CE87C44C1AF195BE00310C07 /* KWSelectorMessagePattern.m in Sources */, CE87C44D1AF195BE00310C07 /* KWMessageTracker.m in Sources */, CE87C44E1AF195BE00310C07 /* KWNull.m in Sources */, + D7A2CE791CC67D9C00AB351F /* KWBlockMessagePattern.m in Sources */, CE87C44F1AF195BE00310C07 /* KWObjCUtilities.m in Sources */, + D766D4991CD016F7005F47AF /* KWBlockInvocation.m in Sources */, CE87C4501AF195BE00310C07 /* KWProbePoller.m in Sources */, CE80E4521AF255BF00D2F0D6 /* KWBackgroundTask.m in Sources */, CE87C4511AF195BE00310C07 /* KWSpec.m in Sources */, @@ -1947,8 +2054,10 @@ CE87C4681AF195BE00310C07 /* KWBeTrueMatcher.m in Sources */, CE87C4691AF195BE00310C07 /* KWBeWithinMatcher.m in Sources */, CE87C46A1AF195BE00310C07 /* KWBeZeroMatcher.m in Sources */, + D775FDB41CC246590081F88E /* KWBlockLayout.m in Sources */, CE87C46B1AF195BE00310C07 /* KWBlockRaiseMatcher.m in Sources */, CE87C46C1AF195BE00310C07 /* KWChangeMatcher.m in Sources */, + D7C3D1411CC4DDA000A0E0AD /* KWProxyBlock.m in Sources */, CE87C46D1AF195BE00310C07 /* KWConformToProtocolMatcher.m in Sources */, CE87C46E1AF195BE00310C07 /* KWContainMatcher.m in Sources */, CE87C46F1AF195BE00310C07 /* KWContainStringMatcher.m in Sources */, @@ -1962,6 +2071,7 @@ CE87C4771AF195BE00310C07 /* KWReceiveMatcher.m in Sources */, CE87C4781AF195BE00310C07 /* KWRegularExpressionPatternMatcher.m in Sources */, CE87C4791AF195BE00310C07 /* KWRespondToSelectorMatcher.m in Sources */, + D73BE5C81CCFB8BC0080CC79 /* KWMessagePattern.m in Sources */, CE87C47A1AF195BE00310C07 /* KWStringContainsMatcher.m in Sources */, CE87C47B1AF195BE00310C07 /* KWStringPrefixMatcher.m in Sources */, CE87C47C1AF195BE00310C07 /* KWUserDefinedMatcher.m in Sources */, @@ -2025,6 +2135,8 @@ CE87C50D1AF1994100310C07 /* KWRealObjectSpyTest.m in Sources */, CE87C50E1AF1994200310C07 /* KWRealObjectStubTest.m in Sources */, CE87C50F1AF1994200310C07 /* KWStubTest.m in Sources */, + D73A29951CC90571007BEAFB /* KWBeEvaluatedMatcherTest.m in Sources */, + D73BE5CB1CCFF4280080CC79 /* KWBlockMessagePatternTest.m in Sources */, CE87C5101AF1994200310C07 /* KWCaptureTest.m in Sources */, CE87C5111AF1994200310C07 /* KWSharedExampleRegistryTest.m in Sources */, CE87C5121AF1994200310C07 /* KWSharedExampleTest.m in Sources */, @@ -2044,6 +2156,7 @@ CE87C5211AF1994200310C07 /* TestVerifier.m in Sources */, CE87C5221AF1994200310C07 /* KWBlockNodeTest.m in Sources */, CE87C5231AF1994200310C07 /* KWContextNodeTest.m in Sources */, + D7C3D1441CC4E7C000A0E0AD /* KWProxyBlockTest.m in Sources */, CE87C5241AF1994200310C07 /* KWExampleSuiteBuilderTest.m in Sources */, CE87C5251AF1994200310C07 /* KWExampleSuiteTest.m in Sources */, CE87C5261AF1994200310C07 /* KWExampleTest.m in Sources */, diff --git a/Tests/KWBeEvaluatedMatcherTest.m b/Tests/KWBeEvaluatedMatcherTest.m new file mode 100644 index 00000000..9133a67f --- /dev/null +++ b/Tests/KWBeEvaluatedMatcherTest.m @@ -0,0 +1,269 @@ +// +// KWBeEvaluatedMatcherTest.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/21/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import +#import "KiwiTestConfiguration.h" +#import "TestClasses.h" + +#if KW_TESTS_ENABLED + +typedef void(^KWTestBlock)(id); + +@interface KWBeEvaluatedMatcherTest : XCTestCase +@property (nonatomic, strong) id subject; +@property (nonatomic, strong) id parameter; +@property (nonatomic, readonly) KWBeEvaluatedMatcher *matcher; +@property (nonatomic, readonly) KWBeEvaluatedMatcher *negativeExpecationMatcher; + +@end + +@implementation KWBeEvaluatedMatcherTest + +@dynamic matcher; +@dynamic negativeExpecationMatcher; + +- (void)setUp { + [super setUp]; + + self.parameter = [NSObject new]; + + id subject = [KWProxyBlock blockWithBlock:^(id object) { [object description]; }]; + + self.subject = subject; +} + +- (KWBeEvaluatedMatcher *)matcher { + return [KWBeEvaluatedMatcher matcherWithSubject:self.subject]; +} + +- (KWBeEvaluatedMatcher *)negativeExpecationMatcher { + KWBeEvaluatedMatcher *matcher = self.matcher; + matcher.willEvaluateAgainstNegativeExpectation = YES; + + return matcher; +} + +- (void)callSubject { + id subject = self.subject; + + if (subject) { + ((KWTestBlock)subject)(self.parameter); + } +} + +- (void)callSubjectWithCount:(NSUInteger)count { + for (NSUInteger i = 0; i < count; i++) { + [self callSubject]; + } +} + +- (void)testItShouldHaveTheRightMatcherStrings { + id matcherStrings = [KWBeEvaluatedMatcher matcherStrings]; + id expectedStrings = @[@"beEvaluated", + @"beEvaluatedWithCount", + @"beEvaluatedWithCountAtLeast:", + @"beEvaluatedWithCountAtMost:", + @"beEvaluatedWithArguments:", + @"beEvaluatedWithCount:arguments:", + @"beEvaluatedWithCountAtLeast:arguments:", + @"beEvaluatedWithCountAtMost:arguments:", + @"beEvaluatedWithUnspecifiedCountOfMessagePattern:", + @"beEvaluatedWithMessagePattern:countType:count:"]; + + XCTAssertEqualObjects([matcherStrings sortedArrayUsingSelector:@selector(compare:)], + [expectedStrings sortedArrayUsingSelector:@selector(compare:)], + @"expected specific matcher strings"); +} + +#pragma mark - beEvaluated testing + +- (void)testItShouldMatchEvaluationsForBeEvaluated { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluated]; + + [self callSubject]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldMatchMultipleEvaluationsForBeEvaluatedWhenAttachedToNegativeVerifier { + KWBeEvaluatedMatcher *matcher = self.negativeExpecationMatcher; + [matcher beEvaluated]; + + [self callSubjectWithCount:2]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldNotMatchMultipleEvaluationsForBeEvaluatedWhenNotAttachedToNegativeVerifier { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluated]; + [matcher beEvaluated]; + + [self callSubjectWithCount:2]; + + XCTAssertFalse([matcher evaluate], @"expected negative match"); +} + +- (void)testItShouldMatchEvaluationsForBeEvaluatedWithCount { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCount:2]; + + [self callSubjectWithCount:2]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldNotMatchEvaluationsForBeEvaluatedWithInappropriateCount { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCount:2]; + + [self callSubjectWithCount:3]; + + XCTAssertFalse([matcher evaluate], @"expected negative match"); +} + +- (void)testItShouldMatchEvaluationsForBeEvaluatedWithCountAtLeast { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCountAtLeast:2]; + + [self callSubjectWithCount:3]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldNotMatchEvaluationsForBeEvaluatedWithInappropriateCountAtLeast { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCountAtLeast:2]; + + [self callSubjectWithCount:1]; + + XCTAssertFalse([matcher evaluate], @"expected negative match"); +} + +- (void)testItShouldMatchEvaluationsForBeEvaluatedWithCountAtMost { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCountAtMost:3]; + + [self callSubjectWithCount:2]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldNotMatchEvaluationsForBeEvaluatedWithInappropriateCountAtMost { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCountAtMost:2]; + + [self callSubjectWithCount:3]; + + XCTAssertFalse([matcher evaluate], @"expected negative match"); +} + +#pragma mark - beEvaluatedWithParameters + +- (void)testItShouldMatchEvaluationsAndParametersForBeEvaluated { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithArguments:self.parameter]; + + [self callSubject]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldMatchMultipleEvaluationsAndParametersForBeEvaluatedWhenAttachedToNegativeVerifier { + KWBeEvaluatedMatcher *matcher = self.negativeExpecationMatcher; + [matcher beEvaluatedWithArguments:self.parameter]; + + [self callSubjectWithCount:2]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldNotMatchMultipleEvaluationsAndParametersForBeEvaluatedWhenNotAttachedToNegativeVerifier { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithArguments:self.parameter]; + [matcher beEvaluatedWithArguments:self.parameter]; + + [self callSubjectWithCount:2]; + + XCTAssertFalse([matcher evaluate], @"expected negative match"); +} + +- (void)testItShouldMatchEvaluationsAndParametersForBeEvaluatedWithCount { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCount:2 arguments:self.parameter]; + + [self callSubjectWithCount:2]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldNotMatchEvaluationsAndParametersForBeEvaluatedWithInappropriateCount { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCount:2 arguments:self.parameter]; + + [self callSubjectWithCount:3]; + + XCTAssertFalse([matcher evaluate], @"expected negative match"); +} + +- (void)testItShouldMatchEvaluationsAndParametersForBeEvaluatedWithCountAtLeast { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCountAtLeast:2 arguments:self.parameter]; + + [self callSubjectWithCount:3]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldNotMatchEvaluationsAndParametersForBeEvaluatedWithInappropriateCountAtLeast { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCountAtLeast:2 arguments:self.parameter]; + + [self callSubjectWithCount:1]; + + XCTAssertFalse([matcher evaluate], @"expected negative match"); +} + +- (void)testItShouldMatchEvaluationsAndParametersForBeEvaluatedWithCountAtMost { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCountAtMost:3 arguments:self.parameter]; + + [self callSubjectWithCount:2]; + + XCTAssertTrue([matcher evaluate], @"expected positive match"); +} + +- (void)testItShouldNotMatchEvaluationsAndParametersForBeEvaluatedWithInappropriateCountAtMost { + KWBeEvaluatedMatcher *matcher = self.matcher; + + [matcher beEvaluatedWithCountAtMost:2 arguments:self.parameter]; + + [self callSubjectWithCount:3]; + + XCTAssertFalse([matcher evaluate], @"expected negative match"); +} + +@end + +#endif // #if KW_TESTS_ENABLED diff --git a/Tests/KWBlockMessagePatternTest.m b/Tests/KWBlockMessagePatternTest.m new file mode 100644 index 00000000..3625a153 --- /dev/null +++ b/Tests/KWBlockMessagePatternTest.m @@ -0,0 +1,163 @@ +// +// KWBlockMessagePatternTest.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/26/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import + +#import "KiwiTestConfiguration.h" +#import "NSMethodSignature+KiwiAdditions.h" +#import "TestClasses.h" +#import "KWBlockInvocation.h" + +#if KW_TESTS_ENABLED + +static NSString * const kKWFoo = @"foo"; +static NSString * const kKWBar = @"bar"; + +typedef void(^KWTestBlock)(id, id); + +@interface KWBlockMessagePatternTest : XCTestCase +@property (nonatomic) KWProxyBlock *block; +@property (nonatomic, readonly) NSMethodSignature *blockSignature; + +- (NSInvocation *)blockInvocationWithArguments:(id)firstBytes, ...; + +@end + +@implementation KWBlockMessagePatternTest + +@dynamic blockSignature; + +- (NSMethodSignature *)blockSignature { + return self.block.methodSignature; +} + +- (NSInvocation *)blockInvocationWithArguments:(id)firstBytes, ... { + NSMethodSignature *blockSignature = self.blockSignature; + NSUInteger numberOfMessageArguments = [blockSignature numberOfMessageArguments]; + + NSInvocation *invocation = [KWBlockInvocation invocationWithTarget:self.block]; + if (numberOfMessageArguments == 0) + return invocation; + + va_list argumentList; + va_start(argumentList, firstBytes); + id bytes = firstBytes; + + NSUInteger vaArgCount = numberOfMessageArguments - 1; + for (NSUInteger i = 0; i < vaArgCount; ++i) { + [invocation setMessageArgument:&bytes atIndex:i]; + bytes = va_arg(argumentList, id); + } + + [invocation setMessageArgument:&bytes atIndex:vaArgCount]; + + va_end(argumentList); + + return invocation; +} + +- (void)setUp { + [super setUp]; + + self.block = [KWProxyBlock blockWithBlock:^(id object1, id object2) { [object1 description]; }]; +} + +- (KWBlockMessagePattern *)messagePatternWithArguments:(id)firstArgument, ... { + va_list argumentList; + va_start(argumentList, firstArgument); + + return [KWBlockMessagePattern messagePatternWithSignature:self.block.methodSignature + firstArgumentFilter:firstArgument + argumentList:argumentList]; +} + +- (void)testItShouldCreateMessagePatternsWithVarArgs { + id value = [KWValue valueWithUnsignedInt:1]; + KWBlockMessagePattern *messagePattern = [self messagePatternWithArguments:nil, value]; + + NSArray *filters = messagePattern.argumentFilters; + + XCTAssertEqualObjects(filters[0], [KWNull null], @"expected matching argument"); + XCTAssertEqualObjects(filters[1], value, @"expected matching argument"); +} + +- (void)testItShouldMatchInvocationsWithNilArguments { + KWBlockMessagePattern *messagePattern = [self messagePatternWithArguments:kKWFoo, nil]; + + NSInvocation *invocation = [self blockInvocationWithArguments:kKWFoo, nil]; + + XCTAssertTrue([messagePattern matchesInvocation:invocation], @"expected matching invocation"); +} + +- (void)testItShouldMatchInvocationsWithAnyArguments { + KWBlockMessagePattern *messagePattern = [self messagePatternWithArguments:kKWFoo, [KWAny any]]; + + NSInvocation *invocation = [self blockInvocationWithArguments:kKWFoo, kKWBar]; + + XCTAssertTrue([messagePattern matchesInvocation:invocation], @"expected matching invocation"); +} + +- (void)testItShouldMatchInvocationsWithClassArgument { + KWBlockMessagePattern *messagePattern = [self messagePatternWithArguments:[self class], nil]; + + NSInvocation *invocation = [self blockInvocationWithArguments:[self class], nil]; + + XCTAssertTrue([messagePattern matchesInvocation:invocation], @"expected matching invocation"); +} + +- (void)testItShouldMatchInvocationsWithAnyArgumentsWhenCreatedWithMessagePatternFromInvocation { + NSInvocation *creationInvocation = [self blockInvocationWithArguments:kKWFoo, [KWAny any]]; + + KWBlockMessagePattern *messagePattern = [KWBlockMessagePattern messagePatternFromInvocation:creationInvocation]; + + NSInvocation *invocation = [self blockInvocationWithArguments:kKWFoo, kKWBar]; + + XCTAssertTrue([messagePattern matchesInvocation:invocation], @"expected matching invocation"); +} + +- (void)testItShouldMatchInvocationsWithAnyArgumentsForBlockParameters { + NSInvocation *creationInvocation = [self blockInvocationWithArguments:kKWFoo, [KWAny any]]; + + KWBlockMessagePattern *messagePattern = [KWBlockMessagePattern messagePatternFromInvocation:creationInvocation]; + + NSInvocation *invocation = [self blockInvocationWithArguments:kKWFoo, ^{}]; + + XCTAssertTrue([messagePattern matchesInvocation:invocation], @"expected matching invocation"); + +} + +- (void)testItShouldNotMatchInvocationsWithAnyArguments { + KWBlockMessagePattern *messagePattern = [self messagePatternWithArguments:kKWBar, [KWAny any]]; + + NSInvocation *invocation = [self blockInvocationWithArguments:kKWFoo, kKWBar]; + + XCTAssertFalse([messagePattern matchesInvocation:invocation], @"expected non-matching invocation"); +} + +- (void)testItShouldNotMatchInvocationsWithDifferentArguments { + KWBlockMessagePattern *messagePattern = [self messagePatternWithArguments:kKWFoo, nil]; + + NSInvocation *invocation = [self blockInvocationWithArguments:kKWFoo, kKWBar]; + + XCTAssertFalse([messagePattern matchesInvocation:invocation], @"expected non-matching invocation"); +} + +- (void)testItShouldCompareMessagePatternsWithNilAndNonNilArgumentFilters { + KWBlockMessagePattern *messagePattern1 = [KWBlockMessagePattern messagePatternWithSignature:self.blockSignature]; + + NSArray *argumentFilters = @[[KWValue valueWithUnsignedInt:42]]; + KWBlockMessagePattern *messagePattern2 = [KWBlockMessagePattern messagePatternWithSignature:self.blockSignature + argumentFilters:argumentFilters]; + + XCTAssertFalse([messagePattern1 isEqual:messagePattern2], @"expected message patterns to compare as not equal"); + XCTAssertFalse([messagePattern2 isEqual:messagePattern1], @"expected message patterns to compare as not equal"); +} + +@end + +#endif // #if KW_TESTS_ENABLED diff --git a/Tests/KWMessagePatternFunctionalTests.m b/Tests/KWMessagePatternFunctionalTests.m index f4c2dd99..641d3b94 100644 --- a/Tests/KWMessagePatternFunctionalTests.m +++ b/Tests/KWMessagePatternFunctionalTests.m @@ -2,17 +2,80 @@ #import "KiwiTestConfiguration.h" #import "TestClasses.h" +typedef void(^KWVoidTestBlock)(); +typedef void(^KWArgumentTestBlock)(id); +typedef void(^KWMultiArgumentTestBlock)(id, id, id); + SPEC_BEGIN(KWMessagePatternFunctionalTests) describe(@"message patterns", ^{ + NSString *description = @"description"; + NSString *format = nil; + Cruiser *cruiser = [Cruiser new]; + + it(@"can match a selector with no arguments", ^{ + [[cruiser should] receive:@selector(computeParsecs)]; + + [cruiser computeParsecs]; + }); + it(@"can match a selector with a specific single argument", ^{ - Cruiser *cruiser = [Cruiser new]; Fighter *fighter = [Fighter mock]; + [[cruiser should] receive:@selector(loadFighter:) withArguments:fighter]; + [cruiser loadFighter:fighter]; }); + + it(@"can match a selector with specific multiple arguments", ^{ + [[cruiser should] receive:@selector(raiseWithName:description:) withArguments:description, format]; + + [cruiser raiseWithName:description description:format]; + }); + + it(@"can match a selector with multiple arguments", ^{ + [[cruiser should] receive:@selector(raiseWithName:description:)]; + + [cruiser raiseWithName:description description:format]; + }); +}); +describe(@"block message patterns", ^{ + id argument1 = [NSObject new]; + id argument2 = [NSObject new]; + + it(@"can match a call with a call without arguments", ^{ + id block = theBlockProxy(^{ }); + + [[block should] beEvaluated]; + + ((KWVoidTestBlock)block)(); + }); + + it(@"can match a call with a specific single argument", ^{ + id block = theBlockProxy(^(id object) { }); + + [[block should] beEvaluatedWithArguments:argument1]; + + ((KWArgumentTestBlock)block)(argument1); + }); + + it(@"can match a call with specific multiple arguments", ^{ + id block = theBlockProxy(^(id object1, id object2, id object3) { }); + + [[block should] beEvaluatedWithArguments:argument1, nil, argument2]; + + ((KWMultiArgumentTestBlock)block)(argument1, nil, argument2); + }); + + it(@"can match a call with multiple arguments", ^{ + id block = theBlockProxy(^(id object1, id object2, id object3) { }); + + [[block should] beEvaluated]; + + ((KWMultiArgumentTestBlock)block)(argument1, nil, argument2); + }); }); SPEC_END diff --git a/Tests/KWProxyBlockTest.m b/Tests/KWProxyBlockTest.m new file mode 100644 index 00000000..adfaa955 --- /dev/null +++ b/Tests/KWProxyBlockTest.m @@ -0,0 +1,173 @@ +// +// KWProxyBlockTest.m +// Kiwi +// +// Created by Oleksa 'trimm' Korin on 4/18/16. +// Copyright © 2016 Allen Ding. All rights reserved. +// + +#import + +#import "KiwiTestConfiguration.h" + +#import "KWProxyBlock.h" + +#if KW_TESTS_ENABLED + + +static const uint8_t KWTestStructValueCount = 4; + +struct KWTestStruct { + uint64_t values[KWTestStructValueCount]; +}; +typedef struct KWTestStruct KWTestStruct; + +static +BOOL KWTestStructEqualsTestStruct(KWTestStruct struct1, KWTestStruct struct2) { + for (uint8_t i = 0; i < KWTestStructValueCount; i++) { + if (struct1.values[i] != struct2.values[i]) { + return NO; + } + } + + return YES; +} + +// test values +static const NSUInteger KWUIntValue = 1; +static NSString * const KWStringValue = @"mama"; +static const KWTestStruct KWStructValue = (KWTestStruct){{1.0, 1.0, 1.0, 1.0}}; + +// test typedefs +typedef void(^__KWVoidBlock)(void); +typedef void(^__KWVoidBlockMultiparam)(NSUInteger, id, KWTestStruct); + +typedef NSUInteger(^__KWPrimitiveBlock)(void); + +typedef id(^__KWObjectBlock)(void); +typedef id(^__KWObjectBlockMultiparam)(NSUInteger, id, KWTestStruct); + +typedef KWTestStruct(^__KWStretBlock)(void); +typedef KWTestStruct(^__KWStretBlockMultiparam)(NSUInteger, id, KWTestStruct); + +@interface KWProxyBlockTest : XCTestCase + +- (void)assertCorrectParamsWithUInteger:(NSUInteger)intValue object:(id)object structure:(KWTestStruct)rect; + +@end + +@implementation KWProxyBlockTest { + __block BOOL _evaluated; +} + +- (void)setUp { + [super setUp]; + + _evaluated = NO; +} + +- (void)tearDown { + XCTAssertTrue(_evaluated, "wrapped block wasn't evaluated"); + + [super tearDown]; +} + +#pragma mark - Test block without parameters + +- (void)testItShouldEvaluateWrappedVoidBlock { + __KWVoidBlock block = ^{ _evaluated = YES; }; + + KWProxyBlock *wrappedBlock = [KWProxyBlock blockWithBlock:block]; + + ((__KWVoidBlock)wrappedBlock)(); +} + +- (void)testItShouldEvaluateWrappedPrimitiveBlock { + __KWPrimitiveBlock block = ^{ + _evaluated = YES; + + return KWUIntValue; + }; + + KWProxyBlock *wrappedBlock = [KWProxyBlock blockWithBlock:block]; + + XCTAssertEqual(KWUIntValue, ((__KWPrimitiveBlock)wrappedBlock)(), "wrapped block didn't return a proper value"); +} + +- (void)testItShouldEvaluateWrappedObjectBlock { + __KWObjectBlock block = ^{ + _evaluated = YES; + + return KWStringValue; + }; + + KWProxyBlock *wrappedBlock = [KWProxyBlock blockWithBlock:block]; + + XCTAssertEqualObjects(KWStringValue, ((__KWObjectBlock)wrappedBlock)(), "wrapped block didn't return a proper value"); +} + +- (void)testItShouldEvaluateWrappedStretBlock { + __KWStretBlock block = ^{ + _evaluated = YES; + + return KWStructValue; + }; + + KWProxyBlock *wrappedBlock = [KWProxyBlock blockWithBlock:block]; + + XCTAssertTrue(KWTestStructEqualsTestStruct(KWStructValue, ((__KWStretBlock)wrappedBlock)()), + "wrapped block didn't return a proper value"); +} + +#pragma mark - Test block with parameters + +- (void)testItShouldEvaluateWrappedVoidBlockWithMultipleParameters { + __KWVoidBlockMultiparam block = ^(NSUInteger intValue, id object, KWTestStruct rect) { + [self assertCorrectParamsWithUInteger:intValue object:object structure:rect]; + }; + + KWProxyBlock *wrappedBlock = [KWProxyBlock blockWithBlock:block]; + + ((__KWVoidBlockMultiparam)wrappedBlock)(KWUIntValue, KWStringValue, KWStructValue); +} + +- (void)testItShouldEvaluateWrappedObjectBlockWithMultipleParameters { + __KWObjectBlockMultiparam block = ^(NSUInteger intValue, id object, KWTestStruct rect) { + [self assertCorrectParamsWithUInteger:intValue object:object structure:rect]; + + return KWStringValue; + }; + + KWProxyBlock *wrappedBlock = [KWProxyBlock blockWithBlock:block]; + + id object = ((__KWObjectBlockMultiparam)wrappedBlock)(KWUIntValue, KWStringValue, KWStructValue); + + XCTAssertEqualObjects(KWStringValue, object, "wrapped block didn't return a proper value"); +} + +- (void)testItShouldEvaluateWrappedStretBlockWithMultipleParameters { + __KWStretBlockMultiparam block = ^(NSUInteger intValue, id object, KWTestStruct rect) { + [self assertCorrectParamsWithUInteger:intValue object:object structure:rect]; + + return KWStructValue; + }; + + KWProxyBlock *wrappedBlock = [KWProxyBlock blockWithBlock:block]; + + KWTestStruct rect = ((__KWStretBlockMultiparam)wrappedBlock)(KWUIntValue, KWStringValue, KWStructValue); + + XCTAssertTrue(KWTestStructEqualsTestStruct(KWStructValue, rect), "wrapped block didn't return a proper value"); +} + + +- (void)assertCorrectParamsWithUInteger:(NSUInteger)intValue object:(id)object structure:(KWTestStruct)rect { + _evaluated = YES; + + XCTAssertTrue(KWTestStructEqualsTestStruct(KWStructValue, rect), "wrapped block didn't return a proper value"); + XCTAssertEqualObjects(KWStringValue, object, "wrapped block didn't return a proper value"); + XCTAssertEqual(KWUIntValue, intValue, "wrapped block didn't return a proper value"); +} + +@end + +#endif \ No newline at end of file From ef3eadd6900d2a25365a366a409ebd23446f35de Mon Sep 17 00:00:00 2001 From: Oleksa 'trimm' Korin Date: Fri, 28 Feb 2020 20:41:06 +0200 Subject: [PATCH 2/2] Fixed tests --- Cartfile.private | 2 +- Classes/Core/KWBlockInvocation.m | 21 ++++++++++++++------- Kiwi.xcodeproj/project.pbxproj | 18 ++++++++++++++++++ Tests/KWMessagePatternFunctionalTests.m | 2 +- Tests/KWProxyBlockTest.m | 10 +++++----- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Cartfile.private b/Cartfile.private index 93a533f9..5db6765f 100644 --- a/Cartfile.private +++ b/Cartfile.private @@ -1,2 +1,2 @@ github "Quick/Nimble" -github "specta/expecta" +github "specta/expecta" "master" diff --git a/Classes/Core/KWBlockInvocation.m b/Classes/Core/KWBlockInvocation.m index 0c428bdf..e3affc08 100644 --- a/Classes/Core/KWBlockInvocation.m +++ b/Classes/Core/KWBlockInvocation.m @@ -24,14 +24,20 @@ + (NSInvocation *)invocationWithTarget:(id)anObject messageArguments:(const void va_list argumentList; va_start(argumentList, firstBytes); - return [self invocationWithTarget:anObject selector:NULL firstArgument:firstBytes argumentList:argumentList]; + return [self invocationWithTarget:anObject + selector:@selector(_doNothing) + firstArgument:firstBytes + argumentList:argumentList]; } + (NSInvocation *)invocationWithTarget:(id)anObject firstArgument:(const void *)firstBytes argumentList:(va_list)argumentList { - return [self invocationWithTarget:anObject selector:NULL firstArgument:firstBytes argumentList:argumentList]; + return [self invocationWithTarget:anObject + selector:@selector(_doNothing) + firstArgument:firstBytes + argumentList:argumentList]; } + (NSInvocation *)invocationWithTarget:(id)anObject @@ -43,9 +49,10 @@ + (NSInvocation *)invocationWithTarget:(id)anObject [NSException raise:NSInvalidArgumentException format:@"%@ - target must be KWProxyBlock", anObject]; } - aSelector = NULL; - - return [super invocationWithTarget:anObject selector:aSelector firstArgument:firstBytes argumentList:argumentList]; + return [super invocationWithTarget:anObject + selector:@selector(_doNothing) + firstArgument:firstBytes + argumentList:argumentList]; } #pragma mark - Argument Offset @@ -56,8 +63,8 @@ - (NSUInteger)argumentOffset { #pragma mark - Properties -- (SEL)selector { - return NULL; +- (void)_doNothing { + } @end diff --git a/Kiwi.xcodeproj/project.pbxproj b/Kiwi.xcodeproj/project.pbxproj index 584a1cda..40184c25 100755 --- a/Kiwi.xcodeproj/project.pbxproj +++ b/Kiwi.xcodeproj/project.pbxproj @@ -553,6 +553,12 @@ D7E699792409851900C3D93C /* KWSelectorMessagePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = D7E699622409851900C3D93C /* KWSelectorMessagePattern.h */; settings = {ATTRIBUTES = (Public, ); }; }; D7E6997A2409851900C3D93C /* KWSelectorMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E699632409851900C3D93C /* KWSelectorMessagePattern.m */; }; D7E6997B2409851900C3D93C /* KWSelectorMessagePattern.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E699632409851900C3D93C /* KWSelectorMessagePattern.m */; }; + D7E699852409938100C3D93C /* KWBlockMessagePatternTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E6997F2409936E00C3D93C /* KWBlockMessagePatternTest.m */; }; + D7E699862409938200C3D93C /* KWBlockMessagePatternTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E6997F2409936E00C3D93C /* KWBlockMessagePatternTest.m */; }; + D7E699872409938500C3D93C /* KWProxyBlockTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E699802409936E00C3D93C /* KWProxyBlockTest.m */; }; + D7E699882409938600C3D93C /* KWProxyBlockTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E699802409936E00C3D93C /* KWProxyBlockTest.m */; }; + D7E699892409938E00C3D93C /* KWBeEvaluatedMatcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E6997C2409934A00C3D93C /* KWBeEvaluatedMatcherTest.m */; }; + D7E6998A2409938F00C3D93C /* KWBeEvaluatedMatcherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E6997C2409934A00C3D93C /* KWBeEvaluatedMatcherTest.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -867,6 +873,9 @@ D7E699612409851900C3D93C /* KWProxyBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWProxyBlock.m; sourceTree = ""; }; D7E699622409851900C3D93C /* KWSelectorMessagePattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KWSelectorMessagePattern.h; sourceTree = ""; }; D7E699632409851900C3D93C /* KWSelectorMessagePattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWSelectorMessagePattern.m; sourceTree = ""; }; + D7E6997C2409934A00C3D93C /* KWBeEvaluatedMatcherTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBeEvaluatedMatcherTest.m; sourceTree = ""; }; + D7E6997F2409936E00C3D93C /* KWBlockMessagePatternTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWBlockMessagePatternTest.m; sourceTree = ""; }; + D7E699802409936E00C3D93C /* KWProxyBlockTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWProxyBlockTest.m; sourceTree = ""; }; DA084D3F17E3804200592D5A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; DA084D4217E3804200592D5A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; DA3EAD0718A7A1D700EBBF57 /* KWSharedExampleFunctionalTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KWSharedExampleFunctionalTest.m; sourceTree = ""; }; @@ -1378,6 +1387,8 @@ F5A1E612117432AC002223E1 /* Support */ = { isa = PBXGroup; children = ( + D7E6997F2409936E00C3D93C /* KWBlockMessagePatternTest.m */, + D7E699802409936E00C3D93C /* KWProxyBlockTest.m */, 4AD7A2091962AC8F005ED93F /* Config.m */, F5D7C8D311643C2900758FEA /* KWDeviceInfoTest.m */, 89861D9316FE0EE5008CE99D /* KWFormatterTest.m */, @@ -1394,6 +1405,7 @@ F5A9EFD211741E7700E9EDA3 /* Matchers */ = { isa = PBXGroup; children = ( + D7E6997C2409934A00C3D93C /* KWBeEvaluatedMatcherTest.m */, F553B2D211756157004FCA2E /* KWBeBetweenMatcherTest.m */, F553B4411175A190004FCA2E /* KWBeEmptyMatcherTest.m */, F5E50320119EA22F00F5D05F /* KWBeIndenticalToMatcherTest.m */, @@ -1942,6 +1954,7 @@ 4AE030951AEB494400556381 /* KWBeTrueMatcherTest.m in Sources */, 4AE030961AEB494400556381 /* KWBeWithinMatcherTest.m in Sources */, 4AE030971AEB494400556381 /* KWBlockRaiseMatcherTest.m in Sources */, + D7E699862409938200C3D93C /* KWBlockMessagePatternTest.m in Sources */, 4B9314A623D0E83C007A295C /* KWNotificationMatcherTest.m in Sources */, 4AE030981AEB494400556381 /* KWChangeMatcherTest.m in Sources */, 4AE030991AEB494400556381 /* KWConformToProtocolMatcherTest.m in Sources */, @@ -1952,9 +1965,11 @@ 4AE0309D1AEB494400556381 /* KWGenericMatcherTest.m in Sources */, 4AE0309E1AEB494400556381 /* KWHaveMatcherTest.m in Sources */, CE7EFF9A1B8475BD00FFE6D6 /* KWSwiftXCTestAssertionTests.swift in Sources */, + D7E699882409938600C3D93C /* KWProxyBlockTest.m in Sources */, 4AE0309F1AEB494400556381 /* KWHaveValueMatcherTest.m in Sources */, 4AE030A01AEB494400556381 /* KWInequalityMatcherTest.m in Sources */, 4AE030A11AEB494400556381 /* KWReceiveMatcherTest.m in Sources */, + D7E6998A2409938F00C3D93C /* KWBeEvaluatedMatcherTest.m in Sources */, 4AE030A21AEB494400556381 /* KWRegularExpressionPatternMatcherTest.m in Sources */, 4AE030A31AEB494400556381 /* KWRespondToSelectorMatcherTest.m in Sources */, 4AE030A41AEB494400556381 /* KWUserDefinedMatcherTest.m in Sources */, @@ -2117,6 +2132,7 @@ CE87C4FB1AF1994100310C07 /* KWBeWithinMatcherTest.m in Sources */, CE87C4FC1AF1994100310C07 /* KWBlockRaiseMatcherTest.m in Sources */, CE87C4FD1AF1994100310C07 /* KWChangeMatcherTest.m in Sources */, + D7E699852409938100C3D93C /* KWBlockMessagePatternTest.m in Sources */, 4B9314A523D0E83C007A295C /* KWNotificationMatcherTest.m in Sources */, CE87C4FE1AF1994100310C07 /* KWConformToProtocolMatcherTest.m in Sources */, CE87C4FF1AF1994100310C07 /* KWContainMatcherTest.m in Sources */, @@ -2127,9 +2143,11 @@ CE87C5031AF1994100310C07 /* KWHaveMatcherTest.m in Sources */, CE87C5041AF1994100310C07 /* KWHaveValueMatcherTest.m in Sources */, CE7EFF991B8475BD00FFE6D6 /* KWSwiftXCTestAssertionTests.swift in Sources */, + D7E699872409938500C3D93C /* KWProxyBlockTest.m in Sources */, CE87C5051AF1994100310C07 /* KWInequalityMatcherTest.m in Sources */, CE87C5061AF1994100310C07 /* KWReceiveMatcherTest.m in Sources */, CE87C5071AF1994100310C07 /* KWRegularExpressionPatternMatcherTest.m in Sources */, + D7E699892409938E00C3D93C /* KWBeEvaluatedMatcherTest.m in Sources */, CE87C5081AF1994100310C07 /* KWRespondToSelectorMatcherTest.m in Sources */, CE87C5091AF1994100310C07 /* KWUserDefinedMatcherTest.m in Sources */, CE87C50A1AF1994100310C07 /* KWBeZeroMatcherTest.m in Sources */, diff --git a/Tests/KWMessagePatternFunctionalTests.m b/Tests/KWMessagePatternFunctionalTests.m index 641d3b94..94976756 100644 --- a/Tests/KWMessagePatternFunctionalTests.m +++ b/Tests/KWMessagePatternFunctionalTests.m @@ -2,7 +2,7 @@ #import "KiwiTestConfiguration.h" #import "TestClasses.h" -typedef void(^KWVoidTestBlock)(); +typedef void(^KWVoidTestBlock)(void); typedef void(^KWArgumentTestBlock)(id); typedef void(^KWMultiArgumentTestBlock)(id, id, id); diff --git a/Tests/KWProxyBlockTest.m b/Tests/KWProxyBlockTest.m index adfaa955..52be77e0 100644 --- a/Tests/KWProxyBlockTest.m +++ b/Tests/KWProxyBlockTest.m @@ -75,7 +75,7 @@ - (void)tearDown { #pragma mark - Test block without parameters - (void)testItShouldEvaluateWrappedVoidBlock { - __KWVoidBlock block = ^{ _evaluated = YES; }; + __KWVoidBlock block = ^{ self->_evaluated = YES; }; KWProxyBlock *wrappedBlock = [KWProxyBlock blockWithBlock:block]; @@ -84,7 +84,7 @@ - (void)testItShouldEvaluateWrappedVoidBlock { - (void)testItShouldEvaluateWrappedPrimitiveBlock { __KWPrimitiveBlock block = ^{ - _evaluated = YES; + self->_evaluated = YES; return KWUIntValue; }; @@ -96,7 +96,7 @@ - (void)testItShouldEvaluateWrappedPrimitiveBlock { - (void)testItShouldEvaluateWrappedObjectBlock { __KWObjectBlock block = ^{ - _evaluated = YES; + self->_evaluated = YES; return KWStringValue; }; @@ -108,7 +108,7 @@ - (void)testItShouldEvaluateWrappedObjectBlock { - (void)testItShouldEvaluateWrappedStretBlock { __KWStretBlock block = ^{ - _evaluated = YES; + self->_evaluated = YES; return KWStructValue; }; @@ -170,4 +170,4 @@ - (void)assertCorrectParamsWithUInteger:(NSUInteger)intValue object:(id)object s @end -#endif \ No newline at end of file +#endif