packages feed

persistent-mtl-0.1.0.0: test/TestUtils/Match.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module TestUtils.Match
  ( Match(..)
  , (@?~)
  , CanMatch(..)
  ) where

import Test.Tasty.HUnit (Assertion, assertFailure)

data Match a = Match a | Anything

instance Show a => Show (Match a) where
  show Anything = "[...]"
  show (Match a) = show a

-- | An HUnit operator for checking that the given arguments match.
(@?~) :: (CanMatch actual expected, Show actual, Show expected) => actual -> expected -> Assertion
(@?~) actual expected =
  if matches actual expected
    then return ()
    else assertFailure $ unlines
      [ "Expected:"
      , "  " ++ show expected
      , "Got:"
      , "  " ++ show actual
      ]

class CanMatch a b where
  matches :: a -> b -> Bool

instance {-# OVERLAPPABLE #-} Eq a => CanMatch a a where
  matches = (==)

instance CanMatch a b => CanMatch a (Match b) where
  matches _ Anything = True
  matches a (Match b) = matches a b

instance CanMatch a b => CanMatch [a] [b] where
  matches as bs = length as == length bs && and (zipWith matches as bs)

instance (CanMatch a c, CanMatch b d) => CanMatch (Either a b) (Either c d) where
  matches (Left a) (Left c) = matches a c
  matches (Right b) (Right d) = matches b d
  matches _ _ = False