stgi-1: test/Testsuite/Test/Language/Prettyprint.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
module Test.Language.Prettyprint (tests) where
import Data.Bifunctor
import Data.Text (Text)
import qualified Data.Text as T
import Stg.Language.Prettyprint
import Stg.Parser.Parser as Parser
import Test.Orphans ()
import Test.QuickCheck.Property
import Test.SmallCheck.Series
import Test.Tasty
import Test.Tasty.QuickCheck as QC
import Test.Tasty.SmallCheck as SC
tests :: TestTree
tests = localOption (QuickCheckMaxSize 3)
( testGroup "Plain prettyprinter is inverse of parser"
[ inverseOfParserQC "Full program" Parser.program
, inverseOfParserQC "Bindings" Parser.binds
, inverseOfParserQC "Lambda form" Parser.lambdaForm
, inverseOfParserQC "Expression" Parser.expr
, inverseOfParserQC "Case alternatives" Parser.alts
, inverseOfParserSC "Literal" Parser.literal
, inverseOfParserSC "Primop" Parser.primOp
, inverseOfParserQC "Atom" Parser.atom ])
inverseOfParserQC
:: (Arbitrary ast, Show ast, Eq ast, Pretty ast)
=> Text
-> StgParser ast
-> TestTree
inverseOfParserQC testName parser
= QC.testProperty (T.unpack testName) (\inputAst ->
case parserRoundtrip parser inputAst of
Left err ->
counterexample (T.unpack (prettyFailure inputAst err))
(property failed)
Right parsedAst ->
counterexample (T.unpack (prettySuccess inputAst parsedAst))
(inputAst == parsedAst) )
inverseOfParserSC
:: (Serial IO ast, Show ast, Eq ast, Pretty ast)
=> Text
-> StgParser ast
-> TestTree
inverseOfParserSC testName parser
= SC.testProperty (T.unpack testName) (SC.forAll (\inputAst ->
case parserRoundtrip parser inputAst of
Left err ->
Left (T.unpack (prettyFailure inputAst err))
Right parsedAst
| inputAst == parsedAst -> Right ("" :: String)
| otherwise -> Left (T.unpack (prettySuccess inputAst parsedAst)) ))
parserRoundtrip
:: Pretty ast
=> StgParser ast
-> ast
-> Either Text ast
parserRoundtrip parser = first prettyprintPlain . parse parser . prettyprintPlain
prettySuccess :: Pretty ast => ast -> ast -> Text
prettySuccess inputAst parsedAst =
T.unlines [ "Input AST:"
, prettyprintPlain inputAst
, "Parsed, parser inverse printed AST:"
, prettyprintPlain parsedAst ]
prettyFailure :: Pretty ast => ast -> Text -> Text
prettyFailure inputAst err =
T.unlines [ "Input AST:"
, prettyprintPlain inputAst
, "Parse error:"
, err ]