content: -- Copyright (c) 2015-2024 Rudy Matela.
  -- Distributed under the 3-Clause BSD licence (see the file LICENSE).
  {-# LANGUAGE CPP #-}
  
  #if __GLASGOW_HASKELL__ >= 908
  {-# OPTIONS_GHC -Wno-x-partial #-}
  #endif
  
  {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
  
  import Test (mainTest)
  
  import Test.LeanCheck.Error
  import Test.LeanCheck.Utils.Types (Nat)
  import Data.List (sort)
  
  main :: IO ()
  main  =  mainTest tests 200
  
  tests :: Int -> [Bool]
  tests n  =
    [ True
  
    , not $ holds     n prop_sortMinE
    , fails           n prop_sortMinE
    , counterExample  n prop_sortMinE == Just ["[]"]
    , counterExamples n prop_sortMinE == [["[]"]]
  
    , holds           n prop_sortMin
    , not $ fails     n prop_sortMin
    , counterExample  n prop_sortMin == Nothing
    , counterExamples n prop_sortMin == []
  
    , exists          n someNumbers
    , witness         n someNumbers == Just ["2"]
    , witnesses       n someNumbers == map ((:[]).show) [2,3,5,7,11,13,17]
  
    , exists          n someOthers
    , witness         n someOthers == Just ["2","2"]
    , witnesses  (20*n) someOthers == (map.map) show [[2,2],[2,4],[3,3]
                                                     ,[2,8],[3,9],[3,27]]
  
    , errorToNothing ()                   ==  Just ()
    , errorToNothing (undefined   :: ())  ==  Nothing
    , errorToNothing (error "err" :: ())  ==  Nothing
  
    , errorToNothing False                  ==  Just False
    , errorToNothing True                   ==  Just True
    , errorToNothing (undefined   :: Bool)  ==  Nothing
    , errorToNothing (error "err" :: Bool)  ==  Nothing
  
    , errorToNothing (0           :: Int)  ==  Just 0
    , errorToNothing (1           :: Int)  ==  Just 1
    , errorToNothing (undefined   :: Int)  ==  Nothing
    , errorToNothing (error "err" :: Int)  ==  Nothing
    , errorToNothing (1 `div` 0   :: Int)  ==  Nothing
  
    , errorToNothing (head "abc")  ==  Just 'a'
    , errorToNothing (tail "abc")  ==  Just "bc"
    , errorToNothing (head "")  ==  Nothing
    , errorToNothing (tail "")  ==  Nothing
  
    , errorToLeft ()                   ==  Right ()
    , errorToLeft (undefined   :: ())  ==  Left "Prelude.undefined"
    , errorToLeft (error "err" :: ())  ==  Left "err"
  
    , errorToLeft False                  ==  Right False
    , errorToLeft True                   ==  Right True
    , errorToLeft (undefined   :: Bool)  ==  Left "Prelude.undefined"
    , errorToLeft (error "err" :: Bool)  ==  Left "err"
  
    , errorToLeft (0           :: Int)  ==  Right 0
    , errorToLeft (1           :: Int)  ==  Right 1
    , errorToLeft (undefined   :: Int)  ==  Left "Prelude.undefined"
    , errorToLeft (error "err" :: Int)  ==  Left "err"
    , errorToLeft (1 `div` 0   :: Int)  ==  Left "divide by zero"
  
    , errorToLeft (head "abc")  ==  Right 'a'
    , errorToLeft (tail "abc")  ==  Right "bc"
  
    , errorToLeft (head "")  ==  Left "Prelude.head: empty list" ||    -- GHC
      errorToLeft (head "")  ==  Left "pattern match failure: head []" -- Hugs
  
    , errorToLeft (tail "")  ==  Left "Prelude.tail: empty list" ||    -- GHC
      errorToLeft (tail "")  ==  Left "pattern match failure: tail []" -- Hugs
  
    , (1 `div` 1  ?==?  2 `div` 2)   == True
    , (1 `div` 1  ?==?  1 `div` 2)   == False
    , (1 `div` 1  ?==?  1 `div` 0)   == False
    , (6 `mod` 0  ?==?  2 `div` 0)   == True
    , (head [] ?==? tail ([]::[()])) == True
    , (error "a"  ?==?  (error "a"::())) == True
    , (error "a"  ?==?  (error "b"::())) == True
  
    , (1 `div` 1  !==!  2 `div` 2)   == True
    , (1 `div` 1  !==!  1 `div` 2)   == False
    , (1 `div` 1  !==!  1 `div` 0)   == False
    , (6 `mod` 0  !==!  2 `div` 0)   == True
    , (head [] !==! tail ([]::[()])) == False
    , (error "a"  !==!  (error "a"::())) == True
    , (error "a"  !==!  (error "b"::())) == False
  
    , holds n $ \x y -> (x !==! y)  ==  (x == (y::Int))
    , holds n $ \x y -> (x !==! y)  ==  (x == (y::Bool))
    , holds n $ \x y -> (x ?==? y)  ==  (x == (y::Int))
    , holds n $ \x y -> (x ?==? y)  ==  (x == (y::Bool))
    ]
  
  prop_sortMinE :: [Nat] -> Bool
  prop_sortMinE xs  =  head (sort xs) == minimum (xs::[Nat])
  
  prop_sortMin :: [Nat] -> Bool
  prop_sortMin xs  =  not (null xs)
                  ==> head (sort xs) == minimum (xs::[Nat])
  
  someNumbers :: Int -> Bool
  someNumbers  2  =  True
  someNumbers  3  =  True
  someNumbers  5  =  True
  someNumbers  7  =  True
  someNumbers 11  =  True
  someNumbers 13  =  True
  someNumbers 17  =  True
  
  someOthers :: Int -> Int -> Bool
  someOthers  =  \x -> case x of 2 -> \y -> case y of 2 -> True
                                                      4 -> True
                                                      8 -> True
                                 3 -> \y -> case y of 3 -> True
                                                      9 -> True
                                                      27 -> True
  