<commit_before>{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module CombinatorTests 
  ( tests_types
  , tests_boolean
  , tests_tuples
  , tests_numerics
  , tests_maybe
  , tests_either
  , tests_lists
  , tests_lifted
  , tests_combinators_hunit
  ) where

import           Common

import qualified Database.DSH as Q
import           Database.DSH (Q, QA)

import           Test.QuickCheck
import           Test.HUnit(assertEqual, Assertion)
import           Test.Framework (Test, defaultMainWithArgs, testGroup)
import           Test.Framework.Providers.QuickCheck2 (testProperty)
import           Test.Framework.Providers.HUnit
import           Data.DeriveTH

import           Data.Char
import           Data.Text (Text)
import qualified Data.Text as Text

import           Data.List
import           Data.Maybe
import           Data.Either
import           GHC.Exts

data D0 = C01 deriving (Eq,Ord,Show)
derive makeArbitrary ''D0
Q.deriveDSH ''D0

data D1 a = C11 a deriving (Eq,Ord,Show)
derive makeArbitrary ''D1
Q.deriveDSH ''D1

data D2 a b = C21 a b b a deriving (Eq,Ord,Show)
derive makeArbitrary ''D2
Q.deriveDSH ''D2

data D3 = C31 | C32 deriving (Eq,Ord,Show)
derive makeArbitrary ''D3
Q.deriveDSH ''D3

data D4 a = C41 a | C42 deriving (Eq,Ord,Show)
derive makeArbitrary ''D4
Q.deriveDSH ''D4

data D5 a = C51 a | C52 | C53 a a | C54 a a a deriving (Eq,Ord,Show)
derive makeArbitrary ''D5
Q.deriveDSH ''D5

data D6 a b c d e = C61 { c611 :: a, c612 :: (a,b,c,d) } | C62 | C63 a b | C64 (a,b,c) | C65 a b c d e deriving (Eq,Ord,Show)
derive makeArbitrary ''D6
Q.deriveDSH ''D6

tests_types :: Test
tests_types = testGroup "Supported Types"
  [ testProperty "()" $ prop_unit
  , testProperty "Bool" $ prop_bool
  , testProperty "Char" $ prop_char
  , testProperty "Text" $ prop_text
  , testProperty "Integer" $ prop_integer
  , testProperty "Double" $ prop_double
  , testProperty "[Integer]" $ prop_list_integer_1
  , testProperty "[[Integer]]" $ prop_list_integer_2
  , testProperty "[[[Integer]]]" $ prop_list_integer_3
  , testProperty "[(Integer, Integer)]" $ prop_list_tuple_integer
  , testProperty "([], [])" $ prop_tuple_list_integer
  , testProperty "Maybe Integer" $ prop_maybe_integer
  , testProperty "Either Integer Integer" $ prop_either_integer
  , testProperty "D0" $ prop_d0
  , testProperty "D1" $ prop_d1
  , testProperty "D2" $ prop_d2
  , testProperty "D3" $ prop_d3
  , testProperty "D4" $ prop_d4
  , testProperty "D5" $ prop_d5
  , testProperty "D6" $ prop_d6
  ]

tests_boolean :: Test
tests_boolean = testGroup "Equality, Boolean Logic and Ordering"
  [ testProperty "&&" $ prop_infix_and
  , testProperty "||" $ prop_infix_or
  , testProperty "not" $ prop_not
  , testProperty "eq" $ prop_eq
  , testProperty "neq" $ prop_neq
  , testProperty "cond" $ prop_cond
  , testProperty "cond tuples" $ prop_cond_tuples
  , testProperty "cond ([[Integer]], [[Integer]])" $ prop_cond_list_tuples
  , testProperty "lt" $ prop_lt
  , testProperty "lte" $ prop_lte
  , testProperty "gt" $ prop_gt
  , testProperty "gte" $ prop_gte
  , testProperty "min_integer" $ prop_min_integer
  , testProperty "min_double" $ prop_min_double
  , testProperty "max_integer" $ prop_max_integer
  , testProperty "max_double" $ prop_max_double
  ]

tests_tuples :: Test
tests_tuples = testGroup "Tuples"
  [ testProperty "fst" $ prop_fst
  , testProperty "snd" $ prop_snd
  ]

tests_numerics :: Test
tests_numerics = testGroup "Numerics"
  [ testProperty "add_integer" $ prop_add_integer
  , testProperty "add_double" $ prop_add_double
  , testProperty "mul_integer" $ prop_mul_integer
  , testProperty "mul_double" $ prop_mul_double
  , testProperty "div_double" $ prop_div_double
  , testProperty "integer_to_double" $ prop_integer_to_double
  , testProperty "integer_to_double_+" $ prop_integer_to_double_arith
  , testProperty "abs_integer" $ prop_abs_integer
  , testProperty "abs_double" $ prop_abs_double
  , testProperty "signum_integer" $ prop_signum_integer
  , testProperty "signum_double" $ prop_signum_double
  , testProperty "negate_integer" $ prop_negate_integer
  , testProperty "negate_double" $ prop_negate_double
  , testProperty "trig_sin" $ prop_trig_sin
  , testProperty "trig_cos" $ prop_trig_cos
  , testProperty "trig_tan" $ prop_trig_tan
  , testProperty "trig_asin" $ prop_trig_asin
  , testProperty "trig_acos" $ prop_trig_acos
  , testProperty "trig_atan" $ prop_trig_atan
  , testProperty "sqrt" $ prop_sqrt
  , testProperty "log" $ prop_log
  , testProperty "exp" $ prop_exp
  ]

tests_maybe :: Test
tests_maybe = testGroup "Maybe"
        [ testProperty "maybe" $ prop_maybe
        , testProperty "just" $ prop_just
        , testProperty "isJust" $ prop_isJust
        , testProperty "isNothing" $ prop_isNothing
        , testProperty "fromJust" $ prop_fromJust
        , testProperty "fromMaybe" $ prop_fromMaybe
        , testProperty "listToMaybe" $ prop_listToMaybe
        , testProperty "maybeToList" $ prop_maybeToList
        , testProperty "catMaybes" $ prop_catMaybes
        , testProperty "mapMaybe" $ prop_mapMaybe
        ]

tests_either :: Test
tests_either = testGroup "Either"
        [ testProperty "left" $ prop_left
        , testProperty "right" $ prop_right
        , testProperty "isLeft" $ prop_isLeft
        , testProperty "isRight" $ prop_isRight
        , testProperty "either" $ prop_either
        , testProperty "lefts" $ prop_lefts
        , testProperty "rights" $ prop_rights
        , testProperty "partitionEithers" $ prop_partitionEithers
        ]

tests_lists :: Test
tests_lists = testGroup "Lists"
        [ testProperty "head" $ prop_head
        , testProperty "tail" $ prop_tail
        , testProperty "cons" $ prop_cons
        , testProperty "snoc" $ prop_snoc
        , testProperty "take" $ prop_take
        , testProperty "drop" $ prop_drop
        , testProperty "take ++ drop" $ prop_takedrop
        , testProperty "map" $ prop_map
        , testProperty "filter" $ prop_filter
        , testProperty "the" $ prop_the
        , testProperty "last" $ prop_last
        , testProperty "init" $ prop_init
        , testProperty "null" $ prop_null
        , testProperty "length" $ prop_length
        , testProperty "length tuple list" $ prop_length_tuple
        , testProperty "index" $ prop_index
        , testProperty "index [[]]" $ prop_index_nest
        , testProperty "reverse" $ prop_reverse
        , testProperty "reverse [[]]" $ prop_reverse_nest
        , testProperty "append" $ prop_append
        , testProperty "append nest" $ prop_append_nest
        , testProperty "groupWith" $ prop_groupWith
        , testProperty "groupWithKey" $ prop_groupWithKey
        , testProperty "groupWith length" $ prop_groupWith_length
        , testProperty "groupWithKey length" $ prop_groupWithKey_length
        , testProperty "sortWith" $ prop_sortWith
        , testProperty "and" $ prop_and
        , testProperty "or" $ prop_or
        , testProperty "any_zero" $ prop_any_zero
        , testProperty "all_zero" $ prop_all_zero
        , testProperty "sum_integer" $ prop_sum_integer
        , testProperty "sum_double" $ prop_sum_double
        , testProperty "avg_integer" $ prop_avg_integer
        , testProperty "avg_double" $ prop_avg_double
        , testProperty "concat" $ prop_concat
        , testProperty "concatMap" $ prop_concatMap
        , testProperty "maximum" $ prop_maximum
        , testProperty "minimum" $ prop_minimum
        , testProperty "splitAt" $ prop_splitAt
        , testProperty "takeWhile" $ prop_takeWhile
        , testProperty "dropWhile" $ prop_dropWhile
        , testProperty "span" $ prop_span
        , testProperty "break" $ prop_break
        , testProperty "elem" $ prop_elem
        , testProperty "notElem" $ prop_notElem
        , testProperty "lookup" $ prop_lookup
        , testProperty "zip" $ prop_zip
        , testProperty "zip3" $ prop_zip3
        , testProperty "zipWith" $ prop_zipWith
        , testProperty "zipWith3" $ prop_zipWith3
        , testProperty "unzip" $ prop_unzip
        , testProperty "unzip3" $ prop_unzip3
        , testProperty "nub" $ prop_nub
        , testProperty "number" $ prop_number
        , testProperty "reshape" $ prop_reshape
        , testProperty "reshape2" $ prop_reshape2
        , testProperty "transpose" $ prop_transpose
        ]

tests_lifted :: Test
tests_lifted = testGroup "Lifted operations"
        [ testProperty "Lifted &&" $ prop_infix_map_and
        , testProperty "Lifted ||" $ prop_infix_map_or
        , testProperty "Lifted not" $ prop_map_not
        , testProperty "Lifted eq" $ prop_map_eq
        , testProperty "Lifted neq" $ prop_map_neq
        , testProperty "Lifted cond" $ prop_map_cond
        , testProperty "Lifted cond tuples" $ prop_map_cond_tuples
        , testProperty "Lifted cond + concat" $ prop_concatmapcond
        , testProperty "Lifted lt" $ prop_map_lt
        , testProperty "Lifted lte" $ prop_map_lte
        , testProperty "Lifted gt" $ prop_map_gt
        , testProperty "Lifted gte" $ prop_map_gte
        , testProperty "Lifted cons" $ prop_map_cons
        , testProperty "Lifted concat" $ prop_map_concat
        , testProperty "Lifted fst" $ prop_map_fst
        , testProperty "Lifted snd" $ prop_map_snd
        , testProperty "Lifted the" $ prop_map_the
        --, testProperty "Lifed and" $ prop_map_and
        , testProperty "map (map (*2))" $ prop_map_map_mul
        , testProperty "map (map (map (*2)))" $ prop_map_map_map_mul
        , testProperty "map (\\x -> map (\\y -> x + y) ..) .." $ prop_map_map_add
        , testProperty "Lifted groupWith" $ prop_map_groupWith
        , testProperty "Lifted groupWithKey" $ prop_map_groupWithKey
        , testProperty "Lifted sortWith" $ prop_map_sortWith
        , testProperty "Lifted sortWith length" $ prop_map_sortWith_length
        , testProperty "Lifted groupWithKey length" $ prop_map_groupWithKey_length
        , testProperty "Lifted length" $ prop_map_length
        , testProperty "Lifted length on [[(a,b)]]" $ prop_map_length_tuple
        , testProperty "Sortwith length nested" $ prop_sortWith_length_nest
        , testProperty "GroupWithKey length nested" $ prop_groupWithKey_length_nest
        , testProperty "Lift minimum" $ prop_map_minimum
        , testProperty "map (map minimum)" $ prop_map_map_minimum
        , testProperty "Lift maximum" $ prop_map_maximum
        , testProperty "map (map maximum)" $ prop_map_map_maximum
        , testProperty "map integer_to_double" $ prop_map_integer_to_double
        , testProperty "map tail" $ prop_map_tail
        , testProperty "map unzip" $ prop_map_unzip
        , testProperty "map reverse" $ prop_map_reverse
        , testProperty "map reverse [[]]" $ prop_map_reverse_nest
        , testProperty "map and" $ prop_map_and
        , testProperty "map (map and)" $ prop_map_map_and
        , testProperty "map sum" $ prop_map_sum
        , testProperty "map avg" $ prop_map_avg
        , testProperty "map (map sum)" $ prop_map_map_sum
        , testProperty "map or" $ prop_map_or
        , testProperty "map (map or)" $ prop_map_map_or
        , testProperty "map any zero" $ prop_map_any_zero
        , testProperty "map all zero" $ prop_map_all_zero
        , testProperty "map filter" $ prop_map_filter
        , testProperty "map append" $ prop_map_append
        , testProperty "map index" $ prop_map_index
        , testProperty "map index [[]]" $ prop_map_index_nest
        , testProperty "map init" $ prop_map_init
        , testProperty "map last" $ prop_map_last
        , testProperty "map null" $ prop_map_null
        , testProperty "map nub" $ prop_map_nub
        , testProperty "map snoc" $ prop_map_snoc
        , testProperty "map take" $ prop_map_take
        , testProperty "map drop" $ prop_map_drop
        , testProperty "map zip" $ prop_map_zip
        , testProperty "map takeWhile" $ prop_map_takeWhile
        , testProperty "map dropWhile" $ prop_map_dropWhile
        , testProperty "map span" $ prop_map_span
        , testProperty "map break" $ prop_map_break
        , testProperty "map number" $ prop_map_number
        , testProperty "map reshape" $ prop_map_reshape
        , testProperty "map reshape2" $ prop_map_reshape2
        -- , testProperty "map transpose" $ prop_map_transpose
        , testProperty "map sin" $ prop_map_trig_sin
        , testProperty "map cos" $ prop_map_trig_cos
        , testProperty "map tan" $ prop_map_trig_tan
        , testProperty "map asin" $ prop_map_trig_asin
        , testProperty "map acos" $ prop_map_trig_acos
        , testProperty "map atan" $ prop_map_trig_atan
        , testProperty "map log" $ prop_map_log
        , testProperty "map exp" $ prop_map_exp
        , testProperty "map sqrt" $ prop_map_sqrt
        ]

tests_combinators_hunit :: Test
tests_combinators_hunit = testGroup "HUnit combinators"
    [ testCase "hnegative_sum" hnegative_sum
    , testCase "hnegative_map_sum" hnegative_map_sum
    , testCase "hmap_transpose" hmap_transpose
    ]

-- * Supported Types

prop_unit :: () -> Property
prop_unit = makeProp id id

prop_bool :: Bool -> Property
prop_bool = makeProp id id

prop_integer :: Integer -> Property
prop_integer = makeProp id id

prop_double :: Double -> Property
prop_double = makePropDouble id id

prop_char :: Char -> Property
prop_char c = isPrint c ==> makeProp id id c

prop_text :: Text -> Property
prop_text t = Text.all isPrint t ==> makeProp id id t

prop_list_integer_1 :: [Integer] -> Property
prop_list_integer_1 = makeProp id id

prop_list_integer_2 :: [[Integer]] -> Property
prop_list_integer_2 = makeProp id id

prop_list_integer_3 :: [[[Integer]]] -> Property
prop_list_integer_3 = makeProp id id

prop_list_tuple_integer :: [(Integer, Integer)] -> Property
prop_list_tuple_integer = makeProp id id

prop_maybe_integer :: Maybe Integer -> Property
prop_maybe_integer = makeProp id id

prop_tuple_list_integer :: ([Integer], [Integer]) -> Property
prop_tuple_list_integer = makeProp id id

prop_either_integer :: Either Integer Integer -> Property
prop_either_integer = makeProp id id

prop_d0 :: D0 -> Property
prop_d0 = makeProp id id

prop_d1 :: D1 Integer -> Property
prop_d1 = makeProp id id

prop_d2 :: D2 Integer Integer -> Property
prop_d2 = makeProp id id

prop_d3 :: D3 -> Property
prop_d3 = makeProp id id

prop_d4 :: D4 Integer -> Property
prop_d4 = makeProp id id

prop_d5 :: D5 Integer -> Property
prop_d5 = makeProp id id

prop_d6 :: D6 Integer Integer Integer Integer Integer -> Property
prop_d6 = makeProp id id

-- * Equality, Boolean Logic and Ordering

prop_infix_and :: (Bool,Bool) -> Property
prop_infix_and = makeProp (uncurryQ (Q.&&)) (uncurry (&&))

prop_infix_map_and :: (Bool, [Bool]) -> Property
prop_infix_map_and = makeProp (\x -> Q.map ((Q.fst x) Q.&&) $ Q.snd x) (\(x,xs) -> map (x &&) xs)

prop_infix_or :: (Bool,Bool) -> Property
prop_infix_or = makeProp (uncurryQ (Q.||)) (uncurry (||))

prop_infix_map_or :: (Bool, [Bool]) -> Property
prop_infix_map_or = makeProp (\x -> Q.map ((Q.fst x) Q.||) $ Q.snd x) (\(x,xs) -> map (x ||) xs)

prop_not :: Bool -> Property
prop_not = makeProp Q.not not

prop_map_not :: [Bool] -> Property
prop_map_not = makeProp (Q.map Q.not) (map not)

prop_eq :: (Integer,Integer) -> Property
prop_eq = makeProp (uncurryQ (Q.==)) (uncurry (==))

prop_map_eq :: (Integer, [Integer]) -> Property
prop_map_eq = makeProp (\x -> Q.map ((Q.fst x) Q.==) $ Q.snd x) (\(x,xs) -> map (x ==) xs)

prop_neq :: (Integer,Integer) -> Property
prop_neq = makeProp (uncurryQ (Q./=)) (uncurry (/=))

prop_map_neq :: (Integer, [Integer]) -> Property
prop_map_neq = makeProp (\x -> Q.map ((Q.fst x) Q./=) $ Q.snd x) (\(x,xs) -> map (x /=) xs)

prop_cond :: Bool -> Property
prop_cond = makeProp (\b -> Q.cond b 0 1) (\b -> if b then (0 :: Integer) else 1)

prop_cond_tuples :: (Bool, (Integer, Integer)) -> Property
prop_cond_tuples = makeProp (\b -> Q.cond (Q.fst b) (Q.pair (Q.fst $ Q.snd b) (Q.fst $ Q.snd b)) (Q.pair (Q.snd $ Q.snd b) (Q.snd $ Q.snd b))) (\b -> if fst b then (fst $ snd b, fst $ snd b) else (snd $ snd b, snd $ snd b))

prop_cond_list_tuples :: (Bool, ([[Integer]], [[Integer]])) -> Property
prop_cond_list_tuples = makeProp (\b -> Q.cond (Q.fst b) (Q.pair (Q.fst $ Q.snd b) (Q.fst $ Q.snd b)) (Q.pair (Q.snd $ Q.snd b) (Q.snd $ Q.snd b))) (\b -> if fst b then (fst $ snd b, fst $ snd b) else (snd $ snd b, snd $ snd b))

prop_map_cond :: [Bool] -> Property
prop_map_cond = makeProp (Q.map (\b -> Q.cond b (0 :: Q Integer) 1)) (map (\b -> if b then 0 else 1))

prop_map_cond_tuples :: [Bool] -> Property
prop_map_cond_tuples = makeProp (Q.map (\b -> Q.cond b (Q.toQ (0, 10) :: Q (Integer, Integer)) (Q.toQ (1, 11)))) (map (\b -> if b then (0, 10) else (1, 11)))

prop_concatmapcond :: [Integer] -> Property
prop_concatmapcond l1 =
        -- FIXME remove precondition as soon as X100 is fixed
    (not $ null l1)
    ==>
    makeProp q n l1
        where q l = Q.concatMap (\x -> Q.cond ((Q.>) x (Q.toQ 0)) (x Q.<| el) el) l
              n l = concatMap (\x -> if x > 0 then [x] else []) l
              el = Q.toQ []

prop_lt :: (Integer, Integer) -> Property
prop_lt = makeProp (uncurryQ (Q.<)) (uncurry (<))

prop_map_lt :: (Integer, [Integer]) -> Property
prop_map_lt = makeProp (\x -> Q.map ((Q.fst x) Q.<) $ Q.snd x) (\(x,xs) -> map (x <) xs)

prop_lte :: (Integer, Integer) -> Property
prop_lte = makeProp (uncurryQ (Q.<=)) (uncurry (<=))

prop_map_lte :: (Integer, [Integer]) -> Property
prop_map_lte = makeProp (\x -> Q.map ((Q.fst x) Q.<=) $ Q.snd x) (\(x,xs) -> map (x <=) xs)

prop_gt :: (Integer, Integer) -> Property
prop_gt = makeProp (uncurryQ (Q.>)) (uncurry (>))

prop_map_gt :: (Integer, [Integer]) -> Property
prop_map_gt = makeProp (\x -> Q.map ((Q.fst x) Q.>) $ Q.snd x) (\(x,xs) -> map (x >) xs)

prop_gte :: (Integer, Integer) -> Property<commit_msg>Eliminated some Jeroen-style code "formatting".<commit_after>{-# LANGUAGE TemplateHaskell       #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module CombinatorTests 
  ( tests_types
  , tests_boolean
  , tests_tuples
  , tests_numerics
  , tests_maybe
  , tests_either
  , tests_lists
  , tests_lifted
  , tests_combinators_hunit
  ) where

import           Common

import qualified Database.DSH as Q
import           Database.DSH (Q, QA)

import           Test.QuickCheck
import           Test.HUnit(assertEqual, Assertion)
import           Test.Framework (Test, defaultMainWithArgs, testGroup)
import           Test.Framework.Providers.QuickCheck2 (testProperty)
import           Test.Framework.Providers.HUnit
import           Data.DeriveTH

import           Data.Char
import           Data.Text (Text)
import qualified Data.Text as Text

import           Data.List
import           Data.Maybe
import           Data.Either
import           GHC.Exts

data D0 = C01 deriving (Eq,Ord,Show)
derive makeArbitrary ''D0
Q.deriveDSH ''D0

data D1 a = C11 a deriving (Eq,Ord,Show)
derive makeArbitrary ''D1
Q.deriveDSH ''D1

data D2 a b = C21 a b b a deriving (Eq,Ord,Show)
derive makeArbitrary ''D2
Q.deriveDSH ''D2

data D3 = C31 | C32 deriving (Eq,Ord,Show)
derive makeArbitrary ''D3
Q.deriveDSH ''D3

data D4 a = C41 a | C42 deriving (Eq,Ord,Show)
derive makeArbitrary ''D4
Q.deriveDSH ''D4

data D5 a = C51 a | C52 | C53 a a | C54 a a a deriving (Eq,Ord,Show)
derive makeArbitrary ''D5
Q.deriveDSH ''D5

data D6 a b c d e = C61 { c611 :: a, c612 :: (a,b,c,d) } | C62 | C63 a b | C64 (a,b,c) | C65 a b c d e deriving (Eq,Ord,Show)
derive makeArbitrary ''D6
Q.deriveDSH ''D6

tests_types :: Test
tests_types = testGroup "Supported Types"
  [ testProperty "()" $ prop_unit
  , testProperty "Bool" $ prop_bool
  , testProperty "Char" $ prop_char
  , testProperty "Text" $ prop_text
  , testProperty "Integer" $ prop_integer
  , testProperty "Double" $ prop_double
  , testProperty "[Integer]" $ prop_list_integer_1
  , testProperty "[[Integer]]" $ prop_list_integer_2
  , testProperty "[[[Integer]]]" $ prop_list_integer_3
  , testProperty "[(Integer, Integer)]" $ prop_list_tuple_integer
  , testProperty "([], [])" $ prop_tuple_list_integer
  , testProperty "Maybe Integer" $ prop_maybe_integer
  , testProperty "Either Integer Integer" $ prop_either_integer
  , testProperty "D0" $ prop_d0
  , testProperty "D1" $ prop_d1
  , testProperty "D2" $ prop_d2
  , testProperty "D3" $ prop_d3
  , testProperty "D4" $ prop_d4
  , testProperty "D5" $ prop_d5
  , testProperty "D6" $ prop_d6
  ]

tests_boolean :: Test
tests_boolean = testGroup "Equality, Boolean Logic and Ordering"
  [ testProperty "&&" $ prop_infix_and
  , testProperty "||" $ prop_infix_or
  , testProperty "not" $ prop_not
  , testProperty "eq" $ prop_eq
  , testProperty "neq" $ prop_neq
  , testProperty "cond" $ prop_cond
  , testProperty "cond tuples" $ prop_cond_tuples
  , testProperty "cond ([[Integer]], [[Integer]])" $ prop_cond_list_tuples
  , testProperty "lt" $ prop_lt
  , testProperty "lte" $ prop_lte
  , testProperty "gt" $ prop_gt
  , testProperty "gte" $ prop_gte
  , testProperty "min_integer" $ prop_min_integer
  , testProperty "min_double" $ prop_min_double
  , testProperty "max_integer" $ prop_max_integer
  , testProperty "max_double" $ prop_max_double
  ]

tests_tuples :: Test
tests_tuples = testGroup "Tuples"
  [ testProperty "fst" $ prop_fst
  , testProperty "snd" $ prop_snd
  ]

tests_numerics :: Test
tests_numerics = testGroup "Numerics"
  [ testProperty "add_integer" $ prop_add_integer
  , testProperty "add_double" $ prop_add_double
  , testProperty "mul_integer" $ prop_mul_integer
  , testProperty "mul_double" $ prop_mul_double
  , testProperty "div_double" $ prop_div_double
  , testProperty "integer_to_double" $ prop_integer_to_double
  , testProperty "integer_to_double_+" $ prop_integer_to_double_arith
  , testProperty "abs_integer" $ prop_abs_integer
  , testProperty "abs_double" $ prop_abs_double
  , testProperty "signum_integer" $ prop_signum_integer
  , testProperty "signum_double" $ prop_signum_double
  , testProperty "negate_integer" $ prop_negate_integer
  , testProperty "negate_double" $ prop_negate_double
  , testProperty "trig_sin" $ prop_trig_sin
  , testProperty "trig_cos" $ prop_trig_cos
  , testProperty "trig_tan" $ prop_trig_tan
  , testProperty "trig_asin" $ prop_trig_asin
  , testProperty "trig_acos" $ prop_trig_acos
  , testProperty "trig_atan" $ prop_trig_atan
  , testProperty "sqrt" $ prop_sqrt
  , testProperty "log" $ prop_log
  , testProperty "exp" $ prop_exp
  ]

tests_maybe :: Test
tests_maybe = testGroup "Maybe"
        [ testProperty "maybe" $ prop_maybe
        , testProperty "just" $ prop_just
        , testProperty "isJust" $ prop_isJust
        , testProperty "isNothing" $ prop_isNothing
        , testProperty "fromJust" $ prop_fromJust
        , testProperty "fromMaybe" $ prop_fromMaybe
        , testProperty "listToMaybe" $ prop_listToMaybe
        , testProperty "maybeToList" $ prop_maybeToList
        , testProperty "catMaybes" $ prop_catMaybes
        , testProperty "mapMaybe" $ prop_mapMaybe
        ]

tests_either :: Test
tests_either = testGroup "Either"
        [ testProperty "left" $ prop_left
        , testProperty "right" $ prop_right
        , testProperty "isLeft" $ prop_isLeft
        , testProperty "isRight" $ prop_isRight
        , testProperty "either" $ prop_either
        , testProperty "lefts" $ prop_lefts
        , testProperty "rights" $ prop_rights
        , testProperty "partitionEithers" $ prop_partitionEithers
        ]

tests_lists :: Test
tests_lists = testGroup "Lists"
        [ testProperty "head" $ prop_head
        , testProperty "tail" $ prop_tail
        , testProperty "cons" $ prop_cons
        , testProperty "snoc" $ prop_snoc
        , testProperty "take" $ prop_take
        , testProperty "drop" $ prop_drop
        , testProperty "take ++ drop" $ prop_takedrop
        , testProperty "map" $ prop_map
        , testProperty "filter" $ prop_filter
        , testProperty "the" $ prop_the
        , testProperty "last" $ prop_last
        , testProperty "init" $ prop_init
        , testProperty "null" $ prop_null
        , testProperty "length" $ prop_length
        , testProperty "length tuple list" $ prop_length_tuple
        , testProperty "index" $ prop_index
        , testProperty "index [[]]" $ prop_index_nest
        , testProperty "reverse" $ prop_reverse
        , testProperty "reverse [[]]" $ prop_reverse_nest
        , testProperty "append" $ prop_append
        , testProperty "append nest" $ prop_append_nest
        , testProperty "groupWith" $ prop_groupWith
        , testProperty "groupWithKey" $ prop_groupWithKey
        , testProperty "groupWith length" $ prop_groupWith_length
        , testProperty "groupWithKey length" $ prop_groupWithKey_length
        , testProperty "sortWith" $ prop_sortWith
        , testProperty "and" $ prop_and
        , testProperty "or" $ prop_or
        , testProperty "any_zero" $ prop_any_zero
        , testProperty "all_zero" $ prop_all_zero
        , testProperty "sum_integer" $ prop_sum_integer
        , testProperty "sum_double" $ prop_sum_double
        , testProperty "avg_integer" $ prop_avg_integer
        , testProperty "avg_double" $ prop_avg_double
        , testProperty "concat" $ prop_concat
        , testProperty "concatMap" $ prop_concatMap
        , testProperty "maximum" $ prop_maximum
        , testProperty "minimum" $ prop_minimum
        , testProperty "splitAt" $ prop_splitAt
        , testProperty "takeWhile" $ prop_takeWhile
        , testProperty "dropWhile" $ prop_dropWhile
        , testProperty "span" $ prop_span
        , testProperty "break" $ prop_break
        , testProperty "elem" $ prop_elem
        , testProperty "notElem" $ prop_notElem
        , testProperty "lookup" $ prop_lookup
        , testProperty "zip" $ prop_zip
        , testProperty "zip3" $ prop_zip3
        , testProperty "zipWith" $ prop_zipWith
        , testProperty "zipWith3" $ prop_zipWith3
        , testProperty "unzip" $ prop_unzip
        , testProperty "unzip3" $ prop_unzip3
        , testProperty "nub" $ prop_nub
        , testProperty "number" $ prop_number
        , testProperty "reshape" $ prop_reshape
        , testProperty "reshape2" $ prop_reshape2
        , testProperty "transpose" $ prop_transpose
        ]

tests_lifted :: Test
tests_lifted = testGroup "Lifted operations"
        [ testProperty "Lifted &&" $ prop_infix_map_and
        , testProperty "Lifted ||" $ prop_infix_map_or
        , testProperty "Lifted not" $ prop_map_not
        , testProperty "Lifted eq" $ prop_map_eq
        , testProperty "Lifted neq" $ prop_map_neq
        , testProperty "Lifted cond" $ prop_map_cond
        , testProperty "Lifted cond tuples" $ prop_map_cond_tuples
        , testProperty "Lifted cond + concat" $ prop_concatmapcond
        , testProperty "Lifted lt" $ prop_map_lt
        , testProperty "Lifted lte" $ prop_map_lte
        , testProperty "Lifted gt" $ prop_map_gt
        , testProperty "Lifted gte" $ prop_map_gte
        , testProperty "Lifted cons" $ prop_map_cons
        , testProperty "Lifted concat" $ prop_map_concat
        , testProperty "Lifted fst" $ prop_map_fst
        , testProperty "Lifted snd" $ prop_map_snd
        , testProperty "Lifted the" $ prop_map_the
        --, testProperty "Lifed and" $ prop_map_and
        , testProperty "map (map (*2))" $ prop_map_map_mul
        , testProperty "map (map (map (*2)))" $ prop_map_map_map_mul
        , testProperty "map (\\x -> map (\\y -> x + y) ..) .." $ prop_map_map_add
        , testProperty "Lifted groupWith" $ prop_map_groupWith
        , testProperty "Lifted groupWithKey" $ prop_map_groupWithKey
        , testProperty "Lifted sortWith" $ prop_map_sortWith
        , testProperty "Lifted sortWith length" $ prop_map_sortWith_length
        , testProperty "Lifted groupWithKey length" $ prop_map_groupWithKey_length
        , testProperty "Lifted length" $ prop_map_length
        , testProperty "Lifted length on [[(a,b)]]" $ prop_map_length_tuple
        , testProperty "Sortwith length nested" $ prop_sortWith_length_nest
        , testProperty "GroupWithKey length nested" $ prop_groupWithKey_length_nest
        , testProperty "Lift minimum" $ prop_map_minimum
        , testProperty "map (map minimum)" $ prop_map_map_minimum
        , testProperty "Lift maximum" $ prop_map_maximum
        , testProperty "map (map maximum)" $ prop_map_map_maximum
        , testProperty "map integer_to_double" $ prop_map_integer_to_double
        , testProperty "map tail" $ prop_map_tail
        , testProperty "map unzip" $ prop_map_unzip
        , testProperty "map reverse" $ prop_map_reverse
        , testProperty "map reverse [[]]" $ prop_map_reverse_nest
        , testProperty "map and" $ prop_map_and
        , testProperty "map (map and)" $ prop_map_map_and
        , testProperty "map sum" $ prop_map_sum
        , testProperty "map avg" $ prop_map_avg
        , testProperty "map (map sum)" $ prop_map_map_sum
        , testProperty "map or" $ prop_map_or
        , testProperty "map (map or)" $ prop_map_map_or
        , testProperty "map any zero" $ prop_map_any_zero
        , testProperty "map all zero" $ prop_map_all_zero
        , testProperty "map filter" $ prop_map_filter
        , testProperty "map append" $ prop_map_append
        , testProperty "map index" $ prop_map_index
        , testProperty "map index [[]]" $ prop_map_index_nest
        , testProperty "map init" $ prop_map_init
        , testProperty "map last" $ prop_map_last
        , testProperty "map null" $ prop_map_null
        , testProperty "map nub" $ prop_map_nub
        , testProperty "map snoc" $ prop_map_snoc
        , testProperty "map take" $ prop_map_take
        , testProperty "map drop" $ prop_map_drop
        , testProperty "map zip" $ prop_map_zip
        , testProperty "map takeWhile" $ prop_map_takeWhile
        , testProperty "map dropWhile" $ prop_map_dropWhile
        , testProperty "map span" $ prop_map_span
        , testProperty "map break" $ prop_map_break
        , testProperty "map number" $ prop_map_number
        , testProperty "map reshape" $ prop_map_reshape
        , testProperty "map reshape2" $ prop_map_reshape2
        -- , testProperty "map transpose" $ prop_map_transpose
        , testProperty "map sin" $ prop_map_trig_sin
        , testProperty "map cos" $ prop_map_trig_cos
        , testProperty "map tan" $ prop_map_trig_tan
        , testProperty "map asin" $ prop_map_trig_asin
        , testProperty "map acos" $ prop_map_trig_acos
        , testProperty "map atan" $ prop_map_trig_atan
        , testProperty "map log" $ prop_map_log
        , testProperty "map exp" $ prop_map_exp
        , testProperty "map sqrt" $ prop_map_sqrt
        ]

tests_combinators_hunit :: Test
tests_combinators_hunit = testGroup "HUnit combinators"
    [ testCase "hnegative_sum" hnegative_sum
    , testCase "hnegative_map_sum" hnegative_map_sum
    , testCase "hmap_transpose" hmap_transpose
    ]

-- * Supported Types

prop_unit :: () -> Property
prop_unit = makeProp id id

prop_bool :: Bool -> Property
prop_bool = makeProp id id

prop_integer :: Integer -> Property
prop_integer = makeProp id id

prop_double :: Double -> Property
prop_double = makePropDouble id id

prop_char :: Char -> Property
prop_char c = isPrint c ==> makeProp id id c

prop_text :: Text -> Property
prop_text t = Text.all isPrint t ==> makeProp id id t

prop_list_integer_1 :: [Integer] -> Property
prop_list_integer_1 = makeProp id id

prop_list_integer_2 :: [[Integer]] -> Property
prop_list_integer_2 = makeProp id id

prop_list_integer_3 :: [[[Integer]]] -> Property
prop_list_integer_3 = makeProp id id

prop_list_tuple_integer :: [(Integer, Integer)] -> Property
prop_list_tuple_integer = makeProp id id

prop_maybe_integer :: Maybe Integer -> Property
prop_maybe_integer = makeProp id id

prop_tuple_list_integer :: ([Integer], [Integer]) -> Property
prop_tuple_list_integer = makeProp id id

prop_either_integer :: Either Integer Integer -> Property
prop_either_integer = makeProp id id

prop_d0 :: D0 -> Property
prop_d0 = makeProp id id

prop_d1 :: D1 Integer -> Property
prop_d1 = makeProp id id

prop_d2 :: D2 Integer Integer -> Property
prop_d2 = makeProp id id

prop_d3 :: D3 -> Property
prop_d3 = makeProp id id

prop_d4 :: D4 Integer -> Property
prop_d4 = makeProp id id

prop_d5 :: D5 Integer -> Property
prop_d5 = makeProp id id

prop_d6 :: D6 Integer Integer Integer Integer Integer -> Property
prop_d6 = makeProp id id

-- * Equality, Boolean Logic and Ordering

prop_infix_and :: (Bool,Bool) -> Property
prop_infix_and = makeProp (uncurryQ (Q.&&)) (uncurry (&&))

prop_infix_map_and :: (Bool, [Bool]) -> Property
prop_infix_map_and = makeProp (\x -> Q.map ((Q.fst x) Q.&&) $ Q.snd x) (\(x,xs) -> map (x &&) xs)

prop_infix_or :: (Bool,Bool) -> Property
prop_infix_or = makeProp (uncurryQ (Q.||)) (uncurry (||))

prop_infix_map_or :: (Bool, [Bool]) -> Property
prop_infix_map_or = makeProp (\x -> Q.map ((Q.fst x) Q.||) $ Q.snd x) (\(x,xs) -> map (x ||) xs)

prop_not :: Bool -> Property
prop_not = makeProp Q.not not

prop_map_not :: [Bool] -> Property
prop_map_not = makeProp (Q.map Q.not) (map not)

prop_eq :: (Integer,Integer) -> Property
prop_eq = makeProp (uncurryQ (Q.==)) (uncurry (==))

prop_map_eq :: (Integer, [Integer]) -> Property
prop_map_eq = makeProp (\x -> Q.map ((Q.fst x) Q.==) $ Q.snd x) (\(x,xs) -> map (x ==) xs)

prop_neq :: (Integer,Integer) -> Property
prop_neq = makeProp (uncurryQ (Q./=)) (uncurry (/=))

prop_map_neq :: (Integer, [Integer]) -> Property
prop_map_neq = makeProp (\x -> Q.map ((Q.fst x) Q./=) $ Q.snd x) (\(x,xs) -> map (x /=) xs)

prop_cond :: Bool -> Property
prop_cond = makeProp (\b -> Q.cond b 0 1) (\b -> if b then (0 :: Integer) else 1)

prop_cond_tuples :: (Bool, (Integer, Integer)) -> Property
prop_cond_tuples = makeProp (\b -> Q.cond (Q.fst b) 
                                          (Q.pair (Q.fst $ Q.snd b) (Q.fst $ Q.snd b)) 
                                          (Q.pair (Q.snd $ Q.snd b) (Q.snd $ Q.snd b))) 
                            (\b -> if fst b 
                                   then (fst $ snd b, fst $ snd b) 
                                   else (snd $ snd b, snd $ snd b))

prop_cond_list_tuples :: (Bool, ([[Integer]], [[Integer]])) -> Property
prop_cond_list_tuples = makeProp (\b -> Q.cond (Q.fst b) 
                                               (Q.pair (Q.fst $ Q.snd b) (Q.fst $ Q.snd b)) 
                                               (Q.pair (Q.snd $ Q.snd b) (Q.snd $ Q.snd b))) 
                                 (\b -> if fst b 
                                        then (fst $ snd b, fst $ snd b) 
                                        else (snd $ snd b, snd $ snd b))

prop_map_cond :: [Bool] -> Property
prop_map_cond = makeProp (Q.map (\b -> Q.cond b (0 :: Q Integer) 1)) (map (\b -> if b then 0 else 1))

prop_map_cond_tuples :: [Bool] -> Property
prop_map_cond_tuples = makeProp (Q.map (\b -> Q.cond b 
                                                     (Q.toQ (0, 10) :: Q (Integer, Integer)) 
                                                     (Q.toQ (1, 11)))) 
                                (map (\b -> if b 
                                            then (0, 10) 
                                            else (1, 11)))

prop_concatmapcond :: [Integer] -> Property
prop_concatmapcond l1 =
        -- FIXME remove precondition as soon as X100 is fixed
    (not $ null l1)
    ==>
    makeProp q n l1
        where q l = Q.concatMap (\x -> Q.cond ((Q.>) x (Q.toQ 0)) (x Q.<| el) el) l
              n l = concatMap (\x -> if x > 0 then [x] else []) l
              el = Q.toQ []

prop_lt :: (Integer, Integer) -> Property
prop_lt = makeProp (uncurryQ (Q.<)) (uncurry (<))

prop_map_lt :: (Integer, [Integer]) -> Property
prop_map_lt = makeProp (\x -> Q.map ((Q.fst x) Q.<) $ Q.snd x) (\(x,xs) -> map (x <) xs)

prop_lte :: (Integer, Integer) -> Property
prop_lte = makeProp (uncurryQ (Q.<=)) (uncurry (<=))

prop_map_lte :: (Integer, [Integer]) -> Property
prop_map_lte = makeProp (\x -> Q.map ((Q.fst x) Q.<=) $ Q.snd x) (\(x,xs) -> map (x <=) xs)

prop_gt :: (Integer, Integer) -> Property
prop_gt = makeProp (uncurryQ (Q.>)) (uncurry (>))

prop_map_gt :: (Integer, [Integer]) -> Property
prop_map_gt = makeProp (\x -> Q.map ((Q.fst x) Q.>) $ Q.snd x) (\(x,xs) -> map (x >) xs)

prop_gte :: (Integer, Integer) -> Property
{'fraction_non_alphanumeric': 0.11158844961661864, 'fraction_numerical': 0.007830768394148676, 'mean_word_length': 3.0438702583837274, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 163, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 25, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3922516', 'n_tokens_mistral': 12457, 'n_tokens_neox': 12218, 'n_words': 3117}