module Spec where
import Test.QuickCheck
import Data.List((\\), sort)
-- Spec: use specification based development techniques
--     Spec.Test: formulate and test properties about the program
--     Spec.Prove: reason about correctness of functional programs
--     Spec.Trans: transform programs on the basis of reasoning 

-- Below is an attempt at a QuickCheck test suite for |qsort :: Ord a => [a] -> [a]|. 

qsort :: Ord a => [a] -> [a]
qsort = sort

prop_minimumBad xs         = head (qsort xs) == minimum xs

prop_orderedBad xs = ordered (qsort xs)
    where  ordered []        = True
           ordered (x:y:xs)  = x <= y && ordered (y:xs)

prop_permutationBad xs = permutation xs (qsort xs)
    where permutation xs ys = null (xs \\ ys) && null (ys \\ ys)


-- Find and correct at least one bug per property in the test suite.
{-
quickCheck (prop_minimumBad :: [Int] -> Bool)
*** Failed! Exception: 'Prelude.head: empty list' (after 1 test): 
[]
-}

prop_minimum :: [Int] -> Property
prop_minimum xs = not (null xs) ==> head (qsort xs) == minimum xs

-- Write a |main| function which tests the three properties (for lists of integers) using QuickCheck.

prop_ordered :: [Int] -> Bool
prop_ordered xs = ordered (qsort xs)
    where  ordered []        = True
           ordered [x]       = True
           ordered (x:y:xs)  = x <= y && ordered (y:xs)

prop_permutation :: [Int] -> Bool
prop_permutation xs = permutation xs (qsort xs)
    where permutation xs ys = null (xs \\ ys) && null (ys \\ xs)

main = do quickCheck prop_minimum
          quickCheck prop_ordered
          quickCheck prop_permutation


{-
  Write a sized generator (|sizedList :: Gen a -> Gen [a]|) for random
  lists. Make sure the list length is random (but bounded by the
  current size).
-}

sizedList :: Gen a -> Gen [a]
sizedList g = sized $ \n ->
              do size <- choose (0, n)
                 myVector size g

myVector :: Int -> Gen a -> Gen [a]
myVector n g = sequence (replicate n g)


----------------------------------------------------------------
-- End of exam question

-- --------------------------------------------------------------
testBad = do quickCheck (prop_minimumBad  :: [Int] -> Bool)
             quickCheck (prop_orderedBad  :: [Int] -> Bool)
             quickCheck (prop_permutationBad :: [Int] -> Bool)


----------------
-- Sanity check

sizedList' :: Gen a -> Gen (Int, [a])
sizedList' g = sized $ \n ->
              do size <- choose (0, n)
                 fmap ((,) n) $ myVector size g