@@ -16,5 +16,146 @@ import Futura
16
16
import XCTest
17
17
18
18
public extension Signal {
19
- // TODO: will be in future :)
19
+
20
+ /// Asserts Signal values if appeared. Fails if there was too few values or timed out.
21
+ /// Timeout assertion is performed by TestExpectation when executing `waitForExpectation()`.
22
+ /// Note that waiting for expectation will block current thread.
23
+ /// Waiting have to be done manually by calling `waitForExpectation()` on returned Expectation.
24
+ ///
25
+ /// - Parameter count: Number of values it will wait for, default is 1
26
+ /// - Parameter validation: Value validation function, assertion will fail if returns false
27
+ /// - Parameter timeout: Wait timeout in seconds, default is 3
28
+ /// - Parameter message: Custom failure message
29
+ /// - Returns: Test expectation of this assertion
30
+ func expectValues( count: UInt = 1 ,
31
+ _ validation: @escaping ( [ Value ] ) -> Bool = { _ in true } ,
32
+ timeout: UInt8 = 3 ,
33
+ message: @escaping @autoclosure ( ) -> String = String ( ) ,
34
+ file: StaticString = #file,
35
+ line: UInt = #line) -> TestExpectation
36
+ {
37
+ let expectation : TestExpectation = . init( timeout: timeout, file: file, line: line)
38
+
39
+ var valuesList : Array < Value > = . init( )
40
+ let valuesMutex : Mutex . Pointer = Mutex . make ( recursive: true )
41
+
42
+ self . values { [ weak expectation] ( value) in
43
+ guard let expectation = expectation else { return }
44
+ Mutex . lock ( valuesMutex)
45
+ defer { Mutex . unlock ( valuesMutex) }
46
+
47
+ if valuesList. count < count {
48
+ valuesList. append ( value)
49
+ } else { /* nothing */ }
50
+ guard valuesList. count == count else { return }
51
+ guard !expectation. timedOut else { return }
52
+ defer { expectation. fulfill ( ) }
53
+ let result = validation ( valuesList)
54
+ guard !result else { return }
55
+ let message = message ( )
56
+ XCTFail ( message. isEmpty ? " Invalid values " : message, file: file, line: line)
57
+ }
58
+ self . finished {
59
+ Mutex . destroy ( valuesMutex)
60
+ }
61
+
62
+ return expectation
63
+ }
64
+
65
+ /// Asserts Signal errors if appeared. Fails if there was too few errors or timed out.
66
+ /// Timeout assertion is performed by TestExpectation when executing `waitForExpectation()`.
67
+ /// Note that waiting for expectation will block current thread.
68
+ /// Waiting have to be done manually by calling `waitForExpectation()` on returned Expectation.
69
+ ///
70
+ /// - Parameter count: Number of errors it will wait for, default is 1
71
+ /// - Parameter validation: Error validation function, assertion will fail if returns false
72
+ /// - Parameter timeout: Wait timeout in seconds, default is 3
73
+ /// - Parameter message: Custom failure message
74
+ /// - Returns: Test expectation of this assertion
75
+ func expectErrors( count: UInt = 1 ,
76
+ _ validation: @escaping ( [ Error ] ) -> Bool = { _ in true } ,
77
+ timeout: UInt8 = 3 ,
78
+ message: @escaping @autoclosure ( ) -> String = String ( ) ,
79
+ file: StaticString = #file,
80
+ line: UInt = #line) -> TestExpectation
81
+ {
82
+ let expectation : TestExpectation = . init( timeout: timeout, file: file, line: line)
83
+
84
+ var errorsList : Array < Error > = . init( )
85
+ let errorsMutex : Mutex . Pointer = Mutex . make ( recursive: true )
86
+
87
+ self . errors { [ weak expectation] ( error) in
88
+ guard let expectation = expectation else { return }
89
+ Mutex . lock ( errorsMutex)
90
+ defer { Mutex . unlock ( errorsMutex) }
91
+ if errorsList. count < count {
92
+ errorsList. append ( error)
93
+ } else { /* nothing */ }
94
+ guard errorsList. count == count else { return }
95
+ guard !expectation. timedOut else { return }
96
+ defer { expectation. fulfill ( ) }
97
+ let result = validation ( errorsList)
98
+ guard !result else { return }
99
+ let message = message ( )
100
+ XCTFail ( message. isEmpty ? " Invalid errors " : message, file: file, line: line)
101
+ }
102
+ self . finished {
103
+ Mutex . destroy ( errorsMutex)
104
+ }
105
+
106
+ return expectation
107
+ }
108
+
109
+ /// Asserts Signal is terminated. Fails if it was finished without error or timed out.
110
+ /// Timeout assertion is performed by TestExpectation when executing `waitForExpectation()`.
111
+ /// Note that waiting for expectation will block current thread.
112
+ /// Waiting have to be done manually by calling `waitForExpectation()` on returned Expectation.
113
+ ///
114
+ /// - Parameter validation: Error validation function, assertion will fail if returns false
115
+ /// - Parameter timeout: Wait timeout in seconds, default is 3
116
+ /// - Parameter message: Custom failure message
117
+ /// - Returns: Test expectation of this assertion
118
+ func expectTerminated( _ validation: @escaping ( Error ) -> Bool = { _ in true } ,
119
+ timeout: UInt8 = 3 ,
120
+ message: @escaping @autoclosure ( ) -> String = String ( ) ,
121
+ file: StaticString = #file,
122
+ line: UInt = #line) -> TestExpectation
123
+ {
124
+ let expectation : TestExpectation = . init( timeout: timeout, file: file, line: line)
125
+
126
+ self . terminated { [ weak expectation] reason in
127
+ guard let expectation = expectation else { return }
128
+ defer { expectation. fulfill ( ) }
129
+ let result = validation ( reason)
130
+ guard !result else { return }
131
+ let message = message ( )
132
+ XCTFail ( message. isEmpty ? " Invalid error " : message, file: file, line: line)
133
+ }
134
+
135
+
136
+ return expectation
137
+ }
138
+
139
+ /// Asserts Signal is ended. Fails if it was finished with error or timed out.
140
+ /// Timeout assertion is performed by TestExpectation when executing `waitForExpectation()`.
141
+ /// Note that waiting for expectation will block current thread.
142
+ /// Waiting have to be done manually by calling `waitForExpectation()` on returned Expectation.
143
+ ///
144
+ /// - Parameter timeout: Wait timeout in seconds, default is 3
145
+ /// - Parameter message: Custom failure message
146
+ /// - Returns: Test expectation of this assertion
147
+ func expectEnded( timeout: UInt8 = 3 ,
148
+ message: @escaping @autoclosure ( ) -> String = String ( ) ,
149
+ file: StaticString = #file,
150
+ line: UInt = #line) -> TestExpectation
151
+ {
152
+ let expectation : TestExpectation = . init( timeout: timeout, file: file, line: line)
153
+
154
+ self . ended { [ weak expectation] in
155
+ guard let expectation = expectation else { return }
156
+ expectation. fulfill ( )
157
+ }
158
+
159
+ return expectation
160
+ }
20
161
}
0 commit comments