org-parser-0.1.0.0: test/Tests/Helpers.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Tests.Helpers
( module Tests.Helpers
, module Test.Tasty
)
where
import Data.Algorithm.DiffContext (getContextDiff, prettyContextDiff)
import Org.Builder (Many)
import Org.Parser
import Org.Parser.Objects (Marked (..))
import Org.Types (OrgDocument, OrgElementData, Properties)
import Test.Tasty
import Test.Tasty.HUnit
import Text.Megaparsec (eof)
import Text.Megaparsec.Error (errorBundlePretty)
import Text.Pretty.Simple
import Text.PrettyPrint (render, text)
{- | This class is mainly used for the tests cases.
@Parsed m a@ is the "monad-stripped" version of parse
tree with which we can compare in the test cases.
-}
class Parsable m a where
type Parsed m a
parse' :: m a -> Text -> Either OrgParseError (Parsed m a)
instance Parsable OrgParser a where
type Parsed OrgParser a = a
parse' p = parseOrg defaultOrgOptions (p <* eof) ""
instance Parsable (Marked OrgParser) a where
type Parsed (Marked OrgParser) a = a
parse' p = parse' (getParser p)
instance PrettyFormable Properties where
type PrettyForm Properties = Properties
prettyForm = id
instance Parsable OrgParser OrgDocument where
type Parsed OrgParser OrgDocument = OrgDocument
parse' p = parseOrg defaultOrgOptions (p <* eof) ""
instance PrettyFormable OrgDocument where
type PrettyForm OrgDocument = OrgDocument
prettyForm = id
class PrettyFormable a where
type PrettyForm a
prettyForm :: a -> PrettyForm a
instance PrettyFormable (Many a) where
type PrettyForm (Many a) = [a]
prettyForm = toList
instance PrettyFormable OrgElementData where
type PrettyForm OrgElementData = OrgElementData
prettyForm = id
prettyParse :: (Parsable m a, PrettyFormable (Parsed m a), Show (PrettyForm (Parsed m a))) => m a -> Text -> IO ()
prettyParse parser txt =
case parse' parser txt of
Left e -> putStrLn $ errorBundlePretty e
Right x -> pPrint $ prettyForm x
infix 1 =?>
(=?>) :: a -> b -> (a, Either () b)
x =?> y = (x, Right y)
infix 1 =!>
(=!>) :: a -> () -> (a, Either () c)
x =!> y = (x, Left y)
infix 4 =:
(=:) :: (Eq a, Show a) => TestName -> (a, a) -> TestTree
(=:) name (x, y) = testCase name (x @?= y)
infix 4 ~:
(~:) ::
HasCallStack =>
(Parsable m a, PrettyFormable (Parsed m a), Eq (Parsed m a), Show (Parsed m a)) =>
TestName ->
m a ->
[(Text, Either () (Parsed m a))] ->
TestTree
(~:) name parser cases =
testGroup name $
flip (`zipWith` [1 ..]) cases $ \(i :: Int) (txt, ref) ->
testCase (name <> " " <> show i) $
case parse' parser txt of
Left e
| isRight ref -> assertFailure $ errorBundlePretty e
| otherwise -> pure ()
Right x
| Right ref' <- ref ->
unless (x == ref') do
let reflines = map toString $ lines (toStrict $ pShow ref')
gotlines = map toString $ lines (toStrict $ pShow x)
diff = getContextDiff 3 reflines gotlines
pdiff = prettyContextDiff (text "Test reference") (text "Parsed") text diff
assertFailure (render pdiff)
| otherwise ->
assertFailure $
"Should not parse, but parsed as:\n" <> show x