packages feed

GenericPretty-1.0.0: TestSuite/Tests.hs

{-# LANGUAGE DeriveGeneric #-}

{- Tests.hs has a number of different custom data types. All of them implement 'Out' and 'Arbitrary'.
Properties are provided for each that specify that the output given by 'pretty' and that given
by 'show' should be identical except for the whitespace 

The different data types follow the same pattern of implementation and functions, so most of the
functions are only commented for the first data type -}

import Text.PrettyPrint.GenericPretty
import Test.QuickCheck
import Control.Monad
import Data.Maybe
import Text.Printf

-- used to make pretty printed and show output identical for comparing purposes
removeSpaces :: String -> String
removeSpaces [] = []
removeSpaces (x:xs)
  | x `elem` " \n" = removeSpaces xs
  | otherwise = x : removeSpaces xs
  
-- checks the output of a specific value
checkOutput :: (Out a, Show a) => a -> Bool
checkOutput a = removeSpaces (pretty a) == removeSpaces (show a)

-- Finite State Machine Type
data FSM q = FSMCons ([q], Alphabet, q, [q], [Transition q]) deriving (Show, Generic)
type Alphabet = String
type Transition q = (q, Char, q)

-- implement 'Out' so we can pretty print
instance (Out a) => Out (FSM a) where
	docPrec = genOut

--implementation needed for quickCheck generation of random values
instance Arbitrary a => Arbitrary (FSM a) where
	arbitrary = liftM FSMCons arbitrary

-- check wether 'Maybe Int' FSM's are outputed the same via pretty and show (modulo the whitespace) 
checkFSM :: FSM (Maybe Int) -> FSM (Maybe Int) -> Bool
checkFSM _ a = removeSpaces (pretty a) == removeSpaces (show a)

-- example of an FSM, you can check the output of this manually with 'checkOutput'
f :: FSM Int
f = FSMCons([0,1,2,3,4],
      "ab",
      0,
      [4],
      [(0,'a',1), (0,'b',1), (0,'a',2), (0,'b',2),
       (1,'b',4), (2,'a',3), (2,'b',3), (3,'b',4),
       (4,'a',4), (4,'b',4)])
	   
-- Binary Tree data type
data BinaryTree a = EmptyBTree | BNode a (BinaryTree a) (BinaryTree a) deriving (Show, Generic)  

instance (Out a) => Out (BinaryTree a) where
	docPrec = genOut

instance (Arbitrary a) => Arbitrary (BinaryTree a) where
	arbitrary = sized arbitTree
		where 
			arbitTree 0 = return EmptyBTree
			arbitTree n 
				| n>0 = oneof [return EmptyBTree, liftM3 BNode arbitrary subTree subTree]
				| otherwise = error "tree size should never be < 0"
				where
					subTree = arbitTree (n `div` 2)

checkBinaryTree :: BinaryTree Char -> BinaryTree Char -> Bool
checkBinaryTree _ a = removeSpaces (pretty a) == removeSpaces (show a)

-- functions for the construction of BinaryTrees					
singleton :: a -> BinaryTree a  
singleton x = BNode x EmptyBTree EmptyBTree  
      
treeInsert :: (Ord a) => a -> BinaryTree a -> BinaryTree a  
treeInsert x EmptyBTree = singleton x  
treeInsert x (BNode a left right)   
    | x == a = BNode x left right  
    | x < a  = BNode a (treeInsert x left) right  
    | x > a  = BNode a left (treeInsert x right)  

nums :: [Int]
nums = [55555,99999,22222,77777,88888,11111,33333,44444,66666]  

-- mkBTree takes a list and creates a BinaryTree docPrec of it
mkBTree :: (Ord a) => [a] -> BinaryTree a
mkBTree = foldr treeInsert EmptyBTree

-- example BinaryTree
bt :: BinaryTree Int
bt = mkBTree nums

-- Tree using record syntax
data RecordTree a = RNode {val :: a, children :: [RecordTree a]} deriving (Show, Generic)  

instance (Out a) => Out (RecordTree a) where
	docPrec = genOut

instance (Arbitrary a) => Arbitrary (RecordTree a) where
	arbitrary = sized arbitTree
		where
			arbitTree 0 = liftM2 RNode arbitrary (return [])
			arbitTree n 
				| n>0 = liftM2 RNode arbitrary childList
				| otherwise = error "tree size should never be < 0"
				where
					childList = resize (floor.sqrt.fromIntegral $ n) (listOf (arbitTree (n`div` 2)) )

checkRecordTree :: RecordTree String -> RecordTree String -> Bool
checkRecordTree _ a = removeSpaces (pretty a) == removeSpaces (show a)
					
rt :: RecordTree Int
rt = RNode (-656565) [RNode 33344 [], RNode 98789 [RNode (-766444) [], RNode 454545 [], RNode 59996 []]]

infixr 5 :*:
infixr 3 :+:
-- tree using infix notation
data InfixTree a = ILeaf a a | (InfixTree a) :*: (InfixTree a) | (InfixTree a) :+: (InfixTree a) 
		deriving (Show, Generic)  
		
instance (Out a) => Out (InfixTree a) where
	docPrec = genOut

instance (Arbitrary a) => Arbitrary (InfixTree a) where
	arbitrary = sized arbitTree
		where
			arbitTree 0 = liftM2 ILeaf arbitrary arbitrary
			arbitTree n 
				| n>0 = oneof [ liftM2 (:*:) subTree subTree, liftM2 (:+:) subTree subTree]
				| otherwise = error "tree size should never be < 0"
				where
					subTree = arbitTree (n `div` 2)

nt :: InfixTree Int
nt = ILeaf 5454544 55 :*: (ILeaf 5375738 44 :+: ((ILeaf 699879 55 :*: ILeaf 2332323 66 :+: ILeaf 676765 77) 
		:*: ILeaf 99999 88) ) :+: ILeaf 555 666

checkInfixTree :: InfixTree (Either Int Char) -> InfixTree (Either Int Char) -> Bool
checkInfixTree _ a = removeSpaces (pretty a) == removeSpaces (show a)
	
infixr 5 :^:
-- infix and record tree, also uses a second user defined type in it's definition, 'Wrap'
data InfixRecordTree a = IRLeaf (Wrap a) | (:^:) {left :: InfixRecordTree a, right :: InfixRecordTree a} 
			deriving (Show, Generic)  
			
instance (Out a) => Out (InfixRecordTree a) where
	docPrec = genOut
	
instance (Arbitrary a) => Arbitrary (InfixRecordTree a) where
	arbitrary = sized arbitTree
	  where
		arbitTree 0 = liftM IRLeaf arbitrary
		arbitTree n
			| n>0 = liftM2 (:^:) subTree subTree
			| otherwise = error "tree size should never be < 0"
			  where
				subTree = arbitTree (n `div` 2)
				
irt :: InfixRecordTree Int
irt = IRLeaf  (Wrap 5454544) :^: (IRLeaf (Wrap (-5375738)) :^: ((IRLeaf  (Wrap 699879) :^: 
		(IRLeaf (Wrap (-2332323)) :^: IRLeaf (Wrap 676765))) :^: IRLeaf (Wrap 99999)))

checkInfixRecordTree :: InfixRecordTree Int -> InfixRecordTree Int -> Bool
checkInfixRecordTree _ a = removeSpaces (pretty a) == removeSpaces (show a)
	
-- just a very simple user defined type that is used in IRTree
data Wrap a = Wrap a deriving (Show, Generic)

instance Out a => Out (Wrap a) where
	docPrec = genOut
	
instance Arbitrary a => Arbitrary (Wrap a) where
	arbitrary = liftM Wrap arbitrary
	
allTests = [	("FSM (Maybe Int)", quickCheck checkFSM),
				("BinaryTree (Char)", quickCheck checkBinaryTree),
				("RecordTree (String)", quickCheck checkRecordTree),
				("InfixTree (Either Int Char)", quickCheck checkInfixTree),
				("InfixRecordTree (Int)", quickCheck checkInfixRecordTree)]
				
main = mapM_ (\(s,r) -> printf "%-30s: " s >> r) allTests