massiv-0.3.0.0: tests/Data/Massiv/CoreArbitrary.hs
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Massiv.CoreArbitrary
( Arr(..)
, ArrTiny(..)
, ArrTiny1(..)
, ArrIx(..)
, ArrP(..)
, ArrS(..)
, ArrIxP(..)
, SzIx(..)
, SzNE(..)
, DimIx(..)
, toIx
, assertException
, assertSomeException
, assertExceptionIO
, assertSomeExceptionIO
, toStringException
, Semigroup((<>))
, applyFun2Compat
, module X
) where
import Control.DeepSeq (NFData, deepseq)
import UnliftIO.Exception (Exception, SomeException, catch, catchAny)
import Data.Foldable as F
import Data.Massiv.Array as X
import Data.Massiv.Core.IndexSpec hiding (spec)
import Data.Typeable
import Test.Hspec as X
import Test.QuickCheck as X hiding (resize)
import Test.QuickCheck.Function as X
import Test.QuickCheck.Monadic as X
#if !MIN_VERSION_base(4,11,0)
import Data.Semigroup
#endif
applyFun2Compat :: Fun (a, b) c -> (a -> b -> c)
#if MIN_VERSION_QuickCheck(2,10,0)
applyFun2Compat = applyFun2
#else
applyFun2Compat (Fun _ f) a b = f (a, b)
instance Function Word where
function = functionMap fromIntegral fromInteger
#endif
-- | Arbitrary non-empty array. Computation strategy can be either `Seq` or `Par`.
newtype Arr r ix e = Arr {unArr :: Array r ix e}
-- | Arbitrary small and possibly empty array. Computation strategy can be either `Seq` or `Par`.
newtype ArrTiny r ix e = ArrTiny {unArrTiny :: Array r ix e}
-- | Tiny but non-empty
newtype ArrTiny1 r ix e = ArrTiny1 {unArrTiny1 :: Array r ix e}
newtype ArrS r ix e = ArrS {unArrS :: Array r ix e}
newtype ArrP r ix e = ArrP {unArrP :: Array r ix e}
-- | Arbitrary non-empty array with a valid index. Can be either `Seq` or `Par`
data ArrIx r ix e = ArrIx (Array r ix e) ix
-- | Arbitrary non-empty array with a valid index and `Seq` computation strategy
data ArrIxS r ix e = ArrIxS (Array r ix e) ix
-- | Arbitrary non-empty array with a valid index and `Par` computation strategy
data ArrIxP r ix e = ArrIxP (Array r ix e) ix
deriving instance (Show (Array r ix e)) => Show (Arr r ix e)
deriving instance (Show (Array r ix e)) => Show (ArrTiny r ix e)
deriving instance (Show (Array r ix e)) => Show (ArrTiny1 r ix e)
deriving instance (Show (Array r ix e)) => Show (ArrS r ix e)
deriving instance (Show (Array r ix e)) => Show (ArrP r ix e)
deriving instance (Show (Array r ix e), Show ix) => Show (ArrIx r ix e)
deriving instance (Show (Array r ix e), Show ix) => Show (ArrIxS r ix e)
deriving instance (Show (Array r ix e), Show ix) => Show (ArrIxP r ix e)
instance Arbitrary Comp where
arbitrary = oneof [pure Seq, fmap ParOn arbitrary]
-- | Arbitrary array
instance (CoArbitrary ix, Arbitrary ix, Typeable e, Construct r ix e, Arbitrary e) =>
Arbitrary (Array r ix e) where
arbitrary = do
sz <- arbitrary
func <- arbitrary
comp <- oneof [pure Seq, pure Par]
return $ makeArray comp sz func
instance (CoArbitrary ix, Arbitrary ix, Typeable e, Construct r ix e, Arbitrary e) =>
Arbitrary (ArrTiny r ix e) where
arbitrary = do
sz <- unSz <$> arbitrary
func <- arbitrary
comp <- oneof [pure Seq, pure Par]
return $ ArrTiny $ makeArray comp (Sz (liftIndex (`mod` 10) sz)) func
-- | Arbitrary small and possibly empty array. Computation strategy can be either `Seq` or `Par`.
instance (CoArbitrary ix, Arbitrary ix, Typeable e, Construct r ix e, Arbitrary e) =>
Arbitrary (ArrTiny1 r ix e) where
arbitrary = do
sz <- unSz <$> arbitrary
func <- arbitrary
comp <- oneof [pure Seq, pure Par]
return $ ArrTiny1 $ makeArray comp (Sz (liftIndex (succ . (`mod` 10)) sz)) func
instance (CoArbitrary ix, Arbitrary ix, Typeable e, Construct r ix e, Arbitrary e) =>
Arbitrary (Arr r ix e) where
arbitrary = do
SzNE sz <- arbitrary
func <- arbitrary
comp <- oneof [pure Seq, pure Par]
return $ Arr $ makeArray comp sz func
-- | Arbitrary non-empty array
instance (CoArbitrary ix, Arbitrary ix, Typeable e, Construct r ix e, Arbitrary e) =>
Arbitrary (ArrS r ix e) where
arbitrary = do
SzNE sz <- arbitrary
ArrS . makeArray Seq sz <$> arbitrary
instance (CoArbitrary ix, Arbitrary ix, Typeable e, Construct r ix e, Arbitrary e) =>
Arbitrary (ArrP r ix e) where
arbitrary = do
Arr arr <- arbitrary
return $ ArrP (setComp Par arr)
instance (CoArbitrary ix, Arbitrary ix, Typeable e, Construct r ix e, Arbitrary e) =>
Arbitrary (ArrIx r ix e) where
arbitrary = do
SzIx sz ix <- arbitrary
func <- arbitrary
comp <- arbitrary
return $ ArrIx (makeArray comp sz func) ix
instance (CoArbitrary ix, Arbitrary ix, Typeable e, Construct r ix e, Arbitrary e) =>
Arbitrary (ArrIxS r ix e) where
arbitrary = do
SzIx sz ix <- arbitrary
func <- arbitrary
return $ ArrIxS (makeArray Seq sz func) ix
-- | Arbitrary non-empty array with a valid index
instance (CoArbitrary ix, Arbitrary ix, Typeable e, Construct r ix e, Arbitrary e) =>
Arbitrary (ArrIxP r ix e) where
arbitrary = do
ArrIx arrIx ix <- arbitrary
return $ ArrIxP (setComp Par arrIx) ix
toIx :: (Dimensions ix' ~ Dimensions ix, Index ix', Index ix) => ix -> ix'
toIx ix = F.foldl' setEachIndex zeroIndex [1.. dimensions (Sz ix)]
where setEachIndex ix' d = setDim' ix' d (getDim' ix d)
assertException :: (NFData a, Exception exc) =>
(exc -> Bool) -- ^ Return True if that is the exception that was expected
-> a -- ^ Value that should throw an exception, when fully evaluated
-> Property
assertException isExc = assertExceptionIO isExc . pure
assertSomeException :: NFData a => a -> Property
assertSomeException = assertSomeExceptionIO . pure
assertExceptionIO :: (NFData a, Exception exc) =>
(exc -> Bool) -- ^ Return True if that is the exception that was expected
-> IO a -- ^ IO Action that should throw an exception
-> Property
assertExceptionIO isExc action =
monadicIO $ do
assert =<<
run
(catch
(do res <- action
res `deepseq` return False)
(\exc -> displayException exc `deepseq` return (isExc exc)))
assertSomeExceptionIO :: NFData a => IO a -> Property
assertSomeExceptionIO action =
monadicIO $ do
assert =<<
run
(catchAny
(do res <- action
res `deepseq` return False)
(\exc -> displayException exc `deepseq` return True))
toStringException :: Either SomeException a -> Either String a
toStringException = either (Left . displayException) Right