packages feed

options-1.2.1.2: tests/Chell.hs

-- 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