packages feed

skeletest-0.4.0: src/Skeletest/Internal/Error.hs

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

module Skeletest.Internal.Error (
  SkeletestError (..),
  skeletestError,
  skeletestPluginError,
  invariantViolation,
) where

import Control.Monad.IO.Class (MonadIO)
import Data.Text (Text)
import Data.Text qualified as Text
import GHC qualified
import GHC.Stack (HasCallStack, callStack, prettyCallStack)
import UnliftIO.Exception (Exception (..), impureThrow, throwIO)

data SkeletestError
  = -- | Thrown for most errors, unless an error needs to be specially caught.
    SkeletestError Text
  | -- | A user error during compilation, e.g. during the preprocessor or plugin phases.
    CompilationError (Maybe GHC.SrcSpan) Text
  | -- | Skip the currently running test
    SkipTest Text
  deriving (Show)

instance Exception SkeletestError where
  displayException =
    Text.unpack . \case
      SkeletestError msg -> msg
      CompilationError _ msg ->
        Text.unlines
          [ ""
          , "******************** skeletest failure ********************"
          , msg
          ]
      SkipTest msg -> "SKIP: " <> msg

skeletestError :: (MonadIO m) => Text -> m a
skeletestError = throwIO . SkeletestError

skeletestPluginError :: Maybe GHC.SrcSpan -> String -> a
skeletestPluginError mloc = impureThrow . CompilationError mloc . Text.pack

invariantViolation :: (HasCallStack) => String -> a
invariantViolation = impureThrow . SkeletestError . Text.pack . toMessage
 where
  toMessage msg =
    unlines
      [ "Invariant violation: " <> msg
      , "**** This is a skeletest bug. Please report it at https://github.com/brandonchinn178/skeletest/issues"
      , ""
      , prettyCallStack callStack
      ]