fixplate-0.1.7: tests/TestSuite/Tools.hs
-- | Auxillary functions useful for testing
{-# LANGUAGE CPP,
DeriveFunctor, DeriveFoldable, DeriveTraversable, StandaloneDeriving,
FlexibleInstances, TypeSynonymInstances
#-}
module TestSuite.Tools where
--------------------------------------------------------------------------------
import Control.Applicative
import Control.Monad hiding (mapM, mapM_, forM, forM_)
import Data.List (sort)
import Data.Foldable
import Data.Traversable
import Prelude hiding (foldl,foldr,mapM,mapM_,concat,concatMap)
import Text.Show
import Text.Read
import Data.Generics.Fixplate.Base
import Test.QuickCheck
import TestSuite.Misc
--------------------------------------------------------------------------------
maxChildren :: Int
maxChildren = 7
data Tree label
= Tree label [Tree label]
deriving (Eq,Ord,Show,Read,Functor,Foldable,Traversable)
data TreeF label t
= TreeF label [t]
deriving (Eq,Ord,Show,Read,Functor,Foldable,Traversable)
type FixT label = Mu (TreeF label)
instance Eq label => EqF (TreeF label) where equalF = (==)
instance Ord label => OrdF (TreeF label) where compareF = compare
instance Show label => ShowF (TreeF label) where showsPrecF = showsPrec
#ifdef __GLASGOW_HASKELL__
instance Read label => ReadF (TreeF label) where readPrecF = readPrec
#else
instance Read label => ReadF (TreeF label) where readsPrecF = readsPrec
#endif
treeF :: l -> [Mu (TreeF l)] -> Mu (TreeF l)
treeF s = Fix . TreeF s
attrTreeF :: a -> l -> [Attr (TreeF l) a] -> Attr (TreeF l) a
attrTreeF x s = Fix . Ann x . TreeF s
--------------------------------------------------------------------------------
-- * draw trees
printTree :: Tree Label -> IO ()
printTree = printTree' (\(Label s) -> s)
printTreeF :: FixT Label -> IO ()
printTreeF = printTreeF' (\(Label s) -> s)
printTree' :: (a -> String) -> Tree a -> IO ()
printTree' h = go 0 where
go i (Tree label children) = do
putStrLn $ if i>0
then concat (replicate (i-1) "| " ++ ["|-", h label])
else h label
mapM_ (go (i+1)) children
printTreeF' :: (a -> String) -> Mu (TreeF a) -> IO ()
printTreeF' h = go 0 where
go i (Fix (TreeF label children)) = do
putStrLn $ if i>0
then concat (replicate (i-1) "| " ++ ["|-", h label])
else h label
mapM_ (go (i+1)) children
--------------------------------------------------------------------------------
-- * random trees
rndTree :: IO (Tree Label)
rndTree = liftM (!!7) $ sample' arbitrary
rndFixT :: IO (FixT Label)
rndFixT = liftM (!!7) $ sample' arbitrary
--------------------------------------------------------------------------------
-- * conversion
toFixT :: Tree l -> Mu (TreeF l)
toFixT (Tree s ts) = treeF s (map toFixT ts)
fromFixT :: FixT l -> Tree l
fromFixT (Fix (TreeF s ts)) = Tree s (map fromFixT ts)
fromAttr :: Attr (TreeF l) a -> Tree (l,a)
fromAttr (Fix (Ann x (TreeF s ts))) = Tree (s,x) (map fromAttr ts)
toAttr :: Tree (l,a) -> Attr (TreeF l) a
toAttr (Tree (s,x) ts) = Fix (Ann x (TreeF s (map toAttr ts)))
--------------------------------------------------------------------------------
-- * arbitrary
pairs :: [a] -> [(a,a)]
pairs (x:xs@(y:_)) = (x,y):(pairs xs)
pairs [_] = []
pairs [] = error "pairs: empty list"
-- | @genPartition n k@ partitions n elements into k groups randomly,
-- and gives back the sizes (which can be zero, too)
genPartition :: Int -> Int -> Gen [Int]
genPartition n k = do
sep <- replicateM (k-1) $ choose (0,n)
let ps = pairs (0 : sort sep ++ [n])
return (map (\(x,y) -> (y-x)) ps)
newtype Label = Label String deriving (Eq,Ord,Show,Read)
unLabel :: Label -> String
unLabel (Label s) = s
instance Arbitrary Label where
arbitrary = do
n <- choose (2, 8)
liftM Label $ vectorOf n $ oneof [ choose ('a','z') , choose ('A','Z') ]
instance Arbitrary l => Arbitrary (Tree l) where
shrink (Tree s sub) = [ Tree s sub' | sub' <- shrink sub ]
arbitrary = sized mkTree where
mkTree n = do
s <- arbitrary
case n of
0 -> return (Tree s [])
1 -> mkTree 0 >>= \t -> return (Tree s [t])
_ -> do
k <- choose (1, min maxChildren n)
ls <- genPartition (n-1) k
subtrees <- forM ls $ \l -> mkTree l
return (Tree s subtrees)
instance Arbitrary l => Arbitrary (Mu (TreeF l)) where
shrink (Fix (TreeF s sub)) = [ Fix (TreeF s sub') | sub' <- shrink sub ]
arbitrary = sized mkTree where
mkTree n = do
s <- arbitrary
case n of
0 -> return (treeF s [])
1 -> mkTree 0 >>= \t -> return (treeF s [t])
_ -> do
k <- choose (1, min maxChildren n)
ls <- genPartition (n-1) k
subtrees <- forM ls $ \l -> mkTree l
return (treeF s subtrees)
{-
instance (Arbitrary a, Arbitrary x) => Arbitrary (Ann TreeF a x) where
shrink (Ann a x) = [ Ann a y | y <- shrink x ]
arbitrary = do
a <- arbitrary
x <- arbitrary
-}
instance (Arbitrary a, Arbitrary l) => Arbitrary (Attr (TreeF l) a) where
shrink (Fix (Ann a (TreeF s sub))) = [ Fix (Ann a (TreeF s sub')) | sub' <- shrink sub ]
arbitrary = sized mkTree where
mkTree n = do
s <- arbitrary
a <- arbitrary
case n of
0 -> return (attrTreeF a s [])
1 -> mkTree 0 >>= \t -> return (attrTreeF a s [t])
_ -> do
k <- choose (1, min maxChildren n)
ls <- genPartition (n-1) k
subtrees <- forM ls $ \l -> mkTree l
return (attrTreeF a s subtrees)
--------------------------------------------------------------------------------