@@ -33,13 +33,24 @@ class OuterOptional: ObservableObject {
3333 }
3434}
3535
36+ @available ( iOS 13 . 0 , OSX 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
37+ class OuterArray : ObservableObject {
38+ @PublishedObject var innerPublishedObject : [ Inner ]
39+ @Published var innerPublished : [ Inner ]
40+
41+ init ( _ value: Int ) {
42+ self . innerPublishedObject = [ Inner ( value) ]
43+ self . innerPublished = [ Inner ( value) ]
44+ }
45+ }
46+
3647@available ( iOS 13 . 0 , OSX 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
3748final class PublishedObjectTests : XCTestCase {
3849 var cancellables : Set < AnyCancellable > = [ ]
39-
40- func testObjectWillChange ( ) throws {
41- let outer = Outer ( 1 )
42-
50+
51+ var outer : Outer ! = Outer ( 1 )
52+
53+ func testObjectWillChange ( ) {
4354 // Setting property on Outer (This will send an update with either @Published or @PublishedObject)
4455
4556 let exp1 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
@@ -66,11 +77,10 @@ final class PublishedObjectTests: XCTestCase {
6677 wait ( for: [ exp4] , timeout: 0.1 )
6778 }
6879
69- func testProjectedValue( ) throws {
70- let outer = Outer ( 1 )
71-
80+ func testProjectedValue( ) {
81+
7282 // Initial value
73-
83+
7484 let exp0 = XCTestExpectation ( description: " projectedValue will be called " )
7585 outer. $innerPublishedObject. first ( ) . sink { inner in
7686 if inner. value == 1 {
@@ -216,10 +226,116 @@ final class PublishedObjectTests: XCTestCase {
216226 wait ( for: [ exp4] , timeout: 0.1 )
217227 }
218228
229+ func testArrayObjectWillChange( ) {
230+ let outer = OuterArray ( 1 )
231+
232+ // Setting property on Outer (This will send an update with either @Published or @PublishedObject)
233+
234+ let exp1 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
235+ outer. objectWillChange. first ( ) . sink { exp1. fulfill ( ) } . store ( in: & cancellables)
236+ outer. innerPublishedObject = [ Inner ( 2 ) ]
237+ wait ( for: [ exp1] , timeout: 0.1 )
238+
239+ let exp2 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
240+ outer. objectWillChange. first ( ) . sink { exp2. fulfill ( ) } . store ( in: & cancellables)
241+ outer. innerPublished = [ Inner ( 2 ) ]
242+ wait ( for: [ exp2] , timeout: 0.1 )
243+
244+ // Setting property on Inner (This will only send an update when using @PublishedObject)
245+
246+ let exp3 = XCTestExpectation ( description: " outer.objectWillChange will be called " )
247+ outer. objectWillChange. first ( ) . sink { exp3. fulfill ( ) } . store ( in: & cancellables)
248+ outer. innerPublishedObject [ 0 ] . value = 3
249+ wait ( for: [ exp3] , timeout: 0.1 )
250+
251+ let exp4 = XCTestExpectation ( description: " outer.objectWillChange will NOT be called " )
252+ exp4. isInverted = true
253+ outer. objectWillChange. first ( ) . sink { exp4. fulfill ( ) } . store ( in: & cancellables)
254+ outer. innerPublished [ 0 ] . value = 3
255+ wait ( for: [ exp4] , timeout: 0.1 )
256+ }
257+
258+ func testArrayProjectedValue( ) {
259+ let outer = OuterArray ( 1 )
260+
261+ // Initial value
262+
263+ let exp0 = XCTestExpectation ( description: " projectedValue will be called " )
264+ outer. $innerPublishedObject. compactMap ( \. first) . first ( ) . sink { inner in
265+ if inner. value == 1 {
266+ exp0. fulfill ( )
267+ }
268+ } . store ( in: & cancellables)
269+ wait ( for: [ exp0] , timeout: 0.1 )
270+
271+ let exp1 = XCTestExpectation ( description: " projectedValue will be called " )
272+ outer. $innerPublished. compactMap ( \. first) . first ( ) . sink { inner in
273+ if inner. value == 1 {
274+ exp1. fulfill ( )
275+ }
276+ } . store ( in: & cancellables)
277+ wait ( for: [ exp1] , timeout: 0.1 )
278+
279+
280+ // Setting property on Outer (This will send an update with either @Published or @PublishedObject)
281+
282+ let exp2 = XCTestExpectation ( description: " projectedValue will be called " )
283+ outer. $innerPublishedObject. compactMap ( \. first) . dropFirst ( ) . first ( ) . sink { inner in
284+ if inner. value == 2 {
285+ exp2. fulfill ( )
286+ }
287+ } . store ( in: & cancellables)
288+ outer. innerPublishedObject [ 0 ] = Inner ( 2 )
289+ wait ( for: [ exp2] , timeout: 0.1 )
290+
291+ let exp3 = XCTestExpectation ( description: " projectedValue will be called " )
292+ outer. $innerPublished. compactMap ( \. first) . dropFirst ( ) . first ( ) . sink { inner in
293+ if inner. value == 2 {
294+ exp3. fulfill ( )
295+ }
296+ } . store ( in: & cancellables)
297+ outer. innerPublished [ 0 ] = Inner ( 2 )
298+ wait ( for: [ exp3] , timeout: 0.1 )
299+
300+ // Setting property on Inner (This will only send an update when using @PublishedObject)
301+
302+ let exp4 = XCTestExpectation ( description: " projectedValue will be called " )
303+ outer. $innerPublishedObject. compactMap ( \. first) . dropFirst ( ) . first ( ) . sink { inner in
304+ if inner. value == 3 {
305+ exp4. fulfill ( )
306+ }
307+ } . store ( in: & cancellables)
308+ outer. innerPublishedObject [ 0 ] . value = 3
309+ wait ( for: [ exp4] , timeout: 0.1 )
310+
311+ let exp5 = XCTestExpectation ( description: " projectedValue will NOT be called " )
312+ exp5. isInverted = true
313+ outer. $innerPublished. compactMap ( \. first) . dropFirst ( ) . first ( ) . sink { inner in
314+ if inner. value == 3 {
315+ exp5. fulfill ( )
316+ }
317+ } . store ( in: & cancellables)
318+ outer. innerPublished [ 0 ] . value = 3
319+ wait ( for: [ exp5] , timeout: 0.1 )
320+ }
321+
322+ func testMemoryLeak( ) {
323+ weak var weakOuter = outer
324+ testObjectWillChange ( )
325+ outer = nil
326+ XCTAssertNil ( weakOuter)
327+ outer = Outer ( 1 )
328+ weakOuter = outer
329+ testProjectedValue ( )
330+ outer = nil
331+ XCTAssertNil ( weakOuter)
332+ }
333+
219334 static var allTests = [
220335 ( " testObjectWillChange " , testObjectWillChange) ,
221336 ( " testProjectedValue " , testProjectedValue) ,
222337 ( " testOptionalWithValue " , testOptionalWithValue) ,
223338 ( " testOptionalWithoutValue " , testOptionalWithoutValue) ,
339+ ( " testMemoryLeak " , testMemoryLeak) ,
224340 ]
225341}
0 commit comments