tptp-0.1.3.0: test/QuickCheckSpec/Main.hs
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE CPP #-}
-- |
-- Module : Main
-- Description : QuickCheck specification for the tptp library.
-- Copyright : (c) Evgenii Kotelnikov, 2019-2021
-- License : GPL-3
-- Maintainer : evgeny.kotelnikov@gmail.com
-- Stability : experimental
--
-- Defines properties of the tptp library and runs QuickCheck on them.
--
module Main where
#if MIN_VERSION_base(4, 8, 0)
import Prelude hiding ((<*))
#endif
import Control.Applicative ((<*))
import Control.Monad (unless)
import Data.Foldable (toList)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as NEL (cons)
import Data.Text (Text)
import Data.Attoparsec.Text (Parser, parseOnly, endOfInput)
import Data.Text.Prettyprint.Doc (Doc, layoutPretty, defaultLayoutOptions)
import Data.Text.Prettyprint.Doc.Render.Text (renderStrict)
import Test.QuickCheck (Gen, Property, Args(..), stdArgs, (===), whenFail,
forAll, forAllProperties, quickCheckWithResult)
import Test.QuickCheck.Poly (A)
import System.Exit (exitFailure)
import Data.TPTP hiding (clause)
import Data.TPTP.Parse.Combinators
import Data.TPTP.Pretty
import ArbitrarilyPretty
import Generators ()
import Normalizers
-- * Helper functions
-- | Generalized idempotent parsing / pretty printing.
ippWith :: (Show e, Show e', Eq e')
=> (e -> Gen (Doc a)) -- ^ Pretty printer.
-> (Doc a -> Gen Text) -- ^ Renderer.
-> Parser e -- ^ Parser.
-> (e -> e') -- ^ Normalizer.
-> e -> Property
ippWith pprint render parse normalize expr =
forAll (pprint expr) $ \doc ->
forAll (render doc) $ \text ->
case parseOnly (parse <* endOfInput) text of
Left err -> whenFail (putStrLn $ "Parsing error: " ++ err) False
Right expr' -> normalize expr' === normalize expr
defaultRender :: Doc a -> Gen Text
defaultRender = return . renderStrict . layoutPretty defaultLayoutOptions
defaultNormalize :: e -> e
defaultNormalize = id
-- | Idempotent parsing / pretty printing modulo normalization.
ippModulo :: (Show e, Eq e, Pretty e) => (e -> e) -> Parser e -> e -> Property
ippModulo = flip $ ippWith (return . pretty) defaultRender
-- | Idempotent parsing / pretty printing.
ipp :: (Show e, Eq e, Pretty e) => Parser e -> e -> Property
ipp = ippModulo defaultNormalize
-- | Idempotent arbitrary parsing / pretty printing modulo normalization.
aippModulo :: (Show e, Eq e, ArbitrarilyPretty e, Show e', Eq e')
=> (e -> e') -> Parser e -> e -> Property
aippModulo = flip $ ippWith apretty defaultRender
-- | Idempotent parsing / pretty printing.
aipp :: (Show e, Eq e, ArbitrarilyPretty e) => Parser e -> e -> Property
aipp = aippModulo defaultNormalize
-- | Idempotent parsing / pretty printing with superfluous parenthesis
-- modulo normalization.
spAippModulo :: (Show e, Eq e, ArbitrarilyPretty (SuperfluousParenthesis e))
=> (e -> e) -> Parser e -> e -> Property
spAippModulo normalize parser expr =
aippModulo (normalize . unSuperfluousParenthesis)
(fmap SuperfluousParenthesis parser)
(SuperfluousParenthesis expr)
-- | Idempotent parsing / pretty printing with superfluous parenthesis.
spAipp :: (Show e, Eq e, ArbitrarilyPretty (SuperfluousParenthesis e))
=> Parser e -> e -> Property
spAipp = spAippModulo defaultNormalize
-- | Idempotent encoding / decoding.
(~=) :: (Eq a, Show a) => (a -> b) -> (b -> Maybe a) -> a -> Property
(~=) to from a = Just a === from (to a)
-- * Properties
-- ** Generators
-- *** Well-formed names
prop_validAtom :: Atom -> Bool
prop_validAtom (Atom t) = isValidAtom t
prop_validVar :: Var -> Bool
prop_validVar (Var t) = isValidVar t
prop_validDistinctObject :: DistinctObject -> Bool
prop_validDistinctObject (DistinctObject t) = isValidDistinctObject t
-- *** Auxiliary data structures
prop_randomSplit :: NonEmpty A -> Property
prop_randomSplit list = forAll (randomSplit list)
$ \(prefix, suffix) -> appendr prefix suffix === list
where
appendr l nel = foldr NEL.cons nel l
prop_randomTree :: NonEmpty A -> Property
prop_randomTree list = forAll (randomTree list)
$ \tree -> toList tree === toList list
-- ** Names
prop_ipp_Atom :: Atom -> Property
prop_ipp_Atom = ipp atom
prop_ipp_Var :: Var -> Property
prop_ipp_Var = ipp var
prop_ipp_DistinctObject :: DistinctObject -> Property
prop_ipp_DistinctObject = ipp distinctObject
prop_ipp_Function :: Name Function -> Property
prop_ipp_Function = ipp function
prop_ipp_Predicate :: Name Predicate -> Property
prop_ipp_Predicate = ipp predicate
-- ** Sorts and types
prop_ipp_Sort :: Name Sort -> Property
prop_ipp_Sort = ipp sort
prop_ipp_TFF1Sort :: TFF1Sort -> Property
prop_ipp_TFF1Sort = ipp tff1Sort
prop_ipp_sp_TFF1Sort :: TFF1Sort -> Property
prop_ipp_sp_TFF1Sort = spAipp tff1Sort
prop_ipp_Type :: Type -> Property
prop_ipp_Type = ippModulo normalizeType type_
prop_ipp_sp_Type :: Type -> Property
prop_ipp_sp_Type = spAippModulo normalizeType type_
-- ** First-order logic
prop_ipp_Number :: Number -> Property
prop_ipp_Number = ipp number
prop_ipp_Term :: Term -> Property
prop_ipp_Term = ipp term
prop_ipp_sp_Term :: Term -> Property
prop_ipp_sp_Term = spAipp term
prop_ipp_Literal :: Literal -> Property
prop_ipp_Literal = ipp literal
prop_ipp_sp_Literal :: Literal -> Property
prop_ipp_sp_Literal = spAipp literal
prop_ipp_Clause :: Clause -> Property
prop_ipp_Clause = ipp clause
prop_ipp_sp_Clause :: Clause -> Property
prop_ipp_sp_Clause = spAipp clause
prop_ipp_UnsortedFO :: UnsortedFirstOrder -> Property
prop_ipp_UnsortedFO = ippModulo reassociate unsortedFirstOrder
prop_ipp_sp_UnsortedFO :: UnsortedFirstOrder -> Property
prop_ipp_sp_UnsortedFO = spAippModulo reassociate unsortedFirstOrder
prop_ipp_MonomorphicFO :: MonomorphicFirstOrder -> Property
prop_ipp_MonomorphicFO = ippModulo reassociate monomorphicFirstOrder
prop_ipp_sp_MonomorphicFO :: MonomorphicFirstOrder -> Property
prop_ipp_sp_MonomorphicFO = spAippModulo reassociate monomorphicFirstOrder
prop_ipp_PolymorphicFO :: PolymorphicFirstOrder -> Property
prop_ipp_PolymorphicFO = ippModulo reassociate polymorphicFirstOrder
prop_ipp_sp_PolymorphicFO :: PolymorphicFirstOrder -> Property
prop_ipp_sp_PolymorphicFO = spAippModulo reassociate polymorphicFirstOrder
-- ** Units
prop_ipp_Unit :: Unit -> Property
prop_ipp_Unit = ippModulo normalizeUnit unit
prop_ipp_sp_Unit :: Unit -> Property
prop_ipp_sp_Unit = spAippModulo normalizeUnit unit
prop_ipp_TPTP :: TPTP -> Property
prop_ipp_TPTP = ippModulo normalizeTPTP tptp
prop_ipp_TSTP :: TSTP -> Property
prop_ipp_TSTP = ippModulo normalizeTSTP tstp
-- ** Annotations
prop_ipp_Parent :: Parent -> Property
prop_ipp_Parent = ippModulo normalizeParent parent
prop_ipp_Source :: Source -> Property
prop_ipp_Source = ippModulo normalizeSource source
prop_ipp_Info :: Info -> Property
prop_ipp_Info = ippModulo normalizeInfo info
-- ** Conversions
prop_unsortFirstOrder :: UnsortedFirstOrder -> Property
prop_unsortFirstOrder = sortFirstOrder ~= unsortFirstOrder
prop_monomorphizeFirstOrder :: MonomorphicFirstOrder -> Property
prop_monomorphizeFirstOrder = polymorphizeFirstOrder ~= monomorphizeFirstOrder
-- * Runner
return []
main :: IO ()
main = do
success <- $forAllProperties $ quickCheckWithResult stdArgs{maxSuccess=1000}
unless success exitFailure