{- Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved. This source code is licensed under the BSD-style license found in the LICENSE file in the root directory of this source tree. -} module Util.HUnit ( absError , assertAbsError , assertElem , assertSubsetOf , assertNotElem , assertPermutationOf , assertThrow ) where import Control.Exception import Data.Either (isLeft) import Data.Foldable (toList) import Data.List import Test.HUnit -- | The absolute error between an expected and actual value. absError :: (Fractional a) => a -> a -> a absError expected actual = abs (expected - actual) -- | Asserts that the absolute error of a value is within a given -- range. If you want the range to be in the realm of machine epsilon, -- use @Data.AEq@ instead. assertAbsError :: (Fractional a, Ord a, Show a) => String -- ^ Error message. -> a -- ^ Expected value. -> a -- ^ Error range (e.g., @1e-3@). -> a -- ^ Actual value. -> Assertion assertAbsError message expected epsilon actual = flip assertBool (absError expected actual <= epsilon) $ concat [ message , " (expected " , show expected , "+/-" , show epsilon , " but got " , show actual , ")" ] assertPermutationOf :: (Ord a, Show a) => String -> [a] -> [a] -> Assertion assertPermutationOf m as bs = assertEqual m (sort as) (sort bs) assertElem :: (Eq a, Show a, Foldable t) => String -> a -> t a -> Assertion assertElem message expected actual = flip assertBool (expected `elem` actual) $ concat [ message , " (expected " , show expected , " to occur in " , show $ toList actual , ")" ] assertSubsetOf :: (Eq a, Show a, Foldable t, Foldable f) => String -> f a -> t a -> Assertion assertSubsetOf message expected actual = flip assertBool (all (`elem` actual) expected) $ concat [ message , " (expected all of" , show $ toList expected , " to occur in " , show $ toList actual , ")" ] assertNotElem :: (Eq a, Show a, Foldable t) => String -> a -> t a -> Assertion assertNotElem message expected actual = flip assertBool (not $ expected `elem` actual) $ concat [ message , " (expected " , show expected , " to not occur in " , show $ toList actual , ")" ] assertThrow :: (Show a) => String -> IO a -> Assertion assertThrow message test = do (actual :: Either SomeException a) <- try test flip assertBool (isLeft actual) $ concat [ message , " (expected: exception thrown; but got: " , show actual , ")" ]