{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Crypto.Lol.Utils.Tests
(nestGroup
,testIOWithGen
,testIOWithoutGen
,testWithGen
,testWithoutGen
,ApproxEqual(..)
,QCG.choose
,QCG.chooseAny
,TF.testGroup
,QC.Gen
,TF.Test) where
import Crypto.Lol.Prelude (Complex, Int64, imag, real)
import Crypto.Lol.Types.Unsafe.ZqBasic
import qualified Test.Framework as TF
import qualified Test.Framework.Providers.QuickCheck2 as QC2
import qualified Test.QuickCheck as QC
import qualified Test.QuickCheck.Gen as QCG
import qualified Test.QuickCheck.Monadic as QCM
approxEqualEpsilon :: Double
approxEqualEpsilon = 1e-6
class ApproxEqual a where
(=~=) :: a -> a -> Bool
instance ApproxEqual Int64 where
x =~= y = x == y
instance Eq r => ApproxEqual (ZqBasic q r) where
x =~= y = x == y
instance ApproxEqual Double where
x =~= y
| x == 0 = abs y < approxEqualEpsilon
| y == 0 = abs x < approxEqualEpsilon
| isNaN x || isNaN y = False
| otherwise = let minDist = minimum $ map (\r -> abs $ abs r - 1) [x/y, y/x] in
minDist < approxEqualEpsilon
instance ApproxEqual (Complex Double) where
x =~= y = (real x =~= real y) && (imag x =~= imag y)
testWithGen :: (Show a, QC.Testable prop) => String -> (a -> prop) -> QC.Gen a -> TF.Test
testWithGen name f gen = QC2.testProperty name $ QC.forAll gen f
testIOWithGen :: (Show a, QC.Testable prop) => String -> (a -> IO prop) -> QC.Gen a -> TF.Test
testIOWithGen name f gen = QC2.testProperty name $ QCM.monadicIO $ QCM.forAllM gen (QCM.run . f)
testWithoutGen :: (QC.Testable prop) => String -> prop -> TF.Test
testWithoutGen name p = QC2.testProperty name $ QC.property p
testIOWithoutGen :: (QC.Testable prop) => String -> IO prop -> TF.Test
testIOWithoutGen name p = QC2.testProperty name $ QCM.monadicIO $ QCM.run p
nestGroup :: String -> [QC.Gen a -> TF.Test] -> QC.Gen a -> TF.Test
nestGroup name ts gen = TF.testGroup name $ map ($ gen) ts