-- Copyright (c) 2017-2019 Rudy Matela.
-- Distributed under the 3-Clause BSD licence (see the file LICENSE).
module Test
( module Test.Extrapolate
, module Test.Extrapolate.Core
, module Test.Extrapolate.Utils
, module Test.LeanCheck.Utils.Operators
, reportTests
, getMaxTestsFromArgs
, mainTest
, printLines
, operatorE
-- * Properties and Tests
, generalizableOK
, exprOK
, idExprEval, showOK
, instancesOK
, namesOK, sameNamesIn, namesIn
, tiersOK, sameTiersIn, tiersIn
, bgEqOK, bgEqOrdOK
, subset, bgSubset
, backgroundOf
, instancesSubset
, module Data.Express.Fixtures
)
where
import System.Exit (exitFailure)
import Data.List (elemIndices)
import System.Environment (getArgs)
import Data.Typeable (typeOf)
import Data.List (isPrefixOf, sort)
import Test.Speculate.Reason
import Test.Extrapolate
import Test.Extrapolate.Core
import Test.Extrapolate.Utils
import Data.Express.Fixtures
import Test.LeanCheck.Utils.Operators
reportTests :: [Bool] -> IO ()
reportTests tests =
case elemIndices False tests of
[] -> putStrLn "Tests passed!"
is -> do putStrLn ("Failed tests:" ++ show is)
exitFailure
getMaxTestsFromArgs :: Int -> IO Int
getMaxTestsFromArgs n = do
as <- getArgs
return $ case as of
(s:_) -> read s
_ -> n
mainTest :: (Int -> [Bool]) -> Int -> IO ()
mainTest tests n' = do
n <- getMaxTestsFromArgs n'
reportTests (tests n)
printLines :: Show a => [a] -> IO ()
printLines = putStrLn . unlines . map show
operatorE :: Expr -> Expr
operatorE ((opE :$ _) :$ _) = opE
operatorE _ = error "operatorE: not a binary operator"
-- Properties and tests --
generalizableOK :: (Eq a, Show a, Generalizable a) => Int -> a -> Bool
generalizableOK n x = holds n (exprOK -:> x)
&& instancesOK (und -: x)
where
und = error "generalizableOK: this should not get evaluated"
exprOK :: (Eq a, Show a, Generalizable a) => a -> Bool
exprOK = idExprEval &&& showOK
idExprEval :: (Eq a, Generalizable a) => a -> Bool
idExprEval x = eval (error "idExprEval: could not eval") (expr x) == x
showOK :: (Show a, Generalizable a) => a -> Bool
showOK x = show x == dropType (show (expr x))
where
dropType :: String -> String
dropType cs | " :: " `isPrefixOf` cs = ""
dropType "" = ""
dropType (c:cs) = c : dropType cs
instancesOK :: (Eq a, Generalizable a) => a -> Bool
instancesOK = namesOK &&& tiersOK
namesOK :: Generalizable a => a -> Bool
namesOK x = name x == head (x `namesIn` x)
&& x `sameNamesIn` [x]
&& x `sameNamesIn` [[x]]
&& x `sameNamesIn` mayb x
&& x `sameNamesIn` (x,x)
&& x `sameNamesIn` (x,())
&& x `sameNamesIn` ((),x)
&& x `sameNamesIn` (x,(),())
&& x `sameNamesIn` ((),x,())
&& x `sameNamesIn` ((),(),x)
sameNamesIn :: (Generalizable a, Generalizable b) => a -> b -> Bool
x `sameNamesIn` c = x `namesIn` x
=| 12 |= x `namesIn` c
namesIn :: (Generalizable a, Generalizable b) => a -> b -> [String]
x `namesIn` c = lookupNames (instances c []) (val x)
tiersOK :: (Eq a, Generalizable a) => a -> Bool
tiersOK x = x `sameTiersIn` x
&& x `sameTiersIn` [x]
&& x `sameTiersIn` [[x]]
&& x `sameTiersIn` (mayb x)
&& x `sameTiersIn` (x,x)
&& x `sameTiersIn` (x,())
&& x `sameTiersIn` ((),x)
&& x `sameTiersIn` (x,(),())
&& x `sameTiersIn` ((),x,())
&& x `sameTiersIn` ((),(),x)
bgEqOK :: (Eq a, Generalizable a) => a -> a -> Bool
bgEqOK = (*==*) ==== (==)
&&&& (*/=*) ==== (/=)
bgEqOrdOK :: (Eq a, Ord a, Generalizable a) => a -> a -> Bool
bgEqOrdOK = bgEqOK &&&& (*<=*) ==== (<=)
&&&& (*<*) ==== (<)
sameTiersIn :: (Eq a, Generalizable a, Generalizable b) => a -> b -> Bool
x `sameTiersIn` cx = isListableT (instances cx []) (typeOf x)
&& (tiers -: [[x]]) =| 6 |= tiersIn cx
tiersIn :: (Generalizable a, Generalizable b) => b -> [[a]]
tiersIn c = ret
where
ret = mapT (eval . error $ "tiersIn: the imposible happened")
$ lookupTiers (instances c []) (val (head (head ret)))
subset :: Ord a => [a] -> [a] -> Bool
xs `subset` ys = sort xs `isSubsequenceOf` sort ys
bgSubset :: (Generalizable a, Generalizable b) => a -> b -> Bool
x `bgSubset` y = backgroundOf x `subset` backgroundOf y
instancesSubset :: (Eq a, Eq b, Generalizable a, Generalizable b) => a -> b -> Bool
x `instancesSubset` y = x `bgSubset` y
&& x `sameTiersIn` y
&& x `sameNamesIn` y
backgroundOf :: Generalizable a => a -> [Expr]
backgroundOf x = concat [evl e | e@(Value "background" _) <- instances x []]
-- available on Data.List since GHC >= 8.0
isSubsequenceOf :: Eq a => [a] -> [a] -> Bool
isSubsequenceOf [] _ = True
isSubsequenceOf (_:_) [] = False
isSubsequenceOf (x:xs) (y:ys)
| x == y = xs `isSubsequenceOf` ys
| otherwise = (x:xs) `isSubsequenceOf` ys
-- Quick and Dirty!
instance Show Thy where
show Thy { rules = rs
, equations = eqs
, canReduceTo = (->-)
, closureLimit = cl
, keepE = keep
}
= "Thy { rules = "
++ drop 14 (indent 14 . listLines $ map showEquation rs)
++ " , equations = "
++ drop 18 (indent 18 . listLines $ map showEquation eqs)
++ " , canReduceTo = " ++ showCanReduceTo (->-) ++ "\n"
++ " , closureLimit = " ++ show cl ++ "\n"
++ " , keepE = " ++ showKeepE keep ++ "\n"
++ " }"
where
showEquation (e1,e2) = showExpr e1 ++ " == " ++ showExpr e2
listLines [] = "[]"
listLines ss = '[':(tail . unlines $ map (", " ++) ss) ++ "]"
showCanReduceTo (->-) = "(??)"
showKeepE keep = "\\e -> ??"
indent :: Int -> String -> String
indent n = unlines . map (replicate n ' ' ++) . lines