Add PromiseKit dependency

- Added PromiseKit dependency
This commit is contained in:
2018-11-15 22:08:00 -04:00
parent 2689d86c18
commit be7b6b5881
541 changed files with 46282 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
import PromiseKit
import Dispatch
import XCTest
enum Error: Swift.Error {
case dummy // we reject with this when we don't intend to test against it
case sentinel(UInt32)
}
private let timeout: TimeInterval = 10
extension XCTestCase {
func describe(_ description: String, file: StaticString = #file, line: UInt = #line, body: () throws -> Void) {
PromiseKit.conf.Q.map = .main
do {
try body()
} catch {
XCTFail(description, file: file, line: line)
}
}
func specify(_ description: String, file: StaticString = #file, line: UInt = #line, body: ((promise: Promise<Void>, fulfill: () -> Void, reject: (Error) -> Void), XCTestExpectation) throws -> Void) {
let expectation = self.expectation(description: description)
let (pending, seal) = Promise<Void>.pending()
do {
try body((pending, { seal.fulfill(()) }, seal.reject), expectation)
waitForExpectations(timeout: timeout) { err in
if let _ = err {
XCTFail("wait failed: \(description)", file: file, line: line)
}
}
} catch {
XCTFail(description, file: file, line: line)
}
}
func testFulfilled(file: StaticString = #file, line: UInt = #line, body: @escaping (Promise<UInt32>, XCTestExpectation, UInt32) -> Void) {
testFulfilled(withExpectationCount: 1, file: file, line: line) {
body($0, $1.first!, $2)
}
}
func testRejected(file: StaticString = #file, line: UInt = #line, body: @escaping (Promise<UInt32>, XCTestExpectation, UInt32) -> Void) {
testRejected(withExpectationCount: 1, file: file, line: line) {
body($0, $1.first!, $2)
}
}
func testFulfilled(withExpectationCount: Int, file: StaticString = #file, line: UInt = #line, body: @escaping (Promise<UInt32>, [XCTestExpectation], UInt32) -> Void) {
let specify = mkspecify(withExpectationCount, file: file, line: line, body: body)
specify("already-fulfilled") { value in
return (.value(value), {})
}
specify("immediately-fulfilled") { value in
let (promise, seal) = Promise<UInt32>.pending()
return (promise, {
seal.fulfill(value)
})
}
specify("eventually-fulfilled") { value in
let (promise, seal) = Promise<UInt32>.pending()
return (promise, {
after(ticks: 5) {
seal.fulfill(value)
}
})
}
}
func testRejected(withExpectationCount: Int, file: StaticString = #file, line: UInt = #line, body: @escaping (Promise<UInt32>, [XCTestExpectation], UInt32) -> Void) {
let specify = mkspecify(withExpectationCount, file: file, line: line, body: body)
specify("already-rejected") { sentinel in
return (Promise(error: Error.sentinel(sentinel)), {})
}
specify("immediately-rejected") { sentinel in
let (promise, seal) = Promise<UInt32>.pending()
return (promise, {
seal.reject(Error.sentinel(sentinel))
})
}
specify("eventually-rejected") { sentinel in
let (promise, seal) = Promise<UInt32>.pending()
return (promise, {
after(ticks: 50) {
seal.reject(Error.sentinel(sentinel))
}
})
}
}
/////////////////////////////////////////////////////////////////////////
private func mkspecify(_ numberOfExpectations: Int, file: StaticString, line: UInt, body: @escaping (Promise<UInt32>, [XCTestExpectation], UInt32) -> Void) -> (String, _ feed: (UInt32) -> (Promise<UInt32>, () -> Void)) -> Void {
return { desc, feed in
let value = arc4random()
let (promise, executeAfter) = feed(value)
let expectations = (1...numberOfExpectations).map {
self.expectation(description: "\(desc) (\($0))")
}
body(promise, expectations, value)
executeAfter()
self.waitForExpectations(timeout: timeout) { err in
if let _ = err {
XCTFail("timed out: \(desc)", file: file, line: line)
}
}
}
}
func mkex() -> XCTestExpectation {
return expectation(description: "")
}
}
func after(ticks: Int, execute body: @escaping () -> Void) {
precondition(ticks > 0)
var ticks = ticks
func f() {
DispatchQueue.main.async {
ticks -= 1
if ticks == 0 {
body()
} else {
f()
}
}
}
f()
}
extension Promise {
func test(onFulfilled: @escaping () -> Void, onRejected: @escaping () -> Void) {
tap { result in
switch result {
case .fulfilled:
onFulfilled()
case .rejected:
onRejected()
}
}.silenceWarning()
}
}
prefix func ++(a: inout Int) -> Int {
a += 1
return a
}
extension Promise {
func silenceWarning() {}
}
#if os(Linux)
import func Glibc.random
func arc4random() -> UInt32 {
return UInt32(random())
}
extension XCTestExpectation {
func fulfill() {
fulfill(#file, line: #line)
}
}
extension XCTestCase {
func wait(for: [XCTestExpectation], timeout: TimeInterval, file: StaticString = #file, line: UInt = #line) {
#if !(swift(>=4.0) && !swift(>=4.1))
let line = Int(line)
#endif
waitForExpectations(timeout: timeout, file: file, line: line)
}
}
#endif

View File

@@ -0,0 +1,26 @@
import PromiseKit
import XCTest
class Test212: XCTestCase {
func test() {
describe("2.1.2.1: When fulfilled, a promise: must not transition to any other state.") {
testFulfilled { promise, expectation, _ in
promise.test(onFulfilled: expectation.fulfill, onRejected: { XCTFail() })
}
specify("trying to fulfill then immediately reject") { d, expectation in
d.promise.test(onFulfilled: expectation.fulfill, onRejected: { XCTFail() })
d.fulfill()
d.reject(Error.dummy)
}
specify("trying to fulfill then reject, delayed") { d, expectation in
d.promise.test(onFulfilled: expectation.fulfill, onRejected: { XCTFail() })
after(ticks: 1) {
d.fulfill()
d.reject(Error.dummy)
}
}
}
}
}

View File

@@ -0,0 +1,34 @@
import PromiseKit
import XCTest
class Test213: XCTestCase {
func test() {
describe("2.1.3.1: When rejected, a promise: must not transition to any other state.") {
testRejected { promise, expectation, _ in
promise.test(onFulfilled: { XCTFail() }, onRejected: expectation.fulfill)
}
specify("trying to reject then immediately fulfill") { d, expectation in
d.promise.test(onFulfilled: { XCTFail() }, onRejected: expectation.fulfill)
d.reject(Error.dummy)
d.fulfill()
}
specify("trying to reject then fulfill, delayed") { d, expectation in
d.promise.test(onFulfilled: { XCTFail() }, onRejected: expectation.fulfill)
after(ticks: 1) {
d.reject(Error.dummy)
d.fulfill()
}
}
specify("trying to reject immediately then fulfill delayed") { d, expectation in
d.promise.test(onFulfilled: { XCTFail() }, onRejected: expectation.fulfill)
d.reject(Error.dummy)
after(ticks: 1) {
d.fulfill()
}
}
}
}
}

View File

@@ -0,0 +1,92 @@
import PromiseKit
import XCTest
class Test222: XCTestCase {
func test() {
describe("2.2.2: If `onFulfilled` is a function,") {
describe("2.2.2.1: it must be called after `promise` is fulfilled, with `promise`s fulfillment value as its first argument.") {
testFulfilled { promise, expectation, sentinel in
promise.done {
XCTAssertEqual(sentinel, $0)
expectation.fulfill()
}.silenceWarning()
}
}
describe("2.2.2.2: it must not be called before `promise` is fulfilled") {
specify("fulfilled after a delay") { d, expectation in
var called = false
d.promise.done {
called = true
expectation.fulfill()
}.silenceWarning()
after(ticks: 5) {
XCTAssertFalse(called)
d.fulfill()
}
}
specify("never fulfilled") { d, expectation in
d.promise.done{ XCTFail() }.silenceWarning()
after(ticks: 1000, execute: expectation.fulfill)
}
}
describe("2.2.2.3: it must not be called more than once.") {
specify("already-fulfilled") { _, expectation in
let ex = (expectation, mkex())
Promise().done {
ex.0.fulfill()
}.silenceWarning()
after(ticks: 1000) {
ex.1.fulfill()
}
}
specify("trying to fulfill a pending promise more than once, immediately") { d, expectation in
d.promise.done(expectation.fulfill).silenceWarning()
d.fulfill()
d.fulfill()
}
specify("trying to fulfill a pending promise more than once, delayed") { d, expectation in
d.promise.done(expectation.fulfill).silenceWarning()
after(ticks: 5) {
d.fulfill()
d.fulfill()
}
}
specify("trying to fulfill a pending promise more than once, immediately then delayed") { d, expectation in
let ex = (expectation, mkex())
d.promise.done(ex.0.fulfill).silenceWarning()
d.fulfill()
after(ticks: 5) {
d.fulfill()
}
after(ticks: 10, execute: ex.1.fulfill)
}
specify("when multiple `then` calls are made, spaced apart in time") { d, expectation in
let ex = (expectation, self.expectation(description: ""), self.expectation(description: ""), self.expectation(description: ""))
do {
d.promise.done(ex.0.fulfill).silenceWarning()
}
after(ticks: 5) {
d.promise.done(ex.1.fulfill).silenceWarning()
}
after(ticks: 10) {
d.promise.done(ex.2.fulfill).silenceWarning()
}
after(ticks: 15) {
d.fulfill()
ex.3.fulfill()
}
}
specify("when `then` is interleaved with fulfillment") { d, expectation in
let ex = (expectation, self.expectation(description: ""), self)
d.promise.done(ex.0.fulfill).silenceWarning()
d.fulfill()
d.promise.done(ex.1.fulfill).silenceWarning()
}
}
}
}
}

View File

@@ -0,0 +1,93 @@
import PromiseKit
import XCTest
class Test223: XCTestCase {
func test() {
describe("2.2.3: If `onRejected` is a function,") {
describe("2.2.3.1: it must be called after `promise` is rejected, with `promise`s rejection reason as its first argument.") {
testRejected { promise, expectation, sentinel in
promise.catch { error in
if case Error.sentinel(let value) = error {
XCTAssertEqual(value, sentinel)
} else {
XCTFail()
}
expectation.fulfill()
}
}
}
describe("2.2.3.2: it must not be called before `promise` is rejected") {
specify("rejected after a delay") { d, expectation in
var called = false
d.promise.catch { _ in
called = true
expectation.fulfill()
}
after(ticks: 1) {
XCTAssertFalse(called)
d.reject(Error.dummy)
}
}
specify("never rejected") { d, expectation in
d.promise.catch { _ in XCTFail() }
after(ticks: 1, execute: expectation.fulfill)
}
}
describe("2.2.3.3: it must not be called more than once.") {
specify("already-rejected") { d, expectation in
var timesCalled = 0
Promise<Int>(error: Error.dummy).catch { _ in
XCTAssertEqual(++timesCalled, 1)
}
after(ticks: 2) {
XCTAssertEqual(timesCalled, 1)
expectation.fulfill()
}
}
specify("trying to reject a pending promise more than once, immediately") { d, expectation in
d.promise.catch{_ in expectation.fulfill() }
d.reject(Error.dummy)
d.reject(Error.dummy)
}
specify("trying to reject a pending promise more than once, delayed") { d, expectation in
d.promise.catch{_ in expectation.fulfill() }
after(ticks: 1) {
d.reject(Error.dummy)
d.reject(Error.dummy)
}
}
specify("trying to reject a pending promise more than once, immediately then delayed") { d, expectation in
d.promise.catch{_ in expectation.fulfill() }
d.reject(Error.dummy)
after(ticks: 1) {
d.reject(Error.dummy)
}
}
specify("when multiple `then` calls are made, spaced apart in time") { d, expectation in
let mk = { self.expectation(description: "") }
let ex = (expectation, mk(), mk(), mk())
do {
d.promise.catch{ _ in ex.0.fulfill() }
}
after(ticks: 1) {
d.promise.catch{ _ in ex.1.fulfill() }
}
after(ticks: 2) {
d.promise.catch{ _ in ex.2.fulfill() }
}
after(ticks: 3) {
d.reject(Error.dummy)
ex.3.fulfill()
}
}
specify("when `then` is interleaved with rejection") { d, expectation in
let ex = (expectation, self.expectation(description: ""))
d.promise.catch{ _ in ex.0.fulfill() }
d.reject(Error.dummy)
d.promise.catch{ _ in ex.1.fulfill() }
}
}
}
}
}

View File

@@ -0,0 +1,146 @@
import PromiseKit
import XCTest
class Test224: XCTestCase {
func test() {
describe("2.2.4: `onFulfilled` or `onRejected` must not be called until the execution context stack contains only platform code.") {
describe("`then` returns before the promise becomes fulfilled or rejected") {
testFulfilled { promise, expectation, dummy in
var thenHasReturned = false
promise.done { _ in
XCTAssert(thenHasReturned)
expectation.fulfill()
}.silenceWarning()
thenHasReturned = true
}
testRejected { promise, expectation, memo in
var catchHasReturned = false
promise.catch { _->() in
XCTAssert(catchHasReturned)
expectation.fulfill()
}
catchHasReturned = true
}
}
describe("Clean-stack execution ordering tests (fulfillment case)") {
specify("when `onFulfilled` is added immediately before the promise is fulfilled") { d, expectation in
var onFulfilledCalled = false
d.promise.done {
onFulfilledCalled = true
expectation.fulfill()
}.silenceWarning()
d.fulfill()
XCTAssertFalse(onFulfilledCalled)
}
specify("when `onFulfilled` is added immediately after the promise is fulfilled") { d, expectation in
var onFulfilledCalled = false
d.fulfill()
d.promise.done {
onFulfilledCalled = true
expectation.fulfill()
}.silenceWarning()
XCTAssertFalse(onFulfilledCalled)
}
specify("when one `onFulfilled` is added inside another `onFulfilled`") { _, expectation in
var firstOnFulfilledFinished = false
let promise = Promise()
promise.done {
promise.done {
XCTAssertTrue(firstOnFulfilledFinished)
expectation.fulfill()
}.silenceWarning()
firstOnFulfilledFinished = true
}.silenceWarning()
}
specify("when `onFulfilled` is added inside an `onRejected`") { _, expectation in
let promise1 = Promise<Void>(error: Error.dummy)
let promise2 = Promise()
var firstOnRejectedFinished = false
promise1.catch { _ in
promise2.done {
XCTAssertTrue(firstOnRejectedFinished)
expectation.fulfill()
}.silenceWarning()
firstOnRejectedFinished = true
}
}
specify("when the promise is fulfilled asynchronously") { d, expectation in
var firstStackFinished = false
after(ticks: 1) {
d.fulfill()
firstStackFinished = true
}
d.promise.done {
XCTAssertTrue(firstStackFinished)
expectation.fulfill()
}.silenceWarning()
}
}
describe("Clean-stack execution ordering tests (rejection case)") {
specify("when `onRejected` is added immediately before the promise is rejected") { d, expectation in
var onRejectedCalled = false
d.promise.catch { _ in
onRejectedCalled = true
expectation.fulfill()
}
d.reject(Error.dummy)
XCTAssertFalse(onRejectedCalled)
}
specify("when `onRejected` is added immediately after the promise is rejected") { d, expectation in
var onRejectedCalled = false
d.reject(Error.dummy)
d.promise.catch { _ in
onRejectedCalled = true
expectation.fulfill()
}
XCTAssertFalse(onRejectedCalled)
}
specify("when `onRejected` is added inside an `onFulfilled`") { d, expectation in
let promise1 = Promise()
let promise2 = Promise<Void>(error: Error.dummy)
var firstOnFulfilledFinished = false
promise1.done { _ in
promise2.catch { _ in
XCTAssertTrue(firstOnFulfilledFinished)
expectation.fulfill()
}
firstOnFulfilledFinished = true
}.silenceWarning()
}
specify("when one `onRejected` is added inside another `onRejected`") { d, expectation in
let promise = Promise<Void>(error: Error.dummy)
var firstOnRejectedFinished = false;
promise.catch { _ in
promise.catch { _ in
XCTAssertTrue(firstOnRejectedFinished)
expectation.fulfill()
}
firstOnRejectedFinished = true
}
}
specify("when the promise is rejected asynchronously") { d, expectation in
var firstStackFinished = false
after(ticks: 1) {
d.reject(Error.dummy)
firstStackFinished = true
}
d.promise.catch { _ in
XCTAssertTrue(firstStackFinished)
expectation.fulfill()
}
}
}
}
}
}

View File

@@ -0,0 +1,275 @@
import PromiseKit
import XCTest
class Test226: XCTestCase {
func test() {
describe("2.2.6: `then` may be called multiple times on the same promise.") {
describe("2.2.6.1: If/when `promise` is fulfilled, all respective `onFulfilled` callbacks must execute in the order of their originating calls to `then`.") {
describe("multiple boring fulfillment handlers") {
testFulfilled(withExpectationCount: 4) { promise, exes, sentinel -> () in
var orderValidator = 0
promise.done {
XCTAssertEqual($0, sentinel)
XCTAssertEqual(++orderValidator, 1)
exes[0].fulfill()
}.silenceWarning()
promise.catch { _ in XCTFail() }
promise.done {
XCTAssertEqual($0, sentinel)
XCTAssertEqual(++orderValidator, 2)
exes[1].fulfill()
}.silenceWarning()
promise.catch { _ in XCTFail() }
promise.done {
XCTAssertEqual($0, sentinel)
XCTAssertEqual(++orderValidator, 3)
exes[2].fulfill()
}.silenceWarning()
promise.catch { _ in XCTFail() }
promise.done {
XCTAssertEqual($0, sentinel)
XCTAssertEqual(++orderValidator, 4)
exes[3].fulfill()
}.silenceWarning()
}
}
describe("multiple fulfillment handlers, one of which throws") {
testFulfilled(withExpectationCount: 4) { promise, exes, sentinel in
var orderValidator = 0
promise.done {
XCTAssertEqual($0, sentinel)
XCTAssertEqual(++orderValidator, 1)
exes[0].fulfill()
}.silenceWarning()
promise.catch { _ in XCTFail() }
promise.done {
XCTAssertEqual($0, sentinel)
XCTAssertEqual(++orderValidator, 2)
exes[1].fulfill()
}.silenceWarning()
promise.catch { _ in XCTFail() }
promise.done {
XCTAssertEqual($0, sentinel)
XCTAssertEqual(++orderValidator, 3)
exes[2].fulfill()
throw Error.dummy
}.silenceWarning()
promise.catch { value in XCTFail() }
promise.done {
XCTAssertEqual($0, sentinel)
XCTAssertEqual(++orderValidator, 4)
exes[3].fulfill()
}.silenceWarning()
}
}
describe("results in multiple branching chains with their own fulfillment values") {
testFulfilled(withExpectationCount: 3) { promise, exes, memo in
let sentinel1 = 671
let sentinel2: UInt32 = 672
let sentinel3 = 673
promise.map { _ in
return sentinel1
}.done { value in
XCTAssertEqual(sentinel1, value)
exes[0].fulfill()
}.silenceWarning()
promise.done { _ in
throw Error.sentinel(sentinel2)
}.catch { err in
switch err {
case Error.sentinel(let err) where err == sentinel2:
break
default:
XCTFail()
}
exes[1].fulfill()
}
promise.map { _ in
sentinel3
}.done {
XCTAssertEqual($0, sentinel3)
exes[2].fulfill()
}.silenceWarning()
}
}
describe("`onFulfilled` handlers are called in the original order") {
testFulfilled(withExpectationCount: 3) { promise, exes, memo in
var orderValidator = 0
promise.done { _ in
XCTAssertEqual(++orderValidator, 1)
exes[0].fulfill()
}.silenceWarning()
promise.done { _ in
XCTAssertEqual(++orderValidator, 2)
exes[1].fulfill()
}.silenceWarning()
promise.done { _ in
XCTAssertEqual(++orderValidator, 3)
exes[2].fulfill()
}.silenceWarning()
}
}
describe("even when one handler is added inside another handler") {
testFulfilled(withExpectationCount: 3) { promise, exes, memo in
var x = 0
promise.done { _ in
XCTAssertEqual(x, 0)
x += 1
exes[0].fulfill()
promise.done { _ in
XCTAssertEqual(x, 2)
x += 1
exes[1].fulfill()
}.silenceWarning()
}.silenceWarning()
promise.done { _ in
XCTAssertEqual(x, 1)
x += 1
exes[2].fulfill()
}.silenceWarning()
}
}
}
describe("2.2.6.2: If/when `promise` is rejected, all respective `onRejected` callbacks must execute in the order of their originating calls to `then`.") {
describe("multiple boring rejection handlers") {
testRejected(withExpectationCount: 4) { promise, exes, sentinel in
var ticket = 0
promise.catch { err in
guard case Error.sentinel(let x) = err, x == sentinel else { return XCTFail() }
XCTAssertEqual(++ticket, 1)
exes[0].fulfill()
}
promise.done { _ in XCTFail() }.silenceWarning()
promise.catch { err in
guard case Error.sentinel(let x) = err, x == sentinel else { return XCTFail() }
XCTAssertEqual(++ticket, 2)
exes[1].fulfill()
}
promise.done { _ in XCTFail() }.silenceWarning()
promise.catch { err in
guard case Error.sentinel(let x) = err, x == sentinel else { return XCTFail() }
XCTAssertEqual(++ticket, 3)
exes[2].fulfill()
}
promise.done { _ in XCTFail() }.silenceWarning()
promise.catch { err in
guard case Error.sentinel(let x) = err, x == sentinel else { return XCTFail() }
XCTAssertEqual(++ticket, 4)
exes[3].fulfill()
}
}
}
describe("multiple rejection handlers, one of which throws") {
testRejected(withExpectationCount: 4) { promise, exes, sentinel in
var orderValidator = 0
promise.catch { err in
guard case Error.sentinel(let x) = err, x == sentinel else { return XCTFail() }
XCTAssertEqual(++orderValidator, 1)
exes[0].fulfill()
}
promise.done { _ in XCTFail() }.silenceWarning()
promise.catch { err in
guard case Error.sentinel(let x) = err, x == sentinel else { return XCTFail() }
XCTAssertEqual(++orderValidator, 2)
exes[1].fulfill()
}
promise.done { _ in XCTFail() }.silenceWarning()
promise.recover { err -> Promise<UInt32> in
if case Error.sentinel(let x) = err {
XCTAssertEqual(x, sentinel)
} else {
XCTFail()
}
XCTAssertEqual(++orderValidator, 3)
exes[2].fulfill()
throw Error.dummy
}.silenceWarning()
promise.done { _ in XCTFail() }.silenceWarning()
promise.catch { err in
guard case Error.sentinel(let x) = err, x == sentinel else { return XCTFail() }
XCTAssertEqual(++orderValidator, 4)
exes[3].fulfill()
}
}
}
describe("results in multiple branching chains with their own fulfillment values") {
testRejected(withExpectationCount: 3) { promise, exes, memo in
let sentinel1 = arc4random()
let sentinel2 = arc4random()
let sentinel3 = arc4random()
promise.recover { _ in
return .value(sentinel1)
}.done { value in
XCTAssertEqual(sentinel1, value)
exes[0].fulfill()
}
promise.recover { _ -> Promise<UInt32> in
throw Error.sentinel(sentinel2)
}.catch { err in
if case Error.sentinel(let x) = err, x == sentinel2 {
exes[1].fulfill()
}
}
promise.recover { _ in
.value(sentinel3)
}.done { value in
XCTAssertEqual(value, sentinel3)
exes[2].fulfill()
}
}
}
describe("`onRejected` handlers are called in the original order") {
testRejected(withExpectationCount: 3) { promise, exes, memo in
var x = 0
promise.catch { _ in
XCTAssertEqual(x, 0)
x += 1
exes[0].fulfill()
}
promise.catch { _ in
XCTAssertEqual(x, 1)
x += 1
exes[1].fulfill()
}
promise.catch { _ in
XCTAssertEqual(x, 2)
x += 1
exes[2].fulfill()
}
}
}
describe("even when one handler is added inside another handler") {
testRejected(withExpectationCount: 3) { promise, exes, memo in
var x = 0
promise.catch { _ in
XCTAssertEqual(x, 0)
x += 1
exes[0].fulfill()
promise.catch { _ in
XCTAssertEqual(x, 2)
x += 1
exes[1].fulfill()
}
}
promise.catch { _ in
XCTAssertEqual(x, 1)
x += 1
exes[2].fulfill()
}
}
}
}
}
}
}

View File

@@ -0,0 +1,33 @@
import PromiseKit
import XCTest
class Test227: XCTestCase {
func test() {
describe("2.2.7: `then` must return a promise: `promise2 = promise1.then(onFulfilled, onRejected)") {
describe("2.2.7.2: If either `onFulfilled` or `onRejected` throws an exception `e`, `promise2` must be rejected with `e` as the reason.") {
testFulfilled { promise1, expectation, _ in
let sentinel = arc4random()
let promise2 = promise1.done { _ in throw Error.sentinel(sentinel) }
promise2.catch {
if case Error.sentinel(let x) = $0, x == sentinel {
expectation.fulfill()
}
}
}
testRejected { promise1, expectation, _ in
let sentinel = arc4random()
let promise2 = promise1.recover { _ -> Promise<UInt32> in throw Error.sentinel(sentinel) }
promise2.catch { error in
if case Error.sentinel(let x) = error, x == sentinel {
expectation.fulfill()
}
}
}
}
}
}
}

View File

@@ -0,0 +1,31 @@
import PromiseKit
import XCTest
class Test231: XCTestCase {
func test() {
describe("2.3.1: If `promise` and `x` refer to the same object, reject `promise` with a `TypeError' as the reason.") {
specify("via return from a fulfilled promise") { d, expectation in
var promise: Promise<Void>!
promise = Promise().then { () -> Promise<Void> in
return promise
}
promise.catch { err in
if case PMKError.returnedSelf = err {
expectation.fulfill()
}
}
}
specify("via return from a rejected promise") { d, expectation in
var promise: Promise<Void>!
promise = Promise<Void>(error: Error.dummy).recover { _ -> Promise<Void> in
return promise
}
promise.catch { err in
if case PMKError.returnedSelf = err {
expectation.fulfill()
}
}
}
}
}
}

View File

@@ -0,0 +1,116 @@
import PromiseKit
import XCTest
class Test232: XCTestCase {
func test() {
describe("2.3.2: If `x` is a promise, adopt its state") {
describe("2.3.2.1: If `x` is pending, `promise` must remain pending until `x` is fulfilled or rejected.") {
func xFactory() -> Promise<UInt32> {
return Promise.pending().promise
}
testPromiseResolution(factory: xFactory) { promise, expectation in
var wasFulfilled = false;
var wasRejected = false;
promise.test(onFulfilled: { wasFulfilled = true }, onRejected: { wasRejected = true })
after(ticks: 4) {
XCTAssertFalse(wasFulfilled)
XCTAssertFalse(wasRejected)
expectation.fulfill()
}
}
}
describe("2.3.2.2: If/when `x` is fulfilled, fulfill `promise` with the same value.") {
describe("`x` is already-fulfilled") {
let sentinel = arc4random()
func xFactory() -> Promise<UInt32> {
return .value(sentinel)
}
testPromiseResolution(factory: xFactory) { promise, expectation in
promise.done {
XCTAssertEqual($0, sentinel)
expectation.fulfill()
}.silenceWarning()
}
}
describe("`x` is eventually-fulfilled") {
let sentinel = arc4random()
func xFactory() -> Promise<UInt32> {
return Promise { seal in
after(ticks: 2) {
seal.fulfill(sentinel)
}
}
}
testPromiseResolution(factory: xFactory) { promise, expectation in
promise.done {
XCTAssertEqual($0, sentinel)
expectation.fulfill()
}.silenceWarning()
}
}
}
describe("2.3.2.3: If/when `x` is rejected, reject `promise` with the same reason.") {
describe("`x` is already-rejected") {
let sentinel = arc4random()
func xFactory() -> Promise<UInt32> {
return Promise(error: Error.sentinel(sentinel))
}
testPromiseResolution(factory: xFactory) { promise, expectation in
promise.catch { err in
if case Error.sentinel(let value) = err, value == sentinel {
expectation.fulfill()
}
}
}
}
describe("`x` is eventually-rejected") {
let sentinel = arc4random()
func xFactory() -> Promise<UInt32> {
return Promise { seal in
after(ticks: 2) {
seal.reject(Error.sentinel(sentinel))
}
}
}
testPromiseResolution(factory: xFactory) { promise, expectation in
promise.catch { err in
if case Error.sentinel(let value) = err, value == sentinel {
expectation.fulfill()
}
}
}
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////
extension Test232 {
fileprivate func testPromiseResolution(factory: @escaping () -> Promise<UInt32>, line: UInt = #line, test: (Promise<UInt32>, XCTestExpectation) -> Void) {
specify("via return from a fulfilled promise", file: #file, line: line) { d, expectation in
let promise = Promise.value(arc4random()).then { _ in factory() }
test(promise, expectation)
}
specify("via return from a rejected promise", file: #file, line: line) { d, expectation in
let promise: Promise<UInt32> = Promise(error: Error.dummy).recover { _ in factory() }
test(promise, expectation)
}
}
}

View File

@@ -0,0 +1,26 @@
import PromiseKit
import XCTest
class Test234: XCTestCase {
func test() {
describe("2.3.4: If `x` is not an object or function, fulfill `promise` with `x`") {
testFulfilled { promise, exception, _ in
promise.map { value -> UInt32 in
return 1
}.done { value in
XCTAssertEqual(value, 1)
exception.fulfill()
}.silenceWarning()
}
testRejected { promise, expectation, _ in
promise.recover { _ -> Promise<UInt32> in
return .value(UInt32(1))
}.done { value in
XCTAssertEqual(value, 1)
expectation.fulfill()
}.silenceWarning()
}
}
}
}

View File

@@ -0,0 +1,13 @@
Resources
=========
* https://github.com/promises-aplus/promises-tests
Skipped
=======
* 2.3.3: Otherwise, if x is an object or function.
This spec is a NOOP for Swift:
- We have decided not to interact with other Promises A+ implementations
- functions cannot have properties
* 2.3.3.4: If then is not a function, fulfill promise with x.
- See: The 2.3.4 suite.