Currently the Expect api has a number of equality assertions specialised for different datastructures.
The problem with these is that they don't compose. This is most notable with the float equality operator (Expect.within). You even get an error message when you try to Expect.equal two Float values, but Expect.equal { foo = 3.14 } { foo = pi } is fine...
This is also the case with listsEqualsetsEqual and dictsEqual, albeit it's a bit less of a problem for those.
Finally, I should mention (and perhaps this is worth highlighting in a separate issue) that the floating equality doesn't deal with NaN values...
API Proposal
So I would propose the following:
equal : a -> a -> Expectation
type NaNBehavior = NaNsAlwaysEqual | NaNsNeverEqual
equalWithNumbers : NaNBehavior -> FloatingPointTolerance -> a -> a -> Expectation
not : (a -> b -> Expectation) -> a -> b -> Expectation
and remove:
notEqual (achieved with subject |> Expect.not Expect.equal expectation)
within (achieved with float |> Expect.equalWithNumbers NaNsAlwaysEqual tolerance expectation)
notWithin (achieved with float |> Expect.not (Expect.equalWithFloats NaNsAlwaysEqual tolerance) expectation)
Numbers are relatively easy to detect, and we can use the arguments to provide correct matching behavior. I'm less sure about the feasability of correctly detecting lists, sets and dicts to provide nice diff formatting...
Currently the
Expect
api has a number of equality assertions specialised for different datastructures.The problem with these is that they don't compose. This is most notable with the float equality operator (Expect.within). You even get an error message when you try to
Expect.equal
twoFloat
values, butExpect.equal { foo = 3.14 } { foo = pi }
is fine...This is also the case with
listsEqual
setsEqual
anddictsEqual
, albeit it's a bit less of a problem for those.Finally, I should mention (and perhaps this is worth highlighting in a separate issue) that the floating equality doesn't deal with
NaN
values...API Proposal
So I would propose the following:
and remove:
notEqual
(achieved withsubject |> Expect.not Expect.equal expectation
)within
(achieved withfloat |> Expect.equalWithNumbers NaNsAlwaysEqual tolerance expectation
)notWithin
(achieved withfloat |> Expect.not (Expect.equalWithFloats NaNsAlwaysEqual tolerance) expectation
)equalLists
(justequal
will do)equalSets
(justequal
will do)equalDicts
(justequal
will do)Implementation concerns
Of course to implement the new APIs I think we would need to reach into native code. Essentially we would be copying https://github.com/elm/core/blob/65cea00afa0de03d7dda0487d964a305fc3d58e3/src/Elm/Kernel/Utils.js#L15, but rather than returning booleans, we would use runtime type information to specialise behavior.
Numbers are relatively easy to detect, and we can use the arguments to provide correct matching behavior. I'm less sure about the feasability of correctly detecting lists, sets and dicts to provide nice diff formatting...