microecta-0.1.0.0: test/Test/Generators/ECTA.hs
{-# LANGUAGE OverloadedStrings #-}
module Test.Generators.ECTA () where
import Prelude hiding (max)
import Control.Monad (replicateM)
import Data.List (subsequences, (\\))
import Test.QuickCheck
import Data.ECTA
import Data.ECTA.Internal.ECTA.Type
import Data.ECTA.Paths
import Data.ECTA.Term
-----------------------------------------------------------------------------------------------
-- Cap size at 3 whenever you will generate all denotations
_MAX_NODE_DEPTH :: Int
_MAX_NODE_DEPTH = 5
capSize :: Int -> Gen a -> Gen a
capSize max g = sized $ \n ->
if n > max
then
resize max g
else
g
instance Arbitrary Node where
arbitrary = capSize _MAX_NODE_DEPTH $ sized $ \_n -> do
k <- chooseInt (1, 3) -- TODO: Should this depend on n?
Node <$> replicateM k arbitrary
shrink EmptyNode = []
shrink (Node es) = [Node es' | s <- subsequences es \\ [es], es' <- mapM shrink s] ++ concatMap (\e -> edgeChildren e) es
shrink (Mu _) = []
shrink (Rec _) = []
testEdgeTypes :: [(Symbol, Int)]
testEdgeTypes =
[ ("f", 1)
, ("g", 2)
, ("h", 1)
, ("w", 3)
, ("a", 0)
, ("b", 0)
, ("c", 0)
]
testConstants :: [Symbol]
testConstants = map fst $ filter ((== 0) . snd) testEdgeTypes
randPathPair :: [Node] -> Gen [Path]
randPathPair ns = do
p1 <- randPath ns
p2 <- randPath ns
return [p1, p2]
randPath :: [Node] -> Gen Path
randPath [] = return EmptyPath
randPath ns = do
i <- chooseInt (0, length ns - 1)
let Node es = ns !! i
ns' <- edgeChildren <$> elements es
b <- arbitrary
if b then return (path [i]) else ConsPath i <$> randPath ns'
instance Arbitrary Edge where
arbitrary =
sized $ \n -> case n of
0 -> Edge <$> elements testConstants <*> pure []
_ -> do
(sym, arity) <- elements testEdgeTypes
ns <- replicateM arity (resize (n - 1) (arbitrary `suchThat` (/= EmptyNode)))
numConstraintPairs <- elements [0, 0, 1, 1, 2, 3]
ps <- replicateM numConstraintPairs (randPathPair ns)
return $ mkEdge sym ns (mkEqConstraints ps)
shrink e = mkEdge (edgeSymbol e) <$> (mapM shrink (edgeChildren e)) <*> pure (edgeEcs e)