UnkindPartition / tasty

Modern and extensible testing framework for Haskell
640 stars 110 forks source link

assertEqual signature is not clear #325

Open yaitskov opened 2 years ago

yaitskov commented 2 years ago

Hi,

I noticed that I often had to check assertEqual signature, because I am not sure about argument order i.e. whether the expected value goes first or vice-versa. VSCode hint shows a value signature without argument comments. I had experience with many test libraries from many languages and they are not consistent about assert arguments. So I guess lots of developers might concentrate attention here unreasonably.

I would like to propose a less ambiguous signature:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DefaultSignatures #-}

import Data.Coercible

class (Eq ex, Eq got, Show ex, Show got) => AssertEq ex got where
  assertEqual' :: ex -> got -> IO ()
  default assertEq :: (Coercible ex got) => ex -> got -> IO () 
  assertEqual' expected got 
    | expected == coerce got = pure () 
    | otherwise = putStrLn $ "Expected: [" ++ show expected ++ "] but: [" ++ show got ++ "]" 

instance (Eq e, Eq g, Show e, Show g, Coercible e g) => AssertEq e g 

Check old and new variants:

$ :t assertEqual
assertEqual :: a -> a -> IO ()

$ :t assertEqual'
assertEqual' :: (Eq ex, Eq got, Show ex, Show got, Coercible ex got) =>  ex -> got -> IO ()

Order of assert arguments might be counterintuitive. Consider following English sentence: "Assert that x equals to y" Y sounds like a model value (i.e. expected value).

In assignments x <- y y is the model value, because it defines x. You get x - value on left not on the right.

Assembler dialects bring even more controversy, because MS assembler and GNU assembler have opposite order of operands. Destination of GAS mov instruction is on the right, meanwhile MS mov destination is on the left.