Adds cocoapods for libraries.

Adds OCMockito and OCHamcrest libs.
This commit is contained in:
2020-09-05 22:06:51 -07:00
parent af47156557
commit c3031fbc39
364 changed files with 17147 additions and 1 deletions

View File

@@ -0,0 +1,96 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@protocol HCMatcher;
NS_ASSUME_NONNULL_BEGIN
/*!
* @header
* Assertion macros for using matchers in testing frameworks.
* Unmet assertions are reported to the HCTestFailureReporterChain.
*/
FOUNDATION_EXPORT void HC_assertThatWithLocation(id testCase, _Nullable id actual, id <HCMatcher> matcher,
const char *fileName, int lineNumber);
#define HC_assertThat(actual, matcher) \
HC_assertThatWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThat(actual, matcher) -
* Asserts that actual value satisfies matcher.
* @param actual The object to evaluate as the actual value.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion assertThat passes the actual value to the matcher for evaluation. If the matcher is
* not satisfied, it is reported to the HCTestFailureReporterChain.
*
* Use assertThat in test case methods. It's designed to integrate with XCTest and other testing
* frameworks where individual tests are executed as methods.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThat instead.
*/
#define assertThat(actual, matcher) HC_assertThat(actual, matcher)
#endif
typedef _Nonnull id (^HCFutureValue)(void);
FOUNDATION_EXPORT void HC_assertWithTimeoutAndLocation(id testCase, NSTimeInterval timeout,
HCFutureValue actualBlock, id <HCMatcher> matcher,
const char *fileName, int lineNumber);
#define HC_assertWithTimeout(timeout, actualBlock, matcher) \
HC_assertWithTimeoutAndLocation(self, timeout, actualBlock, matcher, __FILE__, __LINE__)
#define HC_thatEventually(actual) ^{ return actual; }
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertWithTimeout(timeout, actualBlock, matcher) -
* Asserts that a value provided by a block will satisfy matcher within the specified time.
* @param timeout Maximum time to wait for passing behavior, specified in seconds.
* @param actualBlock A block providing the object to repeatedly evaluate as the actual value.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion <em>assertWithTimeout</em> polls a value provided by a block to asynchronously
* satisfy the matcher. The block is evaluated repeatedly for an actual value, which is passed to
* the matcher for evaluation. If the matcher is not satisfied within the timeout, it is reported to
* the HCTestFailureReporterChain.
*
* An easy way of providing the <em>actualBlock</em> is to use the macro <code>thatEventually</code>.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertWithTimeout instead.
*/
#define assertWithTimeout(timeout, actualBlock, matcher) HC_assertWithTimeout(timeout, actualBlock, matcher)
/*!
* @abstract thatEventually(actual) -
* Evaluates actual value at future time.
* @param actual The object to evaluate as the actual value.
* @discussion Wraps <em>actual</em> in a block so that it can be repeatedly evaluated by
* <code>assertWithTimeout</code>.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_thatEventually instead.
*/
#define thatEventually(actual) HC_thatEventually(actual)
#endif
/*!
* @abstract "Expected <matcher description>, but <mismatch description>"
* @discussion Helper function to let you describe mismatches the way <tt>assertThat</tt> does.
*/
FOUNDATION_EXPORT NSString *HCDescribeMismatch(id <HCMatcher> matcher, id actual);
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,58 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCAssertThat.h"
#import "HCRunloopRunner.h"
#import "HCStringDescription.h"
#import "HCMatcher.h"
#import "HCTestFailure.h"
#import "HCTestFailureReporter.h"
#import "HCTestFailureReporterChain.h"
static void reportMismatch(id testCase, id actual, id <HCMatcher> matcher,
char const *fileName, int lineNumber)
{
HCTestFailure *failure = [[HCTestFailure alloc] initWithTestCase:testCase
fileName:[NSString stringWithUTF8String:fileName]
lineNumber:(NSUInteger)lineNumber
reason:HCDescribeMismatch(matcher, actual)];
HCTestFailureReporter *chain = [HCTestFailureReporterChain reporterChain];
[chain handleFailure:failure];
}
void HC_assertThatWithLocation(id testCase, _Nullable id actual, id <HCMatcher> matcher,
const char *fileName, int lineNumber)
{
if (![matcher matches:actual])
reportMismatch(testCase, actual, matcher, fileName, lineNumber);
}
void HC_assertWithTimeoutAndLocation(id testCase, NSTimeInterval timeout,
HCFutureValue actualBlock, id <HCMatcher> matcher,
const char *fileName, int lineNumber)
{
__block BOOL match = [matcher matches:actualBlock()];
if (!match)
{
HCRunloopRunner *runner = [[HCRunloopRunner alloc] initWithFulfillmentBlock:^{
match = [matcher matches:actualBlock()];
return match;
}];
[runner runUntilFulfilledOrTimeout:timeout];
}
if (!match)
reportMismatch(testCase, actualBlock(), matcher, fileName, lineNumber);
}
NSString *HCDescribeMismatch(id <HCMatcher> matcher, id actual)
{
HCStringDescription *description = [HCStringDescription stringDescription];
[[[description appendText:@"Expected "]
appendDescriptionOf:matcher]
appendText:@", but "];
[matcher describeMismatchOf:actual to:description];
return description.description;
}

View File

@@ -0,0 +1,29 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
#import <OCHamcrest/HCDescription.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Base class for all HCDescription implementations.
*/
@interface HCBaseDescription : NSObject <HCDescription>
@end
/*!
* @abstract Methods that must be provided by subclasses of HCBaseDescription.
*/
@interface HCBaseDescription (SubclassResponsibility)
/*!
* @abstract Appends the specified string to the description.
*/
- (void)append:(NSString *)str;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,101 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCBaseDescription.h"
#import "HCMatcher.h"
@implementation HCBaseDescription
- (id <HCDescription>)appendText:(NSString *)text
{
[self append:text];
return self;
}
- (id <HCDescription>)appendDescriptionOf:(nullable id)value
{
if (value == nil)
[self append:@"nil"];
else if ([value conformsToProtocol:@protocol(HCSelfDescribing)])
[value describeTo:self];
else if ([value respondsToSelector:@selector(isKindOfClass:)] && [value isKindOfClass:[NSString class]])
[self toCSyntaxString:value];
else
[self appendObjectDescriptionOf:value];
return self;
}
- (id <HCDescription>)appendObjectDescriptionOf:(id)value
{
NSString *description = [value description];
NSUInteger descriptionLength = description.length;
if (descriptionLength == 0)
[self append:[NSString stringWithFormat:@"<%@: %p>", NSStringFromClass([value class]), (__bridge void *)value]];
else if ([description characterAtIndex:0] == '<'
&& [description characterAtIndex:descriptionLength - 1] == '>')
{
[self append:description];
}
else
{
[self append:@"<"];
[self append:description];
[self append:@">"];
}
return self;
}
- (id <HCDescription>)appendList:(NSArray *)values
start:(NSString *)start
separator:(NSString *)separator
end:(NSString *)end
{
BOOL separate = NO;
[self append:start];
for (id item in values)
{
if (separate)
[self append:separator];
[self appendDescriptionOf:item];
separate = YES;
}
[self append:end];
return self;
}
- (void)toCSyntaxString:(NSString *)unformatted
{
[self append:@"\""];
NSUInteger length = unformatted.length;
for (NSUInteger index = 0; index < length; ++index)
[self toCSyntax:[unformatted characterAtIndex:index]];
[self append:@"\""];
}
- (void)toCSyntax:(unichar)ch
{
switch (ch)
{
case '"':
[self append:@"\\\""];
break;
case '\n':
[self append:@"\\n"];
break;
case '\r':
[self append:@"\\r"];
break;
case '\t':
[self append:@"\\t"];
break;
default:
[self append:[NSString stringWithCharacters:&ch length:1]];
break;
}
}
@end

View File

@@ -0,0 +1,25 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
#import <OCHamcrest/HCMatcher.h>
#define HC_ABSTRACT_METHOD [self subclassResponsibility:_cmd]
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Base class for all HCMatcher implementations.
* @discussion Simple matchers can just subclass HCBaseMatcher and implement <code>-matches:</code>
* and <code>-describeTo:</code>. But if the matching algorithm has several "no match" paths,
* consider subclassing HCDiagnosingMatcher instead.
*/
@interface HCBaseMatcher : NSObject <HCMatcher, NSCopying>
/*! @abstract Raises exception that command (a pseudo-abstract method) is not implemented. */
- (void)subclassResponsibility:(SEL)command;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,52 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCBaseMatcher.h"
#import "HCStringDescription.h"
@implementation HCBaseMatcher
- (NSString *)description
{
return [HCStringDescription stringFrom:self];
}
- (BOOL)matches:(nullable id)item
{
HC_ABSTRACT_METHOD;
return NO;
}
- (BOOL)matches:(nullable id)item describingMismatchTo:(id <HCDescription>)mismatchDescription
{
BOOL matchResult = [self matches:item];
if (!matchResult)
[self describeMismatchOf:item to:mismatchDescription];
return matchResult;
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[[mismatchDescription appendText:@"was "] appendDescriptionOf:item];
}
- (void)describeTo:(id <HCDescription>)description
{
HC_ABSTRACT_METHOD;
}
- (void)subclassResponsibility:(SEL)command
{
NSString *className = NSStringFromClass([self class]);
[NSException raise:NSGenericException
format:@"-[%@ %@] not implemented", className, NSStringFromSelector(command)];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
@end

View File

@@ -0,0 +1,39 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract A description of an HCMatcher.
* @discussion An HCMatcher will describe itself to a description which can later be used for reporting.
*/
@protocol HCDescription <NSObject>
/*!
* @abstract Appends some plain text to the description.
* @return <code>self</code>, for chaining.
*/
- (id <HCDescription>)appendText:(NSString *)text;
/*!
* @abstract Appends description of specified value to description.
* @discussion If the value implements the HCSelfDescribing protocol, then it will be used.
* @return <code>self</code>, for chaining.
*/
- (id <HCDescription>)appendDescriptionOf:(nullable id)value;
/*!
* @abstract Appends a list of objects to the description.
* @return <code>self</code>, for chaining.
*/
- (id <HCDescription>)appendList:(NSArray *)values
start:(NSString *)start
separator:(NSString *)separator
end:(NSString *)end;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,19 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Base class for matchers that generate mismatch descriptions during the matching.
* @discussion Some matching algorithms have several "no match" paths. It helps to make the mismatch
* description as precise as possible, but we don't want to have to repeat the matching logic to do
* so. For such matchers, subclass HCDiagnosingMatcher and implement HCMatcher's
* <code>-matches:describingMismatchTo:</code>.
*/
@interface HCDiagnosingMatcher : HCBaseMatcher
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,25 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCDiagnosingMatcher.h"
@implementation HCDiagnosingMatcher
- (BOOL)matches:(nullable id)item
{
return [self matches:item describingMismatchTo:nil];
}
- (BOOL)matches:(nullable id)item describingMismatchTo:(id <HCDescription>)mismatchDescription
{
HC_ABSTRACT_METHOD;
return NO;
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[self matches:item describingMismatchTo:mismatchDescription];
}
@end

View File

@@ -0,0 +1,47 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCSelfDescribing.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract A matcher over acceptable values.
* @discussion A matcher is able to describe itself to give feedback when it fails.
*
* HCMatcher implementations should not directly implement this protocol. Instead, extend the
* HCBaseMatcher class, which will ensure that the HCMatcher API can grow to support new features
* and remain compatible with all HCMatcher implementations.
*/
@protocol HCMatcher <HCSelfDescribing>
/*!
* @abstract Evaluates the matcher for argument item.
* @param item The object against which the matcher is evaluated.
* @return <code>YES</code> if item matches, otherwise <code>NO</code>.
*/
- (BOOL)matches:(nullable id)item;
/*!
* @abstract Evaluates the matcher for argument item.
* @param item The object against which the matcher is evaluated.
* @param mismatchDescription The description to be built or appended to if item does not match.
* @return <code>YES</code> if item matches, otherwise <code>NO</code>.
*/
- (BOOL)matches:(nullable id)item describingMismatchTo:(nullable id <HCDescription>)mismatchDescription;
/*!
* @abstract Generates a description of why the matcher has not accepted the item.
* @param item The item that the HCMatcher has rejected.
* @param mismatchDescription The description to be built or appended to.
* @discussion The description will be part of a larger description of why a matching failed, so it
* should be concise.
*
* This method assumes that <code>matches:item</code> is false, but will not check this.
*/
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,26 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
#import <OCHamcrest/HCDescription.h> // Convenience header
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract The ability of an object to describe itself.
*/
@protocol HCSelfDescribing <NSObject>
/*!
* @abstract Generates a description of the object.
* @param description The description to be built or appended to.
* @discussion The description may be part of a description of a larger object of which this is just
* a component, so it should be worded appropriately.
*/
- (void)describeTo:(id <HCDescription>)description;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,36 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseDescription.h>
@protocol HCSelfDescribing;
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract An HCDescription that is stored as a string.
*/
@interface HCStringDescription : HCBaseDescription
/*!
* @abstract Returns the description of an HCSelfDescribing object as a string.
* @param selfDescribing The object to be described.
* @return The description of the object.
*/
+ (NSString *)stringFrom:(id <HCSelfDescribing>)selfDescribing;
/*!
* @abstract Creates and returns an empty description.
*/
+ (instancetype)stringDescription;
/*!
* @abstract Initializes a newly allocated HCStringDescription that is initially empty.
*/
- (instancetype)init NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,45 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCStringDescription.h"
#import "HCSelfDescribing.h"
@interface HCStringDescription ()
@property (nonatomic, strong) NSMutableString *accumulator;
@end
@implementation HCStringDescription
+ (NSString *)stringFrom:(id <HCSelfDescribing>)selfDescribing
{
HCStringDescription *description = [HCStringDescription stringDescription];
[description appendDescriptionOf:selfDescribing];
return description.description;
}
+ (instancetype)stringDescription
{
return [[HCStringDescription alloc] init];
}
- (instancetype)init
{
self = [super init];
if (self)
_accumulator = [[NSMutableString alloc] init];
return self;
}
- (NSString *)description
{
return self.accumulator;
}
- (void)append:(NSString *)str
{
[self.accumulator appendString:str];
}
@end

View File

@@ -0,0 +1,26 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
#import <stdarg.h>
@protocol HCMatcher;
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Returns an array of values from a variable-length comma-separated list terminated
* by <code>nil</code>.
*/
FOUNDATION_EXPORT NSArray * HCCollectItems(id item, va_list args);
/*!
* @abstract Returns an array of matchers from a mixed array of items and matchers.
* @discussion Each item is wrapped in HCWrapInMatcher to transform non-matcher items into equality
* matchers.
*/
FOUNDATION_EXPORT NSArray<id <HCMatcher>> * HCWrapIntoMatchers(NSArray *items);
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,43 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCCollect.h"
#import "HCWrapInMatcher.h"
/*!
* @abstract Returns an array of wrapped items from a variable-length comma-separated list
* terminated by <code>nil</code>.
* @discussion Each item is transformed by passing it to the specified <em>wrap</em> function.
*/
static NSArray * HCCollectWrappedItems(id item, va_list args, id (*wrap)(id))
{
NSMutableArray *list = [NSMutableArray arrayWithObject:wrap(item)];
id nextItem = va_arg(args, id);
while (nextItem)
{
[list addObject:wrap(nextItem)];
nextItem = va_arg(args, id);
}
return list;
}
static id passThrough(id value)
{
return value;
}
NSArray * HCCollectItems(id item, va_list args)
{
return HCCollectWrappedItems(item, args, passThrough);
}
NSArray<id <HCMatcher>> * HCWrapIntoMatchers(NSArray *items)
{
NSMutableArray<id <HCMatcher>> *matchers = [[NSMutableArray alloc] init];
for (id item in items)
[matchers addObject:HCWrapInMatcher(item)];
return matchers;
}

View File

@@ -0,0 +1,42 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Supporting class for matching a feature of an object.
* @discussion Tests whether the result of passing the specified invocation to the value satisfies
* the specified matcher.
*/
@interface HCInvocationMatcher : HCBaseMatcher
/*!
* @abstract Determines whether a mismatch will be described in short form.
* @discussion Default is long form, which describes the object, the name of the invocation, and the
* sub-matcher's mismatch diagnosis. Short form only has the sub-matcher's mismatch diagnosis.
*/
@property (nonatomic, assign) BOOL shortMismatchDescription;
/*!
* @abstract Initializes a newly allocated HCInvocationMatcher with an invocation and a matcher.
*/
- (instancetype)initWithInvocation:(NSInvocation *)anInvocation matching:(id <HCMatcher>)aMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
/*!
* @abstract Invokes stored invocation on the specified item and returns the result.
*/
- (id)invokeOn:(id)item;
/*!
* @abstract Returns string representation of the invocation's selector.
*/
- (NSString *)stringFromSelector;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,81 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCInvocationMatcher.h"
@interface HCInvocationMatcher ()
@property (nonatomic, strong) NSInvocation *invocation;
@property (nonatomic, strong) id <HCMatcher> subMatcher;
@end
@implementation HCInvocationMatcher
- (instancetype)initWithInvocation:(NSInvocation *)anInvocation matching:(id <HCMatcher>)aMatcher
{
self = [super init];
if (self)
{
_invocation = anInvocation;
_subMatcher = aMatcher;
}
return self;
}
- (BOOL)matches:(nullable id)item
{
if ([self invocationNotSupportedForItem:item])
return NO;
return [self.subMatcher matches:[self invokeOn:item]];
}
- (BOOL)invocationNotSupportedForItem:(id)item
{
return ![item respondsToSelector:self.invocation.selector];
}
- (id)invokeOn:(id)item
{
__unsafe_unretained id result = nil;
[self.invocation invokeWithTarget:item];
[self.invocation getReturnValue:&result];
return result;
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
if ([self invocationNotSupportedForItem:item])
[super describeMismatchOf:item to:mismatchDescription];
else
{
[self describeLongMismatchDescriptionOf:item to:mismatchDescription];
[self.subMatcher describeMismatchOf:[self invokeOn:item] to:mismatchDescription];
}
}
- (void)describeLongMismatchDescriptionOf:(id)item to:(id <HCDescription>)mismatchDescription
{
if (!self.shortMismatchDescription)
{
[[[[mismatchDescription appendDescriptionOf:item]
appendText:@" "]
appendText:[self stringFromSelector]]
appendText:@" "];
}
}
- (void)describeTo:(id <HCDescription>)description
{
[[[[description appendText:@"an object with "]
appendText:[self stringFromSelector]]
appendText:@" "]
appendDescriptionOf:self.subMatcher];
}
- (NSString *)stringFromSelector
{
return NSStringFromSelector(self.invocation.selector);
}
@end

View File

@@ -0,0 +1,14 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Throws an NSException if <em>obj</em> is <code>nil</code>.
*/
FOUNDATION_EXPORT void HCRequireNonNilObject(id obj);
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,15 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCRequireNonNilObject.h"
void HCRequireNonNilObject(id obj)
{
if (obj == nil)
{
@throw [NSException exceptionWithName:@"NilObject"
reason:@"Must be non-nil object"
userInfo:nil];
}
}

View File

@@ -0,0 +1,21 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Runs runloop until fulfilled, or timeout is reached.
* @discussion Based on http://bou.io/CTTRunLoopRunUntil.html
*/
@interface HCRunloopRunner : NSObject
- (instancetype)initWithFulfillmentBlock:(BOOL (^)(void))fulfillmentBlock NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
- (void)runUntilFulfilledOrTimeout:(CFTimeInterval)timeout;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,36 @@
#import "HCRunloopRunner.h"
@implementation HCRunloopRunner
{
CFRunLoopObserverRef _observer;
}
- (instancetype)initWithFulfillmentBlock:(BOOL (^)(void))fulfillmentBlock
{
self = [super init];
if (self)
{
_observer = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
if (fulfillmentBlock())
CFRunLoopStop(CFRunLoopGetCurrent());
else
CFRunLoopWakeUp(CFRunLoopGetCurrent());
});
CFRunLoopAddObserver(CFRunLoopGetCurrent(), _observer, kCFRunLoopDefaultMode);
}
return self;
}
- (void)dealloc
{
CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), _observer, kCFRunLoopDefaultMode);
CFRelease(_observer);
}
- (void)runUntilFulfilledOrTimeout:(CFTimeInterval)timeout
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, false);
}
@end

View File

@@ -0,0 +1,17 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@protocol HCMatcher;
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Wraps argument in a matcher, if necessary.
* @return The argument as-is if it is already a matcher, otherwise wrapped in an <em>equalTo</em> matcher.
*/
FOUNDATION_EXPORT _Nullable id <HCMatcher> HCWrapInMatcher(_Nullable id matcherOrValue);
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,17 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCWrapInMatcher.h"
#import "HCIsEqual.h"
_Nullable id <HCMatcher> HCWrapInMatcher(_Nullable id matcherOrValue)
{
if (!matcherOrValue)
return nil;
if ([matcherOrValue conformsToProtocol:@protocol(HCMatcher)])
return matcherOrValue;
return HC_equalTo(matcherOrValue);
}

View File

@@ -0,0 +1,17 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSInvocation (OCHamcrest)
+ (NSInvocation *)och_invocationWithTarget:(id)target selector:(SEL)selector;
+ (NSInvocation *)och_invocationOnObjectOfType:(Class)aClass selector:(SEL)selector;
- (id)och_invoke;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,45 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "NSInvocation+OCHamcrest.h"
#import "HCReturnValueGetter.h"
#import "HCReturnTypeHandlerChain.h"
@implementation NSInvocation (OCHamcrest)
+ (NSInvocation *)och_invocationWithTarget:(id)target selector:(SEL)selector
{
NSMethodSignature *signature = [target methodSignatureForSelector:selector];
NSInvocation *invocation= [self och_invocationWithSignature:signature selector:selector];
invocation.target = target;
return invocation;
}
+ (NSInvocation *)och_invocationOnObjectOfType:(Class)aClass selector:(SEL)selector
{
NSMethodSignature *signature = [aClass instanceMethodSignatureForSelector:selector];
return [self och_invocationWithSignature:signature selector:selector];
}
+ (NSInvocation *)och_invocationWithSignature:(NSMethodSignature *)signature selector:(SEL)selector
{
NSInvocation *invocation = [[self class] invocationWithMethodSignature:signature];
invocation.selector = selector;
return invocation;
}
- (id)och_invoke
{
[self invoke];
return [self och_returnValue];
}
- (id)och_returnValue
{
char const *returnType = self.methodSignature.methodReturnType;
return [HCReturnValueGetterChain() returnValueOfType:returnType fromInvocation:self];
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCBoolReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCBoolReturnGetter.h"
@implementation HCBoolReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(BOOL) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
BOOL value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCCharReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCCharReturnGetter.h"
@implementation HCCharReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(char) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
char value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCDoubleReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCDoubleReturnGetter.h"
@implementation HCDoubleReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(double) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
double value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCFloatReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCFloatReturnGetter.h"
@implementation HCFloatReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(float) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
float value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCIntReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIntReturnGetter.h"
@implementation HCIntReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(int) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
int value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCLongLongReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCLongLongReturnGetter.h"
@implementation HCLongLongReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(long long) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
long long value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCLongReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCLongReturnGetter.h"
@implementation HCLongReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(long) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
long value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCObjectReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCObjectReturnGetter.h"
@implementation HCObjectReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(id) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
__unsafe_unretained id value;
[invocation getReturnValue:&value];
return value;
}
@end

View File

@@ -0,0 +1,12 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@class HCReturnValueGetter;
/*!
* @abstract Returns chain of return type handlers.
*/
FOUNDATION_EXPORT HCReturnValueGetter *HCReturnValueGetterChain(void);

View File

@@ -0,0 +1,44 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnTypeHandlerChain.h"
#import "HCObjectReturnGetter.h"
#import "HCCharReturnGetter.h"
#import "HCBoolReturnGetter.h"
#import "HCIntReturnGetter.h"
#import "HCShortReturnGetter.h"
#import "HCLongReturnGetter.h"
#import "HCLongLongReturnGetter.h"
#import "HCUnsignedCharReturnGetter.h"
#import "HCUnsignedIntReturnGetter.h"
#import "HCUnsignedShortReturnGetter.h"
#import "HCUnsignedLongReturnGetter.h"
#import "HCUnsignedLongLongReturnGetter.h"
#import "HCFloatReturnGetter.h"
#import "HCDoubleReturnGetter.h"
HCReturnValueGetter *HCReturnValueGetterChain(void)
{
static HCReturnValueGetter *chain = nil;
if (!chain)
{
HCReturnValueGetter *doubleHandler = [[HCDoubleReturnGetter alloc] initWithSuccessor:nil];
HCReturnValueGetter *floatHandler = [[HCFloatReturnGetter alloc] initWithSuccessor:doubleHandler];
HCReturnValueGetter *uLongLongHandler = [[HCUnsignedLongLongReturnGetter alloc] initWithSuccessor:floatHandler];
HCReturnValueGetter *uLongHandler = [[HCUnsignedLongReturnGetter alloc] initWithSuccessor:uLongLongHandler];
HCReturnValueGetter *uShortHandler = [[HCUnsignedShortReturnGetter alloc] initWithSuccessor:uLongHandler];
HCReturnValueGetter *uIntHandler = [[HCUnsignedIntReturnGetter alloc] initWithSuccessor:uShortHandler];
HCReturnValueGetter *uCharHandler = [[HCUnsignedCharReturnGetter alloc] initWithSuccessor:uIntHandler];
HCReturnValueGetter *longLongHandler = [[HCLongLongReturnGetter alloc] initWithSuccessor:uCharHandler];
HCReturnValueGetter *longHandler = [[HCLongReturnGetter alloc] initWithSuccessor:longLongHandler];
HCReturnValueGetter *shortHandler = [[HCShortReturnGetter alloc] initWithSuccessor:longHandler];
HCReturnValueGetter *intHandler = [[HCIntReturnGetter alloc] initWithSuccessor:shortHandler];
HCReturnValueGetter *boolHandler = [[HCBoolReturnGetter alloc] initWithSuccessor:intHandler];
HCReturnValueGetter *charHandler = [[HCCharReturnGetter alloc] initWithSuccessor:boolHandler];
HCReturnValueGetter *objectHandler = [[HCObjectReturnGetter alloc] initWithSuccessor:charHandler];
chain = objectHandler;
}
return chain;
}

View File

@@ -0,0 +1,20 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Chain-of-responsibility for handling NSInvocation return types.
*/
@interface HCReturnValueGetter : NSObject
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
- (id)returnValueOfType:(char const *)type fromInvocation:(NSInvocation *)invocation;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,42 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
@interface HCReturnValueGetter (SubclassResponsibility)
- (id)returnValueFromInvocation:(NSInvocation *)invocation;
@end
@interface HCReturnValueGetter ()
@property (nonatomic, assign, readonly) char const *handlerType;
@property (nullable, nonatomic, strong, readonly) HCReturnValueGetter *successor;
@end
@implementation HCReturnValueGetter
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor
{
self = [super init];
if (self)
{
_handlerType = handlerType;
_successor = successor;
}
return self;
}
- (BOOL)handlesReturnType:(char const *)returnType
{
return strcmp(returnType, self.handlerType) == 0;
}
- (id)returnValueOfType:(char const *)type fromInvocation:(NSInvocation *)invocation
{
if ([self handlesReturnType:type])
return [self returnValueFromInvocation:invocation];
return [self.successor returnValueOfType:type fromInvocation:invocation];
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCShortReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCShortReturnGetter.h"
@implementation HCShortReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(short) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
short value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedCharReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedCharReturnGetter.h"
@implementation HCUnsignedCharReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned char) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned char value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedIntReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedIntReturnGetter.h"
@implementation HCUnsignedIntReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned int) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned int value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedLongLongReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedLongLongReturnGetter.h"
@implementation HCUnsignedLongLongReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned long long) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned long long value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedLongReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedLongReturnGetter.h"
@implementation HCUnsignedLongReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned long) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned long value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,16 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCReturnValueGetter.h"
NS_ASSUME_NONNULL_BEGIN
@interface HCUnsignedShortReturnGetter : HCReturnValueGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithType:(char const *)handlerType successor:(nullable HCReturnValueGetter *)successor NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCUnsignedShortReturnGetter.h"
@implementation HCUnsignedShortReturnGetter
- (instancetype)initWithSuccessor:(nullable HCReturnValueGetter *)successor
{
self = [super initWithType:@encode(unsigned short) successor:successor];
return self;
}
- (id)returnValueFromInvocation:(NSInvocation *)invocation
{
unsigned short value;
[invocation getReturnValue:&value];
return @(value);
}
@end

View File

@@ -0,0 +1,8 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporter.h"
@interface HCGenericTestFailureReporter : HCTestFailureReporter
@end

View File

@@ -0,0 +1,31 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCGenericTestFailureReporter.h"
#import "HCTestFailure.h"
@implementation HCGenericTestFailureReporter
- (BOOL)willHandleFailure:(HCTestFailure *)failure
{
return YES;
}
- (void)executeHandlingOfFailure:(HCTestFailure *)failure
{
NSException *exception = [self createExceptionForFailure:failure];
[exception raise];
}
- (NSException *)createExceptionForFailure:(HCTestFailure *)failure
{
NSString *failureReason = [NSString stringWithFormat:@"%@:%lu: matcher error: %@",
failure.fileName,
(unsigned long)failure.lineNumber,
failure.reason];
return [NSException exceptionWithName:@"HCGenericTestFailure" reason:failureReason userInfo:nil];
}
@end

View File

@@ -0,0 +1,8 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporter.h"
@interface HCSenTestFailureReporter : HCTestFailureReporter
@end

View File

@@ -0,0 +1,69 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCSenTestFailureReporter.h"
#import "HCTestFailure.h"
#import "NSInvocation+OCHamcrest.h"
@interface NSObject (PretendMethodsExistOnNSObjectToAvoidLinkingSenTestingKit)
+ (NSException *)failureInFile:(NSString *)filename
atLine:(int)lineNumber
withDescription:(NSString *)formatString, ...;
- (void)failWithException:(NSException *)exception;
@end
@interface NSInvocation (OCHamcrest_SenTestingKit)
@end
@implementation NSInvocation (OCHamcrest_SenTestingKit)
+ (NSInvocation *)och_SenTestFailureInFile:(NSString *)fileName
atLine:(NSUInteger)lineNumber
description:(NSString *)description
{
// SenTestingKit expects a format string, but NSInvocation does not support varargs.
// Mask % symbols in the string so they aren't treated as placeholders.
NSString *massagedDescription = [description stringByReplacingOccurrencesOfString:@"%"
withString:@"%%"];
NSInvocation *invocation = [NSInvocation och_invocationWithTarget:[NSException class]
selector:@selector(failureInFile:atLine:withDescription:)];
[invocation setArgument:&fileName atIndex:2];
[invocation setArgument:&lineNumber atIndex:3];
[invocation setArgument:&massagedDescription atIndex:4];
return invocation;
}
@end
@implementation HCSenTestFailureReporter
- (BOOL)willHandleFailure:(HCTestFailure *)failure
{
return [failure.testCase respondsToSelector:@selector(failWithException:)];
}
- (void)executeHandlingOfFailure:(HCTestFailure *)failure
{
NSException *exception = [self createExceptionForFailure:failure];
[failure.testCase failWithException:exception];
}
- (NSException *)createExceptionForFailure:(HCTestFailure *)failure
{
NSInvocation *invocation = [NSInvocation och_SenTestFailureInFile:failure.fileName
atLine:failure.lineNumber
description:failure.reason];
[invocation invoke];
__unsafe_unretained NSException *result = nil;
[invocation getReturnValue:&result];
return result;
}
@end

View File

@@ -0,0 +1,42 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/*!
@abstract Test failure location and reason.
*/
@interface HCTestFailure : NSObject
/*!
* @abstract Test case used to run test method.
* @discussion Can be <code>nil</code>.
*
* For unmet OCHamcrest assertions, if the assertion was <code>assertThat</code> or
* <code>assertWithTimeout</code>, <em>testCase</em> will be the test case instance.
*/
@property (nonatomic, strong, readonly) id testCase;
/*! @abstract File name to report. */
@property (nonatomic, copy, readonly) NSString *fileName;
/*! @abstract Line number to report. */
@property (nonatomic, assign, readonly) NSUInteger lineNumber;
/*! @abstract Failure reason to report. */
@property (nonatomic, strong, readonly) NSString *reason;
/*!
* @abstract Initializes a newly allocated instance of a test failure.
*/
- (instancetype)initWithTestCase:(id)testCase
fileName:(NSString *)fileName
lineNumber:(NSUInteger)lineNumber
reason:(NSString *)reason;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,25 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailure.h"
@implementation HCTestFailure
- (instancetype)initWithTestCase:(id)testCase
fileName:(NSString *)fileName
lineNumber:(NSUInteger)lineNumber
reason:(NSString *)reason
{
self = [super init];
if (self)
{
_testCase = testCase;
_fileName = [fileName copy];
_lineNumber = lineNumber;
_reason = [reason copy];
}
return self;
}
@end

View File

@@ -0,0 +1,25 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@class HCTestFailure;
NS_ASSUME_NONNULL_BEGIN
/*!
Chain-of-responsibility for handling test failures.
*/
@interface HCTestFailureReporter : NSObject
@property (nullable, nonatomic, strong) HCTestFailureReporter *successor;
/*!
Handle test failure at specific location, or pass to successor.
*/
- (void)handleFailure:(HCTestFailure *)failure;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,22 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporter.h"
@interface HCTestFailureReporter (SubclassResponsibility)
- (BOOL)willHandleFailure:(HCTestFailure *)failure;
- (void)executeHandlingOfFailure:(HCTestFailure *)failure;
@end
@implementation HCTestFailureReporter
- (void)handleFailure:(HCTestFailure *)failure
{
if ([self willHandleFailure:failure])
[self executeHandlingOfFailure:failure];
else
[self.successor handleFailure:failure];
}
@end

View File

@@ -0,0 +1,36 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@class HCTestFailureReporter;
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Manage chain-of-responsibility for reporting test failures.
* @discussion This provides a generic way of reporting test failures without knowing about the
* underlying test framework. By default, we try XCTest first, then SenTestingKit. If we run out of
* options, the final catch-all is to throw an NSException describing the test failure.
*/
@interface HCTestFailureReporterChain : NSObject
/*!
* @abstract Returns current chain of test failure reporters.
*/
+ (HCTestFailureReporter *)reporterChain;
/*!
* @abstract Adds specified test failure reporter to head of chain-of-responsibility.
*/
+ (void)addReporter:(HCTestFailureReporter *)reporter;
/*!
* @abstract Resets chain-of-responsibility to default.
*/
+ (void)reset;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,41 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporterChain.h"
#import "HCGenericTestFailureReporter.h"
#import "HCSenTestFailureReporter.h"
#import "HCXCTestFailureReporter.h"
static HCTestFailureReporter *chainHead = nil;
@implementation HCTestFailureReporterChain
+ (HCTestFailureReporter *)reporterChain
{
if (!chainHead)
{
HCTestFailureReporter *xctestReporter = [[HCXCTestFailureReporter alloc] init];
HCTestFailureReporter *ocunitReporter = [[HCSenTestFailureReporter alloc] init];
HCTestFailureReporter *genericReporter = [[HCGenericTestFailureReporter alloc] init];
chainHead = xctestReporter;
xctestReporter.successor = ocunitReporter;
ocunitReporter.successor = genericReporter;
}
return chainHead;
}
+ (void)addReporter:(HCTestFailureReporter *)reporter
{
reporter.successor = [self reporterChain];
chainHead = reporter;
}
+ (void)reset
{
chainHead = nil;
}
@end

View File

@@ -0,0 +1,8 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCTestFailureReporter.h"
@interface HCXCTestFailureReporter : HCTestFailureReporter
@end

View File

@@ -0,0 +1,33 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCXCTestFailureReporter.h"
#import "HCTestFailure.h"
@interface NSObject (PretendMethodExistsOnNSObjectToAvoidLinkingXCTest)
- (void)recordFailureWithDescription:(NSString *)description
inFile:(NSString *)filename
atLine:(NSUInteger)lineNumber
expected:(BOOL)expected;
@end
@implementation HCXCTestFailureReporter
- (BOOL)willHandleFailure:(HCTestFailure *)failure
{
return [failure.testCase respondsToSelector:@selector(recordFailureWithDescription:inFile:atLine:expected:)];
}
- (void)executeHandlingOfFailure:(HCTestFailure *)failure
{
[failure.testCase recordFailureWithDescription:failure.reason
inFile:failure.fileName
atLine:failure.lineNumber
expected:YES];
}
@end