import Test.QuickCheck
import Monad

-- einfache Eigenschaften
prop_PA :: Int -> Int -> Int -> Bool
prop_PA x y z = (x+y)+z == x+(y+z) 

prop_MC :: Int -> Int -> Bool
prop_MC x y = x-y == y-x 

prop_MCA :: Int -> Int -> Bool
prop_MCA x y = abs (x-y) == abs (y-x)

------------------------------------------------------------
isort        :: Ord a => [a] -> [a]
isort []     =  []
isort (x:xs) =  insert x (isort xs)

insert :: Ord a => a -> [a] -> [a]
insert x [] = [x]
insert x l@(y:ys) | x <= y    = x:l
                  | otherwise = y:insert x ys
               
ordered :: Ord a => [a] -> Bool
ordered xs  = and (zipWith (<=) xs (tail xs))
-- 

prop_IS :: [Int] -> Bool
prop_IS xs = ordered (isort xs)

prop_I0 :: Int -> [Int] -> Bool
prop_I0 x xs = ordered (insert x xs) 

prop_I1 :: Int -> [Int] -> Property 
prop_I1 x xs = ordered xs ==> 
               ordered (insert x xs)                

prop_I2 :: Int -> Property 
prop_I2 x    = forAll orderedLists $ 
                  \ xs -> ordered (insert x xs) 


-- Testgenerator
orderedLists  :: (Num b, Arbitrary b) => Gen [b]
orderedLists  = do x <- arbitrary
                   listsFromf x
 where
  listsFrom x = oneof [ return [],
                        do y <- atLeast x
                           liftM (x:) (listsFrom y) ]
  listsFromf x = frequency [(1, return []),
                            (4, do y <- atLeast x
                                   liftM (x:) (listsFrom y)) ]

  atLeast x   = do diff <- arbitrary
                   return (x + abs diff)

-- Testgenerator für eigene Datenstruktur
data Tree = Leaf Int | Branch Tree Tree 
            deriving (Eq, Show)
tree1 :: Gen Tree
tree1 =  frequency [(1,liftM Leaf arbitrary),
                    (3,liftM2 Branch tree1 tree1)]


tree2 = sized stree
stree :: Int -> Gen Tree
stree 0 = liftM Leaf arbitrary
stree n |n>0 = frequency [(1,liftM Leaf arbitrary),
                          (3,liftM2 Branch subt subt)]
               where subt = stree (n `div` 2)
instance Arbitrary Tree where
  arbitrary = tree2


-- Baumspiegelung
mirror :: Tree -> Tree
mirror (Leaf x) = Leaf x
mirror (Branch l r) = Branch (mirror l) (mirror r)

prop_tree :: Tree -> Bool
prop_tree t = (mirror.mirror $ t) == t


-- Testkontrolle

prop_O :: [Int] -> Property
prop_O xs = classify (ordered xs) "ordered" $ 
            classify (null xs) "empty" $
            classify (length xs == 1) "unit" $
            True


prop_InsertOrdered3 :: Int -> [Int] -> Property 
prop_InsertOrdered3 x xs = ordered xs ==> 
                           trivial (length xs <= 2) $
                           ordered (insert x xs) 

prop_InsertOrdered4 :: Int -> [Int] -> Property 
prop_InsertOrdered4 x xs 
        = ordered xs ==> 
           classify (null xs) "empty" $
           classify (length xs == 1) "unit" $
                    ordered(insert x xs)

prop_InsertOrdered5 :: Int -> [Int] -> Property 
prop_InsertOrdered5 x xs 
        = ordered xs ==> 
           collect (length xs) $
                    ordered(insert x xs)

prop_InsertOrdered6 :: Int -> Property 
prop_InsertOrdered6 x    = forAll orderedLists $ 
                           \ xs -> collect (length xs) $
                                   ordered (insert x xs) 

