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,45 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection satisfies a nested matcher.
*/
@interface HCEvery : HCDiagnosingMatcher
@property (nonatomic, strong, readonly) id <HCMatcher> matcher;
- (instancetype)initWithMatcher:(id <HCMatcher>)matcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_everyItem(id <HCMatcher> itemMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when the examined collection's items are
* all matched by the specified matcher.
* @param itemMatcher The matcher to apply to every item provided by the examined collection.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"bar", \@"baz"], everyItem(startsWith(\@"ba")))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_everyItem instead.
*/
static inline id everyItem(id <HCMatcher> itemMatcher)
{
return HC_everyItem(itemMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,74 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCEvery.h"
#import "HCRequireNonNilObject.h"
@implementation HCEvery
- (instancetype)initWithMatcher:(id <HCMatcher>)matcher
{
HCRequireNonNilObject(matcher);
self = [super init];
if (self)
_matcher = matcher;
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
if ([collection count] == 0)
{
[mismatchDescription appendText:@"was empty"];
return NO;
}
for (id item in collection)
{
if (![self.matcher matches:item])
{
[self describeAllMismatchesInCollection:collection to:mismatchDescription];
return NO;
}
}
return YES;
}
- (void)describeAllMismatchesInCollection:(id)collection to:(id <HCDescription>)mismatchDescription
{
[mismatchDescription appendText:@"mismatches were: ["];
BOOL isPastFirst = NO;
for (id item in collection)
{
if (![self.matcher matches:item])
{
if (isPastFirst)
[mismatchDescription appendText:@", "];
[self.matcher describeMismatchOf:item to:mismatchDescription];
isPastFirst = YES;
}
}
[mismatchDescription appendText:@"]"];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"every item is "] appendDescriptionOf:self.matcher];
}
@end
id HC_everyItem(id <HCMatcher> itemMatcher)
{
return [[HCEvery alloc] initWithMatcher:itemMatcher];
}

View File

@@ -0,0 +1,63 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if collection size satisfies a nested matcher.
*/
@interface HCHasCount : HCBaseMatcher
- (instancetype)initWithMatcher:(id <HCMatcher>)countMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasCount(id <HCMatcher> countMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object's <code>-count</code> method
* returns a value that satisfies the specified matcher.
* @param countMatcher A matcher for the count of an examined collection.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], hasCount(equalTo(@2)))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasCount instead.
*/
static inline id hasCount(id <HCMatcher> countMatcher)
{
return HC_hasCount(countMatcher);
}
#endif
FOUNDATION_EXPORT id HC_hasCountOf(NSUInteger count);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object's <code>-count</code> method
* returns a value that equals the specified value.
* @param value Value to compare against as the expected count.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], hasCountOf(2))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasCountOf instead.
*/
static inline id hasCountOf(NSUInteger value)
{
return HC_hasCountOf(value);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,65 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCHasCount.h"
#import "HCIsEqual.h"
@interface HCHasCount ()
@property (nonatomic, strong, readonly) id <HCMatcher> countMatcher;
@end
@implementation HCHasCount
- (instancetype)initWithMatcher:(id <HCMatcher>)countMatcher
{
self = [super init];
if (self)
_countMatcher = countMatcher;
return self;
}
- (BOOL)matches:(nullable id)item
{
if (![self itemHasCount:item])
return NO;
NSNumber *count = @([item count]);
return [self.countMatcher matches:count];
}
- (BOOL)itemHasCount:(id)item
{
return [item respondsToSelector:@selector(count)];
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[mismatchDescription appendText:@"was "];
if ([self itemHasCount:item])
{
[[[mismatchDescription appendText:@"count of "]
appendDescriptionOf:@([item count])]
appendText:@" with "];
}
[mismatchDescription appendDescriptionOf:item];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a collection with count of "] appendDescriptionOf:self.countMatcher];
}
@end
id HC_hasCount(id <HCMatcher> countMatcher)
{
return [[HCHasCount alloc] initWithMatcher:countMatcher];
}
id HC_hasCountOf(NSUInteger value)
{
return HC_hasCount(HC_equalTo(@(value)));
}

View File

@@ -0,0 +1,95 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if any item in a collection satisfies a nested matcher.
*/
@interface HCIsCollectionContaining : HCDiagnosingMatcher
- (instancetype)initWithMatcher:(id <HCMatcher>)elementMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasItem(id itemMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract hasItem(itemMatcher) -
* Creates a matcher for collections that matches when at least one item in the examined collection
* satisfies the specified matcher.
* @param itemMatcher The matcher to apply to collection elements, or an expected value
* for <em>equalTo</em> matching.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass.
*
* If <em>itemMatcher</em> is not a matcher, it is implicitly wrapped in an <em>equalTo</em> matcher
* to check for equality.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@1, \@2, \@3], hasItem(equalTo(\@2)))</pre>
*
* <pre>assertThat(\@[\@1, \@2, \@3], hasItem(\@2))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasItem instead.
*/
#define hasItem HC_hasItem
#endif
FOUNDATION_EXPORT id HC_hasItemsIn(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when all specified matchers are
* satisfied by any item in the examined collection.
* @param itemMatchers An array of matchers. Any element that is not a matcher is implicitly wrapped
* in an <em>equalTo</em> matcher to check for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing one pass for each matcher.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar", \@"baz"], hasItems(\@[endsWith(\@"z"), endsWith(\@"o")]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasItemsIn instead.
*/
static inline id hasItemsIn(NSArray *itemMatchers)
{
return HC_hasItemsIn(itemMatchers);
}
#endif
FOUNDATION_EXPORT id HC_hasItems(id itemMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when all specified matchers are
* satisfied by any item in the examined collection.
* @param itemMatchers... A comma-separated list of matchers ending with <code>nil</code>.
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check
* for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing one pass for each matcher.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar", \@"baz"], hasItems(endsWith(\@"z"), endsWith(\@"o"), nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasItems instead.
*/
#define hasItems(itemMatchers...) HC_hasItems(itemMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,88 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionContaining.h"
#import "HCAllOf.h"
#import "HCCollect.h"
#import "HCRequireNonNilObject.h"
#import "HCWrapInMatcher.h"
@interface HCIsCollectionContaining ()
@property (nonatomic, strong, readonly) id <HCMatcher> elementMatcher;
@end
@implementation HCIsCollectionContaining
- (instancetype)initWithMatcher:(id <HCMatcher>)elementMatcher
{
self = [super init];
if (self)
_elementMatcher = elementMatcher;
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
if ([collection count] == 0)
{
[mismatchDescription appendText:@"was empty"];
return NO;
}
for (id item in collection)
if ([self.elementMatcher matches:item])
return YES;
[mismatchDescription appendText:@"mismatches were: ["];
BOOL isPastFirst = NO;
for (id item in collection)
{
if (isPastFirst)
[mismatchDescription appendText:@", "];
[self.elementMatcher describeMismatchOf:item to:mismatchDescription];
isPastFirst = YES;
}
[mismatchDescription appendText:@"]"];
return NO;
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a collection containing "]
appendDescriptionOf:self.elementMatcher];
}
@end
id HC_hasItem(id itemMatcher)
{
HCRequireNonNilObject(itemMatcher);
return [[HCIsCollectionContaining alloc] initWithMatcher:HCWrapInMatcher(itemMatcher)];
}
id HC_hasItemsIn(NSArray *itemMatchers)
{
NSMutableArray *matchers = [[NSMutableArray alloc] init];
for (id itemMatcher in itemMatchers)
[matchers addObject:HC_hasItem(itemMatcher)];
return HC_allOfIn(matchers);
}
id HC_hasItems(id itemMatchers, ...)
{
va_list args;
va_start(args, itemMatchers);
NSArray *array = HCCollectItems(itemMatchers, args);
va_end(args);
return HC_hasItemsIn(array);
}

View File

@@ -0,0 +1,79 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection, in any order, satisfy a list of nested matchers.
*/
@interface HCIsCollectionContainingInAnyOrder : HCDiagnosingMatcher
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_containsInAnyOrderIn(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates an order-agnostic matcher for collections that matches when each item in the
* examined collection satisfies one matcher anywhere in the specified list of matchers.
* @param itemMatchers An array of matchers. Any element that is not a matcher is implicitly wrapped
* in an <em>equalTo</em> matcher to check for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. For a positive match, the examined collection must be of the same
* length as the specified list of matchers.
*
* Note: Each matcher in the specified list will only be used once during a given examination, so
* be careful when specifying matchers that may be satisfied by more than one entry in an examined
* collection.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], containsInAnyOrderIn(\@[equalTo(\@"bar"), equalTo(\@"foo")]))</pre>
* <pre>assertThat(\@[\@"foo", \@"bar"], containsInAnyOrderIn(@[\@"bar", \@"foo"]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_containsInAnyOrderIn instead.
*/
static inline id containsInAnyOrderIn(NSArray *itemMatchers)
{
return HC_containsInAnyOrderIn(itemMatchers);
}
#endif
FOUNDATION_EXPORT id HC_containsInAnyOrder(id itemMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates an order-agnostic matcher for collections that matches when each item in the
* examined collection satisfies one matcher anywhere in the specified list of matchers.
* @param itemMatchers... A comma-separated list of matchers ending with <code>nil</code>.
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check
* for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. For a positive match, the examined collection must be of the same
* length as the specified list of matchers.
*
* Note: Each matcher in the specified list will only be used once during a given examination, so
* be careful when specifying matchers that may be satisfied by more than one entry in an examined
* collection.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], containsInAnyOrder(equalTo(\@"bar"), equalTo(\@"foo"), nil))</pre>
* <pre>assertThat(\@[\@"foo", \@"bar"], containsInAnyOrder(\@"bar", \@"foo", nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_containsInAnyOrder instead.
*/
#define containsInAnyOrder(itemMatchers...) HC_containsInAnyOrder(itemMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,115 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionContainingInAnyOrder.h"
#import "HCCollect.h"
@interface HCMatchingInAnyOrder : NSObject
@property (nonatomic, copy, readonly) NSMutableArray<id <HCMatcher>> *matchers;
@property (nonatomic, strong, readonly) id <HCDescription> mismatchDescription;
@end
@implementation HCMatchingInAnyOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
mismatchDescription:(id <HCDescription>)description
{
self = [super init];
if (self)
{
_matchers = [itemMatchers mutableCopy];
_mismatchDescription = description;
}
return self;
}
- (BOOL)matches:(nullable id)item
{
NSUInteger index = 0;
for (id <HCMatcher> matcher in self.matchers)
{
if ([matcher matches:item])
{
[self.matchers removeObjectAtIndex:index];
return YES;
}
++index;
}
[[self.mismatchDescription appendText:@"not matched: "]
appendDescriptionOf:item];
return NO;
}
- (BOOL)isFinishedWith:(NSArray *)collection
{
if (self.matchers.count == 0)
return YES;
[[[[self.mismatchDescription appendText:@"no item matches: "]
appendList:self.matchers start:@"" separator:@", " end:@""]
appendText:@" in "]
appendList:collection start:@"[" separator:@", " end:@"]"];
return NO;
}
@end
@interface HCIsCollectionContainingInAnyOrder ()
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@end
@implementation HCIsCollectionContainingInAnyOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
{
self = [super init];
if (self)
_matchers = [itemMatchers copy];
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
HCMatchingInAnyOrder *matchSequence =
[[HCMatchingInAnyOrder alloc] initWithMatchers:self.matchers
mismatchDescription:mismatchDescription];
for (id item in collection)
if (![matchSequence matches:item])
return NO;
return [matchSequence isFinishedWith:collection];
}
- (void)describeTo:(id <HCDescription>)description
{
[[[description appendText:@"a collection over "]
appendList:self.matchers start:@"[" separator:@", " end:@"]"]
appendText:@" in any order"];
}
@end
id HC_containsInAnyOrderIn(NSArray *itemMatchers)
{
return [[HCIsCollectionContainingInAnyOrder alloc] initWithMatchers:HCWrapIntoMatchers(itemMatchers)];
}
id HC_containsInAnyOrder(id itemMatchers, ...)
{
va_list args;
va_start(args, itemMatchers);
NSArray *array = HCCollectItems(itemMatchers, args);
va_end(args);
return HC_containsInAnyOrderIn(array);
}

View File

@@ -0,0 +1,71 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection satisfies a list of nested matchers, in order.
*/
@interface HCIsCollectionContainingInOrder : HCDiagnosingMatcher
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_containsIn(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when each item in the examined
* collection satisfies the corresponding matcher in the specified list of matchers.
* @param itemMatchers An array of matchers. Any element that is not a matcher is implicitly wrapped
* in an <em>equalTo</em> matcher to check for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. For a positive match, the examined collection must be of the same
* length as the specified list of matchers.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], containsIn(\@[equalTo(\@"foo"), equalTo(\@"bar")]))</pre>
* <pre>assertThat(\@[\@"foo", \@"bar"], containsIn(\@[\@"foo", \@"bar"]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_containsIn instead.)
*/
static inline id containsIn(NSArray *itemMatchers)
{
return HC_containsIn(itemMatchers);
}
#endif
FOUNDATION_EXPORT id HC_contains(id itemMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when each item in the examined
* collection satisfies the corresponding matcher in the specified list of matchers.
* @param itemMatchers... A comma-separated list of matchers ending with <code>nil</code>.
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check
* for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. For a positive match, the examined collection must be of the same
* length as the specified list of matchers.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@"foo", \@"bar"], contains(equalTo(\@"foo"), equalTo(\@"bar"), nil))</pre>
* <pre>assertThat(\@[\@"foo", \@"bar"], contains(\@"foo", \@"bar", nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_contains instead.)
*/
#define contains(itemMatchers...) HC_contains(itemMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,134 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionContainingInOrder.h"
#import "HCCollect.h"
@interface HCMatchSequence : NSObject
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@property (nonatomic, strong, readonly) id <HCDescription> mismatchDescription;
@property (nonatomic, assign) NSUInteger nextMatchIndex;
@end
@implementation HCMatchSequence
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
mismatchDescription:(id <HCDescription>)description
{
self = [super init];
if (self)
{
_matchers = [itemMatchers copy];
_mismatchDescription = description;
}
return self;
}
- (BOOL)matches:(nullable id)item
{
return [self isNotSurplus:item] && [self isMatched:item];
}
- (BOOL)isFinished
{
if (self.nextMatchIndex < self.matchers.count)
{
[[self.mismatchDescription appendText:@"no item was "]
appendDescriptionOf:self.matchers[self.nextMatchIndex]];
return NO;
}
return YES;
}
- (BOOL)isMatched:(id)item
{
id <HCMatcher> matcher = self.matchers[self.nextMatchIndex];
if (![matcher matches:item])
{
[self describeMismatchOfMatcher:matcher item:item];
return NO;
}
++self.nextMatchIndex;
return YES;
}
- (BOOL)isNotSurplus:(id)item
{
if (self.matchers.count <= self.nextMatchIndex)
{
[[self.mismatchDescription
appendText:[NSString stringWithFormat:@"exceeded count of %lu with item ",
(unsigned long)self.matchers.count]]
appendDescriptionOf:item];
return NO;
}
return YES;
}
- (void)describeMismatchOfMatcher:(id <HCMatcher>)matcher item:(id)item
{
[self.mismatchDescription appendText:[NSString stringWithFormat:@"item %lu: ",
(unsigned long)self.nextMatchIndex]];
[matcher describeMismatchOf:item to:self.mismatchDescription];
}
@end
@interface HCIsCollectionContainingInOrder ()
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@end
@implementation HCIsCollectionContainingInOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
{
self = [super init];
if (self)
_matchers = [itemMatchers copy];
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
HCMatchSequence *matchSequence =
[[HCMatchSequence alloc] initWithMatchers:self.matchers
mismatchDescription:mismatchDescription];
for (id item in collection)
if (![matchSequence matches:item])
return NO;
return [matchSequence isFinished];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a collection containing "]
appendList:self.matchers start:@"[" separator:@", " end:@"]"];
}
@end
id HC_containsIn(NSArray *itemMatchers)
{
return [[HCIsCollectionContainingInOrder alloc] initWithMatchers:HCWrapIntoMatchers(itemMatchers)];
}
id HC_contains(id itemMatchers, ...)
{
va_list args;
va_start(args, itemMatchers);
NSArray *array = HCCollectItems(itemMatchers, args);
va_end(args);
return HC_containsIn(array);
}

View File

@@ -0,0 +1,48 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection satisfies a list of nested matchers, in order.
*/
@interface HCIsCollectionContainingInRelativeOrder : HCDiagnosingMatcher
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_containsInRelativeOrder(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when the examined collection contains
* items satisfying the specified list of matchers, in the same relative order.
* @param itemMatchers Array of matchers that must be satisfied by the items provided by the
* examined collection in the same relative order.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass.
*
* Any element of <em>itemMatchers</em> that is not a matcher is implicitly wrapped in an
* <em>equalTo</em> matcher to check for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(\@[\@1, \@2, \@3, \@4, \@5], containsInRelativeOrder(equalTo(\@2), equalTo(\@4)))</pre>
* <pre>assertThat(\@[\@1, \@2, \@3, \@4, \@5], containsInRelativeOrder(\@2, \@4))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_containsInRelativeOrder instead.
*/
static inline id containsInRelativeOrder(NSArray *itemMatchers)
{
return HC_containsInRelativeOrder(itemMatchers);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,124 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionContainingInRelativeOrder.h"
#import "HCCollect.h"
static void HCRequireNonEmptyArray(NSArray *array)
{
if (!array.count)
{
@throw [NSException exceptionWithName:@"EmptyArray"
reason:@"Must be non-empty array"
userInfo:nil];
}
}
@interface HCMatchSequenceInRelativeOrder : NSObject
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@property (nonatomic, strong, readonly) id <HCDescription> mismatchDescription;
@property (nonatomic, assign) NSUInteger nextMatchIndex;
@property (nonatomic, strong) id lastMatchedItem;
@end
@implementation HCMatchSequenceInRelativeOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
mismatchDescription:(id <HCDescription>)description
{
self = [super init];
if (self)
{
_matchers = [itemMatchers copy];
_mismatchDescription = description;
}
return self;
}
- (void)processItems:(NSArray *)sequence
{
for (id item in sequence)
{
if (self.nextMatchIndex < self.matchers.count)
{
id <HCMatcher> matcher = self.matchers[self.nextMatchIndex];
if ([matcher matches:item])
{
self.lastMatchedItem = item;
self.nextMatchIndex += 1;
}
}
}
}
- (BOOL)isFinished
{
if (self.nextMatchIndex < self.matchers.count)
{
[[self.mismatchDescription
appendDescriptionOf:self.matchers[self.nextMatchIndex]]
appendText:@" was not found"];
if (self.lastMatchedItem != nil)
{
[[self.mismatchDescription
appendText:@" after "]
appendDescriptionOf:self.lastMatchedItem];
}
return NO;
}
return YES;
}
@end
@interface HCIsCollectionContainingInRelativeOrder ()
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@end
@implementation HCIsCollectionContainingInRelativeOrder
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)itemMatchers
{
HCRequireNonEmptyArray(itemMatchers);
self = [super init];
if (self)
_matchers = [itemMatchers copy];
return self;
}
- (BOOL)matches:(id)collection describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![collection conformsToProtocol:@protocol(NSFastEnumeration)])
{
[[mismatchDescription appendText:@"was non-collection "] appendDescriptionOf:collection];
return NO;
}
HCMatchSequenceInRelativeOrder *matchSequenceInRelativeOrder =
[[HCMatchSequenceInRelativeOrder alloc] initWithMatchers:self.matchers
mismatchDescription:mismatchDescription];
[matchSequenceInRelativeOrder processItems:collection];
return [matchSequenceInRelativeOrder isFinished];
}
- (void)describeTo:(id <HCDescription>)description
{
[[[description
appendText:@"a collection containing "]
appendList:self.matchers start:@"[" separator:@", " end:@"]"]
appendText:@" in relative order"];
}
@end
id HC_containsInRelativeOrder(NSArray *itemMatchers)
{
NSArray *matchers = HCWrapIntoMatchers(itemMatchers);
return [[HCIsCollectionContainingInRelativeOrder alloc] initWithMatchers:matchers];
}

View File

@@ -0,0 +1,62 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCEvery.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if every item in a collection satisfies any of the nested matchers.
*/
@interface HCIsCollectionOnlyContaining : HCEvery
@end
FOUNDATION_EXPORT id HC_onlyContainsIn(NSArray *itemMatchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when each item of the examined
* collection satisfies any of the specified matchers.
* @param itemMatchers An array of matchers. Any element that is not a matcher is implicitly wrapped
* in an <em>equalTo</em> matcher to check for equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. Any matcher may match multiple elements.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"Jon", \@"John", \@"Bob"], onlyContainsIn(\@[startsWith(\@"Jo"), startsWith(\@("Bo")]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_onlyContainsIn instead.
*/
static inline id onlyContainsIn(NSArray *itemMatchers)
{
return HC_onlyContainsIn(itemMatchers);
}
#endif
FOUNDATION_EXPORT id HC_onlyContains(id itemMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for collections that matches when each item of the examined
* collection satisfies any of the specified matchers.
* @param itemMatchers... A comma-separated list of matchers ending with <code>nil</code>.
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check for
* equality.
* @discussion This matcher works on any collection that conforms to the NSFastEnumeration protocol,
* performing a single pass. Any matcher may match multiple elements.
*
* <b>Example</b><br />
* <pre>assertThat(\@[\@"Jon", \@"John", \@"Bob"], onlyContains(startsWith(\@"Jo"), startsWith(\@("Bo"), nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_onlyContains instead.
*/
#define onlyContains(itemMatchers...) HC_onlyContains(itemMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,34 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCollectionOnlyContaining.h"
#import "HCAnyOf.h"
#import "HCCollect.h"
@implementation HCIsCollectionOnlyContaining
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a collection containing items matching "]
appendDescriptionOf:self.matcher];
}
@end
id HC_onlyContainsIn(NSArray *itemMatchers)
{
return [[HCIsCollectionOnlyContaining alloc] initWithMatcher:HC_anyOfIn(itemMatchers)];
}
id HC_onlyContains(id itemMatchers, ...)
{
va_list args;
va_start(args, itemMatchers);
NSArray *array = HCCollectItems(itemMatchers, args);
va_end(args);
return HC_onlyContainsIn(array);
}

View File

@@ -0,0 +1,47 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if any entry in a dictionary satisfies the nested pair of matchers.
*/
@interface HCIsDictionaryContaining : HCBaseMatcher
- (instancetype)initWithKeyMatcher:(id <HCMatcher>)keyMatcher
valueMatcher:(id <HCMatcher>)valueMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasEntry(id keyMatcher, id valueMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* at least one entry whose key satisfies the specified <code>keyMatcher</code> <b>and</b> whose
* value satisfies the specified <code>valueMatcher</code>.
* @param keyMatcher The matcher to satisfy for the key, or an expected value for <em>equalTo</em> matching.
* @param valueMatcher The matcher to satisfy for the value, or an expected value for <em>equalTo</em> matching.
* @discussion Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em>
* matcher to check for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(myDictionary, hasEntry(equalTo(\@"foo"), equalTo(\@"bar")))</pre>
* <pre>assertThat(myDictionary, hasEntry(\@"foo", \@"bar"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasEntry instead.
*/
static inline id hasEntry(id keyMatcher, id valueMatcher)
{
return HC_hasEntry(keyMatcher, valueMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,56 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsDictionaryContaining.h"
#import "HCRequireNonNilObject.h"
#import "HCWrapInMatcher.h"
@interface HCIsDictionaryContaining ()
@property (nonatomic, strong, readonly) id <HCMatcher> keyMatcher;
@property (nonatomic, strong, readonly) id <HCMatcher> valueMatcher;
@end
@implementation HCIsDictionaryContaining
- (instancetype)initWithKeyMatcher:(id <HCMatcher>)keyMatcher
valueMatcher:(id <HCMatcher>)valueMatcher
{
self = [super init];
if (self)
{
_keyMatcher = keyMatcher;
_valueMatcher = valueMatcher;
}
return self;
}
- (BOOL)matches:(id)dict
{
if ([dict isKindOfClass:[NSDictionary class]])
for (id oneKey in dict)
if ([self.keyMatcher matches:oneKey] && [self.valueMatcher matches:dict[oneKey]])
return YES;
return NO;
}
- (void)describeTo:(id <HCDescription>)description
{
[[[[[description appendText:@"a dictionary containing { "]
appendDescriptionOf:self.keyMatcher]
appendText:@" = "]
appendDescriptionOf:self.valueMatcher]
appendText:@"; }"];
}
@end
id HC_hasEntry(id keyMatcher, id valueMatcher)
{
HCRequireNonNilObject(keyMatcher);
HCRequireNonNilObject(valueMatcher);
return [[HCIsDictionaryContaining alloc] initWithKeyMatcher:HCWrapInMatcher(keyMatcher)
valueMatcher:HCWrapInMatcher(valueMatcher)];
}

View File

@@ -0,0 +1,68 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if dictionary contains entries that satisfy the list of keys and value
* matchers.
*/
@interface HCIsDictionaryContainingEntries : HCDiagnosingMatcher
- (instancetype)initWithKeys:(NSArray *)keys
valueMatchers:(NSArray<id <HCMatcher>> *)valueMatchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasEntriesIn(NSDictionary *valueMatchersForKeys);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* entries satisfying a dictionary of keys and their value matchers.
* @param valueMatchersForKeys A dictionary of keys (not matchers) and their value matchers. Any
* value argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to
* check for equality.
* @discussion
* <b>Examples</b><br />
* <pre>assertThat(personDict, hasEntriesIn(\@{\@"firstName": equalTo(\@"Jon"), \@"lastName": equalTo(\@"Reid")}))</pre>
* <pre>assertThat(personDict, hasEntriesIn(\@{\@"firstName": \@"Jon", \@"lastName": \@"Reid"}))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasEntryIn instead.
*/
static inline id hasEntriesIn(NSDictionary *valueMatchersForKeys)
{
return HC_hasEntriesIn(valueMatchersForKeys);
}
#endif
FOUNDATION_EXPORT id HC_hasEntries(id keysAndValueMatchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* entries satisfying a list of alternating keys and their value matchers.
* @param keysAndValueMatchers... A key (not a matcher) to look up, followed by a value matcher or
* an expected value for <em>equalTo</em> matching, in a comma-separated list ending
* with <code>nil</code>
* @discussion Note that the keys must be actual keys, not matchers. Any value argument that is not
* a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(personDict, hasEntries(\@"firstName", equalTo(\@"Jon"), \@"lastName", equalTo(\@"Reid"), nil))</pre>
* <pre>assertThat(personDict, hasEntries(\@"firstName", \@"Jon", \@"lastName", \@"Reid", nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasEntry instead.
*/
#define hasEntries(keysAndValueMatchers...) HC_hasEntries(keysAndValueMatchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,132 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsDictionaryContainingEntries.h"
#import "HCWrapInMatcher.h"
@interface HCIsDictionaryContainingEntries ()
@property (nonatomic, copy, readonly) NSArray *keys;
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *valueMatchers;
@end
@implementation HCIsDictionaryContainingEntries
- (instancetype)initWithKeys:(NSArray *)keys
valueMatchers:(NSArray<id <HCMatcher>> *)valueMatchers
{
self = [super init];
if (self)
{
_keys = [keys copy];
_valueMatchers = [valueMatchers copy];
}
return self;
}
- (BOOL)matches:(id)dict describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![dict isKindOfClass:[NSDictionary class]])
{
[[mismatchDescription appendText:@"was non-dictionary "] appendDescriptionOf:dict];
return NO;
}
NSUInteger count = self.keys.count;
for (NSUInteger index = 0; index < count; ++index)
{
id key = self.keys[index];
if (dict[key] == nil)
{
[[[[mismatchDescription appendText:@"no "]
appendDescriptionOf:key]
appendText:@" key in "]
appendDescriptionOf:dict];
return NO;
}
id valueMatcher = self.valueMatchers[index];
id actualValue = dict[key];
if (![valueMatcher matches:actualValue])
{
[[[[mismatchDescription appendText:@"value for "]
appendDescriptionOf:key]
appendText:@" was "]
appendDescriptionOf:actualValue];
return NO;
}
}
return YES;
}
- (void)describeKeyValueAtIndex:(NSUInteger)index to:(id <HCDescription>)description
{
[[[[description appendDescriptionOf:self.keys[index]]
appendText:@" = "]
appendDescriptionOf:self.valueMatchers[index]]
appendText:@"; "];
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendText:@"a dictionary containing { "];
NSUInteger count = [self.keys count];
NSUInteger index = 0;
for (; index < count - 1; ++index)
[self describeKeyValueAtIndex:index to:description];
[self describeKeyValueAtIndex:index to:description];
[description appendText:@"}"];
}
@end
static void requirePairedObject(id obj)
{
if (obj == nil)
{
@throw [NSException exceptionWithName:@"NilObject"
reason:@"HC_hasEntries keys and value matchers must be paired"
userInfo:nil];
}
}
id HC_hasEntriesIn(NSDictionary *valueMatchersForKeys)
{
NSArray *keys = valueMatchersForKeys.allKeys;
NSMutableArray<id <HCMatcher>> *valueMatchers = [[NSMutableArray alloc] init];
for (id key in keys)
[valueMatchers addObject:HCWrapInMatcher(valueMatchersForKeys[key])];
return [[HCIsDictionaryContainingEntries alloc] initWithKeys:keys
valueMatchers:valueMatchers];
}
id HC_hasEntries(id keysAndValueMatchers, ...)
{
va_list args;
va_start(args, keysAndValueMatchers);
id key = keysAndValueMatchers;
id valueMatcher = va_arg(args, id);
requirePairedObject(valueMatcher);
NSMutableArray *keys = [NSMutableArray arrayWithObject:key];
NSMutableArray<id <HCMatcher>> *valueMatchers = [NSMutableArray arrayWithObject:HCWrapInMatcher(valueMatcher)];
key = va_arg(args, id);
while (key != nil)
{
[keys addObject:key];
valueMatcher = va_arg(args, id);
requirePairedObject(valueMatcher);
[valueMatchers addObject:HCWrapInMatcher(valueMatcher)];
key = va_arg(args, id);
}
return [[HCIsDictionaryContainingEntries alloc] initWithKeys:keys
valueMatchers:valueMatchers];
}

View File

@@ -0,0 +1,44 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if any entry in a dictionary has a key satisfying the nested matcher.
*/
@interface HCIsDictionaryContainingKey : HCBaseMatcher
- (instancetype)initWithKeyMatcher:(id <HCMatcher>)keyMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasKey(id keyMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* at least key that satisfies the specified matcher.
* @param keyMatcher The matcher to satisfy for the key, or an expected value for <em>equalTo</em> matching.
* @discussion Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em>
* matcher to check for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(myDictionary, hasEntry(equalTo(\@"foo")))</pre>
* <pre>assertThat(myDictionary, hasEntry(\@"foo"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasKey instead.
*/
static inline id hasKey(id keyMatcher)
{
return HC_hasKey(keyMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,46 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsDictionaryContainingKey.h"
#import "HCRequireNonNilObject.h"
#import "HCWrapInMatcher.h"
@interface HCIsDictionaryContainingKey ()
@property (nonatomic, strong, readonly) id <HCMatcher> keyMatcher;
@end
@implementation HCIsDictionaryContainingKey
- (instancetype)initWithKeyMatcher:(id <HCMatcher>)keyMatcher
{
self = [super init];
if (self)
_keyMatcher = keyMatcher;
return self;
}
- (BOOL)matches:(id)dict
{
if ([dict isKindOfClass:[NSDictionary class]])
for (id oneKey in dict)
if ([self.keyMatcher matches:oneKey])
return YES;
return NO;
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a dictionary containing key "]
appendDescriptionOf:self.keyMatcher];
}
@end
id HC_hasKey(id keyMatcher)
{
HCRequireNonNilObject(keyMatcher);
return [[HCIsDictionaryContainingKey alloc] initWithKeyMatcher:HCWrapInMatcher(keyMatcher)];
}

View File

@@ -0,0 +1,46 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if any entry in a dictionary has a value satisfying the nested matcher.
*/
@interface HCIsDictionaryContainingValue : HCBaseMatcher
- (instancetype)initWithValueMatcher:(id <HCMatcher>)valueMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasValue(id valueMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSDictionaries that matches when the examined dictionary contains
* at least value that satisfies the specified matcher.
* @param valueMatcher The matcher to satisfy for the value, or an expected value for <em>equalTo</em> matching.
* @discussion This matcher works on any collection that has an <code>-allValues</code> method.
*
* Any argument that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check
* for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(myDictionary, hasValue(equalTo(\@"bar")))</pre>
* <pre>assertThat(myDictionary, hasValue(\@"bar"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasValue instead.
*/
static inline id hasValue(id valueMatcher)
{
return HC_hasValue(valueMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,46 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsDictionaryContainingValue.h"
#import "HCRequireNonNilObject.h"
#import "HCWrapInMatcher.h"
@interface HCIsDictionaryContainingValue ()
@property (nonatomic, strong, readonly) id <HCMatcher> valueMatcher;
@end
@implementation HCIsDictionaryContainingValue
- (instancetype)initWithValueMatcher:(id <HCMatcher>)valueMatcher
{
self = [super init];
if (self)
_valueMatcher = valueMatcher;
return self;
}
- (BOOL)matches:(id)dict
{
if ([dict respondsToSelector:@selector(allValues)])
for (id oneValue in [dict allValues])
if ([self.valueMatcher matches:oneValue])
return YES;
return NO;
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a dictionary containing value "]
appendDescriptionOf:self.valueMatcher];
}
@end
id HC_hasValue(id valueMatcher)
{
HCRequireNonNilObject(valueMatcher);
return [[HCIsDictionaryContainingValue alloc] initWithValueMatcher:HCWrapInMatcher(valueMatcher)];
}

View File

@@ -0,0 +1,39 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCHasCount.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches empty collections.
*/
@interface HCIsEmptyCollection : HCHasCount
- (instancetype)init;
@end
FOUNDATION_EXPORT id HC_isEmpty(void);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches any examined object whose <code>-count</code> method
* returns zero.
*
* <b>Example</b><br />
* <pre>assertThat(\@[], isEmpty())</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_isEmpty instead.
*/
static inline id isEmpty(void)
{
return HC_isEmpty();
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,33 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsEmptyCollection.h"
#import "HCIsEqual.h"
@implementation HCIsEmptyCollection
- (instancetype)init
{
self = [super initWithMatcher:HC_equalTo(@0)];
return self;
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[[mismatchDescription appendText:@"was "] appendDescriptionOf:item];
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendText:@"empty collection"];
}
@end
FOUNDATION_EXPORT id HC_isEmpty(void)
{
return [[HCIsEmptyCollection alloc] init];
}

View File

@@ -0,0 +1,43 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches if examined object is contained within the nested collection.
*/
@interface HCIsIn : HCBaseMatcher
- (instancetype)initWithCollection:(id)collection NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_isIn(id aCollection);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is found within the specified
* collection.
* @param aCollection The collection to search.
* @discussion Invokes <code>-containsObject:</code> on <em>aCollection</em> to determine if the
* examined object is an element of the collection.
*
* <b>Example</b><br />
* <pre>assertThat(\@"foo", isIn(\@@[\@"bar", \@"foo"]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_isIn instead.
*/
static inline id isIn(id aCollection)
{
return HC_isIn(aCollection);
}
#endif
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 "HCIsIn.h"
@interface HCIsIn ()
@property (nonatomic, strong, readonly) id collection;
@end
@implementation HCIsIn
- (instancetype)initWithCollection:(id)collection
{
if (![collection respondsToSelector:@selector(containsObject:)])
{
@throw [NSException exceptionWithName:@"NotAContainer"
reason:@"Object must respond to -containsObject:"
userInfo:nil];
}
self = [super init];
if (self)
_collection = collection;
return self;
}
- (BOOL)matches:(nullable id)item
{
return [self.collection containsObject:item];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"one of "]
appendList:self.collection start:@"{" separator:@", " end:@"}"];
}
@end
id HC_isIn(id aCollection)
{
return [[HCIsIn alloc] initWithCollection:aCollection];
}

View File

@@ -0,0 +1,41 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Provides a custom description to another matcher.
*/
@interface HCDescribedAs : HCBaseMatcher
- (instancetype)initWithDescription:(NSString *)description
forMatcher:(id <HCMatcher>)matcher
overValues:(NSArray *)templateValues NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_describedAs(NSString *description, id <HCMatcher> matcher, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Wraps an existing matcher, overriding its description with that specified. All other
* functions are delegated to the decorated matcher, including its mismatch description.
* @param description The new description for the wrapped matcher.
* @param matcher The matcher to wrap, followed by a comma-separated list of substitution
* values ending with <code>nil</code>.
* @discussion The description may contain substitution placeholders %0, %1, etc. These will be
* replaced by any values that follow the matcher.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_describedAs instead.
*/
#define describedAs(description, matcher, ...) HC_describedAs(description, matcher, ##__VA_ARGS__)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,121 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCDescribedAs.h"
@interface NSString (OCHamcrest)
@end
@implementation NSString (OCHamcrest)
// Parse decimal number (-1 if not found) and return remaining string.
- (NSString *)och_getDecimalNumber:(int *)number
{
int decimal = 0;
BOOL readDigit = NO;
NSUInteger length = self.length;
NSUInteger index;
for (index = 0; index < length; ++index)
{
unichar character = [self characterAtIndex:index];
if (!isdigit(character))
break;
decimal = decimal * 10 + character - '0';
readDigit = YES;
}
if (!readDigit)
{
*number = -1;
return self;
}
*number = decimal;
return [self substringFromIndex:index];
}
@end
@interface HCDescribedAs ()
@property (nonatomic, copy, readonly) NSString *descriptionTemplate;
@property (nonatomic, strong, readonly) id <HCMatcher> matcher;
@property (nonatomic, copy, readonly) NSArray *values;
@end
@implementation HCDescribedAs
- (instancetype)initWithDescription:(NSString *)description
forMatcher:(id <HCMatcher>)matcher
overValues:(NSArray *)templateValues
{
self = [super init];
if (self)
{
_descriptionTemplate = [description copy];
_matcher = matcher;
_values = [templateValues copy];
}
return self;
}
- (BOOL)matches:(nullable id)item
{
return [self.matcher matches:item];
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[self.matcher describeMismatchOf:item to:mismatchDescription];
}
- (void)describeTo:(id <HCDescription>)description
{
NSArray<NSString *> *components = [self.descriptionTemplate componentsSeparatedByString:@"%"];
BOOL firstComponent = YES;
for (NSString *component in components)
{
if (firstComponent)
{
firstComponent = NO;
[description appendText:component];
}
else
{
[self appendTemplateForComponent:component toDescription:description];
}
}
}
- (void)appendTemplateForComponent:(NSString *)component toDescription:(id <HCDescription>)description
{
int index;
NSString *remainder = [component och_getDecimalNumber:&index];
if (index < 0)
[[description appendText:@"%"] appendText:component];
else
[[description appendDescriptionOf:self.values[(NSUInteger)index]] appendText:remainder];
}
@end
id HC_describedAs(NSString *description, id <HCMatcher> matcher, ...)
{
NSMutableArray *valueList = [NSMutableArray array];
va_list args;
va_start(args, matcher);
id value = va_arg(args, id);
while (value != nil)
{
[valueList addObject:value];
value = va_arg(args, id);
}
va_end(args);
return [[HCDescribedAs alloc] initWithDescription:description
forMatcher:matcher
overValues:valueList];
}

View File

@@ -0,0 +1,55 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Decorates another matcher.
*/
@interface HCIs : HCBaseMatcher
- (instancetype)initWithMatcher:(id <HCMatcher>)matcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_is(_Nullable id value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Wraps an existing matcher, or provides a shortcut to the frequently
* used <code>is(equalTo(x))</code>.
* @param value The matcher to satisfy, or an expected value for <em>equalTo</em> matching.
* @discussion
* If <em>value</em>is a matcher, its behavior is retained, but the test may be slightly more
* expressive. For example:
* <ul>
* <li><code>assertThat(\@(value), equalTo(\@5))</code></li>
* <li><code>assertThat(\@(value), is(equalTo(\@5)))</code></li>
* </ul>
*
* If <em>value</em>is not a matcher, it is wrapped in an <em>equalTo</em> matcher. This makes the
* following statements equivalent:
* <ul>
* <li><code>assertThat(cheese, equalTo(smelly))</code></li>
* <li><code>assertThat(cheese, is(equalTo(smelly)))</code></li>
* <li><code>assertThat(cheese, is(smelly))</code></li>
* </ul>
*
* Choose the style that makes your expression most readable. This will vary depending on context.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_is instead.
*/
static inline id is(_Nullable id value)
{
return HC_is(value);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,44 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIs.h"
#import "HCWrapInMatcher.h"
@interface HCIs ()
@property (nonatomic, strong, readonly) id <HCMatcher> matcher;
@end
@implementation HCIs
- (instancetype)initWithMatcher:(id <HCMatcher>)matcher
{
self = [super init];
if (self)
_matcher = matcher;
return self;
}
- (BOOL)matches:(nullable id)item
{
return [self.matcher matches:item];
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[self.matcher describeMismatchOf:item to:mismatchDescription];
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendDescriptionOf:self.matcher];
}
@end
id HC_is(_Nullable id value)
{
return [[HCIs alloc] initWithMatcher:HCWrapInMatcher(value)];
}

View File

@@ -0,0 +1,64 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Calculates the logical conjunction of multiple matchers.
* @discussion Evaluation is shortcut, so subsequent matchers are not called if an earlier matcher
* returns <code>NO</code>.
*/
@interface HCAllOf : HCDiagnosingMatcher
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)matchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_allOfIn(NSArray<id <HCMatcher>> *matchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object matches <b>all</b> of the
* specified matchers.
* @param matchers An array of matchers. Any element that is not a matcher is implicitly wrapped in
* an <em>equalTo</em> matcher to check for equality.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@"myValue", allOfIn(\@[startsWith(\@"my"), containsSubstring(\@"Val")]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_allOfIn instead.
*/
static inline id allOfIn(NSArray *matchers)
{
return HC_allOfIn(matchers);
}
#endif
FOUNDATION_EXPORT id HC_allOf(id matchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object matches <b>all</b> of the
* specified matchers.
* @param matchers... A comma-separated list of matchers ending with <code>nil</code>. Any argument
* that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check for equality.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@"myValue", allOf(startsWith(\@"my"), containsSubstring(\@"Val"), nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_allOf instead.
*/
#define allOf(matchers...) HC_allOf(matchers)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,60 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCAllOf.h"
#import "HCCollect.h"
@interface HCAllOf ()
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@end
@implementation HCAllOf
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)matchers
{
self = [super init];
if (self)
_matchers = [matchers copy];
return self;
}
- (BOOL)matches:(nullable id)item describingMismatchTo:(id <HCDescription>)mismatchDescription
{
for (id <HCMatcher> oneMatcher in self.matchers)
{
if (![oneMatcher matches:item])
{
[[[mismatchDescription appendText:@"instead of "]
appendDescriptionOf:oneMatcher]
appendText:@", "];
[oneMatcher describeMismatchOf:item to:mismatchDescription];
return NO;
}
}
return YES;
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendList:self.matchers start:@"(" separator:@" and " end:@")"];
}
@end
id HC_allOfIn(NSArray *matchers)
{
return [[HCAllOf alloc] initWithMatchers:HCWrapIntoMatchers(matchers)];
}
id HC_allOf(id matchers, ...)
{
va_list args;
va_start(args, matchers);
NSArray *array = HCCollectItems(matchers, args);
va_end(args);
return HC_allOfIn(array);
}

View File

@@ -0,0 +1,62 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Calculates the logical disjunction of multiple matchers.
* @discussion Evaluation is shortcut, so subsequent matchers are not called if an earlier matcher
* returns <code>NO</code>.
*/
@interface HCAnyOf : HCBaseMatcher
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)matchers NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_anyOfIn(NSArray *matchers);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object matches <b>any</b> of the
* specified matchers.
* @param matchers An array of matchers. Any element that is not a matcher is implicitly wrapped in
* an <em>equalTo</em> matcher to check for equality.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@"myValue", allOf(\@[startsWith(\@"foo"), containsSubstring(\@"Val")]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_anyOf instead.
*/
static inline id anyOfIn(NSArray *matchers)
{
return HC_anyOfIn(matchers);
}
#endif
FOUNDATION_EXPORT id HC_anyOf(id matchers, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object matches <b>any</b> of the
* specified matchers.
* @param matchers... A comma-separated list of matchers ending with <code>nil</code>. Any argument
* that is not a matcher is implicitly wrapped in an <em>equalTo</em> matcher to check for equality.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@"myValue", allOf(startsWith(\@"foo"), containsSubstring(\@"Val"), nil))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_anyOf instead.
*/
#define anyOf(matchers...) HC_anyOf(matchers)
#endif
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 "HCAnyOf.h"
#import "HCCollect.h"
@interface HCAnyOf ()
@property (nonatomic, copy, readonly) NSArray<id <HCMatcher>> *matchers;
@end
@implementation HCAnyOf
- (instancetype)initWithMatchers:(NSArray<id <HCMatcher>> *)matchers
{
self = [super init];
if (self)
_matchers = [matchers copy];
return self;
}
- (BOOL)matches:(nullable id)item
{
for (id <HCMatcher> oneMatcher in self.matchers)
if ([oneMatcher matches:item])
return YES;
return NO;
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendList:self.matchers start:@"(" separator:@" or " end:@")"];
}
@end
id HC_anyOfIn(NSArray *matchers)
{
return [[HCAnyOf alloc] initWithMatchers:HCWrapIntoMatchers(matchers)];
}
id HC_anyOf(id matchers, ...)
{
va_list args;
va_start(args, matchers);
NSArray *array = HCCollectItems(matchers, args);
va_end(args);
return HC_anyOfIn(array);
}

View File

@@ -0,0 +1,55 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches anything.
*/
@interface HCIsAnything : HCBaseMatcher
- (instancetype)init;
- (instancetype)initWithDescription:(NSString *)description NS_DESIGNATED_INITIALIZER;
@end
FOUNDATION_EXPORT id HC_anything(void);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that always matches, regardless of the examined object.
* @discussion
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_anything instead.
*/
static inline id anything(void)
{
return HC_anything();
}
#endif
FOUNDATION_EXPORT id HC_anythingWithDescription(NSString *description);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches anything, regardless of the examined object, but
* describes itself with the specified NSString.
* @param description A meaningful string used to describe this matcher.
* @discussion
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_anything instead.
*/
static inline id anythingWithDescription(NSString *description)
{
return HC_anythingWithDescription(description);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,47 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsAnything.h"
@implementation HCIsAnything
{
NSString *_description;
}
- (instancetype)init
{
self = [self initWithDescription:@"ANYTHING"];
return self;
}
- (instancetype)initWithDescription:(NSString *)description
{
self = [super init];
if (self)
_description = [description copy];
return self;
}
- (BOOL)matches:(nullable id)item
{
return YES;
}
- (void)describeTo:(id <HCDescription>)aDescription
{
[aDescription appendText:_description];
}
@end
id HC_anything()
{
return [[HCIsAnything alloc] init];
}
id HC_anythingWithDescription(NSString *description)
{
return [[HCIsAnything alloc] initWithDescription:description];
}

View File

@@ -0,0 +1,44 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Calculates the logical negation of a matcher.
*/
@interface HCIsNot : HCBaseMatcher
- (instancetype)initWithMatcher:(id <HCMatcher>)matcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_isNot(_Nullable id value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that wraps an existing matcher, but inverts the logic by which it
* will match.
* @param value The matcher to negate, or an expected value to match for inequality.
* @discussion If <em>value</em> is not a matcher, it is implicitly wrapped in an <em>equalTo</em>
* matcher to check for equality, and thus matches for inequality.
*
* <b>Examples</b><br />
* <pre>assertThat(cheese, isNot(equalTo(smelly)))</pre>
* <pre>assertThat(cheese, isNot(smelly))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_isNot instead.
*/
static inline id isNot(_Nullable id value)
{
return HC_isNot(value);
}
#endif
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 "HCIsNot.h"
#import "HCWrapInMatcher.h"
@interface HCIsNot ()
@property (nonatomic, strong, readonly) id <HCMatcher> matcher;
@end
@implementation HCIsNot
- (instancetype)initWithMatcher:(id <HCMatcher>)matcher
{
self = [super init];
if (self)
_matcher = matcher;
return self;
}
- (BOOL)matches:(nullable id)item
{
return ![self.matcher matches:item];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"not "] appendDescriptionOf:self.matcher];
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[self.matcher describeMismatchOf:item to:mismatchDescription];
}
@end
id HC_isNot(_Nullable id value)
{
return [[HCIsNot alloc] initWithMatcher:HCWrapInMatcher(value)];
}

View File

@@ -0,0 +1,43 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matchers numbers close to a value, within a delta range.
*/
@interface HCIsCloseTo : HCBaseMatcher
- (instancetype)initWithValue:(double)value delta:(double)delta NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_closeTo(double value, double delta);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSNumbers that matches when the examined number is close to the
* specified value, within the specified delta.
* @param value The expected value of matching numbers.
* @param delta The delta within which matches will be allowed.
* @discussion Invokes <code>-doubleValue</code> on the examined number to get its value.
*
* <b>Example</b><br />
* <pre>assertThat(\@1.03, closeTo(1.0, 0.03)</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_closeTo instead.
*/
static inline id closeTo(double value, double delta)
{
return HC_closeTo(value, delta);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,69 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsCloseTo.h"
@interface HCIsCloseTo ()
@property (nonatomic, assign, readonly) double value;
@property (nonatomic, assign, readonly) double delta;
@end
@implementation HCIsCloseTo
- (id)initWithValue:(double)value delta:(double)delta
{
self = [super init];
if (self)
{
_value = value;
_delta = delta;
}
return self;
}
- (BOOL)matches:(nullable id)item
{
if ([self itemIsNotNumber:item])
return NO;
return [self actualDelta:item] <= self.delta;
}
- (double)actualDelta:(id)item
{
return fabs([item doubleValue] - self.value);
}
- (BOOL)itemIsNotNumber:(id)item
{
return ![item isKindOfClass:[NSNumber class]];
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
if ([self itemIsNotNumber:item])
[super describeMismatchOf:item to:mismatchDescription];
else
{
[[[mismatchDescription appendDescriptionOf:item]
appendText:@" differed by "]
appendDescriptionOf:@([self actualDelta:item])];
}
}
- (void)describeTo:(id <HCDescription>)description
{
[[[[description appendText:@"a numeric value within "]
appendDescriptionOf:@(self.delta)]
appendText:@" of "]
appendDescriptionOf:@(self.value)];
}
@end
id HC_closeTo(double value, double delta)
{
return [[HCIsCloseTo alloc] initWithValue:value delta:delta];
}

View File

@@ -0,0 +1,289 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
FOUNDATION_EXPORT id HC_equalToChar(char value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified char value.
* @param value The char value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToChar instead.
*/
static inline id equalToChar(char value)
{
return HC_equalToChar(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToDouble(double value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified double value.
* @param value The double value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToDouble instead.
*/
static inline id equalToDouble(double value)
{
return HC_equalToDouble(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToFloat(float value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified float value.
* @param value The float value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToFloat instead.
*/
static inline id equalToFloat(float value)
{
return HC_equalToFloat(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToInt(int value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified int value.
* @param value The int value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToInt instead.
*/
static inline id equalToInt(int value)
{
return HC_equalToInt(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToLong(long value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified long value.
* @param value The long value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToLong instead.
*/
static inline id equalToLong(long value)
{
return HC_equalToLong(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToLongLong(long long value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified long long value.
* @param value The long long value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToLongLong instead.
*/
static inline id equalToLongLong(long long value)
{
return HC_equalToLongLong(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToShort(short value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified short value.
* @param value The short value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToShort instead.
*/
static inline id equalToShort(short value)
{
return HC_equalToShort(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToUnsignedChar(unsigned char value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract equalToUnsignedChar(value) -
* Creates a matcher that matches when the examined object is equal to an NSNumber created from the
* specified unsigned char value.
* @param value The unsigned char value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToUnsignedChar instead.
*/
static inline id equalToUnsignedChar(unsigned char value)
{
return HC_equalToUnsignedChar(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToUnsignedInt(unsigned int value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified unsigned int value.
* @param value The unsigned int value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToUnsignedInt instead.
*/
static inline id equalToUnsignedInt(unsigned int value)
{
return HC_equalToUnsignedInt(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToUnsignedLong(unsigned long value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified unsigned long value.
* @param value The unsigned long value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToUnsignedLong instead.
*/
static inline id equalToUnsignedLong(unsigned long value)
{
return HC_equalToUnsignedLong(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToUnsignedLongLong(unsigned long long value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified unsigned long long value.
* @param value The unsigned long long value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToUnsignedLongLong instead.
*/
static inline id equalToUnsignedLongLong(unsigned long long value)
{
return HC_equalToUnsignedLongLong(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToUnsignedShort(unsigned short value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified unsigned short value.
* @param value The unsigned short value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToUnsignedShort instead.
*/
static inline id equalToUnsignedShort(unsigned short value)
{
return HC_equalToUnsignedShort(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToInteger(NSInteger value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified NSInteger value.
* @param value The NSInteger value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToInteger instead.
*/
static inline id equalToInteger(NSInteger value)
{
return HC_equalToInteger(value);
}
#endif
FOUNDATION_EXPORT id HC_equalToUnsignedInteger(NSUInteger value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to an NSNumber created
* from the specified NSUInteger value.
* @param value The NSUInteger value from which to create an NSNumber.
* @discussion Consider using <code>equalTo(\@(value))</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToUnsignedInteger instead.
*/
static inline id equalToUnsignedInteger(NSUInteger value)
{
return HC_equalToUnsignedInteger(value);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,77 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsEqualToNumber.h"
#import "HCIsEqual.h"
FOUNDATION_EXPORT id HC_equalToChar(char value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToDouble(double value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToFloat(float value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToInt(int value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToLong(long value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToLongLong(long long value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToShort(short value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToUnsignedChar(unsigned char value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToUnsignedInt(unsigned int value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToUnsignedLong(unsigned long value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToUnsignedLongLong(unsigned long long value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToUnsignedShort(unsigned short value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToInteger(NSInteger value)
{
return HC_equalTo(@(value));
}
FOUNDATION_EXPORT id HC_equalToUnsignedInteger(NSUInteger value)
{
return HC_equalTo(@(value));
}

View File

@@ -0,0 +1,55 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches true values.
*/
@interface HCIsTrue : HCBaseMatcher
@end
/*!
* @abstract Matches false values.
*/
@interface HCIsFalse : HCBaseMatcher
@end
FOUNDATION_EXPORT id HC_isTrue(void);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is an non-zero NSNumber.
* @discussion
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_isTrue instead.
*/
static inline id isTrue(void)
{
return HC_isTrue();
}
#endif
FOUNDATION_EXPORT id HC_isFalse(void);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is NSNumber zero.
* @discussion
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_isFalse instead.
*/
static inline id isFalse(void)
{
return HC_isFalse();
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,55 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsTrueFalse.h"
@implementation HCIsTrue
- (BOOL)matches:(nullable id)item
{
if (![item isKindOfClass:[NSNumber class]])
return NO;
return [item boolValue];
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendText:@"true (non-zero)"];
}
@end
FOUNDATION_EXPORT id HC_isTrue(void)
{
return [[HCIsTrue alloc] init];
}
#pragma mark -
@implementation HCIsFalse
- (BOOL)matches:(nullable id)item
{
if (![item isKindOfClass:[NSNumber class]])
return NO;
return ![item boolValue];
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendText:@"false (zero)"];
}
@end
FOUNDATION_EXPORT id HC_isFalse(void)
{
return [[HCIsFalse alloc] init];
}

View File

@@ -0,0 +1,340 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <Foundation/Foundation.h>
@protocol HCMatcher;
NS_ASSUME_NONNULL_BEGIN
FOUNDATION_EXPORT void HC_assertThatBoolWithLocation(id testCase, BOOL actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatBool(actual, matcher) \
HC_assertThatBoolWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatBool(actual, matcher) -
* Asserts that BOOL actual value, converted to an NSNumber, satisfies matcher.
* @param actual The BOOL value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatBool instead.
*/
#define assertThatBool(actual, matcher) HC_assertThatBool(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatCharWithLocation(id testCase, char actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatChar(actual, matcher) \
HC_assertThatCharWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatChar(actual, matcher) -
* Asserts that char actual value, converted to an NSNumber, satisfies matcher.
* @param actual The char value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatChar instead.
*/
#define assertThatChar(actual, matcher) HC_assertThatChar(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatDoubleWithLocation(id testCase, double actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatDouble(actual, matcher) \
HC_assertThatDoubleWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract HC_assertThatDouble(actual, matcher) -
* Asserts that double actual value, converted to an NSNumber, satisfies matcher.
* @param actual The double value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatDouble instead.
*/
#define assertThatDouble(actual, matcher) HC_assertThatDouble(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatFloatWithLocation(id testCase, float actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatFloat(actual, matcher) \
HC_assertThatFloatWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatFloat(actual, matcher) -
* Asserts that float actual value, converted to an NSNumber, satisfies matcher.
* @param actual The float value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatFloat instead.
*/
#define assertThatFloat(actual, matcher) HC_assertThatFloat(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatIntWithLocation(id testCase, int actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatInt(actual, matcher) \
HC_assertThatIntWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatInt(actual, matcher) -
* Asserts that int actual value, converted to an NSNumber, satisfies matcher.
* @param actual The int value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatInt instead.
*/
#define assertThatInt(actual, matcher) HC_assertThatInt(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatLongWithLocation(id testCase, long actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatLong(actual, matcher) \
HC_assertThatLongWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatLong(actual, matcher) -
* Asserts that long actual value, converted to an NSNumber, satisfies matcher.
* @param actual The long value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatLong instead.
*/
#define assertThatLong(actual, matcher) HC_assertThatLong(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatLongLongWithLocation(id testCase, long long actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatLongLong(actual, matcher) \
HC_assertThatLongLongWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatLongLong(actual, matcher) -
* Asserts that <code>long long</code> actual value, converted to an NSNumber, satisfies matcher.
* @param actual The long long value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatLongLong instead.
*/
#define assertThatLongLong(actual, matcher) HC_assertThatLongLong(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatShortWithLocation(id testCase, short actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatShort(actual, matcher) \
HC_assertThatShortWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatShort(actual, matcher) -
* Asserts that short actual value, converted to an NSNumber, satisfies matcher.
* @param actual The short value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatShort instead.
*/
#define assertThatShort(actual, matcher) HC_assertThatShort(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatUnsignedCharWithLocation(id testCase, unsigned char actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatUnsignedChar(actual, matcher) \
HC_assertThatUnsignedCharWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatUnsignedChar(actual, matcher) -
* Asserts that unsigned char actual value, converted to an NSNumber, satisfies matcher.
* @param actual The unsigned char value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatUnsignedChar instead.
*/
#define assertThatUnsignedChar(actual, matcher) HC_assertThatUnsignedChar(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatUnsignedIntWithLocation(id testCase, unsigned int actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatUnsignedInt(actual, matcher) \
HC_assertThatUnsignedIntWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatUnsignedInt(actual, matcher) -
* Asserts that unsigned int actual value, converted to an NSNumber, satisfies matcher.
* @param actual The unsigned int value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatUnsignedInt instead.
*/
#define assertThatUnsignedInt(actual, matcher) HC_assertThatUnsignedInt(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatUnsignedLongWithLocation(id testCase, unsigned long actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatUnsignedLong(actual, matcher) \
HC_assertThatUnsignedLongWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatUnsignedLong(actual, matcher) -
* Asserts that unsigned long actual value, converted to an NSNumber, satisfies matcher.
* @param actual The unsigned long value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatUnsignedLong instead.
*/
#define assertThatUnsignedLong(actual, matcher) HC_assertThatUnsignedLong(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatUnsignedLongLongWithLocation(id testCase, unsigned long long actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatUnsignedLongLong(actual, matcher) \
HC_assertThatUnsignedLongLongWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatUnsignedLongLong(actual, matcher) -
* Asserts that unsigned long long actual value, converted to an NSNumber, satisfies matcher.
* @param actual The unsigned long long value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatUnsignedLongLong instead.
*/
#define assertThatUnsignedLongLong(actual, matcher) HC_assertThatUnsignedLongLong(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatUnsignedShortWithLocation(id testCase, unsigned short actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatUnsignedShort(actual, matcher) \
HC_assertThatUnsignedShortWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatUnsignedShort(actual, matcher) -
* Asserts that unsigned short actual value, converted to an NSNumber, satisfies matcher.
* @param actual The unsigned short value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatUnsignedShort instead.
*/
#define assertThatUnsignedShort(actual, matcher) HC_assertThatUnsignedShort(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatIntegerWithLocation(id testCase, NSInteger actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatInteger(actual, matcher) \
HC_assertThatIntegerWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatInteger(actual, matcher) -
* Asserts that NSInteger actual value, converted to an NSNumber, satisfies matcher.
* @param actual The NSInteger value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatInteger instead.
*/
#define assertThatInteger(actual, matcher) HC_assertThatInteger(actual, matcher)
#endif
FOUNDATION_EXPORT void HC_assertThatUnsignedIntegerWithLocation(id testCase, NSUInteger actual,
id <HCMatcher> matcher, char const *fileName, int lineNumber);
#define HC_assertThatUnsignedInteger(actual, matcher) \
HC_assertThatUnsignedIntegerWithLocation(self, actual, matcher, __FILE__, __LINE__)
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract assertThatUnsignedInteger(actual, matcher) -
* Asserts that NSUInteger actual value, converted to an NSNumber, satisfies matcher.
* @param actual The NSUInteger value to convert to an NSNumber for evaluation.
* @param matcher The matcher to satisfy as the expected condition.
* @discussion Consider using <code>assertThat(\@(actual), matcher)</code> instead.
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_assertThatUnsignedInteger instead.
*/
#define assertThatUnsignedInteger(actual, matcher) HC_assertThatUnsignedInteger(actual, matcher)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,97 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCNumberAssert.h"
#import "HCAssertThat.h"
FOUNDATION_EXPORT void HC_assertThatBoolWithLocation(id testCase, BOOL actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatCharWithLocation(id testCase, char actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatDoubleWithLocation(id testCase, double actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatFloatWithLocation(id testCase, float actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatIntWithLocation(id testCase, int actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatLongWithLocation(id testCase, long actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatLongLongWithLocation(id testCase, long long actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatShortWithLocation(id testCase, short actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatUnsignedCharWithLocation(id testCase, unsigned char actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatUnsignedIntWithLocation(id testCase, unsigned int actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatUnsignedLongWithLocation(id testCase, unsigned long actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatUnsignedLongLongWithLocation(id testCase, unsigned long long actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatUnsignedShortWithLocation(id testCase, unsigned short actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatIntegerWithLocation(id testCase, NSInteger actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}
FOUNDATION_EXPORT void HC_assertThatUnsignedIntegerWithLocation(id testCase, NSUInteger actual,
id <HCMatcher> matcher, char const * fileName, int lineNumber)
{
HC_assertThatWithLocation(testCase, @(actual), matcher, fileName, lineNumber);
}

View File

@@ -0,0 +1,114 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches values with <code>-compare:</code>.
*/
@interface HCOrderingComparison : HCBaseMatcher
- (instancetype)initComparing:(id)expectedValue
minCompare:(NSComparisonResult)min
maxCompare:(NSComparisonResult)max
comparisonDescription:(NSString *)comparisonDescription NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_greaterThan(id value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is greater than the specified
* value, as reported by the <code>-compare:</code> method of the <b>examined</b> object.
* @param value The value which, when passed to the <code>-compare:</code> method of the examined
* object, should return NSOrderedAscending.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@2, greaterThan(\@1))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_greaterThan instead.
*/
static inline id greaterThan(id value)
{
return HC_greaterThan(value);
}
#endif
FOUNDATION_EXPORT id HC_greaterThanOrEqualTo(id value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is greater than or equal to the
* specified value, as reported by the <code>-compare:</code> method of the <b>examined</b> object.
* @param value The value which, when passed to the <code>-compare:</code> method of the examined
* object, should return NSOrderedAscending or NSOrderedSame.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@1, greaterThanOrEqualTo(\@1))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_greaterThanOrEqualTo instead.
*/
static inline id greaterThanOrEqualTo(id value)
{
return HC_greaterThanOrEqualTo(value);
}
#endif
FOUNDATION_EXPORT id HC_lessThan(id value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is less than the specified
* value, as reported by the <code>-compare:</code> method of the <b>examined</b> object.
* @param value The value which, when passed to the <code>-compare:</code> method of the examined
* object, should return NSOrderedDescending.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@1, lessThan(\@2))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_lessThan instead.
*/
static inline id lessThan(id value)
{
return HC_lessThan(value);
}
#endif
FOUNDATION_EXPORT id HC_lessThanOrEqualTo(id value);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is less than or equal to the
* specified value, as reported by the <code>-compare:</code> method of the <b>examined</b> object.
* @param value The value which, when passed to the <code>-compare:</code> method of the examined
* object, should return NSOrderedDescending or NSOrderedSame.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@1, lessThanOrEqualTo(\@1))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_lessThanOrEqualTo instead.
*/
static inline id lessThanOrEqualTo(id value)
{
return HC_lessThanOrEqualTo(value);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,97 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCOrderingComparison.h"
@interface HCOrderingComparison ()
@property (nonatomic, strong, readonly) id expected;
@property (nonatomic, assign, readonly) NSComparisonResult minCompare;
@property (nonatomic, assign, readonly) NSComparisonResult maxCompare;
@property (nonatomic, copy, readonly) NSString *comparisonDescription;
@end
@implementation HCOrderingComparison
- (instancetype)initComparing:(id)expectedValue
minCompare:(NSComparisonResult)min
maxCompare:(NSComparisonResult)max
comparisonDescription:(NSString *)description
{
if (![expectedValue respondsToSelector:@selector(compare:)])
{
@throw [NSException exceptionWithName: @"UncomparableObject"
reason: @"Object must respond to compare:"
userInfo: nil];
}
self = [super init];
if (self)
{
_expected = expectedValue;
_minCompare = min;
_maxCompare = max;
_comparisonDescription = [description copy];
}
return self;
}
- (BOOL)matches:(nullable id)item
{
if (item == nil)
return NO;
NSComparisonResult compare;
@try
{
compare = [self.expected compare:item];
}
@catch (NSException *e)
{
return NO;
}
return self.minCompare <= compare && compare <= self.maxCompare;
}
- (void)describeTo:(id <HCDescription>)description
{
[[[[description appendText:@"a value "]
appendText:self.comparisonDescription]
appendText:@" "]
appendDescriptionOf:self.expected];
}
@end
id HC_greaterThan(id value)
{
return [[HCOrderingComparison alloc] initComparing:value
minCompare:NSOrderedAscending
maxCompare:NSOrderedAscending
comparisonDescription:@"greater than"];
}
id HC_greaterThanOrEqualTo(id value)
{
return [[HCOrderingComparison alloc] initComparing:value
minCompare:NSOrderedAscending
maxCompare:NSOrderedSame
comparisonDescription:@"greater than or equal to"];
}
id HC_lessThan(id value)
{
return [[HCOrderingComparison alloc] initComparing:value
minCompare:NSOrderedDescending
maxCompare:NSOrderedDescending
comparisonDescription:@"less than"];
}
id HC_lessThanOrEqualTo(id value)
{
return [[HCOrderingComparison alloc] initComparing:value
minCompare:NSOrderedSame
maxCompare:NSOrderedDescending
comparisonDescription:@"less than or equal to"];
}

View File

@@ -0,0 +1,44 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCIsAnything.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches anything, capturing all values.
* @discussion This matcher captures all values it was given to match, and always evaluates to
* <code>YES</code>. Use it to capture argument values for further assertions.
*
* Unlike other matchers, this matcher is not idempotent. It should be created outside of any
* expression so that it can be queried for the items it captured.
*/
@interface HCArgumentCaptor : HCIsAnything
/*!
* @abstract Returns the captured value.
* @discussion If <code>-matches:</code> was called more than once then this property returns the
* last captured value.
*
* If <code>-matches:</code> was never invoked and so no value was captured, this property returns
* <code>nil</code>. But if <code>nil</code> was captured, this property returns NSNull.
*/
@property (nullable, nonatomic, readonly) id value;
/*!
* @abstract Returns all captured values.
* @discussion Returns an array containing all captured values, in the order in which they were
* captured. <code>nil</code> values are converted to NSNull.
*/
@property (nonatomic, readonly) NSArray *allValues;
/*!
* @abstract Determines whether subsequent matched values are captured.
* @discussion <code>YES</code> by default.
*/
@property (nonatomic, assign) BOOL captureEnabled;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,56 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCArgumentCaptor.h"
@interface HCArgumentCaptor ()
@property (nonatomic, strong, readonly) NSMutableArray *values;
@end
@implementation HCArgumentCaptor
@dynamic allValues;
@dynamic value;
- (instancetype)init
{
self = [super initWithDescription:@"<Capturing argument>"];
if (self)
{
_values = [[NSMutableArray alloc] init];
_captureEnabled = YES;
}
return self;
}
- (BOOL)matches:(nullable id)item
{
[self capture:item];
return [super matches:item];
}
- (void)capture:(id)item
{
if (self.captureEnabled)
{
id value = item ?: [NSNull null];
if ([value conformsToProtocol:@protocol(NSCopying)])
value = [value copy];
[self.values addObject:value];
}
}
- (id)value
{
if (!self.values.count)
return nil;
return self.values.lastObject;
}
- (NSArray *)allValues
{
return [self.values copy];
}
@end

View File

@@ -0,0 +1,18 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
@interface HCClassMatcher : HCBaseMatcher
@property (nonatomic, strong, readonly) Class theClass;
- (instancetype)initWithClass:(Class)aClass NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
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 "HCClassMatcher.h"
#import "HCRequireNonNilObject.h"
@interface HCClassMatcher (SubclassResponsibility)
- (NSString *)expectation;
@end
@implementation HCClassMatcher
- (instancetype)initWithClass:(Class)aClass
{
HCRequireNonNilObject(aClass);
self = [super init];
if (self)
_theClass = aClass;
return self;
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:[self expectation]]
appendText:NSStringFromClass(self.theClass)];
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[mismatchDescription appendText:@"was "];
if (item)
{
[[mismatchDescription appendText:NSStringFromClass([item class])]
appendText:@" instance "];
}
[mismatchDescription appendDescriptionOf:item];
}
@end

View File

@@ -0,0 +1,42 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
// Contribution by Todd Farrell
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches objects that conform to specified protocol.
*/
@interface HCConformsToProtocol : HCBaseMatcher
- (instancetype)initWithProtocol:(Protocol *)protocol NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_conformsTo(Protocol *aProtocol);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object conforms to the specified
* protocol.
* @param aProtocol The protocol to compare against as the expected protocol.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(myObject, conformsTo(\@protocol(NSCoding))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_conformsTo instead.
*/
static inline id conformsTo(Protocol *aProtocol)
{
return HC_conformsTo(aProtocol);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,44 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
// Contribution by Todd Farrell
//
#import "HCConformsToProtocol.h"
#import "HCRequireNonNilObject.h"
@interface HCConformsToProtocol ()
@property (nonatomic, strong, readonly) Protocol *protocol;
@end
@implementation HCConformsToProtocol
- (instancetype)initWithProtocol:(Protocol *)protocol
{
HCRequireNonNilObject(protocol);
self = [super init];
if (self)
_protocol = protocol;
return self;
}
- (BOOL)matches:(nullable id)item
{
return [item conformsToProtocol:self.protocol];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"an object that conforms to "]
appendText:NSStringFromProtocol(self.protocol)];
}
@end
id HC_conformsTo(Protocol *aProtocol)
{
return [[HCConformsToProtocol alloc] initWithProtocol:aProtocol];
}

View File

@@ -0,0 +1,45 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCInvocationMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches objects whose description satisfies a nested matcher.
*/
@interface HCHasDescription : HCInvocationMatcher
- (instancetype)initWithDescription:(id <HCMatcher>)descriptionMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithInvocation:(NSInvocation *)anInvocation matching:(id <HCMatcher>)aMatcher NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasDescription(id descriptionMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object's <code>-description</code>
* satisfies the specified matcher.
* @param descriptionMatcher The matcher used to verify the description result, or an expected value
* for <em>equalTo</em> matching.
* @discussion If <em>descriptionMatcher</em> is not a matcher, it is implicitly wrapped in
* an <em>equalTo</em> matcher to check for equality.
*
* <b>Examples</b><br />
* <pre>assertThat(myObject, hasDescription(equalTo(\@"foo"))</pre>
* <pre>assertThat(myObject, hasDescription(\@"foo"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasDescription instead.
*/
static inline id hasDescription(id descriptionMatcher)
{
return HC_hasDescription(descriptionMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,28 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCHasDescription.h"
#import "HCWrapInMatcher.h"
#import "NSInvocation+OCHamcrest.h"
@implementation HCHasDescription
- (instancetype)initWithDescription:(id <HCMatcher>)descriptionMatcher
{
NSInvocation *anInvocation = [NSInvocation och_invocationOnObjectOfType:[NSObject class]
selector:@selector(description)];
self = [super initWithInvocation:anInvocation matching:descriptionMatcher];
if (self)
self.shortMismatchDescription = YES;
return self;
}
@end
id HC_hasDescription(id descriptionMatcher)
{
return [[HCHasDescription alloc] initWithDescription:HCWrapInMatcher(descriptionMatcher)];
}

View File

@@ -0,0 +1,47 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
// Contribution by Justin Shacklette
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches objects whose "property" (or simple method) satisfies a nested matcher.
*/
@interface HCHasProperty : HCDiagnosingMatcher
- (instancetype)initWithProperty:(NSString *)propertyName value:(id <HCMatcher>)valueMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_hasProperty(NSString *propertyName, _Nullable id valueMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object has an instance method with the
* specified name whose return value satisfies the specified matcher.
* @param propertyName The name of an instance method without arguments that returns an object.
* @param valueMatcher The matcher to satisfy for the return value, or an expected value for
* <em>equalTo</em> matching.
* @discussion Note: While this matcher factory is called "hasProperty", it applies to the return
* values of any instance methods without arguments, not just properties.
*
* <b>Examples</b><br />
* <pre>assertThat(person, hasProperty(\@"firstName", equalTo(\@"Joe")))</pre>
* <pre>assertThat(person, hasProperty(\@"firstName", \@"Joe"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_hasProperty instead.
*/
static inline id hasProperty(NSString *propertyName, _Nullable id valueMatcher)
{
return HC_hasProperty(propertyName, valueMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,71 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
// Contribution by Justin Shacklette
#import "HCHasProperty.h"
#import "HCRequireNonNilObject.h"
#import "HCWrapInMatcher.h"
#import "NSInvocation+OCHamcrest.h"
@interface HCHasProperty ()
@property (nonatomic, copy, readonly) NSString *propertyName;
@property (nonatomic, strong, readonly) id <HCMatcher> valueMatcher;
@end
@implementation HCHasProperty
- (instancetype)initWithProperty:(NSString *)propertyName value:(id <HCMatcher>)valueMatcher
{
HCRequireNonNilObject(propertyName);
self = [super init];
if (self != nil)
{
_propertyName = [propertyName copy];
_valueMatcher = valueMatcher;
}
return self;
}
- (BOOL)matches:(nullable id)item describingMismatchTo:(id <HCDescription>)mismatchDescription
{
SEL propertyGetter = NSSelectorFromString(self.propertyName);
if (![item respondsToSelector:propertyGetter])
{
[[[[mismatchDescription appendText:@"no "]
appendText:self.propertyName]
appendText:@" on "]
appendDescriptionOf:item];
return NO;
}
NSInvocation *getterInvocation = [NSInvocation och_invocationWithTarget:item selector:propertyGetter];
id propertyValue = [getterInvocation och_invoke];
BOOL match = [self.valueMatcher matches:propertyValue];
if (!match)
{
[[[[[mismatchDescription appendText:self.propertyName]
appendText:@" was "]
appendDescriptionOf:propertyValue]
appendText:@" on "]
appendDescriptionOf:item];
}
return match;
}
- (void)describeTo:(id <HCDescription>)description
{
[[[[description appendText:@"an object with "]
appendText:self.propertyName]
appendText:@" "]
appendDescriptionOf:self.valueMatcher];
}
@end
id HC_hasProperty(NSString *propertyName, _Nullable id valueMatcher)
{
return [[HCHasProperty alloc] initWithProperty:propertyName value:HCWrapInMatcher(valueMatcher)];
}

View File

@@ -0,0 +1,41 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Is the value equal to another value, as tested by the <code>-isEqual:</code> method?
*/
@interface HCIsEqual : HCBaseMatcher
- (instancetype)initEqualTo:(nullable id)expectedValue NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_equalTo(_Nullable id operand);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is equal to the specified
* object, as determined by calling the <code>-isEqual:</code> method on the <b>examined</b> object.
* @param operand The object to compare against as the expected value.
* @discussion If the specified operand is <code>nil</code>, then the created matcher will match if
* the examined object itself is <code>nil</code>, or if the examined object's <code>-isEqual:</code>
* method returns <code>YES</code> when passed a <code>nil</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_equalTo instead.
*/
static inline id equalTo(_Nullable id operand)
{
return HC_equalTo(operand);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,46 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsEqual.h"
@interface HCIsEqual ()
@property (nullable, nonatomic, strong, readonly) id expectedValue;
@end
@implementation HCIsEqual
- (instancetype)initEqualTo:(nullable id)expectedValue
{
self = [super init];
if (self)
_expectedValue = expectedValue;
return self;
}
- (BOOL)matches:(nullable id)item
{
if (item == nil)
return self.expectedValue == nil;
return [item isEqual:self.expectedValue];
}
- (void)describeTo:(id <HCDescription>)description
{
if ([self.expectedValue conformsToProtocol:@protocol(HCMatcher)])
{
[[[description appendText:@"<"]
appendDescriptionOf:self.expectedValue]
appendText:@">"];
}
else
[description appendDescriptionOf:self.expectedValue];
}
@end
id HC_equalTo(_Nullable id operand)
{
return [[HCIsEqual alloc] initEqualTo:operand];
}

View File

@@ -0,0 +1,37 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCClassMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches objects that are of a given class or any subclass.
*/
@interface HCIsInstanceOf : HCClassMatcher
@end
FOUNDATION_EXPORT id HC_instanceOf(Class expectedClass);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is an instance of, or inherits
* from, the specified class.
* @param expectedClass The class to compare against as the expected class.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(canoe, instanceOf([Canoe class]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_instanceOf instead.
*/
static inline id instanceOf(Class expectedClass)
{
return HC_instanceOf(expectedClass);
}
#endif
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 "HCIsInstanceOf.h"
@implementation HCIsInstanceOf
- (BOOL)matches:(nullable id)item
{
return [item isKindOfClass:self.theClass];
}
- (NSString *)expectation
{
return @"an instance of ";
}
@end
id HC_instanceOf(Class expectedClass)
{
return [[HCIsInstanceOf alloc] initWithClass:expectedClass];
}

View File

@@ -0,0 +1,55 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Is the value nil?
*/
@interface HCIsNil : HCBaseMatcher
@end
FOUNDATION_EXPORT id HC_nilValue(void);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is <code>nil</code>.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(myObject, nilValue())</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_nilValue instead.
*/
static inline id nilValue(void)
{
return HC_nilValue();
}
#endif
FOUNDATION_EXPORT id HC_notNilValue(void);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is not <code>nil</code>.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(myObject, notNilValue())</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_notNilValue instead.
*/
static inline id notNilValue(void)
{
return HC_notNilValue();
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,32 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsNil.h"
#import "HCIsNot.h"
@implementation HCIsNil
- (BOOL)matches:(nullable id)item
{
return item == nil;
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendText:@"nil"];
}
@end
id HC_nilValue()
{
return [[HCIsNil alloc] init];
}
id HC_notNilValue()
{
return HC_isNot([[HCIsNil alloc] init]);
}

View File

@@ -0,0 +1,41 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Is the value the same object as another value?
*/
@interface HCIsSame : HCBaseMatcher
- (instancetype)initSameAs:(nullable id)object NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_sameInstance(_Nullable id expectedInstance);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches only when the examined object is the same instance as
* the specified target object.
* @param expectedInstance The expected instance.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(delegate, sameInstance(expectedDelegate))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_sameInstance instead.
*/
static inline id sameInstance(_Nullable id expectedInstance)
{
return HC_sameInstance(expectedInstance);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,46 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsSame.h"
@interface HCIsSame ()
@property (nonatomic, strong, readonly) id object;
@end
@implementation HCIsSame
- (instancetype)initSameAs:(nullable id)object
{
self = [super init];
if (self)
_object = object;
return self;
}
- (BOOL)matches:(nullable id)item
{
return item == self.object;
}
- (void)describeMismatchOf:(nullable id)item to:(nullable id <HCDescription>)mismatchDescription
{
[mismatchDescription appendText:@"was "];
if (item)
[mismatchDescription appendText:[NSString stringWithFormat:@"%p ", (__bridge void *)item]];
[mismatchDescription appendDescriptionOf:item];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:[NSString stringWithFormat:@"same instance as %p ", (__bridge void *)self.object]]
appendDescriptionOf:self.object];
}
@end
id HC_sameInstance(_Nullable id expectedInstance)
{
return [[HCIsSame alloc] initSameAs:expectedInstance];
}

View File

@@ -0,0 +1,37 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCClassMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Matches objects that are of a given class.
*/
@interface HCIsTypeOf : HCClassMatcher
@end
FOUNDATION_EXPORT id HC_isA(Class expectedClass);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is an instance of the specified
* class, but not of any subclass.
* @param expectedClass The class to compare against as the expected class.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(canoe, isA([Canoe class]))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_isA instead.
*/
static inline id isA(Class expectedClass)
{
return HC_isA(expectedClass);
}
#endif
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 "HCIsTypeOf.h"
@implementation HCIsTypeOf
- (BOOL)matches:(nullable id)item
{
return [item isMemberOfClass:self.theClass];
}
- (NSString *)expectation
{
return @"an exact instance of ";
}
@end
id HC_isA(Class expectedClass)
{
return [[HCIsTypeOf alloc] initWithClass:expectedClass];
}

View File

@@ -0,0 +1,41 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCDiagnosingMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Does executing a block throw an exception which satisfies a nested matcher?
*/
@interface HCThrowsException : HCDiagnosingMatcher
- (id)initWithExceptionMatcher:(id)exceptionMatcher NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_throwsException(id exceptionMatcher);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is a block which, when
* executed, throws an exception satisfying the specified matcher.
* @param exceptionMatcher The matcher to satisfy when passed the exception.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(^{ [obj somethingBad]; }, throwsException(hasProperty(@"reason", @"EXPECTED REASON")))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_throwsException instead.
*/
static inline id throwsException(id exceptionMatcher)
{
return HC_throwsException(exceptionMatcher);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,84 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCThrowsException.h"
static void HCRequireMatcher(id obj)
{
if (![obj conformsToProtocol:@protocol(HCMatcher)])
{
@throw [NSException exceptionWithName:@"NonMatcher"
reason:@"Must be matcher"
userInfo:nil];
}
}
@interface HCThrowsException()
@property (nonatomic, strong, readonly) id <HCMatcher> exceptionMatcher;
@end
@implementation HCThrowsException
- (id)initWithExceptionMatcher:(id)exceptionMatcher
{
HCRequireMatcher(exceptionMatcher);
self = [super init];
if (self)
_exceptionMatcher = exceptionMatcher;
return self;
}
- (BOOL)matches:(nullable id)item describingMismatchTo:(id <HCDescription>)mismatchDescription
{
if (![self isBlock:item])
{
[[mismatchDescription appendText:@"was non-block "] appendDescriptionOf:item];
return NO;
}
typedef void (^HCThrowsExceptionBlock)(void);
HCThrowsExceptionBlock block = item;
@try
{
block();
}
@catch (id exception)
{
BOOL match = [self.exceptionMatcher matches:exception];
if (!match)
{
[mismatchDescription appendText:@"exception thrown but "];
[self.exceptionMatcher describeMismatchOf:exception to:mismatchDescription];
}
return match;
}
[mismatchDescription appendText:@"no exception thrown"];
return NO;
}
- (BOOL)isBlock:(id)item
{
id block = ^{};
Class blockClass = [block class];
while ([blockClass superclass] != [NSObject class])
blockClass = [blockClass superclass];
return [item isKindOfClass:blockClass];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendText:@"a block with no arguments, throwing an exception which is "]
appendDescriptionOf:self.exceptionMatcher];
}
@end
id HC_throwsException(id exceptionMatcher)
{
return [[HCThrowsException alloc] initWithExceptionMatcher:exceptionMatcher];
}

View File

@@ -0,0 +1,46 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Tests if a string is equal to another string, when whitespace differences are (mostly) ignored.
*/
@interface HCIsEqualCompressingWhiteSpace : HCBaseMatcher
- (instancetype)initWithString:(NSString *)string NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_equalToCompressingWhiteSpace(NSString *expectedString);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSStrings that matches when the examined string is equal to the
* specified expected string, when whitespace differences are (mostly) ignored.
* @param expectedString The expected value of matched strings. (Must not be <code>nil</code>.)
* @discussion To be exact, the following whitespace rules are applied:
* <ul>
* <li>all leading and trailing whitespace of both the <em>expectedString</em> and the examined string are ignored</li>
* <li>any remaining whitespace, appearing within either string, is collapsed to a single space before comparison</li>
* </ul>
*
* <b>Example</b><br />
* <pre>assertThat(\@" my\tfoo bar ", equalToCompressingWhiteSpace(\@" my foo bar"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToCompressingWhiteSpace instead.
*/
static inline id equalToCompressingWhiteSpace(NSString *expectedString)
{
return HC_equalToCompressingWhiteSpace(expectedString);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,62 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCIsEqualCompressingWhiteSpace.h"
#import "HCRequireNonNilObject.h"
static NSString *stripSpaces(NSString *string)
{
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\s+"
options:0
error:NULL];
NSString *modifiedString = [regex stringByReplacingMatchesInString:string
options:0
range:NSMakeRange(0, string.length)
withTemplate:@" "];
return [modifiedString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
@interface HCIsEqualCompressingWhiteSpace ()
@property (nonatomic, copy, readonly) NSString *originalString;
@property (nonatomic, copy, readonly) NSString *strippedString;
@end
@implementation HCIsEqualCompressingWhiteSpace
- (instancetype)initWithString:(NSString *)string
{
HCRequireNonNilObject(string);
self = [super init];
if (self)
{
_originalString = [string copy];
_strippedString = [stripSpaces(string) copy];
}
return self;
}
- (BOOL)matches:(nullable id)item
{
if (![item isKindOfClass:[NSString class]])
return NO;
return [self.strippedString isEqualToString:stripSpaces(item)];
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendDescriptionOf:self.originalString]
appendText:@" ignoring whitespace"];
}
@end
id HC_equalToCompressingWhiteSpace(NSString *expectedString)
{
return [[HCIsEqualCompressingWhiteSpace alloc] initWithString:expectedString];
}

View File

@@ -0,0 +1,41 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Tests if a string is equal to another string, regardless of the case.
*/
@interface HCIsEqualIgnoringCase : HCBaseMatcher
- (instancetype)initWithString:(NSString *)string NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_equalToIgnoringCase(NSString *expectedString);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher for NSStrings that matches when the examined string is equal to the
* specified expected string, ignoring case differences.
* @param expectedString The expected value of matched strings. (Must not be <code>nil</code>.)
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@"Foo", equalToIgnoringCase(\@"FOO"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_equalToIgnoringCase instead.
*/
static inline id equalToIgnoringCase(NSString *expectedString)
{
return HC_equalToIgnoringCase(expectedString);
}
#endif
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 "HCIsEqualIgnoringCase.h"
#import "HCRequireNonNilObject.h"
@interface HCIsEqualIgnoringCase ()
@property (nonatomic, copy, readonly) NSString *string;
@end
@implementation HCIsEqualIgnoringCase
- (instancetype)initWithString:(NSString *)string
{
HCRequireNonNilObject(string);
self = [super init];
if (self)
_string = [string copy];
return self;
}
- (BOOL)matches:(nullable id)item
{
if (![item isKindOfClass:[NSString class]])
return NO;
return [self.string caseInsensitiveCompare:item] == NSOrderedSame;
}
- (void)describeTo:(id <HCDescription>)description
{
[[description appendDescriptionOf:self.string]
appendText:@" ignoring case"];
}
@end
id HC_equalToIgnoringCase(NSString *expectedString)
{
return [[HCIsEqualIgnoringCase alloc] initWithString:expectedString];
}

View File

@@ -0,0 +1,39 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCSubstringMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Tests if string that contains a substring.
*/
@interface HCStringContains : HCSubstringMatcher
@end
FOUNDATION_EXPORT id HC_containsSubstring(NSString *substring);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is a string containing the
* specified substring anywhere.
* @param substring The string to search for. (Must not be <code>nil</code>.)
* @discussion The matcher invokes <code>-rangeOfString:</code> on the examined object, passing the
* specified <em>substring</em> and matching if it is found.
*
* <b>Example</b><br />
* <pre>assertThat(\@"myStringOfNote", containsSubstring(\@"ring"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_containsSubstring instead.
*/
static inline id containsSubstring(NSString *substring)
{
return HC_containsSubstring(substring);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,28 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCStringContains.h"
@implementation HCStringContains
- (BOOL)matches:(nullable id)item
{
if (![item respondsToSelector:@selector(rangeOfString:)])
return NO;
return [item rangeOfString:self.substring].location != NSNotFound;
}
- (NSString *)relationship
{
return @"containing";
}
@end
id <HCMatcher> HC_containsSubstring(NSString *substring)
{
return [[HCStringContains alloc] initWithSubstring:substring];
}

View File

@@ -0,0 +1,62 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Tests if string that contains a list of substrings in relative order.
*/
@interface HCStringContainsInOrder : HCBaseMatcher
- (instancetype)initWithSubstrings:(NSArray<NSString *> *)substrings NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
FOUNDATION_EXPORT id HC_stringContainsInOrderIn(NSArray<NSString *> *substrings);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates matcher for NSStrings that matches when the examined string contains all of the
* specified substrings, considering the order of their appearance.
* @param substrings An array of strings.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@"myfoobarbaz", stringContainsInOrderIn(\@[\@"bar", \@"foo"]))</pre>
* fails as "foo" occurs before "bar" in the string "myfoobarbaz"
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_stringContainsInOrderIn instead.
*/
static inline id stringContainsInOrderIn(NSArray<NSString *> *substrings)
{
return HC_stringContainsInOrderIn(substrings);
}
#endif
FOUNDATION_EXPORT id HC_stringContainsInOrder(NSString *substrings, ...) NS_REQUIRES_NIL_TERMINATION;
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates matcher for NSStrings that matches when the examined string contains all of the
* specified substrings, considering the order of their appearance.
* @param substrings... A comma-separated list of strings, ending with <code>nil</code>.
* @discussion
* <b>Example</b><br />
* <pre>assertThat(\@"myfoobarbaz", stringContainsInOrder(\@"bar", \@"foo", nil))</pre>
* fails as "foo" occurs before "bar" in the string "myfoobarbaz"
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_stringContainsInOrder instead.
*/
#define stringContainsInOrder(substrings...) HC_stringContainsInOrder(substrings)
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,78 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCStringContainsInOrder.h"
#import "HCCollect.h"
static void requireElementsToBeStrings(NSArray *array)
{
for (id element in array)
{
if (![element isKindOfClass:[NSString class]])
{
@throw [NSException exceptionWithName:@"NotAString"
reason:@"Arguments must be strings"
userInfo:nil];
}
}
}
@interface HCStringContainsInOrder ()
@property (nonatomic, copy, readonly) NSArray<NSString *> *substrings;
@end
@implementation HCStringContainsInOrder
- (instancetype)initWithSubstrings:(NSArray<NSString *> *)substrings
{
self = [super init];
if (self)
{
requireElementsToBeStrings(substrings);
_substrings = [substrings copy];
}
return self;
}
- (BOOL)matches:(nullable id)item
{
if (![item isKindOfClass:[NSString class]])
return NO;
NSRange searchRange = NSMakeRange(0, [item length]);
for (NSString *substring in self.substrings)
{
NSRange substringRange = [item rangeOfString:substring options:0 range:searchRange];
if (substringRange.location == NSNotFound)
return NO;
searchRange.location = substringRange.location + substringRange.length;
searchRange.length = [item length] - searchRange.location;
}
return YES;
}
- (void)describeTo:(id <HCDescription>)description
{
[description appendList:self.substrings start:@"a string containing " separator:@", " end:@" in order"];
}
@end
id HC_stringContainsInOrderIn(NSArray<NSString *> *substrings)
{
return [[HCStringContainsInOrder alloc] initWithSubstrings:substrings];
}
id HC_stringContainsInOrder(NSString *substrings, ...)
{
va_list args;
va_start(args, substrings);
NSArray *array = HCCollectItems(substrings, args);
va_end(args);
return HC_stringContainsInOrderIn(array);
}

View File

@@ -0,0 +1,40 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCSubstringMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Tests if string ends with a substring.
*/
@interface HCStringEndsWith : HCSubstringMatcher
@end
FOUNDATION_EXPORT id HC_endsWith(NSString *suffix);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is a string that ends with the
* specified string.
* @param suffix The substring that the returned matcher will expect at the end of any examined
* string. (Must not be <code>nil</code>.)
* @discussion The matcher invokes <code>-hasSuffix:</code> on the examined object, passing the
* specified <em>suffix</em>.
*
* <b>Example</b><br />
* <pre>assertThat(\@"myStringOfNote", endsWith(\@"Note"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_endsWith instead.
*/
static inline id endsWith(NSString *suffix)
{
return HC_endsWith(suffix);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,28 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCStringEndsWith.h"
@implementation HCStringEndsWith
- (BOOL)matches:(nullable id)item
{
if (![item respondsToSelector:@selector(hasSuffix:)])
return NO;
return [item hasSuffix:self.substring];
}
- (NSString *)relationship
{
return @"ending with";
}
@end
id HC_endsWith(NSString *suffix)
{
return [[HCStringEndsWith alloc] initWithSubstring:suffix];
}

View File

@@ -0,0 +1,40 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCSubstringMatcher.h>
NS_ASSUME_NONNULL_BEGIN
/*!
* @abstract Tests string starts with a substring.
*/
@interface HCStringStartsWith : HCSubstringMatcher
@end
FOUNDATION_EXPORT id HC_startsWith(NSString *prefix);
#ifndef HC_DISABLE_SHORT_SYNTAX
/*!
* @abstract Creates a matcher that matches when the examined object is a string that starts with
* the specified string.
* @param prefix The substring that the returned matcher will expect at the start of any examined
* string. (Must not be <code>nil</code>.)
* @discussion The matcher invokes <code>-hasPrefix:</code> on the examined object, passing the
* specified <em>prefix</em>.
*
* <b>Example</b><br />
* <pre>assertThat(\@"myStringOfNote", startsWith(\@"my"))</pre>
*
* <b>Name Clash</b><br />
* In the event of a name clash, <code>#define HC_DISABLE_SHORT_SYNTAX</code> and use the synonym
* HC_startsWith instead.
*/
static inline id startsWith(NSString *prefix)
{
return HC_startsWith(prefix);
}
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,28 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCStringStartsWith.h"
@implementation HCStringStartsWith
- (BOOL)matches:(nullable id)item
{
if (![item respondsToSelector:@selector(hasPrefix:)])
return NO;
return [item hasPrefix:self.substring];
}
- (NSString *)relationship
{
return @"starting with";
}
@end
id HC_startsWith(NSString *prefix)
{
return [[HCStringStartsWith alloc] initWithSubstring:prefix];
}

View File

@@ -0,0 +1,18 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import <OCHamcrest/HCBaseMatcher.h>
NS_ASSUME_NONNULL_BEGIN
@interface HCSubstringMatcher : HCBaseMatcher
@property (nonatomic, copy, readonly) NSString *substring;
- (instancetype)initWithSubstring:(NSString *)substring NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,34 @@
// OCHamcrest by Jon Reid, https://qualitycoding.org/
// Copyright 2019 hamcrest.org. See LICENSE.txt
#import "HCSubstringMatcher.h"
#import "HCRequireNonNilObject.h"
@interface HCSubstringMatcher (SubclassResponsibility)
- (NSString *)relationship;
@end
@implementation HCSubstringMatcher
- (instancetype)initWithSubstring:(NSString *)substring
{
HCRequireNonNilObject(substring);
self = [super init];
if (self)
_substring = [substring copy];
return self;
}
- (void)describeTo:(id <HCDescription>)description
{
[[[[description appendText:@"a string "]
appendText:[self relationship]]
appendText:@" "]
appendDescriptionOf:self.substring];
}
@end