packages feed

integer-types-0.1.4.0: test/Spec/Conversion.hs

module Spec.Conversion where

import Data.Ord qualified as Ord
import Essentials
import Integer
  ( BoundedBelow (..),
    Integer,
    IntegerConvert (..),
    IntegerEquiv,
    IntegerNarrow (..),
    Natural,
    Positive,
    Signed,
  )
import Integer.Gen (GenIntegral)
import Integer.Gen qualified as Gen
import Test.Hspec (Spec, context, it)
import Test.Hspec.Hedgehog
  ( PropertyT,
    evalMaybe,
    forAll,
    hedgehog,
    modifyMaxSuccess,
    (===),
  )

spec :: Spec
spec = do
  context "convert (convert x) = x" do
    it "A = Integer, B = Signed" $ hedgehog $ checkConvertConvert @Integer @Signed
    it "A = Signed,  B = Integer" $ hedgehog $ checkConvertConvert @Signed @Integer

  context "narrow (convert x) = Just x" do
    modifyMaxSuccess (\_ -> 1000) do
      it "A = Natural,  B = Integer" $ hedgehog $ checkNarrowConvert @Natural @Integer
      it "A = Natural,  B = Signed" $ hedgehog $ checkNarrowConvert @Natural @Signed
      it "A = Positive, B = Integer" $ hedgehog $ checkNarrowConvert @Positive @Integer
      it "A = Positive, B = Signed" $ hedgehog $ checkNarrowConvert @Positive @Signed
      it "A = Positive, B = Natural" $ hedgehog $ checkNarrowConvert @Positive @Natural

  context "narrow x = (Just y | convert y = x) or Nothing" do
    modifyMaxSuccess (\_ -> 1000) do
      it "A = Integer, B = Natural" $ hedgehog $ checkConvertNarrow @Integer @Natural
      it "A = Signed,  B = Natural" $ hedgehog $ checkConvertNarrow @Signed @Natural
      it "A = Integer, B = Positive" $ hedgehog $ checkConvertNarrow @Integer @Positive
      it "A = Signed,  B = Positive" $ hedgehog $ checkConvertNarrow @Signed @Positive
      it "A = Natural, B = Positive" $ hedgehog $ checkConvertNarrow @Natural @Positive

checkConvertConvert ::
  forall a b m.
  (GenIntegral a, IntegerEquiv a b) =>
  Monad m =>
  PropertyT m ()
checkConvertConvert = do
  x :: a <- forAll Gen.integral
  convert (convert x :: b) === x

checkNarrowConvert ::
  forall a b m.
  (GenIntegral a, IntegerConvert a b, IntegerNarrow b a) =>
  Monad m =>
  PropertyT m ()
checkNarrowConvert = do
  x :: a <- forAll Gen.integral
  narrow (convert x :: b) === Just x

checkConvertNarrow ::
  forall a b m.
  (GenIntegral a, BoundedBelow b) =>
  (IntegerConvert b a, IntegerNarrow a b) =>
  (Show b, Eq b) =>
  Monad m =>
  PropertyT m ()
checkConvertNarrow = do
  x :: a <- forAll Gen.integral
  let y :: Maybe b = narrow x
  if x Ord.>= convert (minBound @b)
    then do
      z <- evalMaybe y
      convert z === x
    else y === Nothing