@@ -2,6 +2,7 @@ import XCTest
2
2
import Combine
3
3
@testable import PublishedObject
4
4
5
+ @available ( iOS 13 . 0 , OSX 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
5
6
class Outer : ObservableObject {
6
7
@PublishedObject var innerPublishedObject : Inner
7
8
@Published var innerPublished : Inner
@@ -12,6 +13,7 @@ class Outer: ObservableObject {
12
13
}
13
14
}
14
15
16
+ @available ( iOS 13 . 0 , OSX 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
15
17
class Inner : ObservableObject {
16
18
@Published var value : Int
17
19
@@ -20,6 +22,18 @@ class Inner: ObservableObject {
20
22
}
21
23
}
22
24
25
+ @available ( iOS 13 . 0 , OSX 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
26
+ class OuterOptional : ObservableObject {
27
+ @PublishedObject var innerPublishedObject : Inner ?
28
+ @Published var innerPublished : Inner ?
29
+
30
+ init ( _ value: Int ? ) {
31
+ self . innerPublishedObject = value. map ( Inner . init)
32
+ self . innerPublished = value. map ( Inner . init)
33
+ }
34
+ }
35
+
36
+ @available ( iOS 13 . 0 , OSX 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
23
37
final class PublishedObjectTests : XCTestCase {
24
38
var cancellables : Set < AnyCancellable > = [ ]
25
39
@@ -115,9 +129,97 @@ final class PublishedObjectTests: XCTestCase {
115
129
outer. innerPublished. value = 3
116
130
wait ( for: [ exp5] , timeout: 0.1 )
117
131
}
132
+
133
+ func testOptionalWithValue( ) throws {
134
+ let outer = OuterOptional ( 1 )
135
+
136
+ // Setting property on Inner from the optional init (This will only send an update when using @PublishedObject)
137
+
138
+ let exp5 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
139
+ outer. objectWillChange. first ( ) . sink { exp5. fulfill ( ) } . store ( in: & cancellables)
140
+ outer. innerPublishedObject? . value = 3
141
+ wait ( for: [ exp5] , timeout: 0.1 )
142
+
143
+ let exp6 = XCTestExpectation ( description: " outer.objectWillChange will NOT be called " )
144
+ exp6. isInverted = true
145
+ outer. objectWillChange. first ( ) . sink { exp6. fulfill ( ) } . store ( in: & cancellables)
146
+ outer. innerPublished? . value = 3
147
+ wait ( for: [ exp6] , timeout: 0.1 )
148
+
149
+ // Setting property on Outer (This will send an update with either @Published or @PublishedObject)
150
+
151
+ let exp1 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
152
+ outer. objectWillChange. first ( ) . sink { exp1. fulfill ( ) } . store ( in: & cancellables)
153
+ outer. innerPublishedObject = Inner ( 2 )
154
+ wait ( for: [ exp1] , timeout: 0.1 )
155
+
156
+ let exp2 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
157
+ outer. objectWillChange. first ( ) . sink { exp2. fulfill ( ) } . store ( in: & cancellables)
158
+ outer. innerPublished = Inner ( 2 )
159
+ wait ( for: [ exp2] , timeout: 0.1 )
160
+
161
+ // Setting property on Inner (This will only send an update when using @PublishedObject)
162
+
163
+ let exp3 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
164
+ outer. objectWillChange. first ( ) . sink { exp3. fulfill ( ) } . store ( in: & cancellables)
165
+ outer. innerPublishedObject? . value = 3
166
+ wait ( for: [ exp3] , timeout: 0.1 )
167
+
168
+ let exp4 = XCTestExpectation ( description: " outer.objectWillChange will NOT be called " )
169
+ exp4. isInverted = true
170
+ outer. objectWillChange. first ( ) . sink { exp4. fulfill ( ) } . store ( in: & cancellables)
171
+ outer. innerPublished? . value = 3
172
+ wait ( for: [ exp4] , timeout: 0.1 )
173
+ }
174
+
175
+ func testOptionalWithoutValue( ) throws {
176
+ let outer = OuterOptional ( nil )
177
+
178
+ // Setting property on Inner while it is nil
179
+ // (this should never call objectWillChange because the Inner obj is not there so nothing is changed)
180
+
181
+ let exp5 = XCTestExpectation ( description: " uhhhhm " )
182
+ exp5. isInverted = true
183
+ outer. objectWillChange. first ( ) . sink { exp5. fulfill ( ) } . store ( in: & cancellables)
184
+ outer. innerPublishedObject? . value = 3
185
+ wait ( for: [ exp5] , timeout: 0.1 )
186
+
187
+ let exp6 = XCTestExpectation ( description: " uhhhhm " )
188
+ exp6. isInverted = true
189
+ outer. objectWillChange. first ( ) . sink { exp6. fulfill ( ) } . store ( in: & cancellables)
190
+ outer. innerPublished? . value = 3
191
+ wait ( for: [ exp6] , timeout: 0.1 )
192
+
193
+ // Setting property on Outer (This will send an update with either @Published or @PublishedObject)
194
+
195
+ let exp1 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
196
+ outer. objectWillChange. first ( ) . sink { exp1. fulfill ( ) } . store ( in: & cancellables)
197
+ outer. innerPublishedObject = Inner ( 2 )
198
+ wait ( for: [ exp1] , timeout: 0.1 )
199
+
200
+ let exp2 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
201
+ outer. objectWillChange. first ( ) . sink { exp2. fulfill ( ) } . store ( in: & cancellables)
202
+ outer. innerPublished = Inner ( 2 )
203
+ wait ( for: [ exp2] , timeout: 0.1 )
204
+
205
+ // Setting property on Inner (This will only send an update when using @PublishedObject)
206
+
207
+ let exp3 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
208
+ outer. objectWillChange. first ( ) . sink { exp3. fulfill ( ) } . store ( in: & cancellables)
209
+ outer. innerPublishedObject? . value = 3
210
+ wait ( for: [ exp3] , timeout: 0.1 )
211
+
212
+ let exp4 = XCTestExpectation ( description: " outer.objectWillChange will NOT be called " )
213
+ exp4. isInverted = true
214
+ outer. objectWillChange. first ( ) . sink { exp4. fulfill ( ) } . store ( in: & cancellables)
215
+ outer. innerPublished? . value = 3
216
+ wait ( for: [ exp4] , timeout: 0.1 )
217
+ }
118
218
119
219
static var allTests = [
120
220
( " testObjectWillChange " , testObjectWillChange) ,
121
221
( " testProjectedValue " , testProjectedValue) ,
222
+ ( " testOptionalWithValue " , testOptionalWithValue) ,
223
+ ( " testOptionalWithoutValue " , testOptionalWithoutValue) ,
122
224
]
123
225
}
0 commit comments