packages feed

nat-sized-numbers-0.1.0.0: test/Spec.hs

{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeFamilies          #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Main
  (main)
  where

import           Data.Function
import           Data.Int
import           Data.Proxy
import           Data.Word
import           GHC.TypeLits
import           Numeric.Natural
import           Numeric.Sized.IntOfSize
import           Numeric.Sized.WordOfSize
import           Test.DocTest
import           Test.QuickCheck          hiding (generate)
import qualified Test.SmallCheck          as SmallCheck
import           Test.SmallCheck.Series

instance KnownNat n =>
         Arbitrary (IntOfSize n) where
    arbitrary = arbitraryBoundedEnum

instance KnownNat n =>
         Arbitrary (WordOfSize n) where
    arbitrary = arbitraryBoundedEnum

instance (KnownNat n, Monad m) =>
         Serial m (IntOfSize n) where
    series = generate (`take` allIntsOfSize)

instance (KnownNat n, Monad m) =>
         Serial m (WordOfSize n) where
    series = generate (`take` allWordsOfSize)

type family IntType (n :: Nat) :: * where
        IntType 8  = Int8
        IntType 16 = Int16
        IntType 32 = Int32
        IntType 64 = Int64

type family WordType (n :: Nat) :: * where
        WordType 8  = Word8
        WordType 16 = Word16
        WordType 32 = Word32
        WordType 64 = Word64

sameConvAs
    :: (Integral n, Integral m, Integral i, Show i)
    => Proxy n -> Proxy m -> i -> Property
sameConvAs (_ :: Proxy n) (_ :: Proxy m) (x :: i) =
    ((fromIntegral :: n -> i) . (fromIntegral :: i -> n)) x ===
    ((fromIntegral :: m -> i) . (fromIntegral :: i -> m)) x

sameConvI
    :: (KnownNat n, Integral (IntType n))
    => Proxy n -> Integer -> Property
sameConvI (_ :: Proxy n) =
    sameConvAs (Proxy :: Proxy (IntOfSize n)) (Proxy :: Proxy (IntType n))

sameConvW
    :: (KnownNat n, Integral (WordType n))
    => Proxy n -> Natural -> Property
sameConvW (_ :: Proxy n) =
    sameConvAs (Proxy :: Proxy (WordOfSize n)) (Proxy :: Proxy (WordType n))

sameFncAs
    :: (Integral n, Integral m, Integral i, Show i)
    => (forall a. Integral a =>
                  a -> a -> a)
    -> Proxy n
    -> Proxy m
    -> i
    -> i
    -> Property
sameFncAs f (_ :: Proxy n) (_ :: Proxy m) (x :: i) (y :: i) =
    (fromIntegral :: n -> i) ((f `on` (fromIntegral :: i -> n)) x y) ===
    (fromIntegral :: m -> i) ((f `on` (fromIntegral :: i -> m)) x y)

sameFncI, sameFncINZRhs
    :: (KnownNat n, Integral (IntType n))
    => (forall a. Integral a =>
                  a -> a -> a)
    -> Proxy n
    -> Integer
    -> Integer
    -> Property
sameFncI f (_ :: Proxy n) =
    sameFncAs f (Proxy :: Proxy (IntOfSize n)) (Proxy :: Proxy (IntType n))

sameFncINZRhs f n x y = y /= 0 ==> sameFncI f n x y

sameFncW, sameFncWNZRhs
    :: (KnownNat n, Integral (WordType n))
    => (forall a. Integral a =>
                  a -> a -> a)
    -> Proxy n
    -> Natural
    -> Natural
    -> Property
sameFncW f (_ :: Proxy n) =
    sameFncAs f (Proxy :: Proxy (WordOfSize n)) (Proxy :: Proxy (WordType n))

sameFncWNZRhs f n x y = y /= 0 ==> sameFncW f n x y

sameFncAsS
    :: (Integral n, Integral m, Show n)
    => (forall a. Integral a =>
                  a -> a -> a)
    -> Proxy n
    -> Proxy m
    -> n
    -> n
    -> Either String String
sameFncAsS f (_ :: Proxy n) (_ :: Proxy m) x y =
    if (fromIntegral :: n -> m) (f x y) ==
       (f `on` (fromIntegral :: n -> m)) x y
        then Right ""
        else Left (show x ++ " " ++ show y)

sameFncWS
    :: (KnownNat n, Integral (WordType n))
    => (forall a. Integral a =>
                  a -> a -> a)
    -> Proxy n
    -> WordOfSize n
    -> WordOfSize n
    -> Either String String
sameFncWS f (_ :: Proxy n) =
    sameFncAsS f (Proxy :: Proxy (WordOfSize n)) (Proxy :: Proxy (WordType n))

sameFncWNZRhsS
    :: (KnownNat n, Integral (WordType n), Monad m)
    => (forall a. Integral a =>
                  a -> a -> a)
    -> Proxy n
    -> WordOfSize n
    -> WordOfSize n
    -> SmallCheck.Property m
sameFncWNZRhsS f n x y = y /= 0 SmallCheck.==> sameFncWS f n x y

sameFncIS
    :: (KnownNat n, Integral (IntType n))
    => (forall a. Integral a =>
                  a -> a -> a)
    -> Proxy n
    -> IntOfSize n
    -> IntOfSize n
    -> Either String String
sameFncIS f (_ :: Proxy n) =
    sameFncAsS f (Proxy :: Proxy (IntOfSize n)) (Proxy :: Proxy (IntType n))

sameFncINZRhsS
    :: (KnownNat n, Integral (IntType n), Monad m, Bounded (IntOfSize n))
    => (forall a. Integral a =>
                  a -> a -> a)
    -> Proxy n
    -> IntOfSize n
    -> IntOfSize n
    -> SmallCheck.Property m
sameFncINZRhsS f n x y =
    y /= 0 && (x /= minBound || y /= -1) SmallCheck.==> sameFncIS f n x y

testAll
    :: Testable a
    => (forall n. (KnownNat n, Integral (WordType n), Integral (IntType n)) =>
                  Proxy n -> a)
    -> IO ()
testAll prop = do
    quickCheck (prop (Proxy :: Proxy 8))
    quickCheck (prop (Proxy :: Proxy 16))
    quickCheck (prop (Proxy :: Proxy 32))
    quickCheck (prop (Proxy :: Proxy 64))

main :: IO ()
main = do
    testAll sameConvI
    testAll sameConvW
    testAll (sameFncI (+))
    testAll (sameFncW (+))
    testAll (sameFncI (*))
    testAll (sameFncW (*))
    testAll (sameFncI (-))
    testAll (sameFncW (-))
    testAll (sameFncINZRhs div)
    testAll (sameFncWNZRhs div)
    testAll (sameFncINZRhs mod)
    testAll (sameFncWNZRhs mod)
    testAll (sameFncINZRhs rem)
    testAll (sameFncWNZRhs rem)
    testAll (sameFncINZRhs quot)
    testAll (sameFncWNZRhs quot)
    SmallCheck.smallCheck 100000 (sameFncWS (+) (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncIS (+) (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncWS (*) (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncIS (*) (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncWS (-) (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncIS (-) (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncWNZRhsS div (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncINZRhsS div (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncWNZRhsS mod (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncINZRhsS mod (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncWNZRhsS rem (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncINZRhsS rem (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncWNZRhsS quot (Proxy :: Proxy 8))
    SmallCheck.smallCheck 100000 (sameFncINZRhsS quot (Proxy :: Proxy 8))
    doctest ["-isrc", "src/"]