init iOS module

This commit is contained in:
pengfei.zhou
2019-07-25 19:26:33 +08:00
parent 40416ff3fd
commit f86e7623a2
211 changed files with 20246 additions and 0 deletions

View File

@@ -0,0 +1,389 @@
#import <Foundation/Foundation.h>
@class NMBExpectation;
@class NMBObjCBeCloseToMatcher;
@class NMBObjCRaiseExceptionMatcher;
@protocol NMBMatcher;
NS_ASSUME_NONNULL_BEGIN
#define NIMBLE_OVERLOADABLE __attribute__((overloadable))
#define NIMBLE_EXPORT FOUNDATION_EXPORT
#define NIMBLE_EXPORT_INLINE FOUNDATION_STATIC_INLINE
#define NIMBLE_VALUE_OF(VAL) ({ \
__typeof__((VAL)) val = (VAL); \
[NSValue valueWithBytes:&val objCType:@encode(__typeof__((VAL)))]; \
})
#ifdef NIMBLE_DISABLE_SHORT_SYNTAX
#define NIMBLE_SHORT(PROTO, ORIGINAL)
#define NIMBLE_SHORT_OVERLOADED(PROTO, ORIGINAL)
#else
#define NIMBLE_SHORT(PROTO, ORIGINAL) FOUNDATION_STATIC_INLINE PROTO { return (ORIGINAL); }
#define NIMBLE_SHORT_OVERLOADED(PROTO, ORIGINAL) FOUNDATION_STATIC_INLINE NIMBLE_OVERLOADABLE PROTO { return (ORIGINAL); }
#endif
#define DEFINE_NMB_EXPECT_OVERLOAD(TYPE, EXPR) \
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE \
NMBExpectation *NMB_expect(TYPE(^actualBlock)(void), NSString *file, NSUInteger line) { \
return NMB_expect(^id { return EXPR; }, file, line); \
}
NIMBLE_EXPORT NIMBLE_OVERLOADABLE
NMBExpectation *NMB_expect(id(^actualBlock)(void), NSString *file, NSUInteger line);
// overloaded dispatch for nils - expect(nil)
DEFINE_NMB_EXPECT_OVERLOAD(void*, nil)
DEFINE_NMB_EXPECT_OVERLOAD(NSRange, NIMBLE_VALUE_OF(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(long, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(unsigned long, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(int, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(unsigned int, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(float, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(double, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(long long, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(unsigned long long, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(char, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(unsigned char, @(actualBlock()))
// bool doesn't get the compiler to dispatch to BOOL types, but using BOOL here seems to allow
// the compiler to dispatch to bool.
DEFINE_NMB_EXPECT_OVERLOAD(BOOL, @(actualBlock()))
DEFINE_NMB_EXPECT_OVERLOAD(char *, @(actualBlock()))
#undef DEFINE_NMB_EXPECT_OVERLOAD
NIMBLE_EXPORT NMBExpectation *NMB_expectAction(void(^actualBlock)(void), NSString *file, NSUInteger line);
#define DEFINE_OVERLOAD(TYPE, EXPR) \
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE \
id<NMBMatcher> NMB_equal(TYPE expectedValue) { \
return NMB_equal((EXPR)); \
} \
NIMBLE_SHORT_OVERLOADED(id<NMBMatcher> equal(TYPE expectedValue), NMB_equal(expectedValue));
NIMBLE_EXPORT NIMBLE_OVERLOADABLE
id<NMBMatcher> NMB_equal(__nullable id expectedValue);
NIMBLE_SHORT_OVERLOADED(id<NMBMatcher> equal(__nullable id expectedValue),
NMB_equal(expectedValue));
// overloaded dispatch for nils - expect(nil)
DEFINE_OVERLOAD(void*__nullable, (id)nil)
DEFINE_OVERLOAD(NSRange, NIMBLE_VALUE_OF(expectedValue))
DEFINE_OVERLOAD(long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long, @(expectedValue))
DEFINE_OVERLOAD(int, @(expectedValue))
DEFINE_OVERLOAD(unsigned int, @(expectedValue))
DEFINE_OVERLOAD(float, @(expectedValue))
DEFINE_OVERLOAD(double, @(expectedValue))
DEFINE_OVERLOAD(long long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long long, @(expectedValue))
DEFINE_OVERLOAD(char, @(expectedValue))
DEFINE_OVERLOAD(unsigned char, @(expectedValue))
// bool doesn't get the compiler to dispatch to BOOL types, but using BOOL here seems to allow
// the compiler to dispatch to bool.
DEFINE_OVERLOAD(BOOL, @(expectedValue))
DEFINE_OVERLOAD(char *, @(expectedValue))
#undef DEFINE_OVERLOAD
#define DEFINE_OVERLOAD(TYPE, EXPR) \
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE \
id<NMBMatcher> NMB_haveCount(TYPE expectedValue) { \
return NMB_haveCount((EXPR)); \
} \
NIMBLE_SHORT_OVERLOADED(id<NMBMatcher> haveCount(TYPE expectedValue), \
NMB_haveCount(expectedValue));
NIMBLE_EXPORT NIMBLE_OVERLOADABLE
id<NMBMatcher> NMB_haveCount(id expectedValue);
NIMBLE_SHORT_OVERLOADED(id<NMBMatcher> haveCount(id expectedValue),
NMB_haveCount(expectedValue));
DEFINE_OVERLOAD(long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long, @(expectedValue))
DEFINE_OVERLOAD(int, @(expectedValue))
DEFINE_OVERLOAD(unsigned int, @(expectedValue))
DEFINE_OVERLOAD(long long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long long, @(expectedValue))
DEFINE_OVERLOAD(char, @(expectedValue))
DEFINE_OVERLOAD(unsigned char, @(expectedValue))
#undef DEFINE_OVERLOAD
#define DEFINE_OVERLOAD(TYPE, EXPR) \
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE \
NMBObjCBeCloseToMatcher *NMB_beCloseTo(TYPE expectedValue) { \
return NMB_beCloseTo((NSNumber *)(EXPR)); \
} \
NIMBLE_SHORT_OVERLOADED(NMBObjCBeCloseToMatcher *beCloseTo(TYPE expectedValue), \
NMB_beCloseTo(expectedValue));
NIMBLE_EXPORT NIMBLE_OVERLOADABLE NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue);
NIMBLE_SHORT_OVERLOADED(NMBObjCBeCloseToMatcher *beCloseTo(NSNumber *expectedValue),
NMB_beCloseTo(expectedValue));
// it would be better to only overload float & double, but zero becomes ambigious
DEFINE_OVERLOAD(long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long, @(expectedValue))
DEFINE_OVERLOAD(int, @(expectedValue))
DEFINE_OVERLOAD(unsigned int, @(expectedValue))
DEFINE_OVERLOAD(float, @(expectedValue))
DEFINE_OVERLOAD(double, @(expectedValue))
DEFINE_OVERLOAD(long long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long long, @(expectedValue))
DEFINE_OVERLOAD(char, @(expectedValue))
DEFINE_OVERLOAD(unsigned char, @(expectedValue))
#undef DEFINE_OVERLOAD
NIMBLE_EXPORT id<NMBMatcher> NMB_beAnInstanceOf(Class expectedClass);
NIMBLE_EXPORT_INLINE id<NMBMatcher> beAnInstanceOf(Class expectedClass) {
return NMB_beAnInstanceOf(expectedClass);
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beAKindOf(Class expectedClass);
NIMBLE_EXPORT_INLINE id<NMBMatcher> beAKindOf(Class expectedClass) {
return NMB_beAKindOf(expectedClass);
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beginWith(id itemElementOrSubstring);
NIMBLE_EXPORT_INLINE id<NMBMatcher> beginWith(id itemElementOrSubstring) {
return NMB_beginWith(itemElementOrSubstring);
}
#define DEFINE_OVERLOAD(TYPE, EXPR) \
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE \
id<NMBMatcher> NMB_beGreaterThan(TYPE expectedValue) { \
return NMB_beGreaterThan((EXPR)); \
} \
NIMBLE_SHORT_OVERLOADED(id<NMBMatcher> beGreaterThan(TYPE expectedValue), NMB_beGreaterThan(expectedValue));
NIMBLE_EXPORT NIMBLE_OVERLOADABLE
id<NMBMatcher> NMB_beGreaterThan(NSNumber *expectedValue);
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE
id<NMBMatcher> beGreaterThan(NSNumber *expectedValue) {
return NMB_beGreaterThan(expectedValue);
}
DEFINE_OVERLOAD(long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long, @(expectedValue))
DEFINE_OVERLOAD(int, @(expectedValue))
DEFINE_OVERLOAD(unsigned int, @(expectedValue))
DEFINE_OVERLOAD(float, @(expectedValue))
DEFINE_OVERLOAD(double, @(expectedValue))
DEFINE_OVERLOAD(long long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long long, @(expectedValue))
DEFINE_OVERLOAD(char, @(expectedValue))
DEFINE_OVERLOAD(unsigned char, @(expectedValue))
#undef DEFINE_OVERLOAD
#define DEFINE_OVERLOAD(TYPE, EXPR) \
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE \
id<NMBMatcher> NMB_beGreaterThanOrEqualTo(TYPE expectedValue) { \
return NMB_beGreaterThanOrEqualTo((EXPR)); \
} \
NIMBLE_SHORT_OVERLOADED(id<NMBMatcher> beGreaterThanOrEqualTo(TYPE expectedValue), \
NMB_beGreaterThanOrEqualTo(expectedValue));
NIMBLE_EXPORT NIMBLE_OVERLOADABLE
id<NMBMatcher> NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue);
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE
id<NMBMatcher> beGreaterThanOrEqualTo(NSNumber *expectedValue) {
return NMB_beGreaterThanOrEqualTo(expectedValue);
}
DEFINE_OVERLOAD(long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long, @(expectedValue))
DEFINE_OVERLOAD(int, @(expectedValue))
DEFINE_OVERLOAD(unsigned int, @(expectedValue))
DEFINE_OVERLOAD(float, @(expectedValue))
DEFINE_OVERLOAD(double, @(expectedValue))
DEFINE_OVERLOAD(long long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long long, @(expectedValue))
DEFINE_OVERLOAD(char, @(expectedValue))
DEFINE_OVERLOAD(unsigned char, @(expectedValue))
#undef DEFINE_OVERLOAD
NIMBLE_EXPORT id<NMBMatcher> NMB_beIdenticalTo(id expectedInstance);
NIMBLE_SHORT(id<NMBMatcher> beIdenticalTo(id expectedInstance),
NMB_beIdenticalTo(expectedInstance));
NIMBLE_EXPORT id<NMBMatcher> NMB_be(id expectedInstance);
NIMBLE_SHORT(id<NMBMatcher> be(id expectedInstance),
NMB_be(expectedInstance));
#define DEFINE_OVERLOAD(TYPE, EXPR) \
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE \
id<NMBMatcher> NMB_beLessThan(TYPE expectedValue) { \
return NMB_beLessThan((EXPR)); \
} \
NIMBLE_SHORT_OVERLOADED(id<NMBMatcher> beLessThan(TYPE expectedValue), \
NMB_beLessThan(expectedValue));
NIMBLE_EXPORT NIMBLE_OVERLOADABLE
id<NMBMatcher> NMB_beLessThan(NSNumber *expectedValue);
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE
id<NMBMatcher> beLessThan(NSNumber *expectedValue) {
return NMB_beLessThan(expectedValue);
}
DEFINE_OVERLOAD(long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long, @(expectedValue))
DEFINE_OVERLOAD(int, @(expectedValue))
DEFINE_OVERLOAD(unsigned int, @(expectedValue))
DEFINE_OVERLOAD(float, @(expectedValue))
DEFINE_OVERLOAD(double, @(expectedValue))
DEFINE_OVERLOAD(long long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long long, @(expectedValue))
DEFINE_OVERLOAD(char, @(expectedValue))
DEFINE_OVERLOAD(unsigned char, @(expectedValue))
#undef DEFINE_OVERLOAD
#define DEFINE_OVERLOAD(TYPE, EXPR) \
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE \
id<NMBMatcher> NMB_beLessThanOrEqualTo(TYPE expectedValue) { \
return NMB_beLessThanOrEqualTo((EXPR)); \
} \
NIMBLE_SHORT_OVERLOADED(id<NMBMatcher> beLessThanOrEqualTo(TYPE expectedValue), \
NMB_beLessThanOrEqualTo(expectedValue));
NIMBLE_EXPORT NIMBLE_OVERLOADABLE
id<NMBMatcher> NMB_beLessThanOrEqualTo(NSNumber *expectedValue);
NIMBLE_EXPORT_INLINE NIMBLE_OVERLOADABLE
id<NMBMatcher> beLessThanOrEqualTo(NSNumber *expectedValue) {
return NMB_beLessThanOrEqualTo(expectedValue);
}
DEFINE_OVERLOAD(long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long, @(expectedValue))
DEFINE_OVERLOAD(int, @(expectedValue))
DEFINE_OVERLOAD(unsigned int, @(expectedValue))
DEFINE_OVERLOAD(float, @(expectedValue))
DEFINE_OVERLOAD(double, @(expectedValue))
DEFINE_OVERLOAD(long long, @(expectedValue))
DEFINE_OVERLOAD(unsigned long long, @(expectedValue))
DEFINE_OVERLOAD(char, @(expectedValue))
DEFINE_OVERLOAD(unsigned char, @(expectedValue))
#undef DEFINE_OVERLOAD
NIMBLE_EXPORT id<NMBMatcher> NMB_beTruthy(void);
NIMBLE_SHORT(id<NMBMatcher> beTruthy(void),
NMB_beTruthy());
NIMBLE_EXPORT id<NMBMatcher> NMB_beFalsy(void);
NIMBLE_SHORT(id<NMBMatcher> beFalsy(void),
NMB_beFalsy());
NIMBLE_EXPORT id<NMBMatcher> NMB_beTrue(void);
NIMBLE_SHORT(id<NMBMatcher> beTrue(void),
NMB_beTrue());
NIMBLE_EXPORT id<NMBMatcher> NMB_beFalse(void);
NIMBLE_SHORT(id<NMBMatcher> beFalse(void),
NMB_beFalse());
NIMBLE_EXPORT id<NMBMatcher> NMB_beNil(void);
NIMBLE_SHORT(id<NMBMatcher> beNil(void),
NMB_beNil());
NIMBLE_EXPORT id<NMBMatcher> NMB_beEmpty(void);
NIMBLE_SHORT(id<NMBMatcher> beEmpty(void),
NMB_beEmpty());
NIMBLE_EXPORT id<NMBMatcher> NMB_containWithNilTermination(id itemOrSubstring, ...) NS_REQUIRES_NIL_TERMINATION;
#define NMB_contain(...) NMB_containWithNilTermination(__VA_ARGS__, nil)
#ifndef NIMBLE_DISABLE_SHORT_SYNTAX
#define contain(...) NMB_contain(__VA_ARGS__)
#endif
NIMBLE_EXPORT id<NMBMatcher> NMB_containElementSatisfying(BOOL(^predicate)(id));
NIMBLE_SHORT(id<NMBMatcher> containElementSatisfying(BOOL(^predicate)(id)),
NMB_containElementSatisfying(predicate));
NIMBLE_EXPORT id<NMBMatcher> NMB_endWith(id itemElementOrSubstring);
NIMBLE_SHORT(id<NMBMatcher> endWith(id itemElementOrSubstring),
NMB_endWith(itemElementOrSubstring));
NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException(void);
NIMBLE_SHORT(NMBObjCRaiseExceptionMatcher *raiseException(void),
NMB_raiseException());
NIMBLE_EXPORT id<NMBMatcher> NMB_match(id expectedValue);
NIMBLE_SHORT(id<NMBMatcher> match(id expectedValue),
NMB_match(expectedValue));
NIMBLE_EXPORT id<NMBMatcher> NMB_allPass(id matcher);
NIMBLE_SHORT(id<NMBMatcher> allPass(id matcher),
NMB_allPass(matcher));
NIMBLE_EXPORT id<NMBMatcher> NMB_satisfyAnyOfWithMatchers(id matchers);
#define NMB_satisfyAnyOf(...) NMB_satisfyAnyOfWithMatchers(@[__VA_ARGS__])
#ifndef NIMBLE_DISABLE_SHORT_SYNTAX
#define satisfyAnyOf(...) NMB_satisfyAnyOf(__VA_ARGS__)
#endif
NIMBLE_EXPORT id<NMBMatcher> NMB_satisfyAllOfWithMatchers(id matchers);
#define NMB_satisfyAllOf(...) NMB_satisfyAllOfWithMatchers(@[__VA_ARGS__])
#ifndef NIMBLE_DISABLE_SHORT_SYNTAX
#define satisfyAllOf(...) NMB_satisfyAllOf(__VA_ARGS__)
#endif
// In order to preserve breakpoint behavior despite using macros to fill in __FILE__ and __LINE__,
// define a builder that populates __FILE__ and __LINE__, and returns a block that takes timeout
// and action arguments. See https://github.com/Quick/Quick/pull/185 for details.
typedef void (^NMBWaitUntilTimeoutBlock)(NSTimeInterval timeout, void (^action)(void (^)(void)));
typedef void (^NMBWaitUntilBlock)(void (^action)(void (^)(void)));
NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line);
NIMBLE_EXPORT NMBWaitUntilTimeoutBlock NMB_waitUntilTimeoutBuilder(NSString *file, NSUInteger line);
NIMBLE_EXPORT NMBWaitUntilBlock NMB_waitUntilBuilder(NSString *file, NSUInteger line);
NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line);
#define NMB_waitUntilTimeout NMB_waitUntilTimeoutBuilder(@(__FILE__), __LINE__)
#define NMB_waitUntil NMB_waitUntilBuilder(@(__FILE__), __LINE__)
#ifndef NIMBLE_DISABLE_SHORT_SYNTAX
#define expect(...) NMB_expect(^{ return (__VA_ARGS__); }, @(__FILE__), __LINE__)
#define expectAction(BLOCK) NMB_expectAction((BLOCK), @(__FILE__), __LINE__)
#define failWithMessage(msg) NMB_failWithMessage(msg, @(__FILE__), __LINE__)
#define fail() failWithMessage(@"fail() always fails")
#define waitUntilTimeout NMB_waitUntilTimeout
#define waitUntil NMB_waitUntil
#undef NIMBLE_VALUE_OF
#endif
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,161 @@
#import <Nimble/DSL.h>
#if __has_include("Nimble-Swift.h")
#import "Nimble-Swift.h"
#else
#import <Nimble/Nimble-Swift.h>
#endif
NS_ASSUME_NONNULL_BEGIN
NIMBLE_EXPORT NIMBLE_OVERLOADABLE NMBExpectation *__nonnull NMB_expect(id __nullable(^actualBlock)(void), NSString *__nonnull file, NSUInteger line) {
return [[NMBExpectation alloc] initWithActualBlock:actualBlock
negative:NO
file:file
line:line];
}
NIMBLE_EXPORT NMBExpectation *NMB_expectAction(void(^actualBlock)(void), NSString *file, NSUInteger line) {
return NMB_expect(^id{
actualBlock();
return nil;
}, file, line);
}
NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line) {
return [NMBExpectation failWithMessage:msg file:file line:line];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beAnInstanceOf(Class expectedClass) {
return [NMBObjCMatcher beAnInstanceOfMatcher:expectedClass];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beAKindOf(Class expectedClass) {
return [NMBObjCMatcher beAKindOfMatcher:expectedClass];
}
NIMBLE_EXPORT NIMBLE_OVERLOADABLE NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue) {
return [NMBObjCMatcher beCloseToMatcher:expectedValue within:0.001];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beginWith(id itemElementOrSubstring) {
return [NMBObjCMatcher beginWithMatcher:itemElementOrSubstring];
}
NIMBLE_EXPORT NIMBLE_OVERLOADABLE id<NMBMatcher> NMB_beGreaterThan(NSNumber *expectedValue) {
return [NMBObjCMatcher beGreaterThanMatcher:expectedValue];
}
NIMBLE_EXPORT NIMBLE_OVERLOADABLE id<NMBMatcher> NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue) {
return [NMBObjCMatcher beGreaterThanOrEqualToMatcher:expectedValue];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beIdenticalTo(id expectedInstance) {
return [NMBObjCMatcher beIdenticalToMatcher:expectedInstance];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_be(id expectedInstance) {
return [NMBObjCMatcher beIdenticalToMatcher:expectedInstance];
}
NIMBLE_EXPORT NIMBLE_OVERLOADABLE id<NMBMatcher> NMB_beLessThan(NSNumber *expectedValue) {
return [NMBObjCMatcher beLessThanMatcher:expectedValue];
}
NIMBLE_EXPORT NIMBLE_OVERLOADABLE id<NMBMatcher> NMB_beLessThanOrEqualTo(NSNumber *expectedValue) {
return [NMBObjCMatcher beLessThanOrEqualToMatcher:expectedValue];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beTruthy() {
return [NMBObjCMatcher beTruthyMatcher];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beFalsy() {
return [NMBObjCMatcher beFalsyMatcher];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beTrue() {
return [NMBObjCMatcher beTrueMatcher];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beFalse() {
return [NMBObjCMatcher beFalseMatcher];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beNil() {
return [NMBObjCMatcher beNilMatcher];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_beEmpty() {
return [NMBObjCMatcher beEmptyMatcher];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_containWithNilTermination(id itemOrSubstring, ...) {
NSMutableArray *itemOrSubstringArray = [NSMutableArray array];
if (itemOrSubstring) {
[itemOrSubstringArray addObject:itemOrSubstring];
va_list args;
va_start(args, itemOrSubstring);
id next;
while ((next = va_arg(args, id))) {
[itemOrSubstringArray addObject:next];
}
va_end(args);
}
return [NMBObjCMatcher containMatcher:itemOrSubstringArray];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_containElementSatisfying(BOOL(^predicate)(id)) {
return [NMBObjCMatcher containElementSatisfyingMatcher:predicate];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_endWith(id itemElementOrSubstring) {
return [NMBObjCMatcher endWithMatcher:itemElementOrSubstring];
}
NIMBLE_EXPORT NIMBLE_OVERLOADABLE id<NMBMatcher> NMB_equal(__nullable id expectedValue) {
return [NMBObjCMatcher equalMatcher:expectedValue];
}
NIMBLE_EXPORT NIMBLE_OVERLOADABLE id<NMBMatcher> NMB_haveCount(id expectedValue) {
return [NMBObjCMatcher haveCountMatcher:expectedValue];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_match(id expectedValue) {
return [NMBObjCMatcher matchMatcher:expectedValue];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_allPass(id expectedValue) {
return [NMBObjCMatcher allPassMatcher:expectedValue];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_satisfyAnyOfWithMatchers(id matchers) {
return [NMBObjCMatcher satisfyAnyOfMatcher:matchers];
}
NIMBLE_EXPORT id<NMBMatcher> NMB_satisfyAllOfWithMatchers(id matchers) {
return [NMBObjCMatcher satisfyAllOfMatcher:matchers];
}
NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException() {
return [NMBObjCMatcher raiseExceptionMatcher];
}
NIMBLE_EXPORT NMBWaitUntilTimeoutBlock NMB_waitUntilTimeoutBuilder(NSString *file, NSUInteger line) {
return ^(NSTimeInterval timeout, void (^ _Nonnull action)(void (^ _Nonnull)(void))) {
[NMBWait untilTimeout:timeout file:file line:line action:action];
};
}
NIMBLE_EXPORT NMBWaitUntilBlock NMB_waitUntilBuilder(NSString *file, NSUInteger line) {
return ^(void (^ _Nonnull action)(void (^ _Nonnull)(void))) {
[NMBWait untilFile:file line:line action:action];
};
}
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>
#import <dispatch/dispatch.h>
@interface NMBExceptionCapture : NSObject
- (nonnull instancetype)initWithHandler:(void(^ _Nullable)(NSException * _Nonnull))handler finally:(void(^ _Nullable)(void))finally;
- (void)tryBlock:(__attribute__((noescape)) void(^ _Nonnull)(void))unsafeBlock NS_SWIFT_NAME(tryBlock(_:));
@end
typedef void(^NMBSourceCallbackBlock)(BOOL successful);

View File

@@ -0,0 +1,35 @@
#import "NMBExceptionCapture.h"
@interface NMBExceptionCapture ()
@property (nonatomic, copy) void(^ _Nullable handler)(NSException * _Nullable);
@property (nonatomic, copy) void(^ _Nullable finally)(void);
@end
@implementation NMBExceptionCapture
- (nonnull instancetype)initWithHandler:(void(^ _Nullable)(NSException * _Nonnull))handler finally:(void(^ _Nullable)(void))finally {
self = [super init];
if (self) {
self.handler = handler;
self.finally = finally;
}
return self;
}
- (void)tryBlock:(__attribute__((noescape)) void(^ _Nonnull)(void))unsafeBlock {
@try {
unsafeBlock();
}
@catch (NSException *exception) {
if (self.handler) {
self.handler(exception);
}
}
@finally {
if (self.finally) {
self.finally();
}
}
}
@end

View File

@@ -0,0 +1,18 @@
@class NSString;
/**
* Returns a string appropriate for displaying in test output
* from the provided value.
*
* @param anyObject A value that will show up in a test's output.
*
* @return The string that is returned can be
* customized per type by conforming a type to the `TestOutputStringConvertible`
* protocol. When stringifying a non-`TestOutputStringConvertible` type, this
* function will return the value's debug description and then its
* normal description if available and in that order. Otherwise it
* will return the result of constructing a string from the value.
*
* @see `TestOutputStringConvertible`
*/
extern NSString *_Nonnull NMBStringify(id _Nullable anyObject) __attribute__((warn_unused_result));

View File

@@ -0,0 +1,11 @@
#import "NMBStringify.h"
#if __has_include("Nimble-Swift.h")
#import "Nimble-Swift.h"
#else
#import <Nimble/Nimble-Swift.h>
#endif
NSString *_Nonnull NMBStringify(id _Nullable anyObject) {
return [NMBStringer stringify:anyObject];
}

View File

@@ -0,0 +1,83 @@
#import <XCTest/XCTest.h>
#import <objc/runtime.h>
#if __has_include("Nimble-Swift.h")
#import "Nimble-Swift.h"
#else
#import <Nimble/Nimble-Swift.h>
#endif
#pragma mark - Method Swizzling
/// Swaps the implementations between two instance methods.
///
/// @param class The class containing `originalSelector`.
/// @param originalSelector Original method to replace.
/// @param replacementSelector Replacement method.
void swizzleSelectors(Class class, SEL originalSelector, SEL replacementSelector) {
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method replacementMethod = class_getInstanceMethod(class, replacementSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(replacementMethod),
method_getTypeEncoding(replacementMethod));
if (didAddMethod) {
class_replaceMethod(class,
replacementSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, replacementMethod);
}
}
#pragma mark - Private
@interface XCTestObservationCenter (Private)
- (void)_addLegacyTestObserver:(id)observer;
@end
@implementation XCTestObservationCenter (Register)
/// Uses objc method swizzling to register `CurrentTestCaseTracker` as a test observer. This is necessary
/// because Xcode 7.3 introduced timing issues where if a custom `XCTestObservation` is registered too early
/// it suppresses all console output (generated by `XCTestLog`), breaking any tools that depend on this output.
/// This approach waits to register our custom test observer until XCTest adds its first "legacy" observer,
/// falling back to registering after the first normal observer if this private method ever changes.
+ (void)load {
if (class_getInstanceMethod([self class], @selector(_addLegacyTestObserver:))) {
// Swizzle -_addLegacyTestObserver:
swizzleSelectors([self class], @selector(_addLegacyTestObserver:), @selector(NMB_original__addLegacyTestObserver:));
} else {
// Swizzle -addTestObserver:, only if -_addLegacyTestObserver: is not implemented
swizzleSelectors([self class], @selector(addTestObserver:), @selector(NMB_original_addTestObserver:));
}
}
#pragma mark - Replacement Methods
/// Registers `CurrentTestCaseTracker` as a test observer after `XCTestLog` has been added.
- (void)NMB_original__addLegacyTestObserver:(id)observer {
[self NMB_original__addLegacyTestObserver:observer];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self addTestObserver:[CurrentTestCaseTracker sharedInstance]];
});
}
/// Registers `CurrentTestCaseTracker` as a test observer after `XCTestLog` has been added.
/// This method is only used if `-_addLegacyTestObserver:` is not impelemented. (added in Xcode 7.3)
- (void)NMB_original_addTestObserver:(id<XCTestObservation>)observer {
[self NMB_original_addTestObserver:observer];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self NMB_original_addTestObserver:[CurrentTestCaseTracker sharedInstance]];
});
}
@end