Fix tests on Linux
This commit is contained in:
parent
13fcf1d2e9
commit
0f538f2684
19
.github/LinuxMain.stencil
vendored
Normal file
19
.github/LinuxMain.stencil
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
@testable import Core
|
||||
@testable import A_
|
||||
import XCTest
|
||||
|
||||
//TODO get this to run on CI and don’t have it committed
|
||||
//NOTE problem is Sourcery doesn’t support Linux currently
|
||||
//USAGE: cd PromiseKit/Sources/.. && sourcery --config .github/sourcery.yml
|
||||
|
||||
{% for type in types.classes|based:"XCTestCase" %}
|
||||
extension {{ type.name }} {
|
||||
static var allTests = [
|
||||
{% for method in type.methods %}{% if method.parameters.count == 0 and method.shortName|hasPrefix:"test" %} ("{{ method.shortName }}", {{type.name}}.{{ method.shortName }}),
|
||||
{% endif %}{% endfor %}]
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
XCTMain([
|
||||
{% for type in types.classes|based:"XCTestCase" %}{% if not type.annotations.excludeFromLinuxMain %} testCase({{ type.name }}.allTests),
|
||||
{% endif %}{% endfor %}])
|
||||
2
.github/codecov.yml
vendored
2
.github/codecov.yml
vendored
@ -7,7 +7,7 @@ codecov:
|
||||
|
||||
coverage:
|
||||
precision: 1
|
||||
round: nearest
|
||||
round: up
|
||||
range: "70...100"
|
||||
|
||||
status:
|
||||
|
||||
12
.github/sourcery.yml
vendored
Normal file
12
.github/sourcery.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
sources:
|
||||
include:
|
||||
- ../Tests/A+
|
||||
- ../Tests/CorePromise
|
||||
exclude:
|
||||
- ../Tests/A+/0.0.0.swift
|
||||
- ../Tests/CorePromise/Utilities.swift
|
||||
templates:
|
||||
include:
|
||||
- LinuxMain.stencil
|
||||
output:
|
||||
../Tests/LinuxMain.swift
|
||||
@ -39,7 +39,7 @@
|
||||
6330B5E11F2E991200D60528 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6330B5E01F2E991200D60528 /* Configuration.swift */; };
|
||||
634AAD2B1EAE517C00B17855 /* fwd.h in Headers */ = {isa = PBXBuildFile; fileRef = 634AAD2A1EAE517C00B17855 /* fwd.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
635D641D1D59635300BC0AF5 /* PromiseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64081D59635300BC0AF5 /* PromiseTests.swift */; };
|
||||
635D641E1D59635300BC0AF5 /* 02_CancellationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64091D59635300BC0AF5 /* 02_CancellationTests.swift */; };
|
||||
635D641E1D59635300BC0AF5 /* CancellableErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64091D59635300BC0AF5 /* CancellableErrorTests.swift */; };
|
||||
635D64221D59635300BC0AF5 /* 02_ZalgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D640D1D59635300BC0AF5 /* 02_ZalgoTests.swift */; };
|
||||
635D64231D59635300BC0AF5 /* 03_AfterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D640E1D59635300BC0AF5 /* 03_AfterTests.swift */; };
|
||||
635D64261D59635300BC0AF5 /* 03_JoinTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635D64111D59635300BC0AF5 /* 03_JoinTests.swift */; };
|
||||
@ -55,6 +55,7 @@
|
||||
636A29231F1C17A6001229C2 /* Guarantee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636A29221F1C17A6001229C2 /* Guarantee.swift */; };
|
||||
636A29251F1C3089001229C2 /* race.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636A29241F1C3089001229C2 /* race.swift */; };
|
||||
636A29271F1C3927001229C2 /* Resolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636A29261F1C3927001229C2 /* Resolver.swift */; };
|
||||
639BF757203DF03100FA577B /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639BF755203DF02C00FA577B /* Utilities.swift */; };
|
||||
63B0AC7F1D595E6300FA21D9 /* after.m in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC611D595E6300FA21D9 /* after.m */; };
|
||||
63B0AC801D595E6300FA21D9 /* after.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63B0AC621D595E6300FA21D9 /* after.swift */; };
|
||||
63B0AC811D595E6300FA21D9 /* AnyPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 63B0AC631D595E6300FA21D9 /* AnyPromise.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@ -149,7 +150,7 @@
|
||||
635893961D5BE4F900F14B55 /* PromiseKit.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = PromiseKit.podspec; sourceTree = "<group>"; };
|
||||
635893971D5BE4F900F14B55 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
635D64081D59635300BC0AF5 /* PromiseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PromiseTests.swift; sourceTree = "<group>"; };
|
||||
635D64091D59635300BC0AF5 /* 02_CancellationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 02_CancellationTests.swift; sourceTree = "<group>"; };
|
||||
635D64091D59635300BC0AF5 /* CancellableErrorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CancellableErrorTests.swift; sourceTree = "<group>"; };
|
||||
635D640D1D59635300BC0AF5 /* 02_ZalgoTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 02_ZalgoTests.swift; sourceTree = "<group>"; };
|
||||
635D640E1D59635300BC0AF5 /* 03_AfterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 03_AfterTests.swift; sourceTree = "<group>"; };
|
||||
635D64111D59635300BC0AF5 /* 03_JoinTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 03_JoinTests.swift; sourceTree = "<group>"; };
|
||||
@ -166,6 +167,7 @@
|
||||
636A29221F1C17A6001229C2 /* Guarantee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Guarantee.swift; path = Sources/Guarantee.swift; sourceTree = "<group>"; };
|
||||
636A29241F1C3089001229C2 /* race.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = race.swift; path = Sources/race.swift; sourceTree = "<group>"; };
|
||||
636A29261F1C3927001229C2 /* Resolver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Resolver.swift; path = Sources/Resolver.swift; sourceTree = "<group>"; };
|
||||
639BF755203DF02C00FA577B /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
|
||||
63B0AC571D595E1B00FA21D9 /* PromiseKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PromiseKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
63B0AC611D595E6300FA21D9 /* after.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = after.m; path = Sources/after.m; sourceTree = "<group>"; };
|
||||
63B0AC621D595E6300FA21D9 /* after.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = after.swift; path = Sources/after.swift; sourceTree = "<group>"; };
|
||||
@ -285,8 +287,6 @@
|
||||
6317518A1D59765700A9DDDC /* Core */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
635D64091D59635300BC0AF5 /* 02_CancellationTests.swift */,
|
||||
635D641B1D59635300BC0AF5 /* DefaultDispatchQueueTests.swift */,
|
||||
635D640D1D59635300BC0AF5 /* 02_ZalgoTests.swift */,
|
||||
635D640E1D59635300BC0AF5 /* 03_AfterTests.swift */,
|
||||
0C42F3191FCF86240051309C /* 03_HangTests.swift */,
|
||||
@ -299,9 +299,12 @@
|
||||
635D64171D59635300BC0AF5 /* 99_RegressionTests.swift */,
|
||||
63CF6D7F203CD19200EC8927 /* ThenableTests.swift */,
|
||||
632FBBE41F33B338008F8FBB /* CatchableTests.swift */,
|
||||
635D64091D59635300BC0AF5 /* CancellableErrorTests.swift */,
|
||||
635D64081D59635300BC0AF5 /* PromiseTests.swift */,
|
||||
63CF6D7B203CCDAB00EC8927 /* GuaranteeTests.swift */,
|
||||
63CF6D79203CC66000EC8927 /* ErrorTests.swift */,
|
||||
635D641B1D59635300BC0AF5 /* DefaultDispatchQueueTests.swift */,
|
||||
639BF755203DF02C00FA577B /* Utilities.swift */,
|
||||
);
|
||||
name = Core;
|
||||
path = Tests/CorePromise;
|
||||
@ -585,7 +588,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0C42F31B1FCF86320051309C /* 03_HangTests.swift in Sources */,
|
||||
635D641E1D59635300BC0AF5 /* 02_CancellationTests.swift in Sources */,
|
||||
635D641E1D59635300BC0AF5 /* CancellableErrorTests.swift in Sources */,
|
||||
630A8056203CEF6800D25F23 /* AnyPromiseTests.m in Sources */,
|
||||
635D64221D59635300BC0AF5 /* 02_ZalgoTests.swift in Sources */,
|
||||
635D64271D59635300BC0AF5 /* 03_RaceTests.swift in Sources */,
|
||||
@ -596,6 +599,7 @@
|
||||
630A805B203CF67800D25F23 /* DefaultDispatchQueueTests.swift in Sources */,
|
||||
635D641D1D59635300BC0AF5 /* PromiseTests.swift in Sources */,
|
||||
63CF6D7C203CCDAB00EC8927 /* GuaranteeTests.swift in Sources */,
|
||||
639BF757203DF03100FA577B /* Utilities.swift in Sources */,
|
||||
635D64261D59635300BC0AF5 /* 03_JoinTests.swift in Sources */,
|
||||
635D64231D59635300BC0AF5 /* 03_AfterTests.swift in Sources */,
|
||||
63CF6D7A203CC66000EC8927 /* ErrorTests.swift in Sources */,
|
||||
|
||||
@ -148,3 +148,15 @@ public extension DispatchQueue {
|
||||
return rg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if os(Linux)
|
||||
import func CoreFoundation._CFIsMainThread
|
||||
|
||||
extension Thread {
|
||||
// `isMainThread` is not implemented yet in swift-corelibs-foundation.
|
||||
static var isMainThread: Bool {
|
||||
return _CFIsMainThread()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import PromiseKit
|
||||
import Dispatch
|
||||
import XCTest
|
||||
|
||||
enum Error: Swift.Error {
|
||||
@ -159,3 +160,23 @@ prefix func ++(a: inout Int) -> Int {
|
||||
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) {
|
||||
waitForExpectations(timeout: timeout, file: file, line: line)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -65,7 +65,7 @@ class Test226: XCTestCase {
|
||||
describe("results in multiple branching chains with their own fulfillment values") {
|
||||
testFulfilled(withExpectationCount: 3) { promise, exes, memo in
|
||||
let sentinel1 = 671
|
||||
let sentinel2 = 672
|
||||
let sentinel2: UInt32 = 672
|
||||
let sentinel3 = 673
|
||||
|
||||
promise.map { _ in
|
||||
@ -76,9 +76,14 @@ class Test226: XCTestCase {
|
||||
}.silenceWarning()
|
||||
|
||||
promise.done { _ in
|
||||
throw NSError(domain: NSCocoaErrorDomain, code: sentinel2, userInfo: nil)
|
||||
throw Error.sentinel(sentinel2)
|
||||
}.catch { err in
|
||||
XCTAssertEqual((err as NSError).code, sentinel2)
|
||||
switch err {
|
||||
case Error.sentinel(let err) where err == sentinel2:
|
||||
break
|
||||
default:
|
||||
XCTFail()
|
||||
}
|
||||
exes[1].fulfill()
|
||||
}
|
||||
|
||||
|
||||
@ -235,6 +235,28 @@ class BridgingTests: XCTestCase {
|
||||
|
||||
XCTAssertEqual(p.value, q.value)
|
||||
}
|
||||
|
||||
/// testing NSError to Error for cancelledError types
|
||||
func testErrorCancellationBridging() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
let p = Promise().done {
|
||||
throw LocalError.cancel as NSError
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1)
|
||||
|
||||
// here we verify that Swift’s NSError bridging works as advertised
|
||||
|
||||
XCTAssertTrue(LocalError.cancel.isCancelled)
|
||||
XCTAssertTrue((LocalError.cancel as NSError).isCancelled)
|
||||
}
|
||||
}
|
||||
|
||||
private enum Error: Swift.Error {
|
||||
@ -244,3 +266,15 @@ private enum Error: Swift.Error {
|
||||
extension Promise {
|
||||
func silenceWarning() {}
|
||||
}
|
||||
|
||||
private enum LocalError: CancellableError {
|
||||
case notCancel
|
||||
case cancel
|
||||
|
||||
var isCancelled: Bool {
|
||||
switch self {
|
||||
case .notCancel: return false
|
||||
case .cancel: return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,143 +0,0 @@
|
||||
import Foundation.NSURLError
|
||||
import PromiseKit
|
||||
import XCTest
|
||||
|
||||
class CancellationTests: XCTestCase {
|
||||
func testCancellation() {
|
||||
autoreleasepool {
|
||||
let ex1 = expectation(description: "")
|
||||
|
||||
let p = after(seconds: 0).done { _ in
|
||||
throw LocalError.cancel
|
||||
}.done {
|
||||
XCTFail()
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex1.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 60)
|
||||
}
|
||||
|
||||
func testThrowCancellableErrorThatIsNotCancelled() {
|
||||
let expct = expectation(description: "")
|
||||
|
||||
after(seconds: 0).done { _ in
|
||||
throw LocalError.notCancel
|
||||
}.done {
|
||||
XCTFail()
|
||||
}.catch {
|
||||
XCTAssertFalse($0.isCancelled)
|
||||
expct.fulfill()
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
func testRecoverWithCancellation() {
|
||||
autoreleasepool {
|
||||
let ex1 = expectation(description: "")
|
||||
let ex2 = expectation(description: "")
|
||||
|
||||
let p = after(seconds: 0).done { _ in
|
||||
throw NSError(domain: NSCocoaErrorDomain, code: NSUserCancelledError, userInfo: nil)
|
||||
}.recover(policy: .allErrors) { err -> Promise<Void> in
|
||||
ex1.fulfill()
|
||||
XCTAssertTrue(err.isCancelled)
|
||||
throw err
|
||||
}.done { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex2.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
func testFoundationBridging1() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
let p = after(seconds: 0).done { _ in
|
||||
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.userCancelled.rawValue)
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
func testFoundationBridging2() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
let p = Promise().done {
|
||||
throw NSError(domain: NSURLErrorDomain, code: URLError.cancelled.rawValue)
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
func testBridging() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
let p = Promise().done {
|
||||
throw LocalError.cancel as NSError
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex.fulfill()
|
||||
}
|
||||
waitForExpectations(timeout: 1)
|
||||
|
||||
// here we verify that Swift’s NSError bridging works as advertised
|
||||
|
||||
XCTAssertTrue(LocalError.cancel.isCancelled)
|
||||
XCTAssertTrue((LocalError.cancel as NSError).isCancelled)
|
||||
}
|
||||
|
||||
#if swift(>=3.2)
|
||||
func testIsCancelled() {
|
||||
XCTAssertTrue(PMKError.cancelled.isCancelled)
|
||||
XCTAssertTrue(NSError(domain: NSURLErrorDomain, code: URLError.cancelled.rawValue, userInfo: nil).isCancelled)
|
||||
XCTAssertTrue(NSError(domain: NSCocoaErrorDomain, code: CocoaError.userCancelled.rawValue, userInfo: nil).isCancelled)
|
||||
XCTAssertFalse(NSError(domain: NSCocoaErrorDomain, code: CocoaError.coderInvalidValue.rawValue, userInfo: nil).isCancelled)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private enum LocalError: CancellableError {
|
||||
case notCancel
|
||||
case cancel
|
||||
|
||||
var isCancelled: Bool {
|
||||
switch self {
|
||||
case .notCancel: return false
|
||||
case .cancel: return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,19 +30,17 @@ class ZalgoTests: XCTestCase {
|
||||
|
||||
// returning a pending promise from its own zalgo’d then handler doesn’t hang
|
||||
func test3() {
|
||||
autoreleasepool {
|
||||
let ex = (expectation(description: ""), expectation(description: ""))
|
||||
let ex = (expectation(description: ""), expectation(description: ""))
|
||||
|
||||
var p1: Promise<Void>!
|
||||
p1 = after(.milliseconds(100)).then(on: nil) { _ -> Promise<Void> in
|
||||
ex.0.fulfill()
|
||||
return p1
|
||||
}
|
||||
var p1: Promise<Void>!
|
||||
p1 = after(.milliseconds(100)).then(on: nil) { _ -> Promise<Void> in
|
||||
ex.0.fulfill()
|
||||
return p1
|
||||
}
|
||||
|
||||
p1.catch { err in
|
||||
defer{ ex.1.fulfill() }
|
||||
guard case PMKError.returnedSelf = err else { return XCTFail() }
|
||||
}
|
||||
p1.catch { err in
|
||||
defer{ ex.1.fulfill() }
|
||||
guard case PMKError.returnedSelf = err else { return XCTFail() }
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
|
||||
@ -20,28 +20,6 @@ class JoinTests: XCTestCase {
|
||||
XCTAssert(join2Finished, "Join immediately finishes on fulfilled promises")
|
||||
}
|
||||
|
||||
#if false
|
||||
func testImmediateErrors() {
|
||||
let errorPromise = Promise<Void>(error: NSError(domain: "", code: 0, userInfo: nil))
|
||||
var joinFinished = false
|
||||
when(resolved: errorPromise).asVoid().recover(on: nil) { _ in
|
||||
joinFinished = true
|
||||
return Promise()
|
||||
}
|
||||
XCTAssert(joinFinished, "Join immediately finishes on rejected promise")
|
||||
|
||||
let errorPromise2 = Promise<Void>(error: NSError(domain: "", code: 0, userInfo: nil))
|
||||
let errorPromise3 = Promise<Void>(error: NSError(domain: "", code: 0, userInfo: nil))
|
||||
let errorPromise4 = Promise<Void>(error: NSError(domain: "", code: 0, userInfo: nil))
|
||||
var join2Finished = false
|
||||
when(resolved: errorPromise2, errorPromise3, errorPromise4).asVoid().recover(on: nil) { _ in
|
||||
join2Finished = true
|
||||
return Promise()
|
||||
}
|
||||
XCTAssert(join2Finished, "Join immediately finishes on rejected promises")
|
||||
}
|
||||
#endif
|
||||
|
||||
func testFulfilledAfterAllResolve() {
|
||||
let (promise1, seal1) = Promise<Void>.pending()
|
||||
let (promise2, seal2) = Promise<Void>.pending()
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import PromiseKit
|
||||
import Dispatch
|
||||
import XCTest
|
||||
|
||||
class WhenTests: XCTestCase {
|
||||
|
||||
@ -152,7 +152,7 @@ class WrapTests: XCTestCase {
|
||||
}
|
||||
|
||||
let ex = expectation(description: "")
|
||||
autoreleasepool {
|
||||
do {
|
||||
// for code coverage report for `Resolver.deinit` warning
|
||||
let foo = Foo()
|
||||
foo.ex = ex
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import PromiseKit
|
||||
import Dispatch
|
||||
import XCTest
|
||||
|
||||
class StressTests: XCTestCase {
|
||||
|
||||
130
Tests/CorePromise/CancellableErrorTests.swift
Normal file
130
Tests/CorePromise/CancellableErrorTests.swift
Normal file
@ -0,0 +1,130 @@
|
||||
import Foundation
|
||||
import PromiseKit
|
||||
import XCTest
|
||||
|
||||
class CancellationTests: XCTestCase {
|
||||
func testCancellation() {
|
||||
let ex1 = expectation(description: "")
|
||||
|
||||
let p = after(seconds: 0).done { _ in
|
||||
throw LocalError.cancel
|
||||
}.done {
|
||||
XCTFail()
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex1.fulfill()
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 60)
|
||||
}
|
||||
|
||||
func testThrowCancellableErrorThatIsNotCancelled() {
|
||||
let expct = expectation(description: "")
|
||||
|
||||
after(seconds: 0).done { _ in
|
||||
throw LocalError.notCancel
|
||||
}.done {
|
||||
XCTFail()
|
||||
}.catch {
|
||||
XCTAssertFalse($0.isCancelled)
|
||||
expct.fulfill()
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
func testRecoverWithCancellation() {
|
||||
let ex1 = expectation(description: "")
|
||||
let ex2 = expectation(description: "")
|
||||
|
||||
let p = after(seconds: 0).done { _ in
|
||||
throw CocoaError.cancelled
|
||||
}.recover(policy: .allErrors) { err -> Promise<Void> in
|
||||
ex1.fulfill()
|
||||
XCTAssertTrue(err.isCancelled)
|
||||
throw err
|
||||
}.done { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex2.fulfill()
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
func testFoundationBridging1() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
let p = after(seconds: 0).done { _ in
|
||||
throw CocoaError.cancelled
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
func testFoundationBridging2() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
let p = Promise().done {
|
||||
throw URLError.cancelled
|
||||
}
|
||||
p.catch { _ in
|
||||
XCTFail()
|
||||
}
|
||||
p.catch(policy: .allErrors) {
|
||||
XCTAssertTrue($0.isCancelled)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
#if swift(>=3.2)
|
||||
func testIsCancelled() {
|
||||
XCTAssertTrue(PMKError.cancelled.isCancelled)
|
||||
XCTAssertTrue(URLError.cancelled.isCancelled)
|
||||
XCTAssertTrue(CocoaError.cancelled.isCancelled)
|
||||
XCTAssertFalse(CocoaError(_nsError: NSError(domain: NSCocoaErrorDomain, code: CocoaError.Code.coderInvalidValue.rawValue)).isCancelled)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private enum LocalError: CancellableError {
|
||||
case notCancel
|
||||
case cancel
|
||||
|
||||
var isCancelled: Bool {
|
||||
switch self {
|
||||
case .notCancel: return false
|
||||
case .cancel: return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension URLError {
|
||||
static var cancelled: URLError {
|
||||
return .init(_nsError: NSError(domain: NSURLErrorDomain, code: URLError.Code.cancelled.rawValue))
|
||||
}
|
||||
}
|
||||
|
||||
private extension CocoaError {
|
||||
static var cancelled: CocoaError {
|
||||
return .init(_nsError: NSError(domain: NSCocoaErrorDomain, code: CocoaError.Code.userCancelled.rawValue))
|
||||
}
|
||||
}
|
||||
@ -215,11 +215,6 @@ extension CatchableTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//MARK: Helpers
|
||||
|
||||
private typealias EquatableError = Swift.Error & Equatable
|
||||
|
||||
private enum Error: CancellableError {
|
||||
case dummy
|
||||
case cancelled
|
||||
@ -228,7 +223,3 @@ private enum Error: CancellableError {
|
||||
return self == Error.cancelled
|
||||
}
|
||||
}
|
||||
|
||||
extension Promise {
|
||||
func silenceWarning() {}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
import class Foundation.Thread
|
||||
import PromiseKit
|
||||
import Dispatch
|
||||
import XCTest
|
||||
|
||||
private enum Error: Swift.Error { case dummy }
|
||||
@ -23,6 +24,10 @@ class PMKDefaultDispatchQueueTest: XCTestCase {
|
||||
conf.Q = (myQueue, myQueue)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
conf.Q = (.main, .main)
|
||||
}
|
||||
|
||||
func testOverrodeDefaultThenQueue() {
|
||||
let ex = expectation(description: "resolving")
|
||||
|
||||
|
||||
@ -1,26 +1,27 @@
|
||||
import PromiseKit
|
||||
import Dispatch
|
||||
import XCTest
|
||||
|
||||
class PromiseTests: XCTestCase {
|
||||
func testPending() {
|
||||
func testIsPending() {
|
||||
XCTAssertTrue(Promise<Void>.pending().promise.isPending)
|
||||
XCTAssertFalse(Promise().isPending)
|
||||
XCTAssertFalse(Promise<Void>(error: Error.dummy).isPending)
|
||||
}
|
||||
|
||||
func testResolved() {
|
||||
func testIsResolved() {
|
||||
XCTAssertFalse(Promise<Void>.pending().promise.isResolved)
|
||||
XCTAssertTrue(Promise().isResolved)
|
||||
XCTAssertTrue(Promise<Void>(error: Error.dummy).isResolved)
|
||||
}
|
||||
|
||||
func testFulfilled() {
|
||||
func testIsFulfilled() {
|
||||
XCTAssertFalse(Promise<Void>.pending().promise.isFulfilled)
|
||||
XCTAssertTrue(Promise().isFulfilled)
|
||||
XCTAssertFalse(Promise<Void>(error: Error.dummy).isFulfilled)
|
||||
}
|
||||
|
||||
func testRejected() {
|
||||
func testIsRejected() {
|
||||
XCTAssertFalse(Promise<Void>.pending().promise.isRejected)
|
||||
XCTAssertTrue(Promise<Void>(error: Error.dummy).isRejected)
|
||||
XCTAssertFalse(Promise().isRejected)
|
||||
|
||||
30
Tests/CorePromise/Utilities.swift
Normal file
30
Tests/CorePromise/Utilities.swift
Normal file
@ -0,0 +1,30 @@
|
||||
import PromiseKit
|
||||
|
||||
extension Promise {
|
||||
func silenceWarning() {}
|
||||
}
|
||||
|
||||
#if os(Linux)
|
||||
import func CoreFoundation._CFIsMainThread
|
||||
|
||||
extension Thread {
|
||||
// `isMainThread` is not implemented yet in swift-corelibs-foundation.
|
||||
static var isMainThread: Bool {
|
||||
return _CFIsMainThread()
|
||||
}
|
||||
}
|
||||
|
||||
import XCTest
|
||||
|
||||
extension XCTestCase {
|
||||
func wait(for: [XCTestExpectation], timeout: TimeInterval, file: StaticString = #file, line: UInt = #line) {
|
||||
waitForExpectations(timeout: timeout, file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
extension XCTestExpectation {
|
||||
func fulfill() {
|
||||
fulfill(#file, line: #line)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1,33 +1,284 @@
|
||||
// Generated using Sourcery 0.10.1 — https://github.com/krzysztofzablocki/Sourcery
|
||||
// DO NOT EDIT
|
||||
|
||||
|
||||
@testable import Core
|
||||
@testable import A_
|
||||
import XCTest
|
||||
import A_
|
||||
import Core
|
||||
|
||||
//TODO get this to run on CI and don’t have it committed
|
||||
//NOTE problem is Sourcery doesn’t support Linux currently
|
||||
//USAGE: cd PromiseKit/Sources/.. && sourcery --config .github/sourcery.yml
|
||||
|
||||
extension AfterTests {
|
||||
static var allTests = [
|
||||
("testZero", AfterTests.testZero),
|
||||
("testNegative", AfterTests.testNegative),
|
||||
("testPositive", AfterTests.testPositive),
|
||||
]
|
||||
}
|
||||
|
||||
extension CancellationTests {
|
||||
static var allTests = [
|
||||
("testCancellation", CancellationTests.testCancellation),
|
||||
("testThrowCancellableErrorThatIsNotCancelled", CancellationTests.testThrowCancellableErrorThatIsNotCancelled),
|
||||
("testRecoverWithCancellation", CancellationTests.testRecoverWithCancellation),
|
||||
("testFoundationBridging1", CancellationTests.testFoundationBridging1),
|
||||
("testFoundationBridging2", CancellationTests.testFoundationBridging2),
|
||||
("testIsCancelled", CancellationTests.testIsCancelled),
|
||||
("testIsCancelled", CancellationTests.testIsCancelled),
|
||||
]
|
||||
}
|
||||
|
||||
extension CatchableTests {
|
||||
static var allTests = [
|
||||
("testFinally", CatchableTests.testFinally),
|
||||
("testCauterize", CatchableTests.testCauterize),
|
||||
("test__void_specialized_full_recover", CatchableTests.test__void_specialized_full_recover),
|
||||
("test__void_specialized_full_recover__fulfilled_path", CatchableTests.test__void_specialized_full_recover__fulfilled_path),
|
||||
("test__void_specialized_conditional_recover", CatchableTests.test__void_specialized_conditional_recover),
|
||||
("test__void_specialized_conditional_recover__no_recover", CatchableTests.test__void_specialized_conditional_recover__no_recover),
|
||||
("test__void_specialized_conditional_recover__ignores_cancellation_but_fed_cancellation", CatchableTests.test__void_specialized_conditional_recover__ignores_cancellation_but_fed_cancellation),
|
||||
("test__void_specialized_conditional_recover__fulfilled_path", CatchableTests.test__void_specialized_conditional_recover__fulfilled_path),
|
||||
("test__full_recover", CatchableTests.test__full_recover),
|
||||
("test__full_recover__fulfilled_path", CatchableTests.test__full_recover__fulfilled_path),
|
||||
("test__conditional_recover", CatchableTests.test__conditional_recover),
|
||||
("test__conditional_recover__no_recover", CatchableTests.test__conditional_recover__no_recover),
|
||||
("test__conditional_recover__ignores_cancellation_but_fed_cancellation", CatchableTests.test__conditional_recover__ignores_cancellation_but_fed_cancellation),
|
||||
("test__conditional_recover__fulfilled_path", CatchableTests.test__conditional_recover__fulfilled_path),
|
||||
]
|
||||
}
|
||||
|
||||
extension GuaranteeTests {
|
||||
static var allTests = [
|
||||
("testInit", GuaranteeTests.testInit),
|
||||
("testWait", GuaranteeTests.testWait),
|
||||
]
|
||||
}
|
||||
|
||||
extension HangTests {
|
||||
static var allTests = [
|
||||
("test", HangTests.test),
|
||||
("testError", HangTests.testError),
|
||||
]
|
||||
}
|
||||
|
||||
extension JoinTests {
|
||||
static var allTests = [
|
||||
("testImmediates", JoinTests.testImmediates),
|
||||
("testFulfilledAfterAllResolve", JoinTests.testFulfilledAfterAllResolve),
|
||||
]
|
||||
}
|
||||
|
||||
extension PMKDefaultDispatchQueueTest {
|
||||
static var allTests = [
|
||||
("testOverrodeDefaultThenQueue", PMKDefaultDispatchQueueTest.testOverrodeDefaultThenQueue),
|
||||
("testOverrodeDefaultCatchQueue", PMKDefaultDispatchQueueTest.testOverrodeDefaultCatchQueue),
|
||||
("testOverrodeDefaultAlwaysQueue", PMKDefaultDispatchQueueTest.testOverrodeDefaultAlwaysQueue),
|
||||
]
|
||||
}
|
||||
|
||||
extension PMKErrorTests {
|
||||
static var allTests = [
|
||||
("testCustomStringConvertible", PMKErrorTests.testCustomStringConvertible),
|
||||
("testCustomDebugStringConvertible", PMKErrorTests.testCustomDebugStringConvertible),
|
||||
]
|
||||
}
|
||||
|
||||
extension PromiseTests {
|
||||
static var allTests = [
|
||||
("testIsPending", PromiseTests.testIsPending),
|
||||
("testIsResolved", PromiseTests.testIsResolved),
|
||||
("testIsFulfilled", PromiseTests.testIsFulfilled),
|
||||
("testIsRejected", PromiseTests.testIsRejected),
|
||||
("testDispatchQueueAsyncExtensionReturnsPromise", PromiseTests.testDispatchQueueAsyncExtensionReturnsPromise),
|
||||
("testDispatchQueueAsyncExtensionCanThrowInBody", PromiseTests.testDispatchQueueAsyncExtensionCanThrowInBody),
|
||||
("testCustomStringConvertible", PromiseTests.testCustomStringConvertible),
|
||||
("testCannotFulfillWithError", PromiseTests.testCannotFulfillWithError),
|
||||
("testCanMakeVoidPromise", PromiseTests.testCanMakeVoidPromise),
|
||||
("testCanMakeVoidPromise", PromiseTests.testCanMakeVoidPromise),
|
||||
("testThrowInInitializer", PromiseTests.testThrowInInitializer),
|
||||
("testThrowInFirstly", PromiseTests.testThrowInFirstly),
|
||||
("testWait", PromiseTests.testWait),
|
||||
("testPipeForResolved", PromiseTests.testPipeForResolved),
|
||||
]
|
||||
}
|
||||
|
||||
extension RaceTests {
|
||||
static var allTests = [
|
||||
("test1", RaceTests.test1),
|
||||
("test2", RaceTests.test2),
|
||||
("test1Array", RaceTests.test1Array),
|
||||
("test2Array", RaceTests.test2Array),
|
||||
("testEmptyArray", RaceTests.testEmptyArray),
|
||||
]
|
||||
}
|
||||
|
||||
extension RegressionTests {
|
||||
static var allTests = [
|
||||
("testReturningPreviousPromiseWorks", RegressionTests.testReturningPreviousPromiseWorks),
|
||||
]
|
||||
}
|
||||
|
||||
extension StressTests {
|
||||
static var allTests = [
|
||||
("testThenDataRace", StressTests.testThenDataRace),
|
||||
("testThensAreSequentialForLongTime", StressTests.testThensAreSequentialForLongTime),
|
||||
("testZalgoDataRace", StressTests.testZalgoDataRace),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test212 {
|
||||
static var allTests = [
|
||||
("test", Test212.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test213 {
|
||||
static var allTests = [
|
||||
("test", Test213.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test222 {
|
||||
static var allTests = [
|
||||
("test", Test222.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test223 {
|
||||
static var allTests = [
|
||||
("test", Test223.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test224 {
|
||||
static var allTests = [
|
||||
("test", Test224.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test226 {
|
||||
static var allTests = [
|
||||
("test", Test226.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test227 {
|
||||
static var allTests = [
|
||||
("test", Test227.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test231 {
|
||||
static var allTests = [
|
||||
("test", Test231.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test232 {
|
||||
static var allTests = [
|
||||
("test", Test232.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension Test234 {
|
||||
static var allTests = [
|
||||
("test", Test234.test),
|
||||
]
|
||||
}
|
||||
|
||||
extension ThenableTests {
|
||||
static var allTests = [
|
||||
("testGet", ThenableTests.testGet),
|
||||
("testCompactMapError", ThenableTests.testCompactMapError),
|
||||
("testCompactMapValues", ThenableTests.testCompactMapValues),
|
||||
("testThenMap", ThenableTests.testThenMap),
|
||||
("testThenFlatMap", ThenableTests.testThenFlatMap),
|
||||
("testLastValueForEmpty", ThenableTests.testLastValueForEmpty),
|
||||
("testFirstValueForEmpty", ThenableTests.testFirstValueForEmpty),
|
||||
]
|
||||
}
|
||||
|
||||
extension WhenConcurrentTestCase_Swift {
|
||||
static var allTests = [
|
||||
("testWhen", WhenConcurrentTestCase_Swift.testWhen),
|
||||
("testWhenEmptyGenerator", WhenConcurrentTestCase_Swift.testWhenEmptyGenerator),
|
||||
("testWhenGeneratorError", WhenConcurrentTestCase_Swift.testWhenGeneratorError),
|
||||
("testWhenConcurrency", WhenConcurrentTestCase_Swift.testWhenConcurrency),
|
||||
("testWhenConcurrencyLessThanZero", WhenConcurrentTestCase_Swift.testWhenConcurrencyLessThanZero),
|
||||
("testStopsDequeueingOnceRejected", WhenConcurrentTestCase_Swift.testStopsDequeueingOnceRejected),
|
||||
]
|
||||
}
|
||||
|
||||
extension WhenTests {
|
||||
static var allTests = [
|
||||
("testEmpty", WhenTests.testEmpty),
|
||||
("testInt", WhenTests.testInt),
|
||||
("testDoubleTuple", WhenTests.testDoubleTuple),
|
||||
("testTripleTuple", WhenTests.testTripleTuple),
|
||||
("testQuadrupleTuple", WhenTests.testQuadrupleTuple),
|
||||
("testQuintupleTuple", WhenTests.testQuintupleTuple),
|
||||
("testVoid", WhenTests.testVoid),
|
||||
("testRejected", WhenTests.testRejected),
|
||||
("testProgress", WhenTests.testProgress),
|
||||
("testProgressDoesNotExceed100Percent", WhenTests.testProgressDoesNotExceed100Percent),
|
||||
("testUnhandledErrorHandlerDoesNotFire", WhenTests.testUnhandledErrorHandlerDoesNotFire),
|
||||
("testUnhandledErrorHandlerDoesNotFireForStragglers", WhenTests.testUnhandledErrorHandlerDoesNotFireForStragglers),
|
||||
("testAllSealedRejectedFirstOneRejects", WhenTests.testAllSealedRejectedFirstOneRejects),
|
||||
("testGuaranteeWhen", WhenTests.testGuaranteeWhen),
|
||||
]
|
||||
}
|
||||
|
||||
extension WrapTests {
|
||||
static var allTests = [
|
||||
("testSuccess", WrapTests.testSuccess),
|
||||
("testError", WrapTests.testError),
|
||||
("testInvalidCallingConvention", WrapTests.testInvalidCallingConvention),
|
||||
("testInvertedCallingConvention", WrapTests.testInvertedCallingConvention),
|
||||
("testNonOptionalFirstParameter", WrapTests.testNonOptionalFirstParameter),
|
||||
("testVoidCompletionValue", WrapTests.testVoidCompletionValue),
|
||||
("testVoidCompletionValue", WrapTests.testVoidCompletionValue),
|
||||
("testIsFulfilled", WrapTests.testIsFulfilled),
|
||||
("testPendingPromiseDeallocated", WrapTests.testPendingPromiseDeallocated),
|
||||
]
|
||||
}
|
||||
|
||||
extension ZalgoTests {
|
||||
static var allTests = [
|
||||
("test1", ZalgoTests.test1),
|
||||
("test2", ZalgoTests.test2),
|
||||
("test3", ZalgoTests.test3),
|
||||
("test4", ZalgoTests.test4),
|
||||
]
|
||||
}
|
||||
|
||||
XCTMain([
|
||||
testCase(RaceTests.allTests)
|
||||
testCase(ThenableTests.allTests)
|
||||
testCase(PMKErrorTests.allTests)
|
||||
testCase(ZalgoTests.allTests)
|
||||
testCase(CancellationTests.allTests)
|
||||
testCase(WhenConcurrentTestCase_Swift.allTests)
|
||||
testCase(HangTests.allTests)
|
||||
testCase(JoinTests.allTests)
|
||||
testCase(GuaranteeTests.allTests)
|
||||
testCase(StressTests.allTests)
|
||||
testCase(PMKDefaultDispatchQueueTest.allTests)
|
||||
testCase(PromiseTests.allTests)
|
||||
testCase(CatchableTests.allTests)
|
||||
testCase(AfterTests.allTests)
|
||||
testCase(RegressionTests.allTests)
|
||||
testCase(WrapTests.allTests)
|
||||
testCase(WhenTests.allTests)
|
||||
testCase(Test226.allTests)
|
||||
testCase(Test232.allTests)
|
||||
testCase(Test224.allTests)
|
||||
testCase(Test234.allTests)
|
||||
testCase(Test222.allTests)
|
||||
testCase(Test213.allTests)
|
||||
testCase(Test231.allTests)
|
||||
testCase(Test227.allTests)
|
||||
testCase(Test223.allTests)
|
||||
testCase(Test212.allTests)
|
||||
testCase(AfterTests.allTests),
|
||||
testCase(CancellationTests.allTests),
|
||||
testCase(CatchableTests.allTests),
|
||||
testCase(GuaranteeTests.allTests),
|
||||
testCase(HangTests.allTests),
|
||||
testCase(JoinTests.allTests),
|
||||
testCase(PMKDefaultDispatchQueueTest.allTests),
|
||||
testCase(PMKErrorTests.allTests),
|
||||
testCase(PromiseTests.allTests),
|
||||
testCase(RaceTests.allTests),
|
||||
testCase(RegressionTests.allTests),
|
||||
testCase(StressTests.allTests),
|
||||
testCase(Test212.allTests),
|
||||
testCase(Test213.allTests),
|
||||
testCase(Test222.allTests),
|
||||
testCase(Test223.allTests),
|
||||
testCase(Test224.allTests),
|
||||
testCase(Test226.allTests),
|
||||
testCase(Test227.allTests),
|
||||
testCase(Test231.allTests),
|
||||
testCase(Test232.allTests),
|
||||
testCase(Test234.allTests),
|
||||
testCase(ThenableTests.allTests),
|
||||
testCase(WhenConcurrentTestCase_Swift.allTests),
|
||||
testCase(WhenTests.allTests),
|
||||
testCase(WrapTests.allTests),
|
||||
testCase(ZalgoTests.allTests),
|
||||
])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user