@@ -33,7 +33,7 @@ struct CompareValuesCompatibilityTests {
3333 }
3434
3535 @Test
36- func testStructCompare ( ) throws {
36+ func structCompare ( ) throws {
3737 struct A1 {
3838 var a : Int
3939 var b : Bool
@@ -59,4 +59,165 @@ struct CompareValuesCompatibilityTests {
5959 }
6060 }
6161 }
62+
63+
64+ // Below is the graph to show the expected behavior of compareValues with different modes and types
65+ // ┌──────────────────┬────────────────────┬──────────────────┬──────────────────┐
66+ // │ │ mode │ Layout not ready │ Layout ready │
67+ // ├──────────────────┼────────────────────┼──────────────────┼──────────────────┤
68+ // │ │ bitwise │ bitwise │ bitwise │
69+ // │ PODEquatable │ equatableUnlessPOD │ bitwise │ bitwise │
70+ // │ │ equatableAlways │ bitwise │ equatable │
71+ // ├──────────────────┼────────────────────┼──────────────────┼──────────────────┤
72+ // │ │ bitwise │ bitwise │ bitwise │
73+ // │ NonPODEquatable │ equatableUnlessPOD │ bitwise │ equatable │
74+ // │ │ equatableAlways │ bitwise │ equatable │
75+ // └──────────────────┴────────────────────┴──────────────────┴──────────────────┘
76+
77+ struct POD {
78+ var id : Int
79+ }
80+
81+ struct PODEquatable : Equatable {
82+ var id : Int
83+ var v1 : Int
84+
85+ static func == ( lhs: Self , rhs: Self ) -> Bool {
86+ lhs. id == rhs. id && ( lhs. v1 - rhs. v1) % 2 == 0
87+ }
88+ }
89+
90+ struct PODEquatableTrue : Equatable {
91+ var id : Int
92+
93+ static func == ( lhs: Self , rhs: Self ) -> Bool {
94+ true
95+ }
96+ }
97+
98+ struct PODEquatableFalse : Equatable {
99+ var id : Int
100+
101+ static func == ( lhs: Self , rhs: Self ) -> Bool {
102+ false
103+ }
104+ }
105+
106+ struct NonPODEquatable : Equatable {
107+ init ( id: Int , v1: Int ) {
108+ self . id = id
109+ self . m = M ( v: v1)
110+ }
111+
112+ var id : Int
113+ var v1 : Int { m. v }
114+
115+ class M : Equatable {
116+ var v : Int
117+ init ( v: Int ) { self . v = v }
118+
119+ static func == ( lhs: M , rhs: M ) -> Bool {
120+ lhs. v == rhs. v
121+ }
122+ }
123+ var m : M
124+
125+ static func == ( lhs: NonPODEquatable , rhs: NonPODEquatable ) -> Bool {
126+ lhs. id == rhs. id && ( lhs. v1 - rhs. v1) % 2 == 0
127+ }
128+ }
129+
130+ @Test
131+ func bitwizeMode( ) async throws {
132+ let mode = ComparisonMode . bitwise
133+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
134+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
135+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
136+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
137+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
138+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
139+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
140+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == false )
141+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == true )
142+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
143+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == false , " bitwize compare will fail since M is a class " )
144+ }
145+
146+ @Test
147+ func equatableUnlessPODMode( ) async throws {
148+ let mode = ComparisonMode . equatableUnlessPOD
149+ // layout is not ready, use bitwise copmare
150+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
151+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
152+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
153+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
154+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
155+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
156+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
157+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == false )
158+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == true )
159+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
160+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == false )
161+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
162+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
163+
164+ try await Task . sleep ( for: . seconds( 1 ) )
165+
166+ // layout is ready, use Equatable copmare only for non POD type when avaiable
167+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
168+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
169+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
170+
171+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
172+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
173+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false , " POD type, use bitwise compare " )
174+
175+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
176+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == false , " POD type, use bitwise compare " )
177+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == true , " POD type, use bitwise compare " )
178+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
179+
180+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true , " Non POD type, use Equatable compare " )
181+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
182+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 4 ) , mode: mode) == true , " Non POD type, use Equatable compare " )
183+ }
184+
185+ @Test
186+ func equatableAlwaysMode( ) async throws {
187+ let mode = ComparisonMode . equatableAlways
188+ // When layout is not ready, the same as bitwize
189+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
190+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
191+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
192+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
193+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
194+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
195+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
196+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == false )
197+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == true )
198+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
199+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == false )
200+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
201+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
202+
203+ try await Task . sleep ( for: . seconds( 1 ) )
204+
205+ // layout is ready, Equatable is used when avaiable
206+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
207+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
208+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
209+
210+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
211+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
212+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == true , " use Equatable compare " )
213+
214+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
215+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == true , " use Equatable compare " )
216+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == false , " use Equatable compare " )
217+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
218+
219+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true , " use Equatable compare " )
220+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
221+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 4 ) , mode: mode) == true , " use Equatable compare " )
222+ }
62223}
0 commit comments