{-# OPTIONS_GHC -fno-warn-orphans #-} import Control.Applicative import Data.Foldable import Data.Functor.Classes import qualified Data.Set as Set import qualified Data.Set.Unique as Unique import qualified Data.Set.Unique.Properties as Unique import Data.Tree.Binary import qualified Data.Tree.Braun as Braun import qualified Data.Tree.Braun.Sized as Sized import qualified Data.Tree.Braun.Sized.Properties as Sized import Test.DocTest import Test.QuickCheck import Test.QuickCheck.Checkers import Test.QuickCheck.Classes import Test.QuickCheck.Poly toUniqOrdList :: Ord a => [a] -> [a] toUniqOrdList = Set.toList . Set.fromList instance Arbitrary a => Arbitrary (Tree a) where arbitrary = sized go where go 0 = pure Leaf go n | n <= 0 = pure Leaf | otherwise = oneof [pure Leaf, liftA3 Node arbitrary sub sub] where sub = go (n `div` 2) shrink Leaf = [] shrink (Node x l r) = Leaf : l : r : [ Node x' l' r' | (x',l',r') <- shrink (x, l, r) ] instance Arbitrary a => Arbitrary (Sized.Braun a) where arbitrary = fmap Sized.fromList arbitrary shrink = fmap Sized.fromList . shrink . toList instance (Show a, Eq a) => EqProp (Tree a) where x =-= y = whenFail (putStrLn (drawBinaryTree x ++ "\n/=\n" ++ drawBinaryTree y)) (x == y) instance (Arbitrary a, Ord a) => Arbitrary (Unique.Set a) where arbitrary = fmap Unique.fromList arbitrary shrink = fmap Unique.fromList . shrink . toList eq1Prop :: (Eq (f a), Eq1 f, Show (f a), Eq a) => Gen (f a) -> (f a -> [f a]) -> Property eq1Prop arb shrnk = forAllShrink arb shrnk $ \xs -> forAllShrink (oneof [pure xs, arb]) shrnk $ \ys -> liftEq (==) xs ys === (xs == ys) validSized :: Show a => Sized.Braun a -> Property validSized br = whenFail (putStrLn ("Not a valid Braun tree:\n" ++ drawBinaryTree (Sized.tree br))) (Sized.isBraun br) .&&. counterexample "Invalid size" (Sized.validSize br) validUnique :: Show a => Unique.Set a -> Property validUnique s = conjoin [ counterexample "sizes not in bounds" $ Unique.sizesInBound s , counterexample "subtrees not braun" $ Unique.allBraun s , counterexample "subtrees not correct sizes" $ Unique.allCorrectSizes s , counterexample "incorrect size" $ Unique.validSize s] validSetOpsProp :: [OrdA] -> OrdA -> Unique.Set OrdA -> Property validSetOpsProp xs x s = conjoin [ validUnique s , counterexample "after insert" $ validUnique (Unique.insert x s) , counterexample "after delete" $ validUnique (Unique.delete x s) , counterexample "after fromAscList" $ validUnique (Unique.fromDistinctAscList xs) ] validOpsProp :: Show a => a -> Sized.Braun a -> Property validOpsProp x br = conjoin [ validSized br , counterexample "after snoc" (validSized (Sized.snoc x br)) , counterexample "after cons" (validSized (Sized.cons x br)) , counterexample "after uncons" (conjoin $ fmap (validSized . snd) (toList (Sized.uncons br))) , counterexample "after unsnoc" (conjoin $ fmap (validSized . snd) (toList (Sized.uncons br)))] setMemberProp :: Property setMemberProp = property $ do xs <- arbitrary :: Gen [OrdA] x <- arbitrary :: Gen OrdA ys <- shuffle (x : xs) pure (Unique.member x (Unique.fromList ys) && not (Unique.member x (Unique.fromList (filter (x /=) ys)))) setShuffleProp :: Property setShuffleProp = property $ do xs <- arbitrary :: Gen [OrdA] ys <- shuffle xs pure (Unique.fromList xs === Unique.fromList ys) setFromListWithProp :: Property setFromListWithProp = property $ do xs <- arbitrary :: Gen [OrdA] pure (Unique.fromList xs === Unique.fromListBy compare xs) insertSizedProp :: [OrdA] -> Property insertSizedProp xs = foldr (Sized.insertBy compare) Sized.empty xs === Sized.fromList (toUniqOrdList xs) deleteSizedProp :: OrdA -> [OrdA] -> Property deleteSizedProp x xs = Sized.fromList setwo === deled .&&. validSized deled where setwi = toUniqOrdList (x : xs) setwo = toUniqOrdList [ y | y <- xs , y /= x ] deled = Sized.deleteBy compare x (Sized.fromList setwi) main :: IO () main = do quickCheck (eq1Prop (arbitrary :: Gen (Tree Int)) shrink) quickBatch (ord (\x -> oneof [pure (x :: Tree Int), arbitrary])) quickBatch (ordRel (\x y -> liftCompare compare x y /= GT) (\x -> oneof [pure (x :: Tree Int), arbitrary])) quickCheck (\xs -> show (xs :: Tree Int) === liftShowsPrec showsPrec showList 0 xs "") quickCheck (\xs -> Braun.size (fromList xs) === length (xs :: [Int])) quickCheck (validOpsProp (1 :: Int)) quickCheck insertSizedProp quickCheck deleteSizedProp quickCheck validSetOpsProp quickCheck setMemberProp quickCheck setShuffleProp quickCheck setFromListWithProp quickBatch (monoid (Leaf :: Tree Int)) doctest ["-isrc", "src/"]