init iOS module
This commit is contained in:
17
iOS/Example/Pods/Quick/Sources/Quick/Behavior.swift
generated
Normal file
17
iOS/Example/Pods/Quick/Sources/Quick/Behavior.swift
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
A `Behavior` encapsulates a set of examples that can be re-used in several locations using the `itBehavesLike` function with a context instance of the generic type.
|
||||
*/
|
||||
|
||||
open class Behavior<Context> {
|
||||
|
||||
open static var name: String { return String(describing: self) }
|
||||
/**
|
||||
override this method in your behavior to define a set of reusable examples.
|
||||
|
||||
This behaves just like an example group defines using `describe` or `context`--it may contain any number of `beforeEach`
|
||||
and `afterEach` closures, as well as any number of examples (defined using `it`).
|
||||
|
||||
- parameter aContext: A closure that, when evaluated, returns a `Context` instance that provide the information on the subject.
|
||||
*/
|
||||
open class func spec(_ aContext: @escaping () -> Context) {}
|
||||
}
|
||||
45
iOS/Example/Pods/Quick/Sources/Quick/Callsite.swift
generated
Normal file
45
iOS/Example/Pods/Quick/Sources/Quick/Callsite.swift
generated
Normal file
@@ -0,0 +1,45 @@
|
||||
import Foundation
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _CallsiteBase: NSObject {}
|
||||
#else
|
||||
public class _CallsiteBase: NSObject {}
|
||||
#endif
|
||||
#else
|
||||
public class _CallsiteBase: NSObject {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
An object encapsulating the file and line number at which
|
||||
a particular example is defined.
|
||||
*/
|
||||
final public class Callsite: _CallsiteBase {
|
||||
/**
|
||||
The absolute path of the file in which an example is defined.
|
||||
*/
|
||||
public let file: String
|
||||
|
||||
/**
|
||||
The line number on which an example is defined.
|
||||
*/
|
||||
public let line: UInt
|
||||
|
||||
internal init(file: String, line: UInt) {
|
||||
self.file = file
|
||||
self.line = line
|
||||
}
|
||||
}
|
||||
|
||||
extension Callsite {
|
||||
/**
|
||||
Returns a boolean indicating whether two Callsite objects are equal.
|
||||
If two callsites are in the same file and on the same line, they must be equal.
|
||||
*/
|
||||
@nonobjc public static func == (lhs: Callsite, rhs: Callsite) -> Bool {
|
||||
return lhs.file == rhs.file && lhs.line == rhs.line
|
||||
}
|
||||
}
|
||||
161
iOS/Example/Pods/Quick/Sources/Quick/Configuration/Configuration.swift
generated
Normal file
161
iOS/Example/Pods/Quick/Sources/Quick/Configuration/Configuration.swift
generated
Normal file
@@ -0,0 +1,161 @@
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
A closure that temporarily exposes a Configuration object within
|
||||
the scope of the closure.
|
||||
*/
|
||||
public typealias QuickConfigurer = (_ configuration: Configuration) -> Void
|
||||
|
||||
/**
|
||||
A closure that, given metadata about an example, returns a boolean value
|
||||
indicating whether that example should be run.
|
||||
*/
|
||||
public typealias ExampleFilter = (_ example: Example) -> Bool
|
||||
|
||||
/**
|
||||
A configuration encapsulates various options you can use
|
||||
to configure Quick's behavior.
|
||||
*/
|
||||
final public class Configuration: NSObject {
|
||||
internal let exampleHooks = ExampleHooks()
|
||||
internal let suiteHooks = SuiteHooks()
|
||||
internal var exclusionFilters: [ExampleFilter] = [ { example in
|
||||
if let pending = example.filterFlags[Filter.pending] {
|
||||
return pending
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}]
|
||||
internal var inclusionFilters: [ExampleFilter] = [ { example in
|
||||
if let focused = example.filterFlags[Filter.focused] {
|
||||
return focused
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}]
|
||||
|
||||
/**
|
||||
Run all examples if none match the configured filters. True by default.
|
||||
*/
|
||||
public var runAllWhenEverythingFiltered = true
|
||||
|
||||
/**
|
||||
Registers an inclusion filter.
|
||||
|
||||
All examples are filtered using all inclusion filters.
|
||||
The remaining examples are run. If no examples remain, all examples are run.
|
||||
|
||||
- parameter filter: A filter that, given an example, returns a value indicating
|
||||
whether that example should be included in the examples
|
||||
that are run.
|
||||
*/
|
||||
public func include(_ filter: @escaping ExampleFilter) {
|
||||
inclusionFilters.append(filter)
|
||||
}
|
||||
|
||||
/**
|
||||
Registers an exclusion filter.
|
||||
|
||||
All examples that remain after being filtered by the inclusion filters are
|
||||
then filtered via all exclusion filters.
|
||||
|
||||
- parameter filter: A filter that, given an example, returns a value indicating
|
||||
whether that example should be excluded from the examples
|
||||
that are run.
|
||||
*/
|
||||
public func exclude(_ filter: @escaping ExampleFilter) {
|
||||
exclusionFilters.append(filter)
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to Quick.Configuration.beforeEach, except the closure is
|
||||
provided with metadata on the example that the closure is being run
|
||||
prior to.
|
||||
*/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
@objc(beforeEachWithMetadata:)
|
||||
public func beforeEach(_ closure: @escaping BeforeExampleWithMetadataClosure) {
|
||||
exampleHooks.appendBefore(closure)
|
||||
}
|
||||
#else
|
||||
public func beforeEach(_ closure: @escaping BeforeExampleWithMetadataClosure) {
|
||||
exampleHooks.appendBefore(closure)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Like Quick.DSL.beforeEach, this configures Quick to execute the
|
||||
given closure before each example that is run. The closure
|
||||
passed to this method is executed before each example Quick runs,
|
||||
globally across the test suite. You may call this method multiple
|
||||
times across mulitple +[QuickConfigure configure:] methods in order
|
||||
to define several closures to run before each example.
|
||||
|
||||
Note that, since Quick makes no guarantee as to the order in which
|
||||
+[QuickConfiguration configure:] methods are evaluated, there is no
|
||||
guarantee as to the order in which beforeEach closures are evaluated
|
||||
either. Mulitple beforeEach defined on a single configuration, however,
|
||||
will be executed in the order they're defined.
|
||||
|
||||
- parameter closure: The closure to be executed before each example
|
||||
in the test suite.
|
||||
*/
|
||||
public func beforeEach(_ closure: @escaping BeforeExampleClosure) {
|
||||
exampleHooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to Quick.Configuration.afterEach, except the closure
|
||||
is provided with metadata on the example that the closure is being
|
||||
run after.
|
||||
*/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
@objc(afterEachWithMetadata:)
|
||||
public func afterEach(_ closure: @escaping AfterExampleWithMetadataClosure) {
|
||||
exampleHooks.appendAfter(closure)
|
||||
}
|
||||
#else
|
||||
public func afterEach(_ closure: @escaping AfterExampleWithMetadataClosure) {
|
||||
exampleHooks.appendAfter(closure)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Like Quick.DSL.afterEach, this configures Quick to execute the
|
||||
given closure after each example that is run. The closure
|
||||
passed to this method is executed after each example Quick runs,
|
||||
globally across the test suite. You may call this method multiple
|
||||
times across mulitple +[QuickConfigure configure:] methods in order
|
||||
to define several closures to run after each example.
|
||||
|
||||
Note that, since Quick makes no guarantee as to the order in which
|
||||
+[QuickConfiguration configure:] methods are evaluated, there is no
|
||||
guarantee as to the order in which afterEach closures are evaluated
|
||||
either. Mulitple afterEach defined on a single configuration, however,
|
||||
will be executed in the order they're defined.
|
||||
|
||||
- parameter closure: The closure to be executed before each example
|
||||
in the test suite.
|
||||
*/
|
||||
public func afterEach(_ closure: @escaping AfterExampleClosure) {
|
||||
exampleHooks.appendAfter(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Like Quick.DSL.beforeSuite, this configures Quick to execute
|
||||
the given closure prior to any and all examples that are run.
|
||||
The two methods are functionally equivalent.
|
||||
*/
|
||||
public func beforeSuite(_ closure: @escaping BeforeSuiteClosure) {
|
||||
suiteHooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Like Quick.DSL.afterSuite, this configures Quick to execute
|
||||
the given closure after all examples have been run.
|
||||
The two methods are functionally equivalent.
|
||||
*/
|
||||
public func afterSuite(_ closure: @escaping AfterSuiteClosure) {
|
||||
suiteHooks.appendAfter(closure)
|
||||
}
|
||||
}
|
||||
271
iOS/Example/Pods/Quick/Sources/Quick/DSL/DSL.swift
generated
Normal file
271
iOS/Example/Pods/Quick/Sources/Quick/DSL/DSL.swift
generated
Normal file
@@ -0,0 +1,271 @@
|
||||
/**
|
||||
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.
|
||||
|
||||
- parameter closure: The closure to be run prior to any examples in the test suite.
|
||||
*/
|
||||
public func beforeSuite(_ closure: @escaping BeforeSuiteClosure) {
|
||||
World.sharedWorld.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.
|
||||
|
||||
- parameter closure: The closure to be run after all of the examples in the test suite.
|
||||
*/
|
||||
public func afterSuite(_ closure: @escaping AfterSuiteClosure) {
|
||||
World.sharedWorld.afterSuite(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a group of shared examples. These examples can be re-used in several locations
|
||||
by using the `itBehavesLike` function.
|
||||
|
||||
- parameter name: The name of the shared example group. This must be unique across all shared example
|
||||
groups defined in a test suite.
|
||||
- parameter 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`).
|
||||
*/
|
||||
public func sharedExamples(_ name: String, closure: @escaping () -> Void) {
|
||||
World.sharedWorld.sharedExamples(name) { _ in closure() }
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a group of shared examples. These examples can be re-used in several locations
|
||||
by using the `itBehavesLike` function.
|
||||
|
||||
- parameter name: The name of the shared example group. This must be unique across all shared example
|
||||
groups defined in a test suite.
|
||||
- parameter 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`).
|
||||
|
||||
The closure takes a SharedExampleContext as an argument. This context is a function
|
||||
that can be executed to retrieve parameters passed in via an `itBehavesLike` function.
|
||||
*/
|
||||
public func sharedExamples(_ name: String, closure: @escaping SharedExampleClosure) {
|
||||
World.sharedWorld.sharedExamples(name, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example group. Example groups are logical groupings of examples.
|
||||
Example groups can share setup and teardown code.
|
||||
|
||||
- parameter description: An arbitrary string describing the example group.
|
||||
- parameter closure: A closure that can contain other examples.
|
||||
- parameter flags: A mapping of string keys to booleans that can be used to filter examples or example groups.
|
||||
*/
|
||||
public func describe(_ description: String, flags: FilterFlags = [:], closure: () -> Void) {
|
||||
World.sharedWorld.describe(description, flags: flags, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example group. Equivalent to `describe`.
|
||||
*/
|
||||
public func context(_ description: String, flags: FilterFlags = [:], closure: () -> Void) {
|
||||
World.sharedWorld.context(description, flags: flags, closure: 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.
|
||||
|
||||
- parameter closure: The closure to be run prior to each example.
|
||||
*/
|
||||
public func beforeEach(_ closure: @escaping BeforeExampleClosure) {
|
||||
World.sharedWorld.beforeEach(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to Quick.DSL.beforeEach, except the closure is provided with
|
||||
metadata on the example that the closure is being run prior to.
|
||||
*/
|
||||
public func beforeEach(_ closure: @escaping BeforeExampleWithMetadataClosure) {
|
||||
World.sharedWorld.beforeEach(closure: 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.
|
||||
|
||||
- parameter closure: The closure to be run after each example.
|
||||
*/
|
||||
public func afterEach(_ closure: @escaping AfterExampleClosure) {
|
||||
World.sharedWorld.afterEach(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to Quick.DSL.afterEach, except the closure is provided with
|
||||
metadata on the example that the closure is being run after.
|
||||
*/
|
||||
public func afterEach(_ closure: @escaping AfterExampleWithMetadataClosure) {
|
||||
World.sharedWorld.afterEach(closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example. Examples use assertions to demonstrate how code should
|
||||
behave. These are like "tests" in XCTest.
|
||||
|
||||
- parameter description: An arbitrary string describing what the example is meant to specify.
|
||||
- parameter closure: A closure that can contain assertions.
|
||||
- parameter flags: A mapping of string keys to booleans that can be used to filter examples or example groups.
|
||||
Empty by default.
|
||||
- parameter file: The absolute path to the file containing the example. A sensible default is provided.
|
||||
- parameter line: The line containing the example. A sensible default is provided.
|
||||
*/
|
||||
public func it(_ description: String, flags: FilterFlags = [:], file: String = #file, line: UInt = #line, closure: @escaping () -> Void) {
|
||||
World.sharedWorld.it(description, flags: flags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Inserts the examples defined using a `sharedExamples` function into the current example group.
|
||||
The shared examples are executed at this location, as if they were written out manually.
|
||||
|
||||
- parameter name: The name of the shared examples group to be executed. This must be identical to the
|
||||
name of a shared examples group defined using `sharedExamples`. If there are no shared
|
||||
examples that match the name given, an exception is thrown and the test suite will crash.
|
||||
- parameter flags: A mapping of string keys to booleans that can be used to filter examples or example groups.
|
||||
Empty by default.
|
||||
- parameter file: The absolute path to the file containing the current example group. A sensible default is provided.
|
||||
- parameter line: The line containing the current example group. A sensible default is provided.
|
||||
*/
|
||||
public func itBehavesLike(_ name: String, flags: FilterFlags = [:], file: String = #file, line: UInt = #line) {
|
||||
itBehavesLike(name, flags: flags, file: file, line: line, sharedExampleContext: { return [:] })
|
||||
}
|
||||
|
||||
/**
|
||||
Inserts the examples defined using a `sharedExamples` function into the current example group.
|
||||
The shared examples are executed at this location, as if they were written out manually.
|
||||
This function also passes those shared examples a context that can be evaluated to give the shared
|
||||
examples extra information on the subject of the example.
|
||||
|
||||
- parameter name: The name of the shared examples group to be executed. This must be identical to the
|
||||
name of a shared examples group defined using `sharedExamples`. If there are no shared
|
||||
examples that match the name given, an exception is thrown and the test suite will crash.
|
||||
- parameter sharedExampleContext: A closure that, when evaluated, returns key-value pairs that provide the
|
||||
shared examples with extra information on the subject of the example.
|
||||
- parameter flags: A mapping of string keys to booleans that can be used to filter examples or example groups.
|
||||
Empty by default.
|
||||
- parameter file: The absolute path to the file containing the current example group. A sensible default is provided.
|
||||
- parameter line: The line containing the current example group. A sensible default is provided.
|
||||
*/
|
||||
public func itBehavesLike(_ name: String, flags: FilterFlags = [:], file: String = #file, line: UInt = #line, sharedExampleContext: @escaping SharedExampleContext) {
|
||||
World.sharedWorld.itBehavesLike(name, sharedExampleContext: sharedExampleContext, flags: flags, file: file, line: line)
|
||||
}
|
||||
|
||||
/**
|
||||
Inserts the examples defined using a `Behavior` into the current example group.
|
||||
The shared examples are executed at this location, as if they were written out manually.
|
||||
This function also passes a strongly-typed context that can be evaluated to give the shared examples extra information on the subject of the example.
|
||||
|
||||
- parameter behavior: The type of `Behavior` class defining the example group to be executed.
|
||||
- parameter context: A closure that, when evaluated, returns an instance of `Behavior`'s context type to provide its example group with extra information on the subject of the example.
|
||||
- parameter flags: A mapping of string keys to booleans that can be used to filter examples or example groups.
|
||||
Empty by default.
|
||||
- parameter file: The absolute path to the file containing the current example group. A sensible default is provided.
|
||||
- parameter line: The line containing the current example group. A sensible default is provided.
|
||||
*/
|
||||
public func itBehavesLike<C>(_ behavior: Behavior<C>.Type, flags: FilterFlags = [:], file: String = #file, line: UInt = #line, context: @escaping () -> C) {
|
||||
World.sharedWorld.itBehavesLike(behavior, context: context, flags: flags, file: file, line: line)
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
- parameter description: An arbitrary string describing the example or example group.
|
||||
- parameter closure: A closure that will not be evaluated.
|
||||
*/
|
||||
public func pending(_ description: String, closure: () -> Void) {
|
||||
World.sharedWorld.pending(description, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark a `describe` closure as pending.
|
||||
This disables all examples within the closure.
|
||||
*/
|
||||
public func xdescribe(_ description: String, flags: FilterFlags, closure: () -> Void) {
|
||||
World.sharedWorld.xdescribe(description, flags: flags, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark a `context` closure as pending.
|
||||
This disables all examples within the closure.
|
||||
*/
|
||||
public func xcontext(_ description: String, flags: FilterFlags, closure: () -> Void) {
|
||||
xdescribe(description, flags: flags, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark an `it` closure as pending.
|
||||
This disables the example and ensures the code within the closure is never run.
|
||||
*/
|
||||
public func xit(_ description: String, flags: FilterFlags = [:], file: String = #file, line: UInt = #line, closure: @escaping () -> Void) {
|
||||
World.sharedWorld.xit(description, flags: flags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quicklu mark an `itBehavesLike` closure as pending.
|
||||
This disables the example group defined by this behavior and ensures the code within is never run.
|
||||
*/
|
||||
public func xitBehavesLike<C>(_ behavior: Behavior<C>.Type, flags: FilterFlags = [:], file: String = #file, line: UInt = #line, context: @escaping () -> C) {
|
||||
World.sharedWorld.xitBehavesLike(behavior, context: context, flags: flags, file: file, line: line)
|
||||
}
|
||||
/**
|
||||
Use this to quickly focus a `describe` closure, focusing the examples in the closure.
|
||||
If any examples in the test suite are focused, only those examples are executed.
|
||||
This trumps any explicitly focused or unfocused examples within the closure--they are all treated as focused.
|
||||
*/
|
||||
public func fdescribe(_ description: String, flags: FilterFlags = [:], closure: () -> Void) {
|
||||
World.sharedWorld.fdescribe(description, flags: flags, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus a `context` closure. Equivalent to `fdescribe`.
|
||||
*/
|
||||
public func fcontext(_ description: String, flags: FilterFlags = [:], closure: () -> Void) {
|
||||
fdescribe(description, flags: flags, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus an `it` closure, focusing the example.
|
||||
If any examples in the test suite are focused, only those examples are executed.
|
||||
*/
|
||||
public func fit(_ description: String, flags: FilterFlags = [:], file: String = #file, line: UInt = #line, closure: @escaping () -> Void) {
|
||||
World.sharedWorld.fit(description, flags: flags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus an `itBehavesLike` closure.
|
||||
*/
|
||||
public func fitBehavesLike(_ name: String, flags: FilterFlags = [:], file: String = #file, line: UInt = #line) {
|
||||
fitBehavesLike(name, flags: flags, file: file, line: line, sharedExampleContext: { return [:] })
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus an `itBehavesLike` closure.
|
||||
*/
|
||||
public func fitBehavesLike(_ name: String, flags: FilterFlags = [:], file: String = #file, line: UInt = #line, sharedExampleContext: @escaping SharedExampleContext) {
|
||||
World.sharedWorld.fitBehavesLike(name, sharedExampleContext: sharedExampleContext, flags: flags, file: file, line: line)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus on `itBehavesLike` closure.
|
||||
*/
|
||||
public func fitBehavesLike<C>(_ behavior: Behavior<C>.Type, flags: FilterFlags = [:], file: String = #file, line: UInt = #line, context: @escaping () -> C) {
|
||||
World.sharedWorld.fitBehavesLike(behavior, context: context, flags: flags, file: file, line: line)
|
||||
}
|
||||
205
iOS/Example/Pods/Quick/Sources/Quick/DSL/World+DSL.swift
generated
Normal file
205
iOS/Example/Pods/Quick/Sources/Quick/DSL/World+DSL.swift
generated
Normal file
@@ -0,0 +1,205 @@
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Adds methods to World to support top-level DSL functions (Swift) and
|
||||
macros (Objective-C). These functions map directly to the DSL that test
|
||||
writers use in their specs.
|
||||
*/
|
||||
extension World {
|
||||
internal func beforeSuite(_ closure: @escaping BeforeSuiteClosure) {
|
||||
suiteHooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
internal func afterSuite(_ closure: @escaping AfterSuiteClosure) {
|
||||
suiteHooks.appendAfter(closure)
|
||||
}
|
||||
|
||||
internal func sharedExamples(_ name: String, closure: @escaping SharedExampleClosure) {
|
||||
registerSharedExample(name, closure: closure)
|
||||
}
|
||||
|
||||
internal func describe(_ description: String, flags: FilterFlags, closure: () -> Void) {
|
||||
guard currentExampleMetadata == nil else {
|
||||
raiseError("'describe' cannot be used inside '\(currentPhase)', 'describe' may only be used inside 'context' or 'describe'. ")
|
||||
}
|
||||
guard currentExampleGroup != nil else {
|
||||
raiseError("Error: example group was not created by its parent QuickSpec spec. Check that describe() or context() was used in QuickSpec.spec() and not a more general context (i.e. an XCTestCase test)")
|
||||
}
|
||||
let group = ExampleGroup(description: description, flags: flags)
|
||||
currentExampleGroup.appendExampleGroup(group)
|
||||
performWithCurrentExampleGroup(group, closure: closure)
|
||||
}
|
||||
|
||||
internal func context(_ description: String, flags: FilterFlags, closure: () -> Void) {
|
||||
guard currentExampleMetadata == nil else {
|
||||
raiseError("'context' cannot be used inside '\(currentPhase)', 'context' may only be used inside 'context' or 'describe'. ")
|
||||
}
|
||||
self.describe(description, flags: flags, closure: closure)
|
||||
}
|
||||
|
||||
internal func fdescribe(_ description: String, flags: FilterFlags, closure: () -> Void) {
|
||||
var focusedFlags = flags
|
||||
focusedFlags[Filter.focused] = true
|
||||
self.describe(description, flags: focusedFlags, closure: closure)
|
||||
}
|
||||
|
||||
internal func xdescribe(_ description: String, flags: FilterFlags, closure: () -> Void) {
|
||||
var pendingFlags = flags
|
||||
pendingFlags[Filter.pending] = true
|
||||
self.describe(description, flags: pendingFlags, closure: closure)
|
||||
}
|
||||
|
||||
internal func beforeEach(_ closure: @escaping BeforeExampleClosure) {
|
||||
guard currentExampleMetadata == nil else {
|
||||
raiseError("'beforeEach' cannot be used inside '\(currentPhase)', 'beforeEach' may only be used inside 'context' or 'describe'. ")
|
||||
}
|
||||
currentExampleGroup.hooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objc(beforeEachWithMetadata:)
|
||||
internal func beforeEach(closure: @escaping BeforeExampleWithMetadataClosure) {
|
||||
currentExampleGroup.hooks.appendBefore(closure)
|
||||
}
|
||||
#else
|
||||
internal func beforeEach(closure: @escaping BeforeExampleWithMetadataClosure) {
|
||||
currentExampleGroup.hooks.appendBefore(closure)
|
||||
}
|
||||
#endif
|
||||
|
||||
internal func afterEach(_ closure: @escaping AfterExampleClosure) {
|
||||
guard currentExampleMetadata == nil else {
|
||||
raiseError("'afterEach' cannot be used inside '\(currentPhase)', 'afterEach' may only be used inside 'context' or 'describe'. ")
|
||||
}
|
||||
currentExampleGroup.hooks.appendAfter(closure)
|
||||
}
|
||||
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objc(afterEachWithMetadata:)
|
||||
internal func afterEach(closure: @escaping AfterExampleWithMetadataClosure) {
|
||||
currentExampleGroup.hooks.appendAfter(closure)
|
||||
}
|
||||
#else
|
||||
internal func afterEach(closure: @escaping AfterExampleWithMetadataClosure) {
|
||||
currentExampleGroup.hooks.appendAfter(closure)
|
||||
}
|
||||
#endif
|
||||
|
||||
internal func it(_ description: String, flags: FilterFlags, file: String, line: UInt, closure: @escaping () -> Void) {
|
||||
if beforesCurrentlyExecuting {
|
||||
raiseError("'it' cannot be used inside 'beforeEach', 'it' may only be used inside 'context' or 'describe'. ")
|
||||
}
|
||||
if aftersCurrentlyExecuting {
|
||||
raiseError("'it' cannot be used inside 'afterEach', 'it' may only be used inside 'context' or 'describe'. ")
|
||||
}
|
||||
guard currentExampleMetadata == nil else {
|
||||
raiseError("'it' cannot be used inside 'it', 'it' may only be used inside 'context' or 'describe'. ")
|
||||
}
|
||||
let callsite = Callsite(file: file, line: line)
|
||||
let example = Example(description: description, callsite: callsite, flags: flags, closure: closure)
|
||||
currentExampleGroup.appendExample(example)
|
||||
}
|
||||
|
||||
internal func fit(_ description: String, flags: FilterFlags, file: String, line: UInt, closure: @escaping () -> Void) {
|
||||
var focusedFlags = flags
|
||||
focusedFlags[Filter.focused] = true
|
||||
self.it(description, flags: focusedFlags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
internal func xit(_ description: String, flags: FilterFlags, file: String, line: UInt, closure: @escaping () -> Void) {
|
||||
var pendingFlags = flags
|
||||
pendingFlags[Filter.pending] = true
|
||||
self.it(description, flags: pendingFlags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
internal func itBehavesLike(_ name: String, sharedExampleContext: @escaping SharedExampleContext, flags: FilterFlags, file: String, line: UInt) {
|
||||
guard currentExampleMetadata == nil else {
|
||||
raiseError("'itBehavesLike' cannot be used inside '\(currentPhase)', 'itBehavesLike' may only be used inside 'context' or 'describe'. ")
|
||||
}
|
||||
let callsite = Callsite(file: file, line: line)
|
||||
let closure = World.sharedWorld.sharedExample(name)
|
||||
|
||||
let group = ExampleGroup(description: name, flags: flags)
|
||||
currentExampleGroup.appendExampleGroup(group)
|
||||
performWithCurrentExampleGroup(group) {
|
||||
closure(sharedExampleContext)
|
||||
}
|
||||
|
||||
group.walkDownExamples { (example: Example) in
|
||||
example.isSharedExample = true
|
||||
example.callsite = callsite
|
||||
}
|
||||
}
|
||||
|
||||
internal func fitBehavesLike(_ name: String, sharedExampleContext: @escaping SharedExampleContext, flags: FilterFlags, file: String, line: UInt) {
|
||||
var focusedFlags = flags
|
||||
focusedFlags[Filter.focused] = true
|
||||
self.itBehavesLike(name, sharedExampleContext: sharedExampleContext, flags: focusedFlags, file: file, line: line)
|
||||
}
|
||||
|
||||
internal func itBehavesLike<C>(_ behavior: Behavior<C>.Type, context: @escaping () -> C, flags: FilterFlags, file: String, line: UInt) {
|
||||
guard currentExampleMetadata == nil else {
|
||||
raiseError("'itBehavesLike' cannot be used inside '\(currentPhase)', 'itBehavesLike' may only be used inside 'context' or 'describe'. ")
|
||||
}
|
||||
let callsite = Callsite(file: file, line: line)
|
||||
let closure = behavior.spec
|
||||
let group = ExampleGroup(description: behavior.name, flags: flags)
|
||||
currentExampleGroup.appendExampleGroup(group)
|
||||
performWithCurrentExampleGroup(group) {
|
||||
closure(context)
|
||||
}
|
||||
|
||||
group.walkDownExamples { (example: Example) in
|
||||
example.isSharedExample = true
|
||||
example.callsite = callsite
|
||||
}
|
||||
}
|
||||
|
||||
internal func fitBehavesLike<C>(_ behavior: Behavior<C>.Type, context: @escaping () -> C, flags: FilterFlags, file: String, line: UInt) {
|
||||
var focusedFlags = flags
|
||||
focusedFlags[Filter.focused] = true
|
||||
self.itBehavesLike(behavior, context: context, flags: focusedFlags, file: file, line: line)
|
||||
}
|
||||
|
||||
internal func xitBehavesLike<C>(_ behavior: Behavior<C>.Type, context: @escaping () -> C, flags: FilterFlags, file: String, line: UInt) {
|
||||
var pendingFlags = flags
|
||||
pendingFlags[Filter.pending] = true
|
||||
self.itBehavesLike(behavior, context: context, flags: pendingFlags, file: file, line: line)
|
||||
}
|
||||
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objc(itWithDescription:flags:file:line:closure:)
|
||||
private func objc_it(_ description: String, flags: FilterFlags, file: String, line: UInt, closure: @escaping () -> Void) {
|
||||
it(description, flags: flags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
@objc(fitWithDescription:flags:file:line:closure:)
|
||||
private func objc_fit(_ description: String, flags: FilterFlags, file: String, line: UInt, closure: @escaping () -> Void) {
|
||||
fit(description, flags: flags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
@objc(xitWithDescription:flags:file:line:closure:)
|
||||
private func objc_xit(_ description: String, flags: FilterFlags, file: String, line: UInt, closure: @escaping () -> Void) {
|
||||
xit(description, flags: flags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
@objc(itBehavesLikeSharedExampleNamed:sharedExampleContext:flags:file:line:)
|
||||
private func objc_itBehavesLike(_ name: String, sharedExampleContext: @escaping SharedExampleContext, flags: FilterFlags, file: String, line: UInt) {
|
||||
itBehavesLike(name, sharedExampleContext: sharedExampleContext, flags: flags, file: file, line: line)
|
||||
}
|
||||
#endif
|
||||
|
||||
internal func pending(_ description: String, closure: () -> Void) {
|
||||
print("Pending: \(description)")
|
||||
}
|
||||
|
||||
private var currentPhase: String {
|
||||
if beforesCurrentlyExecuting {
|
||||
return "beforeEach"
|
||||
} else if aftersCurrentlyExecuting {
|
||||
return "afterEach"
|
||||
}
|
||||
|
||||
return "it"
|
||||
}
|
||||
}
|
||||
10
iOS/Example/Pods/Quick/Sources/Quick/ErrorUtility.swift
generated
Normal file
10
iOS/Example/Pods/Quick/Sources/Quick/ErrorUtility.swift
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
import Foundation
|
||||
|
||||
internal func raiseError(_ message: String) -> Never {
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
NSException(name: .internalInconsistencyException, reason: message, userInfo: nil).raise()
|
||||
#endif
|
||||
|
||||
// This won't be reached when ObjC is available and the exception above is raisd
|
||||
fatalError(message)
|
||||
}
|
||||
131
iOS/Example/Pods/Quick/Sources/Quick/Example.swift
generated
Normal file
131
iOS/Example/Pods/Quick/Sources/Quick/Example.swift
generated
Normal file
@@ -0,0 +1,131 @@
|
||||
import Foundation
|
||||
|
||||
private var numberOfExamplesRun = 0
|
||||
private var numberOfIncludedExamples = 0
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _ExampleBase: NSObject {}
|
||||
#else
|
||||
public class _ExampleBase: NSObject {}
|
||||
#endif
|
||||
#else
|
||||
public class _ExampleBase: NSObject {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
Examples, defined with the `it` function, use assertions to
|
||||
demonstrate how code should behave. These are like "tests" in XCTest.
|
||||
*/
|
||||
final public class Example: _ExampleBase {
|
||||
/**
|
||||
A boolean indicating whether the example is a shared example;
|
||||
i.e.: whether it is an example defined with `itBehavesLike`.
|
||||
*/
|
||||
public var isSharedExample = false
|
||||
|
||||
/**
|
||||
The site at which the example is defined.
|
||||
This must be set correctly in order for Xcode to highlight
|
||||
the correct line in red when reporting a failure.
|
||||
*/
|
||||
public var callsite: Callsite
|
||||
|
||||
weak internal var group: ExampleGroup?
|
||||
|
||||
private let internalDescription: String
|
||||
private let closure: () -> Void
|
||||
private let flags: FilterFlags
|
||||
|
||||
internal init(description: String, callsite: Callsite, flags: FilterFlags, closure: @escaping () -> Void) {
|
||||
self.internalDescription = description
|
||||
self.closure = closure
|
||||
self.callsite = callsite
|
||||
self.flags = flags
|
||||
}
|
||||
|
||||
public override var description: String {
|
||||
return internalDescription
|
||||
}
|
||||
|
||||
/**
|
||||
The example name. A name is a concatenation of the name of
|
||||
the example group the example belongs to, followed by the
|
||||
description of the example itself.
|
||||
|
||||
The example name is used to generate a test method selector
|
||||
to be displayed in Xcode's test navigator.
|
||||
*/
|
||||
public var name: String {
|
||||
guard let groupName = group?.name else { return description }
|
||||
return "\(groupName), \(description)"
|
||||
}
|
||||
|
||||
/**
|
||||
Executes the example closure, as well as all before and after
|
||||
closures defined in the its surrounding example groups.
|
||||
*/
|
||||
public func run() {
|
||||
let world = World.sharedWorld
|
||||
|
||||
if numberOfIncludedExamples == 0 {
|
||||
numberOfIncludedExamples = world.includedExampleCount
|
||||
}
|
||||
|
||||
if numberOfExamplesRun == 0 {
|
||||
world.suiteHooks.executeBefores()
|
||||
}
|
||||
|
||||
let exampleMetadata = ExampleMetadata(example: self, exampleIndex: numberOfExamplesRun)
|
||||
world.currentExampleMetadata = exampleMetadata
|
||||
|
||||
world.exampleHooks.executeBefores(exampleMetadata)
|
||||
group!.phase = .beforesExecuting
|
||||
for before in group!.befores {
|
||||
before(exampleMetadata)
|
||||
}
|
||||
group!.phase = .beforesFinished
|
||||
|
||||
closure()
|
||||
|
||||
group!.phase = .aftersExecuting
|
||||
for after in group!.afters {
|
||||
after(exampleMetadata)
|
||||
}
|
||||
group!.phase = .aftersFinished
|
||||
world.exampleHooks.executeAfters(exampleMetadata)
|
||||
|
||||
numberOfExamplesRun += 1
|
||||
|
||||
if !world.isRunningAdditionalSuites && numberOfExamplesRun >= numberOfIncludedExamples {
|
||||
world.suiteHooks.executeAfters()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Evaluates the filter flags set on this example and on the example groups
|
||||
this example belongs to. Flags set on the example are trumped by flags on
|
||||
the example group it belongs to. Flags on inner example groups are trumped
|
||||
by flags on outer example groups.
|
||||
*/
|
||||
internal var filterFlags: FilterFlags {
|
||||
var aggregateFlags = flags
|
||||
for (key, value) in group!.filterFlags {
|
||||
aggregateFlags[key] = value
|
||||
}
|
||||
return aggregateFlags
|
||||
}
|
||||
}
|
||||
|
||||
extension Example {
|
||||
/**
|
||||
Returns a boolean indicating whether two Example objects are equal.
|
||||
If two examples are defined at the exact same callsite, they must be equal.
|
||||
*/
|
||||
@nonobjc public static func == (lhs: Example, rhs: Example) -> Bool {
|
||||
return lhs.callsite == rhs.callsite
|
||||
}
|
||||
}
|
||||
99
iOS/Example/Pods/Quick/Sources/Quick/ExampleGroup.swift
generated
Normal file
99
iOS/Example/Pods/Quick/Sources/Quick/ExampleGroup.swift
generated
Normal file
@@ -0,0 +1,99 @@
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Example groups are logical groupings of examples, defined with
|
||||
the `describe` and `context` functions. Example groups can share
|
||||
setup and teardown code.
|
||||
*/
|
||||
final public class ExampleGroup: NSObject {
|
||||
weak internal var parent: ExampleGroup?
|
||||
internal let hooks = ExampleHooks()
|
||||
|
||||
internal var phase: HooksPhase = .nothingExecuted
|
||||
|
||||
private let internalDescription: String
|
||||
private let flags: FilterFlags
|
||||
private let isInternalRootExampleGroup: Bool
|
||||
private var childGroups = [ExampleGroup]()
|
||||
private var childExamples = [Example]()
|
||||
|
||||
internal init(description: String, flags: FilterFlags, isInternalRootExampleGroup: Bool = false) {
|
||||
self.internalDescription = description
|
||||
self.flags = flags
|
||||
self.isInternalRootExampleGroup = isInternalRootExampleGroup
|
||||
}
|
||||
|
||||
public override var description: String {
|
||||
return internalDescription
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a list of examples that belong to this example group,
|
||||
or to any of its descendant example groups.
|
||||
*/
|
||||
public var examples: [Example] {
|
||||
return childExamples + childGroups.flatMap { $0.examples }
|
||||
}
|
||||
|
||||
internal var name: String? {
|
||||
guard let parent = parent else {
|
||||
return isInternalRootExampleGroup ? nil : description
|
||||
}
|
||||
|
||||
guard let name = parent.name else { return description }
|
||||
return "\(name), \(description)"
|
||||
}
|
||||
|
||||
internal var filterFlags: FilterFlags {
|
||||
var aggregateFlags = flags
|
||||
walkUp { group in
|
||||
for (key, value) in group.flags {
|
||||
aggregateFlags[key] = value
|
||||
}
|
||||
}
|
||||
return aggregateFlags
|
||||
}
|
||||
|
||||
internal var befores: [BeforeExampleWithMetadataClosure] {
|
||||
var closures = Array(hooks.befores.reversed())
|
||||
walkUp { group in
|
||||
closures.append(contentsOf: Array(group.hooks.befores.reversed()))
|
||||
}
|
||||
return Array(closures.reversed())
|
||||
}
|
||||
|
||||
internal var afters: [AfterExampleWithMetadataClosure] {
|
||||
var closures = hooks.afters
|
||||
walkUp { group in
|
||||
closures.append(contentsOf: group.hooks.afters)
|
||||
}
|
||||
return closures
|
||||
}
|
||||
|
||||
internal func walkDownExamples(_ callback: (_ example: Example) -> Void) {
|
||||
for example in childExamples {
|
||||
callback(example)
|
||||
}
|
||||
for group in childGroups {
|
||||
group.walkDownExamples(callback)
|
||||
}
|
||||
}
|
||||
|
||||
internal func appendExampleGroup(_ group: ExampleGroup) {
|
||||
group.parent = self
|
||||
childGroups.append(group)
|
||||
}
|
||||
|
||||
internal func appendExample(_ example: Example) {
|
||||
example.group = self
|
||||
childExamples.append(example)
|
||||
}
|
||||
|
||||
private func walkUp(_ callback: (_ group: ExampleGroup) -> Void) {
|
||||
var group = self
|
||||
while let parent = group.parent {
|
||||
callback(parent)
|
||||
group = parent
|
||||
}
|
||||
}
|
||||
}
|
||||
37
iOS/Example/Pods/Quick/Sources/Quick/ExampleMetadata.swift
generated
Normal file
37
iOS/Example/Pods/Quick/Sources/Quick/ExampleMetadata.swift
generated
Normal file
@@ -0,0 +1,37 @@
|
||||
import Foundation
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _ExampleMetadataBase: NSObject {}
|
||||
#else
|
||||
public class _ExampleMetadataBase: NSObject {}
|
||||
#endif
|
||||
#else
|
||||
public class _ExampleMetadataBase: NSObject {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
A class that encapsulates information about an example,
|
||||
including the index at which the example was executed, as
|
||||
well as the example itself.
|
||||
*/
|
||||
final public class ExampleMetadata: _ExampleMetadataBase {
|
||||
/**
|
||||
The example for which this metadata was collected.
|
||||
*/
|
||||
public let example: Example
|
||||
|
||||
/**
|
||||
The index at which this example was executed in the
|
||||
test suite.
|
||||
*/
|
||||
public let exampleIndex: Int
|
||||
|
||||
internal init(example: Example, exampleIndex: Int) {
|
||||
self.example = example
|
||||
self.exampleIndex = exampleIndex
|
||||
}
|
||||
}
|
||||
44
iOS/Example/Pods/Quick/Sources/Quick/Filter.swift
generated
Normal file
44
iOS/Example/Pods/Quick/Sources/Quick/Filter.swift
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
import Foundation
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _FilterBase: NSObject {}
|
||||
#else
|
||||
public class _FilterBase: NSObject {}
|
||||
#endif
|
||||
#else
|
||||
public class _FilterBase: NSObject {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
A mapping of string keys to booleans that can be used to
|
||||
filter examples or example groups. For example, a "focused"
|
||||
example would have the flags [Focused: true].
|
||||
*/
|
||||
public typealias FilterFlags = [String: Bool]
|
||||
|
||||
/**
|
||||
A namespace for filter flag keys, defined primarily to make the
|
||||
keys available in Objective-C.
|
||||
*/
|
||||
final public class Filter: _FilterBase {
|
||||
/**
|
||||
Example and example groups with [Focused: true] are included in test runs,
|
||||
excluding all other examples without this flag. Use this to only run one or
|
||||
two tests that you're currently focusing on.
|
||||
*/
|
||||
public class var focused: String {
|
||||
return "focused"
|
||||
}
|
||||
|
||||
/**
|
||||
Example and example groups with [Pending: true] are excluded from test runs.
|
||||
Use this to temporarily suspend examples that you know do not pass yet.
|
||||
*/
|
||||
public class var pending: String {
|
||||
return "pending"
|
||||
}
|
||||
}
|
||||
35
iOS/Example/Pods/Quick/Sources/Quick/Hooks/Closures.swift
generated
Normal file
35
iOS/Example/Pods/Quick/Sources/Quick/Hooks/Closures.swift
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
// MARK: Example Hooks
|
||||
|
||||
/**
|
||||
A closure executed before an example is run.
|
||||
*/
|
||||
public typealias BeforeExampleClosure = () -> Void
|
||||
|
||||
/**
|
||||
A closure executed before an example is run. The closure is given example metadata,
|
||||
which contains information about the example that is about to be run.
|
||||
*/
|
||||
public typealias BeforeExampleWithMetadataClosure = (_ exampleMetadata: ExampleMetadata) -> Void
|
||||
|
||||
/**
|
||||
A closure executed after an example is run.
|
||||
*/
|
||||
public typealias AfterExampleClosure = BeforeExampleClosure
|
||||
|
||||
/**
|
||||
A closure executed after an example is run. The closure is given example metadata,
|
||||
which contains information about the example that has just finished running.
|
||||
*/
|
||||
public typealias AfterExampleWithMetadataClosure = BeforeExampleWithMetadataClosure
|
||||
|
||||
// MARK: Suite Hooks
|
||||
|
||||
/**
|
||||
A closure executed before any examples are run.
|
||||
*/
|
||||
public typealias BeforeSuiteClosure = () -> Void
|
||||
|
||||
/**
|
||||
A closure executed after all examples have finished running.
|
||||
*/
|
||||
public typealias AfterSuiteClosure = BeforeSuiteClosure
|
||||
42
iOS/Example/Pods/Quick/Sources/Quick/Hooks/ExampleHooks.swift
generated
Normal file
42
iOS/Example/Pods/Quick/Sources/Quick/Hooks/ExampleHooks.swift
generated
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
A container for closures to be executed before and after each example.
|
||||
*/
|
||||
final internal class ExampleHooks {
|
||||
internal var befores: [BeforeExampleWithMetadataClosure] = []
|
||||
internal var afters: [AfterExampleWithMetadataClosure] = []
|
||||
internal var phase: HooksPhase = .nothingExecuted
|
||||
|
||||
internal func appendBefore(_ closure: @escaping BeforeExampleWithMetadataClosure) {
|
||||
befores.append(closure)
|
||||
}
|
||||
|
||||
internal func appendBefore(_ closure: @escaping BeforeExampleClosure) {
|
||||
befores.append { (_: ExampleMetadata) in closure() }
|
||||
}
|
||||
|
||||
internal func appendAfter(_ closure: @escaping AfterExampleWithMetadataClosure) {
|
||||
afters.append(closure)
|
||||
}
|
||||
|
||||
internal func appendAfter(_ closure: @escaping AfterExampleClosure) {
|
||||
afters.append { (_: ExampleMetadata) in closure() }
|
||||
}
|
||||
|
||||
internal func executeBefores(_ exampleMetadata: ExampleMetadata) {
|
||||
phase = .beforesExecuting
|
||||
for before in befores {
|
||||
before(exampleMetadata)
|
||||
}
|
||||
|
||||
phase = .beforesFinished
|
||||
}
|
||||
|
||||
internal func executeAfters(_ exampleMetadata: ExampleMetadata) {
|
||||
phase = .aftersExecuting
|
||||
for after in afters {
|
||||
after(exampleMetadata)
|
||||
}
|
||||
|
||||
phase = .aftersFinished
|
||||
}
|
||||
}
|
||||
11
iOS/Example/Pods/Quick/Sources/Quick/Hooks/HooksPhase.swift
generated
Normal file
11
iOS/Example/Pods/Quick/Sources/Quick/Hooks/HooksPhase.swift
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
A description of the execution cycle of the current example with
|
||||
respect to the hooks of that example.
|
||||
*/
|
||||
internal enum HooksPhase {
|
||||
case nothingExecuted
|
||||
case beforesExecuting
|
||||
case beforesFinished
|
||||
case aftersExecuting
|
||||
case aftersFinished
|
||||
}
|
||||
32
iOS/Example/Pods/Quick/Sources/Quick/Hooks/SuiteHooks.swift
generated
Normal file
32
iOS/Example/Pods/Quick/Sources/Quick/Hooks/SuiteHooks.swift
generated
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
A container for closures to be executed before and after all examples.
|
||||
*/
|
||||
final internal class SuiteHooks {
|
||||
internal var befores: [BeforeSuiteClosure] = []
|
||||
internal var afters: [AfterSuiteClosure] = []
|
||||
internal var phase: HooksPhase = .nothingExecuted
|
||||
|
||||
internal func appendBefore(_ closure: @escaping BeforeSuiteClosure) {
|
||||
befores.append(closure)
|
||||
}
|
||||
|
||||
internal func appendAfter(_ closure: @escaping AfterSuiteClosure) {
|
||||
afters.append(closure)
|
||||
}
|
||||
|
||||
internal func executeBefores() {
|
||||
phase = .beforesExecuting
|
||||
for before in befores {
|
||||
before()
|
||||
}
|
||||
phase = .beforesFinished
|
||||
}
|
||||
|
||||
internal func executeAfters() {
|
||||
phase = .aftersExecuting
|
||||
for after in afters {
|
||||
after()
|
||||
}
|
||||
phase = .aftersFinished
|
||||
}
|
||||
}
|
||||
25
iOS/Example/Pods/Quick/Sources/Quick/NSBundle+CurrentTestBundle.swift
generated
Normal file
25
iOS/Example/Pods/Quick/Sources/Quick/NSBundle+CurrentTestBundle.swift
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Bundle {
|
||||
|
||||
/**
|
||||
Locates the first bundle with a '.xctest' file extension.
|
||||
*/
|
||||
internal static var currentTestBundle: Bundle? {
|
||||
return allBundles.first { $0.bundlePath.hasSuffix(".xctest") }
|
||||
}
|
||||
|
||||
/**
|
||||
Return the module name of the bundle.
|
||||
Uses the bundle filename and transform it to match Xcode's transformation.
|
||||
Module name has to be a valid "C99 extended identifier".
|
||||
*/
|
||||
internal var moduleName: String {
|
||||
let fileName = bundleURL.fileName as NSString
|
||||
return fileName.c99ExtendedIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
33
iOS/Example/Pods/Quick/Sources/Quick/NSString+C99ExtendedIdentifier.swift
generated
Normal file
33
iOS/Example/Pods/Quick/Sources/Quick/NSString+C99ExtendedIdentifier.swift
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
import Foundation
|
||||
|
||||
public extension NSString {
|
||||
|
||||
private static var invalidCharacters: CharacterSet = {
|
||||
var invalidCharacters = CharacterSet()
|
||||
|
||||
let invalidCharacterSets: [CharacterSet] = [
|
||||
.whitespacesAndNewlines,
|
||||
.illegalCharacters,
|
||||
.controlCharacters,
|
||||
.punctuationCharacters,
|
||||
.nonBaseCharacters,
|
||||
.symbols
|
||||
]
|
||||
|
||||
for invalidSet in invalidCharacterSets {
|
||||
invalidCharacters.formUnion(invalidSet)
|
||||
}
|
||||
|
||||
return invalidCharacters
|
||||
}()
|
||||
|
||||
@objc(qck_c99ExtendedIdentifier)
|
||||
var c99ExtendedIdentifier: String {
|
||||
let validComponents = components(separatedBy: NSString.invalidCharacters)
|
||||
let result = validComponents.joined(separator: "_")
|
||||
|
||||
return result.isEmpty ? "_" : result
|
||||
}
|
||||
}
|
||||
#endif
|
||||
74
iOS/Example/Pods/Quick/Sources/Quick/QuickSelectedTestSuiteBuilder.swift
generated
Normal file
74
iOS/Example/Pods/Quick/Sources/Quick/QuickSelectedTestSuiteBuilder.swift
generated
Normal file
@@ -0,0 +1,74 @@
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
Responsible for building a "Selected tests" suite. This corresponds to a single
|
||||
spec, and all its examples.
|
||||
*/
|
||||
internal class QuickSelectedTestSuiteBuilder: QuickTestSuiteBuilder {
|
||||
|
||||
/**
|
||||
The test spec class to run.
|
||||
*/
|
||||
let testCaseClass: AnyClass!
|
||||
|
||||
/**
|
||||
For Objective-C classes, returns the class name. For Swift classes without,
|
||||
an explicit Objective-C name, returns a module-namespaced class name
|
||||
(e.g., "FooTests.FooSpec").
|
||||
*/
|
||||
var testSuiteClassName: String {
|
||||
return NSStringFromClass(testCaseClass)
|
||||
}
|
||||
|
||||
/**
|
||||
Given a test case name:
|
||||
|
||||
FooSpec/testFoo
|
||||
|
||||
Optionally constructs a test suite builder for the named test case class
|
||||
in the running test bundle.
|
||||
|
||||
If no test bundle can be found, or the test case class can't be found,
|
||||
initialization fails and returns `nil`.
|
||||
*/
|
||||
init?(forTestCaseWithName name: String) {
|
||||
guard let testCaseClass = testCaseClassForTestCaseWithName(name) else {
|
||||
self.testCaseClass = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
self.testCaseClass = testCaseClass
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a `QuickTestSuite` that runs the associated test case class.
|
||||
*/
|
||||
func buildTestSuite() -> QuickTestSuite {
|
||||
return QuickTestSuite(forTestCaseClass: testCaseClass)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Searches `Bundle.allBundles()` for an xctest bundle, then looks up the named
|
||||
test case class in that bundle.
|
||||
|
||||
Returns `nil` if a bundle or test case class cannot be found.
|
||||
*/
|
||||
private func testCaseClassForTestCaseWithName(_ name: String) -> AnyClass? {
|
||||
func extractClassName(_ name: String) -> String? {
|
||||
return name.components(separatedBy: "/").first
|
||||
}
|
||||
|
||||
guard let className = extractClassName(name) else { return nil }
|
||||
guard let bundle = Bundle.currentTestBundle else { return nil }
|
||||
|
||||
if let testCaseClass = bundle.classNamed(className) { return testCaseClass }
|
||||
|
||||
let moduleName = bundle.moduleName
|
||||
|
||||
return NSClassFromString("\(moduleName).\(className)")
|
||||
}
|
||||
|
||||
#endif
|
||||
52
iOS/Example/Pods/Quick/Sources/Quick/QuickTestSuite.swift
generated
Normal file
52
iOS/Example/Pods/Quick/Sources/Quick/QuickTestSuite.swift
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
|
||||
import XCTest
|
||||
|
||||
/**
|
||||
This protocol defines the role of an object that builds test suites.
|
||||
*/
|
||||
internal protocol QuickTestSuiteBuilder {
|
||||
|
||||
/**
|
||||
Construct a `QuickTestSuite` instance with the appropriate test cases added as tests.
|
||||
|
||||
Subsequent calls to this method should return equivalent test suites.
|
||||
*/
|
||||
func buildTestSuite() -> QuickTestSuite
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
A base class for a class cluster of Quick test suites, that should correctly
|
||||
build dynamic test suites for XCTest to execute.
|
||||
*/
|
||||
public class QuickTestSuite: XCTestSuite {
|
||||
|
||||
private static var builtTestSuites: Set<String> = Set()
|
||||
|
||||
/**
|
||||
Construct a test suite for a specific, selected subset of test cases (rather
|
||||
than the default, which as all test cases).
|
||||
|
||||
If this method is called multiple times for the same test case class, e.g..
|
||||
|
||||
FooSpec/testFoo
|
||||
FooSpec/testBar
|
||||
|
||||
It is expected that the first call should return a valid test suite, and
|
||||
all subsequent calls should return `nil`.
|
||||
*/
|
||||
@objc
|
||||
public static func selectedTestSuite(forTestCaseWithName name: String) -> QuickTestSuite? {
|
||||
guard let builder = QuickSelectedTestSuiteBuilder(forTestCaseWithName: name) else { return nil }
|
||||
|
||||
let (inserted, _) = builtTestSuites.insert(builder.testSuiteClassName)
|
||||
if inserted {
|
||||
return builder.buildTestSuite()
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
12
iOS/Example/Pods/Quick/Sources/Quick/URL+FileName.swift
generated
Normal file
12
iOS/Example/Pods/Quick/Sources/Quick/URL+FileName.swift
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
import Foundation
|
||||
|
||||
extension URL {
|
||||
|
||||
/**
|
||||
Returns the path file name without file extension.
|
||||
*/
|
||||
var fileName: String {
|
||||
return self.deletingPathExtension().lastPathComponent
|
||||
}
|
||||
|
||||
}
|
||||
247
iOS/Example/Pods/Quick/Sources/Quick/World.swift
generated
Normal file
247
iOS/Example/Pods/Quick/Sources/Quick/World.swift
generated
Normal file
@@ -0,0 +1,247 @@
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
A closure that, when evaluated, returns a dictionary of key-value
|
||||
pairs that can be accessed from within a group of shared examples.
|
||||
*/
|
||||
public typealias SharedExampleContext = () -> [String: Any]
|
||||
|
||||
/**
|
||||
A closure that is used to define a group of shared examples. This
|
||||
closure may contain any number of example and example groups.
|
||||
*/
|
||||
public typealias SharedExampleClosure = (@escaping SharedExampleContext) -> Void
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
internal class _WorldBase: NSObject {}
|
||||
#else
|
||||
internal class _WorldBase: NSObject {}
|
||||
#endif
|
||||
#else
|
||||
internal class _WorldBase: NSObject {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
A collection of state Quick builds up in order to work its magic.
|
||||
World is primarily responsible for maintaining a mapping of QuickSpec
|
||||
classes to root example groups for those classes.
|
||||
|
||||
It also maintains a mapping of shared example names to shared
|
||||
example closures.
|
||||
|
||||
You may configure how Quick behaves by calling the -[World configure:]
|
||||
method from within an overridden +[QuickConfiguration configure:] method.
|
||||
*/
|
||||
final internal class World: _WorldBase {
|
||||
/**
|
||||
The example group that is currently being run.
|
||||
The DSL requires that this group is correctly set in order to build a
|
||||
correct hierarchy of example groups and their examples.
|
||||
*/
|
||||
internal var currentExampleGroup: ExampleGroup!
|
||||
|
||||
/**
|
||||
The example metadata of the test that is currently being run.
|
||||
This is useful for using the Quick test metadata (like its name) at
|
||||
runtime.
|
||||
*/
|
||||
|
||||
internal var currentExampleMetadata: ExampleMetadata?
|
||||
|
||||
/**
|
||||
A flag that indicates whether additional test suites are being run
|
||||
within this test suite. This is only true within the context of Quick
|
||||
functional tests.
|
||||
*/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
// Convention of generating Objective-C selector has been changed on Swift 3
|
||||
@objc(isRunningAdditionalSuites)
|
||||
internal var isRunningAdditionalSuites = false
|
||||
#else
|
||||
internal var isRunningAdditionalSuites = false
|
||||
#endif
|
||||
|
||||
private var specs: [String: ExampleGroup] = [:]
|
||||
private var sharedExamples: [String: SharedExampleClosure] = [:]
|
||||
private let configuration = Configuration()
|
||||
|
||||
internal private(set) var isConfigurationFinalized = false
|
||||
|
||||
internal var exampleHooks: ExampleHooks {return configuration.exampleHooks }
|
||||
internal var suiteHooks: SuiteHooks { return configuration.suiteHooks }
|
||||
|
||||
// MARK: Singleton Constructor
|
||||
|
||||
private override init() {}
|
||||
|
||||
static let sharedWorld = World()
|
||||
|
||||
// MARK: Public Interface
|
||||
|
||||
/**
|
||||
Exposes the World's Configuration object within the scope of the closure
|
||||
so that it may be configured. This method must not be called outside of
|
||||
an overridden +[QuickConfiguration configure:] method.
|
||||
|
||||
- parameter closure: A closure that takes a Configuration object that can
|
||||
be mutated to change Quick's behavior.
|
||||
*/
|
||||
internal func configure(_ closure: QuickConfigurer) {
|
||||
assert(!isConfigurationFinalized,
|
||||
"Quick cannot be configured outside of a +[QuickConfiguration configure:] method. You should not call -[World configure:] directly. Instead, subclass QuickConfiguration and override the +[QuickConfiguration configure:] method.")
|
||||
closure(configuration)
|
||||
}
|
||||
|
||||
/**
|
||||
Finalizes the World's configuration.
|
||||
Any subsequent calls to World.configure() will raise.
|
||||
*/
|
||||
internal func finalizeConfiguration() {
|
||||
isConfigurationFinalized = true
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an internally constructed root example group for the given
|
||||
QuickSpec class.
|
||||
|
||||
A root example group with the description "root example group" is lazily
|
||||
initialized for each QuickSpec class. This root example group wraps the
|
||||
top level of a -[QuickSpec spec] method--it's thanks to this group that
|
||||
users can define beforeEach and it closures at the top level, like so:
|
||||
|
||||
override func spec() {
|
||||
// These belong to the root example group
|
||||
beforeEach {}
|
||||
it("is at the top level") {}
|
||||
}
|
||||
|
||||
- parameter cls: The QuickSpec class for which to retrieve the root example group.
|
||||
- returns: The root example group for the class.
|
||||
*/
|
||||
internal func rootExampleGroupForSpecClass(_ cls: AnyClass) -> ExampleGroup {
|
||||
let name = String(describing: cls)
|
||||
|
||||
if let group = specs[name] {
|
||||
return group
|
||||
} else {
|
||||
let group = ExampleGroup(
|
||||
description: "root example group",
|
||||
flags: [:],
|
||||
isInternalRootExampleGroup: true
|
||||
)
|
||||
specs[name] = group
|
||||
return group
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all examples that should be run for a given spec class.
|
||||
There are two filtering passes that occur when determining which examples should be run.
|
||||
That is, these examples are the ones that are included by inclusion filters, and are
|
||||
not excluded by exclusion filters.
|
||||
|
||||
- parameter specClass: The QuickSpec subclass for which examples are to be returned.
|
||||
- returns: A list of examples to be run as test invocations.
|
||||
*/
|
||||
internal func examples(_ specClass: AnyClass) -> [Example] {
|
||||
// 1. Grab all included examples.
|
||||
let included = includedExamples
|
||||
// 2. Grab the intersection of (a) examples for this spec, and (b) included examples.
|
||||
let spec = rootExampleGroupForSpecClass(specClass).examples.filter { included.contains($0) }
|
||||
// 3. Remove all excluded examples.
|
||||
return spec.filter { example in
|
||||
!self.configuration.exclusionFilters.reduce(false) { $0 || $1(example) }
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
@objc(examplesForSpecClass:)
|
||||
private func objc_examples(_ specClass: AnyClass) -> [Example] {
|
||||
return examples(specClass)
|
||||
}
|
||||
#endif
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal func registerSharedExample(_ name: String, closure: @escaping SharedExampleClosure) {
|
||||
raiseIfSharedExampleAlreadyRegistered(name)
|
||||
sharedExamples[name] = closure
|
||||
}
|
||||
|
||||
internal func sharedExample(_ name: String) -> SharedExampleClosure {
|
||||
raiseIfSharedExampleNotRegistered(name)
|
||||
return sharedExamples[name]!
|
||||
}
|
||||
|
||||
internal var includedExampleCount: Int {
|
||||
return includedExamples.count
|
||||
}
|
||||
|
||||
internal var beforesCurrentlyExecuting: Bool {
|
||||
let suiteBeforesExecuting = suiteHooks.phase == .beforesExecuting
|
||||
let exampleBeforesExecuting = exampleHooks.phase == .beforesExecuting
|
||||
var groupBeforesExecuting = false
|
||||
if let runningExampleGroup = currentExampleMetadata?.example.group {
|
||||
groupBeforesExecuting = runningExampleGroup.phase == .beforesExecuting
|
||||
}
|
||||
|
||||
return suiteBeforesExecuting || exampleBeforesExecuting || groupBeforesExecuting
|
||||
}
|
||||
|
||||
internal var aftersCurrentlyExecuting: Bool {
|
||||
let suiteAftersExecuting = suiteHooks.phase == .aftersExecuting
|
||||
let exampleAftersExecuting = exampleHooks.phase == .aftersExecuting
|
||||
var groupAftersExecuting = false
|
||||
if let runningExampleGroup = currentExampleMetadata?.example.group {
|
||||
groupAftersExecuting = runningExampleGroup.phase == .aftersExecuting
|
||||
}
|
||||
|
||||
return suiteAftersExecuting || exampleAftersExecuting || groupAftersExecuting
|
||||
}
|
||||
|
||||
internal func performWithCurrentExampleGroup(_ group: ExampleGroup, closure: () -> Void) {
|
||||
let previousExampleGroup = currentExampleGroup
|
||||
currentExampleGroup = group
|
||||
|
||||
closure()
|
||||
|
||||
currentExampleGroup = previousExampleGroup
|
||||
}
|
||||
|
||||
private var allExamples: [Example] {
|
||||
var all: [Example] = []
|
||||
for (_, group) in specs {
|
||||
group.walkDownExamples { all.append($0) }
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
private var includedExamples: [Example] {
|
||||
let all = allExamples
|
||||
let included = all.filter { example in
|
||||
return self.configuration.inclusionFilters.reduce(false) { $0 || $1(example) }
|
||||
}
|
||||
|
||||
if included.isEmpty && configuration.runAllWhenEverythingFiltered {
|
||||
return all
|
||||
} else {
|
||||
return included
|
||||
}
|
||||
}
|
||||
|
||||
private func raiseIfSharedExampleAlreadyRegistered(_ name: String) {
|
||||
if sharedExamples[name] != nil {
|
||||
raiseError("A shared example named '\(name)' has already been registered.")
|
||||
}
|
||||
}
|
||||
|
||||
private func raiseIfSharedExampleNotRegistered(_ name: String) {
|
||||
if sharedExamples[name] == nil {
|
||||
raiseError("No shared example named '\(name)' has been registered. Registered shared examples: '\(Array(sharedExamples.keys))'")
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
55
iOS/Example/Pods/Quick/Sources/QuickSpecBase/QuickSpecBase.m
generated
Normal file
55
iOS/Example/Pods/Quick/Sources/QuickSpecBase/QuickSpecBase.m
generated
Normal file
@@ -0,0 +1,55 @@
|
||||
#import "QuickSpecBase.h"
|
||||
|
||||
#pragma mark - _QuickSelectorWrapper
|
||||
|
||||
@interface _QuickSelectorWrapper ()
|
||||
@property(nonatomic, assign) SEL selector;
|
||||
@end
|
||||
|
||||
@implementation _QuickSelectorWrapper
|
||||
|
||||
- (instancetype)initWithSelector:(SEL)selector {
|
||||
self = [super init];
|
||||
_selector = selector;
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - _QuickSpecBase
|
||||
|
||||
@implementation _QuickSpecBase
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super initWithInvocation: nil];
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
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<NSInvocation *> *)testInvocations {
|
||||
NSArray<_QuickSelectorWrapper *> *wrappers = [self _qck_testMethodSelectors];
|
||||
NSMutableArray<NSInvocation *> *invocations = [NSMutableArray arrayWithCapacity:wrappers.count];
|
||||
|
||||
for (_QuickSelectorWrapper *wrapper in wrappers) {
|
||||
SEL selector = wrapper.selector;
|
||||
NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector];
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||
invocation.selector = selector;
|
||||
|
||||
[invocations addObject:invocation];
|
||||
}
|
||||
|
||||
return invocations;
|
||||
}
|
||||
|
||||
+ (NSArray<_QuickSelectorWrapper *> *)_qck_testMethodSelectors {
|
||||
return @[];
|
||||
}
|
||||
|
||||
@end
|
||||
11
iOS/Example/Pods/Quick/Sources/QuickSpecBase/include/QuickSpecBase.h
generated
Normal file
11
iOS/Example/Pods/Quick/Sources/QuickSpecBase/include/QuickSpecBase.h
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
@interface _QuickSelectorWrapper : NSObject
|
||||
- (instancetype)initWithSelector:(SEL)selector;
|
||||
@end
|
||||
|
||||
@interface _QuickSpecBase : XCTestCase
|
||||
+ (NSArray<_QuickSelectorWrapper *> *)_qck_testMethodSelectors;
|
||||
- (instancetype)init NS_DESIGNATED_INITIALIZER;
|
||||
@end
|
||||
Reference in New Issue
Block a user