@@ -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,200 @@ 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 . wrapper = Wrapper ( v: v1)
110+ }
111+
112+ var id : Int
113+ var v1 : Int { wrapper. v }
114+
115+ class Wrapper : Equatable {
116+ var v : Int
117+ init ( v: Int ) { self . v = v }
118+
119+ static func == ( lhs: Wrapper , rhs: Wrapper ) -> Bool {
120+ lhs. v == rhs. v
121+ }
122+ }
123+ private var wrapper : Wrapper
124+
125+ static func == ( lhs: NonPODEquatable , rhs: NonPODEquatable ) -> Bool {
126+ lhs. id == rhs. id && ( lhs. v1 - rhs. v1) % 2 == 0
127+ }
128+ }
129+
130+ struct NonPODEquatableTrue : Equatable {
131+ init ( ) {
132+ self . wrapper = Wrapper ( )
133+ }
134+
135+ private var wrapper : Wrapper
136+
137+ class Wrapper { }
138+
139+ static func == ( lhs: NonPODEquatableTrue , rhs: NonPODEquatableTrue ) -> Bool {
140+ true
141+ }
142+ }
143+
144+ struct NonPODEquatableFalse : Equatable {
145+ init ( ) {
146+ self . wrapper = Wrapper . shared
147+ }
148+
149+ private var wrapper : Wrapper
150+
151+ class Wrapper {
152+ static let shared = Wrapper ( )
153+ }
154+
155+ static func == ( lhs: NonPODEquatableFalse , rhs: NonPODEquatableFalse ) -> Bool {
156+ false
157+ }
158+ }
159+
160+ @Test
161+ func bitwizeMode( ) async throws {
162+ let mode = ComparisonMode . bitwise
163+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
164+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
165+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
166+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
167+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
168+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
169+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
170+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == false )
171+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == true )
172+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
173+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == false , " bitwize compare will fail since M is a class " )
174+ }
175+
176+ @Test
177+ func equatableUnlessPODMode( ) async throws {
178+ let mode = ComparisonMode . equatableUnlessPOD
179+ // layout is not ready, use bitwise copmare
180+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
181+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
182+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
183+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
184+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
185+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
186+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
187+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == false )
188+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == true )
189+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
190+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == false )
191+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
192+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
193+ #expect( compareValues ( NonPODEquatableTrue ( ) , NonPODEquatableTrue ( ) , mode: mode) == false )
194+ #expect( compareValues ( NonPODEquatableFalse ( ) , NonPODEquatableFalse ( ) , mode: mode) == true )
195+
196+ try await Task . sleep ( nanoseconds: 1_000_000_000 )
197+
198+ // layout is ready, use Equatable copmare only for non POD type when avaiable
199+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
200+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
201+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
202+
203+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
204+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
205+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false , " POD type, use bitwise compare " )
206+
207+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
208+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == false , " POD type, use bitwise compare " )
209+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == true , " POD type, use bitwise compare " )
210+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
211+
212+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true , " Non POD type, use Equatable compare " )
213+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
214+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 4 ) , mode: mode) == true , " Non POD type, use Equatable compare " )
215+
216+ #expect( compareValues ( NonPODEquatableTrue ( ) , NonPODEquatableTrue ( ) , mode: mode) == true )
217+ #expect( compareValues ( NonPODEquatableFalse ( ) , NonPODEquatableFalse ( ) , mode: mode) == false )
218+ }
219+
220+ @Test
221+ func equatableAlwaysMode( ) async throws {
222+ let mode = ComparisonMode . equatableAlways
223+ // When layout is not ready, the same as bitwize
224+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
225+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
226+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
227+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
228+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
229+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
230+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
231+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == false )
232+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == true )
233+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
234+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == false )
235+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
236+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 4 ) , mode: mode) == false )
237+
238+ try await Task . sleep ( nanoseconds: 1_000_000_000 )
239+
240+ // layout is ready, Equatable is used when avaiable
241+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 1 ) , mode: mode) == true )
242+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 2 ) , mode: mode) == false )
243+ #expect( compareValues ( POD ( id: 1 ) , POD ( id: 3 ) , mode: mode) == false )
244+
245+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true )
246+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
247+ #expect( compareValues ( PODEquatable ( id: 1 , v1: 2 ) , PODEquatable ( id: 1 , v1: 4 ) , mode: mode) == true , " use Equatable compare " )
248+
249+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 1 ) , mode: mode) == true )
250+ #expect( compareValues ( PODEquatableTrue ( id: 1 ) , PODEquatableTrue ( id: 2 ) , mode: mode) == true , " use Equatable compare " )
251+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 1 ) , mode: mode) == false , " use Equatable compare " )
252+ #expect( compareValues ( PODEquatableFalse ( id: 1 ) , PODEquatableFalse ( id: 2 ) , mode: mode) == false )
253+
254+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 2 ) , mode: mode) == true , " use Equatable compare " )
255+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 3 ) , mode: mode) == false )
256+ #expect( compareValues ( NonPODEquatable ( id: 1 , v1: 2 ) , NonPODEquatable ( id: 1 , v1: 4 ) , mode: mode) == true , " use Equatable compare " )
257+ }
62258}
0 commit comments