-
-
Notifications
You must be signed in to change notification settings - Fork 51
/
Copy pathUnitTestUtils.swift
161 lines (143 loc) · 5.47 KB
/
UnitTestUtils.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import JavaScriptKit
var printTestNames = false
// Uncomment the next line to print the name of each test suite before running it.
// This will make it easier to debug any errors that occur on the JS side.
//printTestNames = true
func test(_ name: String, testBlock: () throws -> Void) throws {
if printTestNames { print(name) }
do {
try testBlock()
} catch {
print("Error in \(name)")
print(error)
throw error
}
print("✅ \(name)")
}
struct MessageError: Error {
let message: String
let file: StaticString
let line: UInt
let column: UInt
init(_ message: String, file: StaticString, line: UInt, column: UInt) {
self.message = message
self.file = file
self.line = line
self.column = column
}
}
func expectEqual<T: Equatable>(
_ lhs: T, _ rhs: T,
file: StaticString = #file, line: UInt = #line, column: UInt = #column
) throws {
if lhs != rhs {
throw MessageError("Expect to be equal \"\(lhs)\" and \"\(rhs)\"", file: file, line: line, column: column)
}
}
func expectNotEqual<T: Equatable>(
_ lhs: T, _ rhs: T,
file: StaticString = #file, line: UInt = #line, column: UInt = #column
) throws {
if lhs == rhs {
throw MessageError("Expect to not be equal \"\(lhs)\" and \"\(rhs)\"", file: file, line: line, column: column)
}
}
func expectObject(_ value: JSValue, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws -> JSObject {
switch value {
case let .object(ref): return ref
default:
throw MessageError("Type of \(value) should be \"object\"", file: file, line: line, column: column)
}
}
func expectArray(_ value: JSValue, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws -> JSArray {
guard let array = value.array else {
throw MessageError("Type of \(value) should be \"object\"", file: file, line: line, column: column)
}
return array
}
func expectFunction(_ value: JSValue, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws -> JSFunction {
switch value {
case let .function(ref): return ref
default:
throw MessageError("Type of \(value) should be \"function\"", file: file, line: line, column: column)
}
}
func expectBoolean(_ value: JSValue, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws -> Bool {
switch value {
case let .boolean(bool): return bool
default:
throw MessageError("Type of \(value) should be \"boolean\"", file: file, line: line, column: column)
}
}
func expectNumber(_ value: JSValue, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws -> Double {
switch value {
case let .number(number): return number
default:
throw MessageError("Type of \(value) should be \"number\"", file: file, line: line, column: column)
}
}
func expectString(_ value: JSValue, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws -> String {
switch value {
case let .string(string): return String(string)
default:
throw MessageError("Type of \(value) should be \"string\"", file: file, line: line, column: column)
}
}
func expect(_ description: String, _ result: Bool, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws {
if !result {
throw MessageError(description, file: file, line: line, column: column)
}
}
func expectThrow<T>(_ body: @autoclosure () throws -> T, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws -> Error {
do {
_ = try body()
} catch {
return error
}
throw MessageError("Expect to throw an exception", file: file, line: line, column: column)
}
func wrapUnsafeThrowableFunction(_ body: @escaping () -> Void, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws -> JSValue {
JSObject.global.callThrowingClosure.function!(JSClosure { _ in
body()
return .undefined
})
}
func expectNotNil<T>(_ value: T?, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws {
switch value {
case .some: return
case .none:
throw MessageError("Expect a non-nil value", file: file, line: line, column: column)
}
}
func expectNil<T>(_ value: T?, file: StaticString = #file, line: UInt = #line, column: UInt = #column) throws {
switch value {
case .some:
throw MessageError("Expect an nil", file: file, line: line, column: column)
case .none: return
}
}
class Expectation {
private(set) var isFulfilled: Bool = false
private let label: String
private let expectedFulfillmentCount: Int
private var fulfillmentCount: Int = 0
init(label: String, expectedFulfillmentCount: Int = 1) {
self.label = label
self.expectedFulfillmentCount = expectedFulfillmentCount
}
func fulfill() {
assert(!isFulfilled, "Too many fulfillment (label: \(label)): expectedFulfillmentCount is \(expectedFulfillmentCount)")
fulfillmentCount += 1
if fulfillmentCount == expectedFulfillmentCount {
isFulfilled = true
}
}
static func wait(_ expectations: [Expectation]) {
var timer: JSTimer!
timer = JSTimer(millisecondsDelay: 5.0, isRepeating: true) {
guard expectations.allSatisfy(\.isFulfilled) else { return }
assert(timer != nil)
timer = nil
}
}
}