-- Excerpts copied out of the `chell` package and slightly modified
-- for use with `hspec`.
module Chell where
import Control.Monad (unless)
import Data.List (foldl', intercalate)
import Data.Maybe (isNothing)
import Patience qualified
import Test.Hspec (Expectation, expectationFailure)
assertBool :: Bool -> String -> Expectation
assertBool b s = unless b $ expectationFailure s
-- | Assert that some value is @Nothing@.
nothing :: Show a => Maybe a -> Expectation
nothing x =
assertBool
(isNothing x)
("nothing: received " ++ showsPrec 11 x "")
-- | Assert that some value is @Right@.
right :: Show a => Either a b -> Expectation
right (Right _) = pure ()
right (Left a) = expectationFailure ("right: received " ++ showsPrec 11 dummy "")
where
dummy = Left a `asTypeOf` Right ()
-- | Assert that some value is @Left@.
left :: Show b => Either a b -> Expectation
left (Left _) = pure ()
left (Right b) = expectationFailure ("left: received " ++ showsPrec 11 dummy "")
where
dummy = Right b `asTypeOf` Left ()
-- | Assert that two pieces of text are equal. This uses a diff algorithm
-- to check line-by-line, so the error message will be easier to read on
-- large inputs.
equalLines :: String -> String -> Expectation
equalLines x y = checkLinesDiff "equalLines" (lines x) (lines y)
checkLinesDiff :: String -> [String] -> [String] -> Expectation
checkLinesDiff label = go
where
go xs ys =
case checkItems (Patience.diff xs ys) of
(same, diff) -> assertBool same diff
checkItems diffItems =
case foldl' checkItem (True, []) diffItems of
(same, diff) -> (same, errorMsg (intercalate "\n" (reverse diff)))
checkItem (same, acc) item =
case item of
Patience.Old t -> (False, ("\t- " ++ t) : acc)
Patience.New t -> (False, ("\t+ " ++ t) : acc)
Patience.Both t _ -> (same, ("\t " ++ t) : acc)
errorMsg diff = label ++ ": lines differ\n" ++ diff