packages feed

dataframe-3.7.0.0: tests/Assertions.hs

{-# LANGUAGE ScopedTypeVariables #-}

module Assertions where

import qualified Data.List as L

import Control.Exception
import GHC.Float (castDoubleToWord64, castFloatToWord32)
import Test.HUnit

-- Adapted from BartMassey/chunk, hunit.hs.
assertExpectException ::
    String ->
    String ->
    IO a ->
    Assertion
assertExpectException preface expected action = do
    r <-
        catch
            (action >> (return . Just) "no exception thrown")
            ( \(e :: SomeException) ->
                return (checkForExpectedException e)
            )
    case r of
        Nothing -> return ()
        Just msg -> assertFailure $ preface ++ ": " ++ msg
  where
    checkForExpectedException :: SomeException -> Maybe String
    checkForExpectedException e
        | expected `L.isInfixOf` show e = Nothing
        | otherwise =
            Just $
                "wrong exception detail, expected "
                    ++ expected
                    ++ ", got: "
                    ++ show e

-- | Equality that tells NaNs and signed zeros apart for floating types.
class BitEq a where
    bitEq :: a -> a -> Bool

instance BitEq Double where
    bitEq a b = castDoubleToWord64 a == castDoubleToWord64 b
instance BitEq Float where
    bitEq a b = castFloatToWord32 a == castFloatToWord32 b
instance BitEq Int where
    bitEq = (==)
instance BitEq Bool where
    bitEq = (==)
instance (BitEq a) => BitEq (Maybe a) where
    bitEq (Just a) (Just b) = bitEq a b
    bitEq Nothing Nothing = True
    bitEq _ _ = False

-- | Lists equal under 'bitEq'; on failure, reports the first differing row.
assertBitEq :: (BitEq a, Show a) => String -> [a] -> [a] -> Assertion
assertBitEq label expected actual
    | length expected /= length actual =
        assertFailure
            ( label
                ++ ": "
                ++ show (length actual)
                ++ " rows, expected "
                ++ show (length expected)
            )
    | otherwise = case [(i, e, a) | (i, e, a) <- zip3 [0 :: Int ..] expected actual, not (bitEq e a)] of
        [] -> pure ()
        (i, e, a) : _ ->
            assertFailure
                (label ++ ": row " ++ show i ++ " expected " ++ show e ++ ", got " ++ show a)