packages feed

lean-peano-1.0.0.0: test/Spec.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell     #-}
{-# LANGUAGE TypeApplications    #-}

import           Hedgehog
import           Hedgehog.Main
import qualified Hedgehog.Gen        as Gen
import qualified Hedgehog.Range      as Range

import           Numeric.Peano

import           Control.Monad
import           Data.Ix

binaryProp
    :: forall a.
       Integral a
    => (forall t. Integral t => t -> t -> t)
    -> Integer
    -> Integer
    -> (Integer -> Integer -> Bool)
    -> Property
binaryProp op lb ub cond = property $ do
    x <- forAll (Gen.integral (Range.linear lb ub))
    y <- forAll (Gen.integral (Range.linear lb ub))
    guard (cond x y)
    let zb = op x y
    let zt = op (fromInteger @a x) (fromInteger y)
    zb === toInteger zt

nats :: Gen Nat
nats = Gen.integral (Range.linear 0 1000)

holdsForLength :: Foldable f => (a -> Bool) -> f a -> Int
holdsForLength p = flip (foldr f id) 0 where
  f e a i | p e = a (i + 1)
          | otherwise = i

prop_Enum :: Property
prop_Enum = property $ do
    x <- forAll (Gen.integral (Range.linear 0 1000))
    annotate "from . to"
    (fromEnum @Nat . toEnum) x === x
    annotate "to . from"
    n <- forAll nats
    (toEnum . fromEnum) n === n
    annotate "[n..]"
    let lhs1 = take 100 $ map fromEnum [n..]
        rhs1 = take 100 [fromEnum n..]
        len1 = min (holdsForLength (>= 0) lhs1) (holdsForLength (>= 0) rhs1)
    take len1 lhs1 === take len1 rhs1
    annotate "[n,m..]"
    m <- forAll nats
    let lhs2 = take 100 $ map fromEnum [n,m..]
        rhs2 = take 100 [fromEnum n, fromEnum m..]
        len2 = min (holdsForLength (>= 0) lhs2) (holdsForLength (>= 0) rhs2)
    take len2 lhs2 === take len2 rhs2
    when (m >= n) $ do
        annotate "[n..m]"
        map fromEnum [n..m] === [fromEnum n..fromEnum m]
    l <- forAll nats
    when (((l > n) == (n > m)) && (l /= n)) $ do
        annotate "[l,n..m]"
        map fromEnum [l,n..m] === [fromEnum l, fromEnum n..fromEnum m]

prop_Add :: Property
prop_Add = binaryProp @Nat (+) 0 1000 (\_ _ -> True)

prop_Mul :: Property
prop_Mul = binaryProp @Nat (*) 0 1000 (\_ _ -> True)

prop_Sub :: Property
prop_Sub = withDiscards 1000 $ binaryProp @Nat (-) 0 1000 (>=)

prop_Rem :: Property
prop_Rem = binaryProp @Nat rem 0 1000 (\_ y -> y > 0)

prop_quot :: Property
prop_quot = binaryProp @Nat quot 0 1000 (\_ y -> y > 0)

prop_ord :: Property
prop_ord = property $ do
  x <- forAll nats
  y <- forAll nats
  annotate "<="
  (x <= y) === (fromEnum x <= fromEnum y)
  (x <= x) === True
  annotate "<"
  (x < y) === (fromEnum x < fromEnum y)
  (x < x) === False
  annotate ">="
  (x >= y) === (y <= x)
  annotate ">"
  (x > y) === (y < x)
  annotate "compare"
  compare x y === compare (fromEnum x) (fromEnum y)

prop_InRange :: Property
prop_InRange = property $ do
    l <- forAll (Gen.integral (Range.linear Z 100))
    u <- forAll (Gen.integral (Range.linear l (l+100)))
    i <- forAll (Gen.integral (Range.linear 0 300))
    inRange (l,u) i === (l <= i &&  i <= u)

prop_Index :: Property
prop_Index = property $ do
    l <- forAll (Gen.integral (Range.linear Z 100))
    u <- forAll (Gen.integral (Range.linear l (l+100)))
    i <- forAll (Gen.integral (Range.linear l u))
    unless (inRange (l,u) i) discard
    index (l,u) i === fromEnum (i - l)

main :: IO ()
main = defaultMain [checkParallel $$(discover)]