import Test.QuickCheck hiding (OrderedList (..), orderedList)
import Data.List (sort, insert)



-- In this file we want to test the `insert` function from Data.List:
--
--     insert :: Ord a => a -> [a] -> [a]

-- Check if a list is ordered
ordered :: Ord a => [a] -> Bool
ordered (x:y:xs) = x <= y && ordered (y:xs)
ordered _        = True

-- try 1, does not work

prop_insert1 :: Int -> [Int] -> Bool
prop_insert1 x xs =
  ordered (insert x xs)

-- try 2, works badly

prop_insert2 :: Int -> [Int] -> Property
prop_insert2 x xs =
  collect (length xs) $
    ordered xs ==> ordered (insert x xs)

-- try 3, works better

orderedList :: Gen [Int]
orderedList =
  do xs <- arbitrary
     return (sort xs)

-- Because there already exists an `Arbitrary` instance for lists (which
-- generates unordered lists in general), we have to make a new type for
-- ordered lists, and give an `Arbitrary` instance for this type
data OrderedList = Ordered [Int]
  deriving (Show)

instance Arbitrary OrderedList where
  arbitrary =
    do xs <- orderedList
       return (Ordered xs)

prop_insert3 x (Ordered xs) =
  collect (length xs) $
    ordered (insert x xs)

-- Note that `OrderedList` (and other similar types) already exists in
-- Test.QuickCheck

-- Other examples:

prop_pos (Positive n) = n > 0

prop_nonNeg (NonNegative n) = n >= 0