{-# OPTIONS_GHC -cpp -pgmP "cpphs --layout --hashes --cpp" #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE BangPatterns #-} -- -- Copyright (c) 2005-2022 Stefan Wehr - http://www.stefanwehr.de -- -- This library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- This library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with this library; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA -- {-| This module provides assert-like functions for writing unit tests. -} module Test.Framework.HUnitWrapper ( -- * Assertions on Bool values assertBool, assertBoolVerbose, -- * Equality assertions assertEqual, assertEqualVerbose, assertEqualPretty, assertEqualPrettyVerbose, assertEqualNoShow, assertEqualNoShowVerbose, -- * Inequality assertions assertNotEqual, assertNotEqualVerbose, assertNotEqualPretty, assertNotEqualPrettyVerbose, assertNotEqualNoShow, assertNotEqualNoShowVerbose, -- * Assertions on lists assertListsEqualAsSets, assertListsEqualAsSetsVerbose, assertNotEmpty, assertNotEmptyVerbose, assertEmpty, assertEmptyVerbose, assertElem, assertElemVerbose, -- * Assertions for exceptions assertThrows, assertThrowsVerbose, assertThrowsSome, assertThrowsSomeVerbose, assertThrowsIO, assertThrowsIOVerbose, assertThrowsSomeIO, assertThrowsSomeIOVerbose, assertThrowsM, assertThrowsMVerbose, assertThrowsSomeM, assertThrowsSomeMVerbose, -- * Assertions on Either values assertLeft, assertLeftVerbose, assertLeftNoShow, assertLeftNoShowVerbose, assertRight, assertRightVerbose, assertRightNoShow, assertRightNoShowVerbose, -- * Assertions on Just values assertJust, assertJustVerbose, assertNothing, assertNothingVerbose, assertNothingNoShow, assertNothingNoShowVerbose, -- * General failure assertFailure, -- * Pending unit tests unitTestPending, unitTestPending', -- * Sub assertions subAssert, subAssertVerbose, -- * Generalized assertions and failures in AssertM {- | The following definitions generalize the the monad in which assertions are executed. Usually, assertions are executed in the @IO@ monad. The @AssertM@ monad (see "Test.Framework.AssertM") allows you to evaluate assertions also as pure functions. -} -- ** Assertions on Bool values gassertBool, gassertBoolVerbose, -- ** Equality assertions gassertEqual, gassertEqualVerbose, gassertEqualPretty, gassertEqualPrettyVerbose, gassertEqualNoShow, gassertEqualNoShowVerbose, -- ** Inequality assertions gassertNotEqual, gassertNotEqualVerbose, gassertNotEqualPretty, gassertNotEqualPrettyVerbose, gassertNotEqualNoShow, gassertNotEqualNoShowVerbose, -- ** Assertions on lists gassertListsEqualAsSets, gassertListsEqualAsSetsVerbose, gassertNotEmpty, gassertNotEmptyVerbose, gassertEmpty, gassertEmptyVerbose, gassertElem, gassertElemVerbose, -- ** Assertions on Either values gassertLeft, gassertLeftVerbose, gassertLeftNoShow, gassertLeftNoShowVerbose, gassertRight, gassertRightVerbose, gassertRightNoShow, gassertRightNoShowVerbose, -- ** Assertions on Just values gassertJust, gassertJustVerbose, gassertNothing, gassertNothingVerbose, gassertNothingNoShow, gassertNothingNoShowVerbose, -- ** General failure gassertFailure, -- ** Sub assertions gsubAssert, gsubAssertVerbose, -- * HUnit re-exports HU.HUnitFailure, -- * Tests (for internal use) hunitWrapperTests ) where import Control.Exception import qualified Control.Exception.Lifted as ExL import Control.Monad.Trans.Control import Control.Monad.Trans import qualified Test.HUnit.Lang as HU #if !MIN_VERSION_HUnit(1,4,0) import qualified Test.HUnit.Base as HU #endif import GHC.Stack import Data.List ( (\\) ) import System.IO.Unsafe (unsafePerformIO) import Test.Framework.TestInterface import Test.Framework.Location import Test.Framework.Diff import Test.Framework.Colors import Test.Framework.Pretty import Test.Framework.AssertM import Test.Framework.PrettyHaskell import Test.Framework.Utils import qualified Data.Text as T import qualified Data.List as List -- WARNING: do not forget to add a preprocessor macro for new assertions!! {- | Fail with the given reason in some 'AssertM' monad. -} gassertFailure :: (HasCallStack, AssertM m) => String -> m a gassertFailure s = genericAssertFailure (mkMsg "assertFailure" "" s) -- | Specialization of 'gassertFailure' to @IO@. assertFailure :: HasCallStack => String -> IO a assertFailure = gassertFailure {- | Signals that the current unit test is pending. -} unitTestPending :: String -> IO a unitTestPending s = failHTF (FullTestResult emptyHtfStack (Just $ noColor s) (Just Pending)) {- | Use @unitTestPending' msg test@ to mark the given test as pending without removing it from the test suite and without deleting or commenting out the test code. -} unitTestPending' :: String -> IO a -> IO a unitTestPending' msg _ = unitTestPending msg mkMsg :: String -> String -> String -> ColorString mkMsg s1 s2 s3 = mkColorMsg s1 s2 (noColor s3) mkColorMsg :: String -> String -> ColorString -> ColorString mkColorMsg fun extraInfo s = let pref = if null extraInfo then fun ++ " " else fun ++ " (" ++ extraInfo ++ ") " in noColor pref +++ s -- -- Boolean Assertions -- assertBool_ :: (HasCallStack, AssertM m) => String -> String -> Bool -> m () assertBool_ name s False = genericAssertFailure (mkMsg name s "failed") assertBool_ _ _ True = return () -- | Fail if the 'Bool' value is 'False'. assertBool :: HasCallStack => Bool -> IO () assertBool = assertBool_ "assertBool" "" assertBoolVerbose :: HasCallStack => String -> Bool -> IO () assertBoolVerbose = assertBool_ "assertBoolVerbose" gassertBool :: (HasCallStack, AssertM m) => Bool -> m () gassertBool = assertBool_ "gassertBool" "" gassertBoolVerbose :: (HasCallStack, AssertM m) => String -> Bool -> m () gassertBoolVerbose = assertBool_ "gassertBoolVerbose" -- -- Equality Assertions -- equalityFailedMessage' :: String -> String -> ColorString equalityFailedMessage' exp act = let !diff = unsafePerformIO (diffWithSensibleConfig exp act) expected_ = colorize firstDiffColor "* expected:" but_got_ = colorize secondDiffColor "* but got:" diff_ = colorize diffColor "* diff:" in ("\n" +++ expected_ +++ " " +++ noColor (withNewline (trim exp)) +++ "\n" +++ but_got_ +++ " " +++ noColor (withNewline (trim act)) +++ "\n" +++ diff_ +++ " " +++ newlineBeforeDiff diff +++ diff +++ (if (exp == act) then "\nWARNING: strings are equal but actual values differ!" else "")) where withNewline s = case lines s of [] -> s [_] -> s _ -> '\n':s newlineBeforeDiff d = let f b = case colorStringFind (\c -> c == '\n') d b of Just _ -> "\n" Nothing -> "" in noColor' (f True) (f False) trim s = case List.splitAt maxLen s of (_, []) -> s (prefix, rest) -> prefix ++ " (removed " ++ show (length rest) ++ " trailing chars)" maxLen = 10000 asString :: Show a => a -> Maybe String asString x = readM (show x) equalityFailedMessage :: (Show a) => a -> a -> ColorString equalityFailedMessage exp act = equalityFailedMessage' expP actP where (expP, actP) = case (asString exp, asString act) of (Just expS, Just actS) | expS /= actS -> (expS, actS) _ -> case (prettyHaskell' exp, prettyHaskell' act) of (Nothing, _) -> (show exp, show act) (_, Nothing) -> (show exp, show act) (Just expP, Just actP) | expP == actP -> (show exp, show act) | otherwise -> (expP, actP) notEqualityFailedMessage :: Show a => a -> String notEqualityFailedMessage exp = notEqualityFailedMessage' (prettyHaskell exp) notEqualityFailedMessage' :: String -> String notEqualityFailedMessage' exp = (": Objects are equal\n" ++ exp) failedAt :: HasCallStack => String failedAt = case failureLocation of Nothing -> "failed" Just loc -> "failed at " ++ showLoc loc assertEqual_ :: (Eq a, Show a, AssertM m, HasCallStack) => String -> String -> a -> a -> m () assertEqual_ name s expected actual = if expected /= actual then do let x = equalityFailedMessage expected actual genericAssertFailure (mkColorMsg name s $ noColor failedAt +++ x) else return () -- | Fail in some 'AssertM' monad if the two values of type @a@ are not equal, supplying -- an additional message. -- Use if @a@ is an instance of 'Show' but not of 'Pretty'. gassertEqualVerbose :: (Eq a, Show a, AssertM m, HasCallStack) => String -> a -> a -> m () gassertEqualVerbose = assertEqual_ "gassertEqualVerbose" -- | Fail in some 'AssertM' monad if the two values of type @a@ are not equal. -- Use if @a@ is an instance of 'Show' but not of 'Pretty'. gassertEqual :: (Eq a, Show a, AssertM m, HasCallStack) => a -> a -> m () gassertEqual = assertEqual_ "gassertEqual" "" -- | Fail if the two values of type @a@ are not equal, supplying -- an additional message. -- Use if @a@ is an instance of 'Show' but not of 'Pretty'. assertEqualVerbose :: (Eq a, Show a, HasCallStack) => String -> a -> a -> IO () assertEqualVerbose = assertEqual_ "assertEqualVerbose" -- | Fail if the two values of type @a@ are not equal. -- Use if @a@ is an instance of 'Show' but not of 'Pretty'. assertEqual :: (Eq a, Show a, HasCallStack) => a -> a -> IO () assertEqual = assertEqual_ "assertEqual" "" assertNotEqual_ :: (Eq a, Show a, AssertM m, HasCallStack) => String -> String -> a -> a -> m () assertNotEqual_ name s expected actual = if expected == actual then do let x = notEqualityFailedMessage expected genericAssertFailure (mkMsg name s $ failedAt ++ x) else return () -- | Fail in some 'AssertM' monad if the two values of type @a@ are equal, supplying -- an additional message. -- Use if @a@ is an instance of 'Show' but not of 'Pretty'. gassertNotEqualVerbose :: (Eq a, Show a, AssertM m, HasCallStack) => String -> a -> a -> m () gassertNotEqualVerbose = assertNotEqual_ "gassertNotEqualVerbose" -- | Fail in some 'AssertM' monad if the two values of type @a@ are equal. -- Use if @a@ is an instance of 'Show' but not of 'Pretty'. gassertNotEqual :: (Eq a, Show a, AssertM m, HasCallStack) => a -> a -> m () gassertNotEqual = assertNotEqual_ "gassertNotEqual" "" -- | Fail if the two values of type @a@ are equal, supplying -- an additional message. -- Use if @a@ is an instance of 'Show' but not of 'Pretty'. assertNotEqualVerbose :: (Eq a, Show a, HasCallStack) => String -> a -> a -> IO () assertNotEqualVerbose = assertNotEqual_ "assertNotEqualVerbose" -- | Fail if the two values of type @a@ are equal. -- Use if @a@ is an instance of 'Show' but not of 'Pretty'. assertNotEqual :: (Eq a, Show a, HasCallStack) => a -> a -> IO () assertNotEqual = assertNotEqual_ "assertNotEqual" "" assertEqualPretty_ :: (Eq a, Pretty a, AssertM m, HasCallStack) => String -> String -> a -> a -> m () assertEqualPretty_ name s expected actual = if expected /= actual then do let x = equalityFailedMessage' (showPretty expected) (showPretty actual) genericAssertFailure (mkColorMsg name s (noColor failedAt +++ x)) else return () -- | Fail in some 'AssertM' monad if the two values of type @a@ are not equal, supplying -- an additional message. -- Use if @a@ is an instance of 'Pretty'. gassertEqualPrettyVerbose :: (Eq a, Pretty a, AssertM m, HasCallStack) => String -> a -> a -> m () gassertEqualPrettyVerbose = assertEqualPretty_ "gassertEqualPrettyVerbose" -- | Fail in some 'AssertM' monad if the two values of type @a@ are not equal. -- Use if @a@ is an instance of 'Pretty'. gassertEqualPretty :: (Eq a, Pretty a, AssertM m, HasCallStack) => a -> a -> m () gassertEqualPretty = assertEqualPretty_ "gassertEqualPretty" "" -- | Fail if the two values of type @a@ are not equal, supplying -- an additional message. -- Use if @a@ is an instance of 'Pretty'. assertEqualPrettyVerbose :: (Eq a, Pretty a, HasCallStack) => String -> a -> a -> IO () assertEqualPrettyVerbose = assertEqualPretty_ "assertEqualPrettyVerbose" -- | Fail if the two values of type @a@ are not equal. -- Use if @a@ is an instance of 'Pretty'. assertEqualPretty :: (Eq a, Pretty a, HasCallStack) => a -> a -> IO () assertEqualPretty = assertEqualPretty_ "assertEqualPretty" "" assertNotEqualPretty_ :: (Eq a, Pretty a, AssertM m, HasCallStack) => String -> String -> a -> a -> m () assertNotEqualPretty_ name s expected actual = if expected == actual then do let x = notEqualityFailedMessage' (showPretty expected) genericAssertFailure (mkMsg name s $ failedAt ++ x) else return () -- | Fail in some 'AssertM' monad if the two values of type @a@ are equal, supplying -- an additional message. -- Use if @a@ is an instance of 'Pretty'. gassertNotEqualPrettyVerbose :: (Eq a, Pretty a, AssertM m, HasCallStack) => String -> a -> a -> m () gassertNotEqualPrettyVerbose = assertNotEqualPretty_ "gassertNotEqualPrettyVerbose" -- | Fail in some 'AssertM' monad if the two values of type @a@ are equal. -- Use if @a@ is an instance of 'Pretty'. gassertNotEqualPretty :: (Eq a, Pretty a, AssertM m, HasCallStack) => a -> a -> m () gassertNotEqualPretty = assertNotEqualPretty_ "gassertNotEqualPretty" "" -- | Fail if the two values of type @a@ are equal, supplying -- an additional message. -- Use if @a@ is an instance of 'Pretty'. assertNotEqualPrettyVerbose :: (Eq a, Pretty a, HasCallStack) => String -> a -> a -> IO () assertNotEqualPrettyVerbose = assertNotEqualPretty_ "assertNotEqualPrettyVerbose" -- | Fail if the two values of type @a@ are equal. -- Use if @a@ is an instance of 'Pretty'. assertNotEqualPretty :: (Eq a, Pretty a, HasCallStack) => a -> a -> IO () assertNotEqualPretty = assertNotEqualPretty_ "assertNotEqualPretty" "" assertEqualNoShow_ :: (Eq a, AssertM m, HasCallStack) => String -> String -> a -> a -> m () assertEqualNoShow_ name s expected actual = if expected /= actual then genericAssertFailure (mkMsg name s failedAt) else return () -- | Fail in some 'AssertM' monad if the two values of type @a@ are not equal, supplying -- an additional message. -- Use if @a@ is neither an instance of 'Show' nor of 'Pretty'. gassertEqualNoShowVerbose :: (Eq a, AssertM m, HasCallStack) => String -> a -> a -> m () gassertEqualNoShowVerbose = assertEqualNoShow_ "gassertEqualNoShowVerbose" -- | Fail in some 'AssertM' monad if the two values of type @a@ are not equal. -- Use if @a@ is neither an instance of 'Show' nor of 'Pretty'. gassertEqualNoShow :: (Eq a, AssertM m, HasCallStack) => a -> a -> m () gassertEqualNoShow = assertEqualNoShow_ "gassertEqualNoShow" "" -- | Fail if the two values of type @a@ are not equal, supplying -- an additional message. -- Use if @a@ is neither an instance of 'Show' nor of 'Pretty'. assertEqualNoShowVerbose :: (Eq a, HasCallStack) => String -> a -> a -> IO () assertEqualNoShowVerbose = assertEqualNoShow_ "assertEqualNoShowVerbose" -- | Fail if the two values of type @a@ are not equal. -- Use if @a@ is neither an instance of 'Show' nor of 'Pretty'. assertEqualNoShow :: (Eq a, HasCallStack) => a -> a -> IO () assertEqualNoShow = assertEqualNoShow_ "assertEqualNoShow" "" assertNotEqualNoShow_ :: (Eq a, AssertM m, HasCallStack) => String -> String -> a -> a -> m () assertNotEqualNoShow_ name s expected actual = if expected == actual then genericAssertFailure (mkMsg name s failedAt) else return () -- | Fail in some 'AssertM' monad if the two values of type @a@ are equal, supplying -- an additional message. -- Use if @a@ is neither an instance of 'Show' nor of 'Pretty'. gassertNotEqualNoShowVerbose :: (Eq a, AssertM m, HasCallStack) => String -> a -> a -> m () gassertNotEqualNoShowVerbose = assertNotEqualNoShow_ "gassertNotEqualNoShowVerbose" -- | Fail in some 'AssertM' monad if the two values of type @a@ are equal. -- Use if @a@ is neither an instance of 'Show' nor of 'Pretty'. gassertNotEqualNoShow :: (Eq a, AssertM m, HasCallStack) => a -> a -> m () gassertNotEqualNoShow = assertNotEqualNoShow_ "gassertNotEqualNoShow" "" -- | Fail if the two values of type @a@ are equal, supplying -- an additional message. -- Use if @a@ is neither an instance of 'Show' nor of 'Pretty'. assertNotEqualNoShowVerbose :: (Eq a, HasCallStack) => String -> a -> a -> IO () assertNotEqualNoShowVerbose = assertNotEqualNoShow_ "assertNotEqualNoShowVerbose" -- | Fail if the two values of type @a@ are equal. -- Use if @a@ is neither an instance of 'Show' nor of 'Pretty'. assertNotEqualNoShow :: (Eq a, HasCallStack) => a -> a -> IO () assertNotEqualNoShow = assertNotEqualNoShow_ "assertNotEqualNoShow" "" -- -- Assertions on Lists -- assertListsEqualAsSets_ :: (Eq a, Show a, AssertM m, HasCallStack) => String -> String -> [a] -> [a] -> m () assertListsEqualAsSets_ name s expected actual = let ne = length expected na = length actual in case () of _| ne /= na -> do let x = equalityFailedMessage expected actual genericAssertFailure (mkColorMsg name s (noColor (failedAt ++ "\n expected length: " ++ show ne ++ "\n actual length: " ++ show na) +++ (if maxLength x < 5000 then x else emptyColorString))) | not (unorderedEq expected actual) -> do let x = equalityFailedMessage expected actual genericAssertFailure (mkColorMsg "assertSetEqual" s (noColor failedAt +++ x)) | otherwise -> return () where unorderedEq l1 l2 = null (l1 \\ l2) && null (l2 \\ l1) -- | Fail in some 'AssertM' monad if the two given lists are not equal when considered as sets, -- supplying an additional error message. gassertListsEqualAsSetsVerbose :: (Eq a, Show a, AssertM m, HasCallStack) => String -> [a] -> [a] -> m () gassertListsEqualAsSetsVerbose = assertListsEqualAsSets_ "gassertListsEqualAsSetsVerbose" -- | Fail in some 'AssertM' monad if the two given lists are not equal when considered as sets. gassertListsEqualAsSets :: (Eq a, Show a, AssertM m, HasCallStack) => [a] -> [a] -> m () gassertListsEqualAsSets= assertListsEqualAsSets_ "gassertListsEqualAsSets" "" -- | Fail if the two given lists are not equal when considered as sets, -- supplying an additional error message. assertListsEqualAsSetsVerbose :: (Eq a, Show a, HasCallStack) => String -> [a] -> [a] -> IO () assertListsEqualAsSetsVerbose = assertListsEqualAsSets_ "assertListsEqualAsSetsVerbose" -- | Fail if the two given lists are not equal when considered as sets. assertListsEqualAsSets :: (Eq a, Show a, HasCallStack) => [a] -> [a] -> IO () assertListsEqualAsSets = assertListsEqualAsSets_ "assertListsEqualAsSets" "" assertNotEmpty_ :: (AssertM m, HasCallStack) => String -> String -> [a] -> m () assertNotEmpty_ name s [] = genericAssertFailure (mkMsg name s failedAt) assertNotEmpty_ _ _ (_:_) = return () -- | Fail in some 'AssertM' monad if the given list is empty, supplying an -- additional error message. gassertNotEmptyVerbose :: (AssertM m, HasCallStack) => String -> [a] -> m () gassertNotEmptyVerbose = assertNotEmpty_ "gassertNotEmptyVerbose" -- | Fail in some 'AssertM' monad if the given list is empty. gassertNotEmpty :: (HasCallStack, AssertM m) => [a] -> m () gassertNotEmpty = assertNotEmpty_ "gassertNotEmpty" "" -- | Fail if the given list is empty, supplying an -- additional error message. assertNotEmptyVerbose :: HasCallStack => String -> [a] -> IO () assertNotEmptyVerbose = assertNotEmpty_ "assertNotEmptyVerbose" -- | Fail if the given list is empty. assertNotEmpty :: HasCallStack => [a] -> IO () assertNotEmpty = assertNotEmpty_ "assertNotEmpty" "" assertEmpty_ :: (AssertM m, HasCallStack) => String -> String -> [a] -> m () assertEmpty_ name s (_:_) = genericAssertFailure (mkMsg name s failedAt) assertEmpty_ _ _ [] = return () -- | Fail in some 'AssertM' monad if the given list is not empty, supplying an -- additional error message. gassertEmptyVerbose :: (AssertM m, HasCallStack) => String -> [a] -> m () gassertEmptyVerbose = assertEmpty_ "gassertEmptyVerbose" -- | Fail in some 'AssertM' monad if the given list is not empty. gassertEmpty :: (HasCallStack, AssertM m) => [a] -> m () gassertEmpty = assertEmpty_ "gassertEmpty" "" -- | Fail if the given list is not empty, supplying an -- additional error message. assertEmptyVerbose :: HasCallStack => String -> [a] -> IO () assertEmptyVerbose = assertEmpty_ "assertEmptyVerbose" -- | Fail if the given list is not empty. assertEmpty :: HasCallStack => [a] -> IO () assertEmpty = assertEmpty_ "assertEmpty" "" assertElem_ :: (Eq a, Show a, AssertM m, HasCallStack) => String -> String -> a -> [a] -> m () assertElem_ name s x l = if x `elem` l then return () else genericAssertFailure (mkMsg name s (failedAt ++ "\n element: " ++ show x ++ "\n list: " ++ show l)) -- | Fail in some 'AssertM' monad if the element given is not contained in the list, supplying -- an additional error message. gassertElemVerbose :: (Eq a, Show a, AssertM m, HasCallStack) => String -> a -> [a] -> m () gassertElemVerbose = assertElem_ "gassertElemVerbose" -- | Fail in some 'AssertM' monad if the element given is not contained in the list. gassertElem :: (Eq a, Show a, AssertM m, HasCallStack) => a -> [a] -> m () gassertElem = assertElem_ "gassertElem" "" -- | Fail if the element given is not contained in the list, supplying -- an additional error message. assertElemVerbose :: (Eq a, Show a, HasCallStack) => String -> a -> [a] -> IO () assertElemVerbose = assertElem_ "assertElemVerbose" -- | Fail if the element given is not contained in the list. assertElem :: (Eq a, Show a, HasCallStack) => a -> [a] -> IO () assertElem = assertElem_ "assertElem" "" -- -- Assertions for Exceptions -- assertThrowsIO_ :: (HasCallStack, Exception e) => String -> String -> IO a -> (e -> Bool) -> IO () assertThrowsIO_ name s x f = assertThrowsM_ name s x f -- | Fail if executing the 'IO' action does not throw an exception satisfying the given predicate -- @(e -> Bool)@, supplying an additional error message. assertThrowsIOVerbose :: (HasCallStack, Exception e) => String -> IO a -> (e -> Bool) -> IO () assertThrowsIOVerbose = assertThrowsIO_ "assertThrowsIOVerbose" -- | Fail if executing the 'IO' action does not throw an exception satisfying the given predicate -- @(e -> Bool)@. assertThrowsIO :: (HasCallStack, Exception e) => IO a -> (e -> Bool) -> IO () assertThrowsIO = assertThrowsIO_ "assertThrowsIO" "" assertThrowsSomeIO_ :: HasCallStack => String -> String -> IO a -> IO () assertThrowsSomeIO_ name s x = assertThrowsIO_ name s x (\ (_e::SomeException) -> True) -- | Fail if executing the 'IO' action does not throw any exception, -- supplying an additional error message. assertThrowsSomeIOVerbose :: HasCallStack => String -> IO a -> IO () assertThrowsSomeIOVerbose = assertThrowsSomeIO_ "assertThrowsSomeIOVerbose" -- | Fail if executing the 'IO' action does not throw any exception. assertThrowsSomeIO :: HasCallStack => IO a -> IO () assertThrowsSomeIO = assertThrowsSomeIO_ "assertThrowsSomeIO" "" assertThrowsM_ :: (MonadBaseControl IO m, MonadIO m, Exception e, HasCallStack) => String -> String -> m a -> (e -> Bool) -> m () assertThrowsM_ name s x f = do res <- ExL.try x case res of Right _ -> liftIO $ genericAssertFailure (mkMsg name s (failedAt ++ ": no exception was thrown")) Left e -> if f e then return () else liftIO $ genericAssertFailure (mkMsg name s (failedAt ++ ": wrong exception was thrown: " ++ show e)) -- | Fail if executing the @m@ action does not throw an exception satisfying the given predicate -- @(e -> Bool)@, supplying an additional error message. assertThrowsMVerbose :: (MonadBaseControl IO m, MonadIO m, Exception e, HasCallStack) => String -> m a -> (e -> Bool) -> m () assertThrowsMVerbose = assertThrowsM_ "assertThrowsMVerbose" -- | Fail if executing the @m@ action does not throw an exception satisfying the given predicate -- @(e -> Bool)@. assertThrowsM :: (MonadBaseControl IO m, MonadIO m, Exception e, HasCallStack) => m a -> (e -> Bool) -> m () assertThrowsM = assertThrowsM_ "assertThrowsM" "" assertThrowsSomeM_ :: (MonadBaseControl IO m, MonadIO m, HasCallStack) => String -> String -> m a -> m () assertThrowsSomeM_ name s x = assertThrowsM_ name s x (\ (_e::SomeException) -> True) -- | Fail if executing the @m@ action does not throw any exception, -- supplying an additional error message. assertThrowsSomeMVerbose :: (MonadBaseControl IO m, MonadIO m, HasCallStack) => String -> m a -> m () assertThrowsSomeMVerbose = assertThrowsSomeM_ "assertThrowsSomeMVerbose" -- | Fail if executing the @m@ action does not throw any exception. assertThrowsSomeM :: (MonadBaseControl IO m, MonadIO m, HasCallStack) => m a -> m () assertThrowsSomeM = assertThrowsSomeM_ "assertThrowsSomeM" "" assertThrows_ :: (HasCallStack, Exception e) => String -> String -> a -> (e -> Bool) -> IO () assertThrows_ name s x f = assertThrowsIO_ name s (evaluate x) f -- | Fail if evaluating the expression of type @a@ does not -- throw an exception satisfying the given predicate @(e -> Bool)@, -- supplying an additional error message. assertThrowsVerbose :: (HasCallStack, Exception e) => String -> a -> (e -> Bool) -> IO () assertThrowsVerbose = assertThrows_ "assertThrowsVerbose" -- | Fail if evaluating the expression of type @a@ does not -- throw an exception satisfying the given predicate @(e -> Bool)@. assertThrows :: (HasCallStack, Exception e) => a -> (e -> Bool) -> IO () assertThrows = assertThrows_ "assertThrows" "" assertThrowsSome_ :: HasCallStack => String -> String -> a -> IO () assertThrowsSome_ name s x = assertThrows_ name s x (\ (_e::SomeException) -> True) -- | Fail if evaluating the expression of type @a@ does not -- throw any exception, supplying an additional error message. assertThrowsSomeVerbose :: HasCallStack => String -> a -> IO () assertThrowsSomeVerbose = assertThrowsSome_ "assertThrowsSomeVerbose" -- | Fail if evaluating the expression of type @a@ does not -- throw any exception. assertThrowsSome :: HasCallStack => a -> IO () assertThrowsSome = assertThrowsSome_ "assertThrowsSome" "" -- -- Assertions on Either -- assertLeft_ :: forall a b m . (AssertM m, Show b, HasCallStack) => String -> String -> Either a b -> m a assertLeft_ _ _ (Left x) = return x assertLeft_ name s (Right x) = genericAssertFailure (mkMsg name s (failedAt ++ ": expected a Left value, given " ++ show (Right x :: Either b b))) -- | Fail in some 'AssertM' monad if the given @Either a b@ value is a 'Right', -- supplying an additional error message. -- Use this function if @b@ is an instance of 'Show'. gassertLeftVerbose :: (Show b, AssertM m, HasCallStack) => String -> Either a b -> m a gassertLeftVerbose = assertLeft_ "gassertLeftVerbose" -- | Fail in some 'AssertM' monad if the given @Either a b@ value is a 'Right'. -- Use this function if @b@ is an instance of 'Show'. gassertLeft :: (Show b, AssertM m, HasCallStack) => Either a b -> m a gassertLeft = assertLeft_ "gassertLeft" "" -- | Fail if the given @Either a b@ value is a 'Right', -- supplying an additional error message. -- Use this function if @b@ is an instance of 'Show'. assertLeftVerbose :: (Show b, HasCallStack) => String -> Either a b -> IO a assertLeftVerbose = assertLeft_ "assertLeftVerbose" -- | Fail if the given @Either a b@ value is a 'Right'. -- Use this function if @b@ is an instance of 'Show'. assertLeft :: (HasCallStack, Show b) => Either a b -> IO a assertLeft = assertLeft_ "assertLeft" "" assertLeftNoShow_ :: (HasCallStack, AssertM m) => String -> String -> Either a b -> m a assertLeftNoShow_ _ _ (Left x) = return x assertLeftNoShow_ name s (Right _) = genericAssertFailure (mkMsg name s (failedAt ++ ": expected a Left value, given a Right value")) -- | Fail in some 'AssertM' monad if the given @Either a b@ value is a 'Right', -- supplying an additional error message. -- Use this function if @b@ is not an instance of 'Show'. gassertLeftNoShowVerbose :: (HasCallStack, AssertM m) => String -> Either a b -> m a gassertLeftNoShowVerbose = assertLeftNoShow_ "gassertLeftNoShowVerbose" -- | Fail in some 'AssertM' monad if the given @Either a b@ value is a 'Right'. -- Use this function if @b@ is not an instance of 'Show'. gassertLeftNoShow :: (HasCallStack, AssertM m) => Either a b -> m a gassertLeftNoShow = assertLeftNoShow_ "gassertLeftNoShow" "" -- | Fail if the given @Either a b@ value is a 'Right', -- supplying an additional error message. -- Use this function if @b@ is not an instance of 'Show'. assertLeftNoShowVerbose :: HasCallStack => String -> Either a b -> IO a assertLeftNoShowVerbose = assertLeftNoShow_ "assertLeftNoShowVerbose" -- | Fail if the given @Either a b@ value is a 'Right'. -- Use this function if @b@ is not an instance of 'Show'. assertLeftNoShow :: HasCallStack => Either a b -> IO a assertLeftNoShow = assertLeftNoShow_ "assertLeftNoShow" "" assertRight_ :: forall a b m . (AssertM m, Show a, HasCallStack) => String -> String -> Either a b -> m b assertRight_ _ _ (Right x) = return x assertRight_ name s (Left x) = genericAssertFailure (mkMsg name s (failedAt ++ ": expected a Right value, given " ++ show (Left x :: Either a a))) -- | Fail in some 'AssertM' monad if the given @Either a b@ value is a 'Left', -- supplying an additional error message. -- Use this function if @a@ is an instance of 'Show'. gassertRightVerbose :: (Show a, AssertM m, HasCallStack) => String -> Either a b -> m b gassertRightVerbose = assertRight_ "gassertRightVerbose" -- | Fail in some 'AssertM' monad if the given @Either a b@ value is a 'Left'. -- Use this function if @a@ is an instance of 'Show'. gassertRight :: (Show a, AssertM m, HasCallStack) => Either a b -> m b gassertRight = assertRight_ "gassertRight" "" -- | Fail if the given @Either a b@ value is a 'Left', -- supplying an additional error message. -- Use this function if @a@ is an instance of 'Show'. assertRightVerbose :: (Show a, HasCallStack) => String -> Either a b -> IO b assertRightVerbose = assertRight_ "assertRightVerbose" -- | Fail if the given @Either a b@ value is a 'Left'. -- Use this function if @a@ is an instance of 'Show'. assertRight :: (HasCallStack, Show a) => Either a b -> IO b assertRight = assertRight_ "assertRight" "" assertRightNoShow_ :: (HasCallStack, AssertM m) => String -> String -> Either a b -> m b assertRightNoShow_ _ _ (Right x) = return x assertRightNoShow_ name s (Left _) = genericAssertFailure (mkMsg name s (failedAt ++ ": expected a Right value, given a Left value")) -- | Fail in some 'AssertM' monad if the given @Either a b@ value is a 'Left', -- supplying an additional error message. -- Use this function if @a@ is not an instance of 'Show'. gassertRightNoShowVerbose :: (HasCallStack, AssertM m) => String -> Either a b -> m b gassertRightNoShowVerbose = assertRightNoShow_ "gassertRightNoShowVerbose" -- | Fail in some 'AssertM' monad if the given @Either a b@ value is a 'Left'. -- Use this function if @a@ is not an instance of 'Show'. gassertRightNoShow :: (HasCallStack, AssertM m) => Either a b -> m b gassertRightNoShow = assertRightNoShow_ "gassertRightNoShow" "" -- | Fail if the given @Either a b@ value is a 'Left', -- supplying an additional error message. -- Use this function if @a@ is not an instance of 'Show'. assertRightNoShowVerbose :: HasCallStack => String -> Either a b -> IO b assertRightNoShowVerbose = assertRightNoShow_ "assertRightNoShowVerbose" -- | Fail if the given @Either a b@ value is a 'Left'. -- Use this function if @a@ is not an instance of 'Show'. assertRightNoShow :: HasCallStack => Either a b -> IO b assertRightNoShow = assertRightNoShow_ "assertRightNoShow" "" -- -- Assertions on Maybe -- assertJust_ :: (HasCallStack, AssertM m) => String -> String -> Maybe a -> m a assertJust_ _ _ (Just x) = return x assertJust_ name s Nothing = genericAssertFailure (mkMsg name s (failedAt ++ ": expected a Just value, given Nothing")) -- | Fail in some 'AssertM' monad if the given value is a Nothing, supplying an additional -- error message. gassertJustVerbose :: (HasCallStack, AssertM m) => String -> Maybe a -> m a gassertJustVerbose = assertJust_ "gassertJustVerbose" -- | Fail in some 'AssertM' monad if the given value is a Nothing. gassertJust :: (HasCallStack, AssertM m) => Maybe a -> m a gassertJust = assertJust_ "gassertJust" "" -- | Fail if the given value is a Nothing, supplying an additional -- error message. assertJustVerbose :: HasCallStack => String -> Maybe a -> IO a assertJustVerbose = assertJust_ "assertJustVerbose" -- | Fail if the given value is a Nothing. assertJust :: HasCallStack => Maybe a -> IO a assertJust = assertJust_ "assertJust" "" assertNothing_ :: (Show a, AssertM m, HasCallStack) => String -> String -> Maybe a -> m () assertNothing_ _ _ Nothing = return () assertNothing_ name s jx = genericAssertFailure (mkMsg name s (failedAt ++ ": expected Nothing, given " ++ show jx)) -- | Fail in some 'AssertM' monad if the given @Maybe a@ value is a 'Just', supplying an additional -- error message. -- Use this function if @a@ is an instance of 'Show'. gassertNothingVerbose :: (Show a, AssertM m, HasCallStack) => String -> Maybe a -> m () gassertNothingVerbose = assertNothing_ "gassertNothingVerbose" -- | Fail in some 'AssertM' monad if the given @Maybe a@ value is a 'Just'. -- Use this function if @a@ is an instance of 'Show'. gassertNothing :: (Show a, AssertM m, HasCallStack) => Maybe a -> m () gassertNothing = assertNothing_ "gassertNothing" "" -- | Fail if the given @Maybe a@ value is a 'Just', supplying an additional -- error message. -- Use this function if @a@ is an instance of 'Show'. assertNothingVerbose :: (Show a, HasCallStack) => String -> Maybe a -> IO () assertNothingVerbose = assertNothing_ "assertNothingVerbose" -- | Fail if the given @Maybe a@ value is a 'Just'. -- Use this function if @a@ is an instance of 'Show'. assertNothing :: (HasCallStack, Show a) => Maybe a -> IO () assertNothing = assertNothing_ "assertNothing" "" assertNothingNoShow_ :: (HasCallStack, AssertM m) => String -> String -> Maybe a -> m () assertNothingNoShow_ _ _ Nothing = return () assertNothingNoShow_ name s _ = genericAssertFailure (mkMsg name s (failedAt ++ ": expected Nothing, given a Just value")) -- | Fail in some 'AssertM' monad if the given @Maybe a@ value is a 'Just', supplying an additional -- error message. -- Use this function if @a@ is not an instance of 'Show'. gassertNothingNoShowVerbose :: (HasCallStack, AssertM m) => String -> Maybe a -> m () gassertNothingNoShowVerbose = assertNothingNoShow_ "gassertNothingNoShowVerbose" -- | Fail in some 'AssertM' monad if the given @Maybe a@ value is a 'Just'. -- Use this function if @a@ is not an instance of 'Show'. gassertNothingNoShow :: (HasCallStack, AssertM m) => Maybe a -> m () gassertNothingNoShow = assertNothingNoShow_ "gassertNothingNoShow" "" -- | Fail if the given @Maybe a@ value is a 'Just', supplying an additional -- error message. -- Use this function if @a@ is not an instance of 'Show'. assertNothingNoShowVerbose :: HasCallStack => String -> Maybe a -> IO () assertNothingNoShowVerbose = assertNothingNoShow_ "assertNothingNoShowVerbose" -- | Fail if the given @Maybe a@ value is a 'Just'. -- Use this function if @a@ is not an instance of 'Show'. assertNothingNoShow :: HasCallStack => Maybe a -> IO () assertNothingNoShow = assertNothingNoShow_ "assertNothingNoShow" "" -- -- Sub assertions -- -- | Use 'subAssert' if you want location information for the call site but the function -- being called does not carry a 'HasCallStack' constraint. subAssert :: (HasCallStack, MonadBaseControl IO m) => m a -> m a subAssert = subAssertHTF Nothing gsubAssert :: (HasCallStack, AssertM m) => m a -> m a gsubAssert = genericSubAssert Nothing subAssertVerbose :: (HasCallStack, MonadBaseControl IO m) => String -> m a -> m a subAssertVerbose msg = subAssertHTF (Just msg) gsubAssertVerbose :: (HasCallStack, AssertM m) => String -> m a -> m a gsubAssertVerbose msg = genericSubAssert (Just msg) testEqualityFailedMessage1 :: IO () testEqualityFailedMessage1 = let msg = T.unpack $ renderColorString (equalityFailedMessage [1,2,3] [1,2,3,4]) False in HU.assertEqual "error" msg exp where exp = "\n* expected: [1, 2, 3]\n* but got: [1, 2, 3, 4]\n* " ++ "diff: \nC <...[1, 2, 3...>C \nS , 4\nC ]<......>C " testEqualityFailedMessage2 :: IO () testEqualityFailedMessage2 = let msg = T.unpack $ renderColorString (equalityFailedMessage [1,2,3] [1,2,3]) False in HU.assertEqual "error" msg exp where exp = "\n* expected: [1,2,3]\n* but got: [1,2,3]\n* " ++ "diff: \nWARNING: strings are equal but actual values differ!" hunitWrapperTests = [("testEqualityFailedMessage1", testEqualityFailedMessage1) ,("testEqualityFailedMessage2", testEqualityFailedMessage2)]