Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added block beEvaluated family of matchers to Kiwi. #673

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cartfile.private
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github "Quick/Nimble"
github "specta/expecta"
github "specta/expecta" "master"
23 changes: 23 additions & 0 deletions Classes/Core/KWBlockInvocation.h
Original file line number Diff line number Diff line change
@@ -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
70 changes: 70 additions & 0 deletions Classes/Core/KWBlockInvocation.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// 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:@selector(_doNothing)
firstArgument:firstBytes
argumentList:argumentList];
}

+ (NSInvocation *)invocationWithTarget:(id)anObject
firstArgument:(const void *)firstBytes
argumentList:(va_list)argumentList
{
return [self invocationWithTarget:anObject
selector:@selector(_doNothing)
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];
}

return [super invocationWithTarget:anObject
selector:@selector(_doNothing)
firstArgument:firstBytes
argumentList:argumentList];
}

#pragma mark - Argument Offset

- (NSUInteger)argumentOffset {
return 1;
}

#pragma mark - Properties

- (void)_doNothing {

}

@end
100 changes: 100 additions & 0 deletions Classes/Core/KWBlockLayout.h
Original file line number Diff line number Diff line change
@@ -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);
108 changes: 108 additions & 0 deletions Classes/Core/KWBlockLayout.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//
// KWBlockLayout.m
// Kiwi
//
// Created by Oleksa 'trimm' Korin on 4/16/16.
// Copyright © 2016 Allen Ding. All rights reserved.
//

#import <objc/message.h>

#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);
}
31 changes: 31 additions & 0 deletions Classes/Core/KWBlockMessagePattern.h
Original file line number Diff line number Diff line change
@@ -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
Loading