@@ -206,22 +206,50 @@ end
206
206
end
207
207
208
208
@testset " equality & hashing" begin
209
- # singletons (identity and property lens) are object equal
210
- for (l, r ) ∈ [
209
+ # singletons (identity and property lens) are egal
210
+ for (l1, l2 ) ∈ [
211
211
@lens (_) => @lens (_),
212
212
@lens (_. a) => @lens (_. a)
213
213
]
214
- @test l === r
214
+ @test l1 === l2
215
+ @test l1 == l2
216
+ @test hash (l1) == hash (l2)
215
217
end
216
218
217
219
# composite and index lenses are structurally equal
218
- for (l, r ) ∈ [
220
+ for (l1, l2 ) ∈ [
219
221
@lens (_[1 ]) => @lens (_[1 ])
220
222
@lens (_. a[2 ]) => @lens (_. a[2 ])
223
+ @lens (_. a. b[3 ]) => @lens (_. a. b[3 ])
221
224
]
222
- @test l == r
223
- @test hash (l ) == hash (r )
225
+ @test l1 == l2
226
+ @test hash (l1 ) == hash (l2 )
224
227
end
228
+
229
+ # inequality
230
+ for (l1, l2) ∈ [
231
+ @lens (_[1 ]) => @lens (_[2 ])
232
+ @lens (_. a[1 ]) => @lens (_. a[2 ])
233
+ @lens (_. a[1 ]) => @lens (_. b[1 ])
234
+ ]
235
+ @test l1 != l2
236
+ end
237
+
238
+ # Hash property: equality implies equal hashes, or in other terms:
239
+ # lenses either have equal hashes or are unequal
240
+ # Because collisions can occur theoretically (though unlikely), this is a property test,
241
+ # not a unit test.
242
+ random_lenses = (@lens (_. a[rand (Int)]) for _ in 1 : 1000 )
243
+ @test all ((hash (l2) == hash (l1)) || (l1 != l2)
244
+ for (l1, l2) in zip (random_lenses, random_lenses))
245
+
246
+ # Lenses should hash differently from the underlying tuples, to avoid confusion.
247
+ # To account for potential collisions, we check that the property holds with high
248
+ # probability.
249
+ @test count (hash (@lens (_[i])) != hash ((i,)) for i = 1 : 1000 ) > 900
250
+
251
+ # Same for tuples of tuples (√(1000) ≈ 32).
252
+ @test count (hash (@lens (_[i][j])) != hash (((i,), (j,))) for i = 1 : 32 , j = 1 : 32 ) > 900
225
253
end
226
254
227
255
0 commit comments