integer-types-0.1.2.0: test/Integer/Gen.hs
module Integer.Gen
( GenIntegral (integral),
GenFinite (finite),
astronomical,
)
where
import Data.Int (Int)
import Data.Word (Word)
import Essentials
import Hedgehog qualified
import Hedgehog.Gen qualified as Gen
import Hedgehog.Range qualified as Range
import Integer
( BoundedBelow (..),
Integer,
Natural,
Positive,
Sign (..),
Signed (..),
)
import Prelude qualified as Bounded (Bounded (..))
import Prelude qualified as Num (Integral (..), Num (..), (+), (^))
---
class (Num.Integral a, Show a) => GenIntegral a where
-- | Generators for 'Integer', 'Natural', 'Positive',
-- or 'Signed' selected from one of three methods:
--
-- * small numbers (magnitude less than ten)
-- * large numbers (well in excess of 64-bit)
-- * numbers at or around a bound of 'Int' or 'Word'
integral :: Hedgehog.Gen a
instance GenIntegral Integer where integral = integer
instance GenIntegral Natural where integral = boundedBelow
instance GenIntegral Positive where integral = boundedBelow
instance GenIntegral Signed where integral = signed
---
class (Num.Integral a, Bounded.Bounded a, Show a) => GenFinite a where
finite :: Hedgehog.Gen a
instance GenFinite Int where finite = defaultFinite
instance GenFinite Word where finite = defaultFinite
defaultFinite :: (Num.Integral a, Bounded.Bounded a) => Hedgehog.Gen a
defaultFinite =
Gen.choice
[ Gen.integral $ Range.linear Bounded.minBound Bounded.maxBound,
Gen.integral $ Range.linear Bounded.maxBound Bounded.minBound
]
---
smol :: Num.Integral a => a
smol = 10
astronomical :: Num.Integral a => a
astronomical = 2 Num.^ (99 :: Integer)
bigRange :: Num.Integral a => Range.Range a
bigRange = Range.exponential smol astronomical
---
integer :: Hedgehog.Gen Integer
integer = Gen.choice [smolInteger, nearFiniteBoundInteger, bigInteger]
smolInteger :: Hedgehog.Gen Integer
smolInteger = Gen.integral $ Range.linearFrom 0 (Num.negate smol) smol
bigInteger :: Hedgehog.Gen Integer
bigInteger = Gen.element [id, Num.negate] <*> Gen.integral bigRange
nearFiniteBoundInteger :: Hedgehog.Gen Integer
nearFiniteBoundInteger = Gen.element [id, Num.negate] <*> nearPositiveFiniteBound
---
boundedBelow :: forall a. (BoundedBelow a, Num.Integral a) => Hedgehog.Gen a
boundedBelow = Gen.choice [smolBoundedBelow, nearPositiveFiniteBound, bigBoundedBelow]
smolBoundedBelow :: forall a. (BoundedBelow a, Num.Integral a) => Hedgehog.Gen a
smolBoundedBelow = fmap Num.fromInteger $ Gen.integral $ Range.linear (Num.toInteger $ minBound @a) smol
bigBoundedBelow :: forall a. (BoundedBelow a, Num.Integral a) => Hedgehog.Gen a
bigBoundedBelow = fmap Num.fromInteger $ Gen.integral bigRange
nearPositiveFiniteBound :: forall a. Num.Integral a => Hedgehog.Gen a
nearPositiveFiniteBound =
fmap Num.fromInteger $
pure (Num.+)
<*> Gen.element
[ Num.toInteger (Bounded.maxBound :: Int),
Num.toInteger (Bounded.maxBound :: Word)
]
<*> smolInteger
---
signed :: Hedgehog.Gen Signed
signed = Gen.choice [smolSigned, nearFiniteBoundSigned, bigSigned]
smolSigned :: Hedgehog.Gen Signed
smolSigned =
Gen.frequency
[ (,) 1 $ pure Zero,
(,) 9 $ pure NonZero <*> sign <*> smolBoundedBelow
]
bigSigned :: Hedgehog.Gen Signed
bigSigned = pure NonZero <*> sign <*> bigBoundedBelow
nearFiniteBoundSigned :: Hedgehog.Gen Signed
nearFiniteBoundSigned = pure NonZero <*> sign <*> nearPositiveFiniteBound
---
sign :: Hedgehog.Gen Sign
sign = Gen.element [PlusSign, MinusSign]