init iOS module
This commit is contained in:
30
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/Configuration/QuickConfiguration.h
generated
Normal file
30
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/Configuration/QuickConfiguration.h
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Configuration;
|
||||
|
||||
/**
|
||||
Subclass QuickConfiguration and override the +[QuickConfiguration configure:]
|
||||
method in order to configure how Quick behaves when running specs, or to define
|
||||
shared examples that are used across spec files.
|
||||
*/
|
||||
@interface QuickConfiguration : NSObject
|
||||
|
||||
/**
|
||||
This method is executed on each subclass of this class before Quick runs
|
||||
any examples. You may override this method on as many subclasses as you like, but
|
||||
there is no guarantee as to the order in which these methods are executed.
|
||||
|
||||
You can override this method in order to:
|
||||
|
||||
1. Configure how Quick behaves, by modifying properties on the Configuration object.
|
||||
Setting the same properties in several methods has undefined behavior.
|
||||
|
||||
2. Define shared examples using `sharedExamples`.
|
||||
|
||||
@param configuration A mutable object that is used to configure how Quick behaves on
|
||||
a framework level. For details on all the options, see the
|
||||
documentation in Configuration.swift.
|
||||
*/
|
||||
+ (void)configure:(Configuration *)configuration;
|
||||
|
||||
@end
|
83
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/Configuration/QuickConfiguration.m
generated
Normal file
83
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/Configuration/QuickConfiguration.m
generated
Normal file
@@ -0,0 +1,83 @@
|
||||
#import "QuickConfiguration.h"
|
||||
#import "World.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
typedef void (^QCKClassEnumerationBlock)(Class klass);
|
||||
|
||||
/**
|
||||
Finds all direct subclasses of the given class and passes them to the block provided.
|
||||
The classes are iterated over in the order that objc_getClassList returns them.
|
||||
|
||||
@param klass The base class to find subclasses of.
|
||||
@param block A block that takes a Class. This block will be executed once for each subclass of klass.
|
||||
*/
|
||||
void qck_enumerateSubclasses(Class klass, QCKClassEnumerationBlock block) {
|
||||
Class *classes = NULL;
|
||||
int classesCount = objc_getClassList(NULL, 0);
|
||||
|
||||
if (classesCount > 0) {
|
||||
classes = (Class *)calloc(sizeof(Class), classesCount);
|
||||
classesCount = objc_getClassList(classes, classesCount);
|
||||
|
||||
Class subclass, superclass;
|
||||
for(int i = 0; i < classesCount; i++) {
|
||||
subclass = classes[i];
|
||||
superclass = class_getSuperclass(subclass);
|
||||
if (superclass == klass && block) {
|
||||
block(subclass);
|
||||
}
|
||||
}
|
||||
|
||||
free(classes);
|
||||
}
|
||||
}
|
||||
|
||||
@implementation QuickConfiguration
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
/**
|
||||
QuickConfiguration is not meant to be instantiated; it merely provides a hook
|
||||
for users to configure how Quick behaves. Raise an exception if an instance of
|
||||
QuickConfiguration is created.
|
||||
*/
|
||||
- (instancetype)init {
|
||||
NSString *className = NSStringFromClass([self class]);
|
||||
NSString *selectorName = NSStringFromSelector(@selector(configure:));
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"%@ is not meant to be instantiated; "
|
||||
@"subclass %@ and override %@ to configure Quick.",
|
||||
className, className, selectorName];
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - NSObject Overrides
|
||||
|
||||
/**
|
||||
Hook into when QuickConfiguration is initialized in the runtime in order to
|
||||
call +[QuickConfiguration configure:] on each of its subclasses.
|
||||
*/
|
||||
+ (void)initialize {
|
||||
// Only enumerate over the subclasses of QuickConfiguration, not any of its subclasses.
|
||||
if ([self class] == [QuickConfiguration class]) {
|
||||
|
||||
// Only enumerate over subclasses once, even if +[QuickConfiguration initialize]
|
||||
// were to be called several times. This is necessary because +[QuickSpec initialize]
|
||||
// manually calls +[QuickConfiguration initialize].
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
qck_enumerateSubclasses([QuickConfiguration class], ^(__unsafe_unretained Class klass) {
|
||||
[[World sharedWorld] configure:^(Configuration *configuration) {
|
||||
[klass configure:configuration];
|
||||
}];
|
||||
});
|
||||
[[World sharedWorld] finalizeConfiguration];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Public Interface
|
||||
|
||||
+ (void)configure:(Configuration *)configuration { }
|
||||
|
||||
@end
|
234
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/DSL/QCKDSL.h
generated
Normal file
234
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/DSL/QCKDSL.h
generated
Normal file
@@ -0,0 +1,234 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ExampleMetadata;
|
||||
|
||||
/**
|
||||
Provides a hook for Quick to be configured before any examples are run.
|
||||
Within this scope, override the +[QuickConfiguration configure:] method
|
||||
to set properties on a configuration object to customize Quick behavior.
|
||||
For details, see the documentation for Configuraiton.swift.
|
||||
|
||||
@param name The name of the configuration class. Like any Objective-C
|
||||
class name, this must be unique to the current runtime
|
||||
environment.
|
||||
*/
|
||||
#define QuickConfigurationBegin(name) \
|
||||
@interface name : QuickConfiguration; @end \
|
||||
@implementation name \
|
||||
|
||||
|
||||
/**
|
||||
Marks the end of a Quick configuration.
|
||||
Make sure you put this after `QuickConfigurationBegin`.
|
||||
*/
|
||||
#define QuickConfigurationEnd \
|
||||
@end \
|
||||
|
||||
|
||||
/**
|
||||
Defines a new QuickSpec. Define examples and example groups within the space
|
||||
between this and `QuickSpecEnd`.
|
||||
|
||||
@param name The name of the spec class. Like any Objective-C class name, this
|
||||
must be unique to the current runtime environment.
|
||||
*/
|
||||
#define QuickSpecBegin(name) \
|
||||
@interface name : QuickSpec; @end \
|
||||
@implementation name \
|
||||
- (void)spec { \
|
||||
|
||||
|
||||
/**
|
||||
Marks the end of a QuickSpec. Make sure you put this after `QuickSpecBegin`.
|
||||
*/
|
||||
#define QuickSpecEnd \
|
||||
} \
|
||||
@end \
|
||||
|
||||
typedef NSDictionary *(^QCKDSLSharedExampleContext)(void);
|
||||
typedef void (^QCKDSLSharedExampleBlock)(QCKDSLSharedExampleContext);
|
||||
typedef void (^QCKDSLEmptyBlock)(void);
|
||||
typedef void (^QCKDSLExampleMetadataBlock)(ExampleMetadata *exampleMetadata);
|
||||
|
||||
#define QUICK_EXPORT FOUNDATION_EXPORT
|
||||
|
||||
QUICK_EXPORT void qck_beforeSuite(QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_afterSuite(QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure);
|
||||
QUICK_EXPORT void qck_describe(NSString *description, QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_context(NSString *description, QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_beforeEach(QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_beforeEachWithMetadata(QCKDSLExampleMetadataBlock closure);
|
||||
QUICK_EXPORT void qck_afterEach(QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_afterEachWithMetadata(QCKDSLExampleMetadataBlock closure);
|
||||
QUICK_EXPORT void qck_pending(NSString *description, QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_xdescribe(NSString *description, QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_xcontext(NSString *description, QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_fdescribe(NSString *description, QCKDSLEmptyBlock closure);
|
||||
QUICK_EXPORT void qck_fcontext(NSString *description, QCKDSLEmptyBlock closure);
|
||||
|
||||
#ifndef QUICK_DISABLE_SHORT_SYNTAX
|
||||
/**
|
||||
Defines a closure to be run prior to any examples in the test suite.
|
||||
You may define an unlimited number of these closures, but there is no
|
||||
guarantee as to the order in which they're run.
|
||||
|
||||
If the test suite crashes before the first example is run, this closure
|
||||
will not be executed.
|
||||
|
||||
@param closure The closure to be run prior to any examples in the test suite.
|
||||
*/
|
||||
static inline void beforeSuite(QCKDSLEmptyBlock closure) {
|
||||
qck_beforeSuite(closure);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Defines a closure to be run after all of the examples in the test suite.
|
||||
You may define an unlimited number of these closures, but there is no
|
||||
guarantee as to the order in which they're run.
|
||||
|
||||
If the test suite crashes before all examples are run, this closure
|
||||
will not be executed.
|
||||
|
||||
@param closure The closure to be run after all of the examples in the test suite.
|
||||
*/
|
||||
static inline void afterSuite(QCKDSLEmptyBlock closure) {
|
||||
qck_afterSuite(closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a group of shared examples. These examples can be re-used in several locations
|
||||
by using the `itBehavesLike` function.
|
||||
|
||||
@param name The name of the shared example group. This must be unique across all shared example
|
||||
groups defined in a test suite.
|
||||
@param closure A closure containing the examples. This behaves just like an example group defined
|
||||
using `describe` or `context`--the closure may contain any number of `beforeEach`
|
||||
and `afterEach` closures, as well as any number of examples (defined using `it`).
|
||||
*/
|
||||
static inline void sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure) {
|
||||
qck_sharedExamples(name, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example group. Example groups are logical groupings of examples.
|
||||
Example groups can share setup and teardown code.
|
||||
|
||||
@param description An arbitrary string describing the example group.
|
||||
@param closure A closure that can contain other examples.
|
||||
*/
|
||||
static inline void describe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_describe(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example group. Equivalent to `describe`.
|
||||
*/
|
||||
static inline void context(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_context(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a closure to be run prior to each example in the current example
|
||||
group. This closure is not run for pending or otherwise disabled examples.
|
||||
An example group may contain an unlimited number of beforeEach. They'll be
|
||||
run in the order they're defined, but you shouldn't rely on that behavior.
|
||||
|
||||
@param closure The closure to be run prior to each example.
|
||||
*/
|
||||
static inline void beforeEach(QCKDSLEmptyBlock closure) {
|
||||
qck_beforeEach(closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to QCKDSL.beforeEach, except the closure is provided with
|
||||
metadata on the example that the closure is being run prior to.
|
||||
*/
|
||||
static inline void beforeEachWithMetadata(QCKDSLExampleMetadataBlock closure) {
|
||||
qck_beforeEachWithMetadata(closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a closure to be run after each example in the current example
|
||||
group. This closure is not run for pending or otherwise disabled examples.
|
||||
An example group may contain an unlimited number of afterEach. They'll be
|
||||
run in the order they're defined, but you shouldn't rely on that behavior.
|
||||
|
||||
@param closure The closure to be run after each example.
|
||||
*/
|
||||
static inline void afterEach(QCKDSLEmptyBlock closure) {
|
||||
qck_afterEach(closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to QCKDSL.afterEach, except the closure is provided with
|
||||
metadata on the example that the closure is being run after.
|
||||
*/
|
||||
static inline void afterEachWithMetadata(QCKDSLExampleMetadataBlock closure) {
|
||||
qck_afterEachWithMetadata(closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example or example group that should not be executed. Use `pending` to temporarily disable
|
||||
examples or groups that should not be run yet.
|
||||
|
||||
@param description An arbitrary string describing the example or example group.
|
||||
@param closure A closure that will not be evaluated.
|
||||
*/
|
||||
static inline void pending(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_pending(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark a `describe` block as pending.
|
||||
This disables all examples within the block.
|
||||
*/
|
||||
static inline void xdescribe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_xdescribe(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark a `context` block as pending.
|
||||
This disables all examples within the block.
|
||||
*/
|
||||
static inline void xcontext(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_xcontext(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus a `describe` block, focusing the examples in the block.
|
||||
If any examples in the test suite are focused, only those examples are executed.
|
||||
This trumps any explicitly focused or unfocused examples within the block--they are all treated as focused.
|
||||
*/
|
||||
static inline void fdescribe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_fdescribe(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus a `context` block. Equivalent to `fdescribe`.
|
||||
*/
|
||||
static inline void fcontext(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_fcontext(description, closure);
|
||||
}
|
||||
|
||||
#define it qck_it
|
||||
#define xit qck_xit
|
||||
#define fit qck_fit
|
||||
#define itBehavesLike qck_itBehavesLike
|
||||
#define xitBehavesLike qck_xitBehavesLike
|
||||
#define fitBehavesLike qck_fitBehavesLike
|
||||
#endif
|
||||
|
||||
#define qck_it qck_it_builder(@{}, @(__FILE__), __LINE__)
|
||||
#define qck_xit qck_it_builder(@{Filter.pending: @YES}, @(__FILE__), __LINE__)
|
||||
#define qck_fit qck_it_builder(@{Filter.focused: @YES}, @(__FILE__), __LINE__)
|
||||
#define qck_itBehavesLike qck_itBehavesLike_builder(@{}, @(__FILE__), __LINE__)
|
||||
#define qck_xitBehavesLike qck_itBehavesLike_builder(@{Filter.pending: @YES}, @(__FILE__), __LINE__)
|
||||
#define qck_fitBehavesLike qck_itBehavesLike_builder(@{Filter.focused: @YES}, @(__FILE__), __LINE__)
|
||||
|
||||
typedef void (^QCKItBlock)(NSString *description, QCKDSLEmptyBlock closure);
|
||||
typedef void (^QCKItBehavesLikeBlock)(NSString *description, QCKDSLSharedExampleContext context);
|
||||
|
||||
QUICK_EXPORT QCKItBlock qck_it_builder(NSDictionary *flags, NSString *file, NSUInteger line);
|
||||
QUICK_EXPORT QCKItBehavesLikeBlock qck_itBehavesLike_builder(NSDictionary *flags, NSString *file, NSUInteger line);
|
79
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/DSL/QCKDSL.m
generated
Normal file
79
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/DSL/QCKDSL.m
generated
Normal file
@@ -0,0 +1,79 @@
|
||||
#import "QCKDSL.h"
|
||||
#import "World.h"
|
||||
#import "World+DSL.h"
|
||||
|
||||
void qck_beforeSuite(QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] beforeSuite:closure];
|
||||
}
|
||||
|
||||
void qck_afterSuite(QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] afterSuite:closure];
|
||||
}
|
||||
|
||||
void qck_sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure) {
|
||||
[[World sharedWorld] sharedExamples:name closure:closure];
|
||||
}
|
||||
|
||||
void qck_describe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] describe:description flags:@{} closure:closure];
|
||||
}
|
||||
|
||||
void qck_context(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_describe(description, closure);
|
||||
}
|
||||
|
||||
void qck_beforeEach(QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] beforeEach:closure];
|
||||
}
|
||||
|
||||
void qck_beforeEachWithMetadata(QCKDSLExampleMetadataBlock closure) {
|
||||
[[World sharedWorld] beforeEachWithMetadata:closure];
|
||||
}
|
||||
|
||||
void qck_afterEach(QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] afterEach:closure];
|
||||
}
|
||||
|
||||
void qck_afterEachWithMetadata(QCKDSLExampleMetadataBlock closure) {
|
||||
[[World sharedWorld] afterEachWithMetadata:closure];
|
||||
}
|
||||
|
||||
QCKItBlock qck_it_builder(NSDictionary *flags, NSString *file, NSUInteger line) {
|
||||
return ^(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] itWithDescription:description
|
||||
flags:flags
|
||||
file:file
|
||||
line:line
|
||||
closure:closure];
|
||||
};
|
||||
}
|
||||
|
||||
QCKItBehavesLikeBlock qck_itBehavesLike_builder(NSDictionary *flags, NSString *file, NSUInteger line) {
|
||||
return ^(NSString *name, QCKDSLSharedExampleContext context) {
|
||||
[[World sharedWorld] itBehavesLikeSharedExampleNamed:name
|
||||
sharedExampleContext:context
|
||||
flags:flags
|
||||
file:file
|
||||
line:line];
|
||||
};
|
||||
}
|
||||
|
||||
void qck_pending(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] pending:description closure:closure];
|
||||
}
|
||||
|
||||
void qck_xdescribe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] xdescribe:description flags:@{} closure:closure];
|
||||
}
|
||||
|
||||
void qck_xcontext(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_xdescribe(description, closure);
|
||||
}
|
||||
|
||||
void qck_fdescribe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] fdescribe:description flags:@{} closure:closure];
|
||||
}
|
||||
|
||||
void qck_fcontext(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_fdescribe(description, closure);
|
||||
}
|
20
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/DSL/World+DSL.h
generated
Normal file
20
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/DSL/World+DSL.h
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
#import <Quick/Quick-Swift.h>
|
||||
|
||||
@interface World (SWIFT_EXTENSION(Quick))
|
||||
- (void)beforeSuite:(void (^ __nonnull)(void))closure;
|
||||
- (void)afterSuite:(void (^ __nonnull)(void))closure;
|
||||
- (void)sharedExamples:(NSString * __nonnull)name closure:(void (^ __nonnull)(NSDictionary * __nonnull (^ __nonnull)(void)))closure;
|
||||
- (void)describe:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure;
|
||||
- (void)context:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure;
|
||||
- (void)fdescribe:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure;
|
||||
- (void)xdescribe:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure;
|
||||
- (void)beforeEach:(void (^ __nonnull)(void))closure;
|
||||
- (void)beforeEachWithMetadata:(void (^ __nonnull)(ExampleMetadata * __nonnull))closure;
|
||||
- (void)afterEach:(void (^ __nonnull)(void))closure;
|
||||
- (void)afterEachWithMetadata:(void (^ __nonnull)(ExampleMetadata * __nonnull))closure;
|
||||
- (void)itWithDescription:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line closure:(void (^ __nonnull)(void))closure;
|
||||
- (void)fitWithDescription:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line closure:(void (^ __nonnull)(void))closure;
|
||||
- (void)xitWithDescription:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line closure:(void (^ __nonnull)(void))closure;
|
||||
- (void)itBehavesLikeSharedExampleNamed:(NSString * __nonnull)name sharedExampleContext:(NSDictionary * __nonnull (^ __nonnull)(void))sharedExampleContext flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line;
|
||||
- (void)pending:(NSString * __nonnull)description closure:(void (^ __nonnull)(void))closure;
|
||||
@end
|
11
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/Quick.h
generated
Normal file
11
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/Quick.h
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for Quick.
|
||||
FOUNDATION_EXPORT double QuickVersionNumber;
|
||||
|
||||
//! Project version string for Quick.
|
||||
FOUNDATION_EXPORT const unsigned char QuickVersionString[];
|
||||
|
||||
#import "QuickSpec.h"
|
||||
#import "QCKDSL.h"
|
||||
#import "QuickConfiguration.h"
|
50
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/QuickSpec.h
generated
Normal file
50
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/QuickSpec.h
generated
Normal file
@@ -0,0 +1,50 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
/**
|
||||
QuickSpec is a base class all specs written in Quick inherit from.
|
||||
They need to inherit from QuickSpec, a subclass of XCTestCase, in
|
||||
order to be discovered by the XCTest framework.
|
||||
|
||||
XCTest automatically compiles a list of XCTestCase subclasses included
|
||||
in the test target. It iterates over each class in that list, and creates
|
||||
a new instance of that class for each test method. It then creates an
|
||||
"invocation" to execute that test method. The invocation is an instance of
|
||||
NSInvocation, which represents a single message send in Objective-C.
|
||||
The invocation is set on the XCTestCase instance, and the test is run.
|
||||
|
||||
Most of the code in QuickSpec is dedicated to hooking into XCTest events.
|
||||
First, when the spec is first loaded and before it is sent any messages,
|
||||
the +[NSObject initialize] method is called. QuickSpec overrides this method
|
||||
to call +[QuickSpec spec]. This builds the example group stacks and
|
||||
registers them with Quick.World, a global register of examples.
|
||||
|
||||
Then, XCTest queries QuickSpec for a list of test methods. Normally, XCTest
|
||||
automatically finds all methods whose selectors begin with the string "test".
|
||||
However, QuickSpec overrides this default behavior by implementing the
|
||||
+[XCTestCase testInvocations] method. This method iterates over each example
|
||||
registered in Quick.World, defines a new method for that example, and
|
||||
returns an invocation to call that method to XCTest. Those invocations are
|
||||
the tests that are run by XCTest. Their selector names are displayed in
|
||||
the Xcode test navigation bar.
|
||||
*/
|
||||
@interface QuickSpec : XCTestCase
|
||||
|
||||
/**
|
||||
Override this method in your spec to define a set of example groups
|
||||
and examples.
|
||||
|
||||
@code
|
||||
override func spec() {
|
||||
describe("winter") {
|
||||
it("is coming") {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
@endcode
|
||||
|
||||
See DSL.swift for more information on what syntax is available.
|
||||
*/
|
||||
- (void)spec;
|
||||
|
||||
@end
|
141
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/QuickSpec.m
generated
Normal file
141
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/QuickSpec.m
generated
Normal file
@@ -0,0 +1,141 @@
|
||||
#import "QuickSpec.h"
|
||||
#import "QuickConfiguration.h"
|
||||
#import "World.h"
|
||||
#import <Quick/Quick-Swift.h>
|
||||
|
||||
static QuickSpec *currentSpec = nil;
|
||||
|
||||
@interface QuickSpec ()
|
||||
@property (nonatomic, strong) Example *example;
|
||||
@end
|
||||
|
||||
@implementation QuickSpec
|
||||
|
||||
#pragma mark - XCTestCase Overrides
|
||||
|
||||
/**
|
||||
The runtime sends initialize to each class in a program just before the class, or any class
|
||||
that inherits from it, is sent its first message from within the program. QuickSpec hooks into
|
||||
this event to compile the example groups for this spec subclass.
|
||||
|
||||
If an exception occurs when compiling the examples, report it to the user. Chances are they
|
||||
included an expectation outside of a "it", "describe", or "context" block.
|
||||
*/
|
||||
+ (void)initialize {
|
||||
[QuickConfiguration initialize];
|
||||
|
||||
World *world = [World sharedWorld];
|
||||
[world performWithCurrentExampleGroup:[world rootExampleGroupForSpecClass:self] closure:^{
|
||||
QuickSpec *spec = [self new];
|
||||
|
||||
@try {
|
||||
[spec spec];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"An exception occurred when building Quick's example groups.\n"
|
||||
@"Some possible reasons this might happen include:\n\n"
|
||||
@"- An 'expect(...).to' expectation was evaluated outside of "
|
||||
@"an 'it', 'context', or 'describe' block\n"
|
||||
@"- 'sharedExamples' was called twice with the same name\n"
|
||||
@"- 'itBehavesLike' was called with a name that is not registered as a shared example\n\n"
|
||||
@"Here's the original exception: '%@', reason: '%@', userInfo: '%@'",
|
||||
exception.name, exception.reason, exception.userInfo];
|
||||
}
|
||||
[self testInvocations];
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
Invocations for each test method in the test case. QuickSpec overrides this method to define a
|
||||
new method for each example defined in +[QuickSpec spec].
|
||||
|
||||
@return An array of invocations that execute the newly defined example methods.
|
||||
*/
|
||||
+ (NSArray *)testInvocations {
|
||||
NSArray *examples = [[World sharedWorld] examplesForSpecClass:[self class]];
|
||||
NSMutableArray *invocations = [NSMutableArray arrayWithCapacity:[examples count]];
|
||||
|
||||
NSMutableSet<NSString*> *selectorNames = [NSMutableSet set];
|
||||
|
||||
for (Example *example in examples) {
|
||||
SEL selector = [self addInstanceMethodForExample:example classSelectorNames:selectorNames];
|
||||
|
||||
NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector];
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||
invocation.selector = selector;
|
||||
|
||||
[invocations addObject:invocation];
|
||||
}
|
||||
|
||||
return invocations;
|
||||
}
|
||||
|
||||
#pragma mark - Public Interface
|
||||
|
||||
- (void)spec { }
|
||||
|
||||
#pragma mark - Internal Methods
|
||||
|
||||
/**
|
||||
QuickSpec uses this method to dynamically define a new instance method for the
|
||||
given example. The instance method runs the example, catching any exceptions.
|
||||
The exceptions are then reported as test failures.
|
||||
|
||||
In order to report the correct file and line number, examples must raise exceptions
|
||||
containing following keys in their userInfo:
|
||||
|
||||
- "SenTestFilenameKey": A String representing the file name
|
||||
- "SenTestLineNumberKey": An Int representing the line number
|
||||
|
||||
These keys used to be used by SenTestingKit, and are still used by some testing tools
|
||||
in the wild. See: https://github.com/Quick/Quick/pull/41
|
||||
|
||||
@return The selector of the newly defined instance method.
|
||||
*/
|
||||
+ (SEL)addInstanceMethodForExample:(Example *)example classSelectorNames:(NSMutableSet<NSString*> *)selectorNames {
|
||||
IMP implementation = imp_implementationWithBlock(^(QuickSpec *self){
|
||||
self.example = example;
|
||||
currentSpec = self;
|
||||
[example run];
|
||||
});
|
||||
|
||||
const char *types = [[NSString stringWithFormat:@"%s%s%s", @encode(void), @encode(id), @encode(SEL)] UTF8String];
|
||||
|
||||
NSString *originalName = example.name.qck_c99ExtendedIdentifier;
|
||||
NSString *selectorName = originalName;
|
||||
NSUInteger i = 2;
|
||||
|
||||
while ([selectorNames containsObject:selectorName]) {
|
||||
selectorName = [NSString stringWithFormat:@"%@_%tu", originalName, i++];
|
||||
}
|
||||
|
||||
[selectorNames addObject:selectorName];
|
||||
|
||||
SEL selector = NSSelectorFromString(selectorName);
|
||||
class_addMethod(self, selector, implementation, types);
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
/**
|
||||
This method is used to record failures, whether they represent example
|
||||
expectations that were not met, or exceptions raised during test setup
|
||||
and teardown. By default, the failure will be reported as an
|
||||
XCTest failure, and the example will be highlighted in Xcode.
|
||||
*/
|
||||
- (void)recordFailureWithDescription:(NSString *)description
|
||||
inFile:(NSString *)filePath
|
||||
atLine:(NSUInteger)lineNumber
|
||||
expected:(BOOL)expected {
|
||||
if (self.example.isSharedExample) {
|
||||
filePath = self.example.callsite.file;
|
||||
lineNumber = self.example.callsite.line;
|
||||
}
|
||||
[currentSpec.testRun recordFailureWithDescription:description
|
||||
inFile:filePath
|
||||
atLine:lineNumber
|
||||
expected:expected];
|
||||
}
|
||||
|
||||
@end
|
18
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/World.h
generated
Normal file
18
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/World.h
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
#import <Quick/Quick-Swift.h>
|
||||
|
||||
@class ExampleGroup;
|
||||
@class ExampleMetadata;
|
||||
|
||||
SWIFT_CLASS("_TtC5Quick5World")
|
||||
@interface World
|
||||
|
||||
@property (nonatomic) ExampleGroup * __nullable currentExampleGroup;
|
||||
@property (nonatomic) ExampleMetadata * __nullable currentExampleMetadata;
|
||||
@property (nonatomic) BOOL isRunningAdditionalSuites;
|
||||
+ (World * __nonnull)sharedWorld;
|
||||
- (void)configure:(void (^ __nonnull)(Configuration * __nonnull))closure;
|
||||
- (void)finalizeConfiguration;
|
||||
- (ExampleGroup * __nonnull)rootExampleGroupForSpecClass:(Class __nonnull)cls;
|
||||
- (NSArray * __nonnull)examplesForSpecClass:(Class __nonnull)specClass;
|
||||
- (void)performWithCurrentExampleGroup:(ExampleGroup * __nonnull)group closure:(void (^ __nonnull)(void))closure;
|
||||
@end
|
40
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/XCTestSuite+QuickTestSuiteBuilder.m
generated
Normal file
40
iOS/Example/Pods/Quick/Sources/QuickObjectiveC/XCTestSuite+QuickTestSuiteBuilder.m
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <Quick/Quick-Swift.h>
|
||||
|
||||
@interface XCTestSuite (QuickTestSuiteBuilder)
|
||||
@end
|
||||
|
||||
@implementation XCTestSuite (QuickTestSuiteBuilder)
|
||||
|
||||
/**
|
||||
In order to ensure we can correctly build dynamic test suites, we need to
|
||||
replace some of the default test suite constructors.
|
||||
*/
|
||||
+ (void)load {
|
||||
Method testCaseWithName = class_getClassMethod(self, @selector(testSuiteForTestCaseWithName:));
|
||||
Method hooked_testCaseWithName = class_getClassMethod(self, @selector(qck_hooked_testSuiteForTestCaseWithName:));
|
||||
method_exchangeImplementations(testCaseWithName, hooked_testCaseWithName);
|
||||
}
|
||||
|
||||
/**
|
||||
The `+testSuiteForTestCaseWithName:` method is called when a specific test case
|
||||
class is run from the Xcode test navigator. If the built test suite is `nil`,
|
||||
Xcode will not run any tests for that test case.
|
||||
|
||||
Given if the following test case class is run from the Xcode test navigator:
|
||||
|
||||
FooSpec
|
||||
testFoo
|
||||
testBar
|
||||
|
||||
XCTest will invoke this once per test case, with test case names following this format:
|
||||
|
||||
FooSpec/testFoo
|
||||
FooSpec/testBar
|
||||
*/
|
||||
+ (nullable instancetype)qck_hooked_testSuiteForTestCaseWithName:(nonnull NSString *)name {
|
||||
return [QuickTestSuite selectedTestSuiteForTestCaseWithName:name];
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user