recover-rtti-0.6.1: tests/Test/RecoverRTTI/Prim.hs
{-# LANGUAGE CPP #-}
module Test.RecoverRTTI.Prim (
-- * Equality
canComparePrim
-- * Arbitrary
, Wrap(..)
, primSatisfiesArbitrary
, arbitraryPrimClassifier
) where
import Control.Monad (replicateM)
import Data.Aeson qualified as Aeson
import Data.ByteString qualified as BS.Strict
import Data.ByteString.Lazy qualified as BS.Lazy
import Data.Int
import Data.IntSet (IntSet)
import Data.Primitive.ByteArray qualified as Prim (ByteArray)
import Data.SOP (Compose)
import Data.SOP.Dict
import Data.String (fromString)
import Data.Text qualified as Text.Strict
import Data.Text.Lazy qualified as Text.Lazy
import Data.Vector qualified as Vector.Boxed
import Data.Vector.Primitive qualified as Vector.Primitive
import Data.Vector.Storable qualified as Vector.Storable
import Data.Word
import Unsafe.Coerce (unsafeCoerce)
#if MIN_VERSION_base(4,17,0)
import GHC.IsList qualified as IsList
#else
import GHC.Exts qualified as IsList (fromList)
#endif
#if !MIN_VERSION_bytestring(0,12,0)
import Data.ByteString.Short qualified as BS.Short
#endif
import Debug.RecoverRTTI
import Test.QuickCheck (Arbitrary(..), Gen)
import Test.QuickCheck qualified as QC
import Test.RecoverRTTI.Globals
import Test.RecoverRTTI.Orphans ()
{-------------------------------------------------------------------------------
Equality
-------------------------------------------------------------------------------}
canComparePrim :: PrimClassifier a -> Dict Eq a
canComparePrim = primSatisfies
{-------------------------------------------------------------------------------
Arbitrary support for the primitive types
-------------------------------------------------------------------------------}
primSatisfiesArbitrary :: PrimClassifier a -> Dict (Compose Arbitrary Wrap) a
primSatisfiesArbitrary = primSatisfies
arbitraryPrimClassifier :: Gen (Some PrimClassifier)
arbitraryPrimClassifier = QC.elements [
-- Primitive types
Some C_Bool
, Some C_Char
, Some C_Double
, Some C_Float
, Some C_Int
, Some C_Int16
, Some C_Int8
, Some C_Int32
, Some C_Int64
, Some C_Integer
, Some C_Ordering
, Some C_Unit
, Some C_Word
, Some C_Word8
, Some C_Word16
, Some C_Word32
, Some C_Word64
-- String types
, Some C_BS_Strict
, Some C_BS_Lazy
, Some C_Text_Strict
, Some C_Text_Lazy
#if !MIN_VERSION_bytestring(0,12,0)
, Some C_BS_Short
#endif
-- Aeson
, Some C_Value
-- Reference cells
, Some C_STRef
, Some C_TVar
, Some C_MVar
-- Functions
, Some C_Fun
-- Containers with no type arguments
, Some C_IntSet
, Some C_Prim_ArrayM
, Some C_Vector_Storable
, Some C_Vector_StorableM
, Some C_Vector_Primitive
, Some C_Vector_PrimitiveM
, Some C_ByteArray
, Some C_MutableByteArray
]
where
_checkAllCases :: PrimClassifier a -> ()
_checkAllCases = \case
-- Primitive types
C_Bool -> ()
C_Char -> ()
C_Double -> ()
C_Float -> ()
C_Int -> ()
C_Int16 -> ()
C_Int8 -> ()
C_Int32 -> ()
C_Int64 -> ()
C_Integer -> ()
C_Ordering -> ()
C_Unit -> ()
C_Word -> ()
C_Word8 -> ()
C_Word16 -> ()
C_Word32 -> ()
C_Word64 -> ()
-- String types
C_BS_Strict -> ()
C_BS_Lazy -> ()
C_Text_Strict -> ()
C_Text_Lazy -> ()
#if !MIN_VERSION_bytestring(0,12,0)
C_BS_Short -> ()
#endif
-- Aeson
C_Value -> ()
-- Reference cells
C_STRef -> ()
C_TVar -> ()
C_MVar -> ()
-- Functions
C_Fun -> ()
-- Containers with no type arguments
C_IntSet -> ()
C_Prim_ArrayM -> ()
C_Vector_Storable -> ()
C_Vector_StorableM -> ()
C_Vector_Primitive -> ()
C_Vector_PrimitiveM -> ()
C_ByteArray -> ()
C_MutableByteArray -> ()
{-------------------------------------------------------------------------------
Arbitrary instances for specific types
-------------------------------------------------------------------------------}
-- | 'Wrap' makes it possible to override an 'Arbitrary' instance if needed.
newtype Wrap a = Wrap { unwrap :: a }
deriving newtype instance Arbitrary (Wrap ())
deriving newtype instance Arbitrary (Wrap Bool)
deriving newtype instance Arbitrary (Wrap Char)
deriving newtype instance Arbitrary (Wrap Double)
deriving newtype instance Arbitrary (Wrap Float)
deriving newtype instance Arbitrary (Wrap Int)
deriving newtype instance Arbitrary (Wrap Int16)
deriving newtype instance Arbitrary (Wrap Int32)
deriving newtype instance Arbitrary (Wrap Int64)
deriving newtype instance Arbitrary (Wrap Int8)
deriving newtype instance Arbitrary (Wrap Integer)
deriving newtype instance Arbitrary (Wrap IntSet)
deriving newtype instance Arbitrary (Wrap Ordering)
deriving newtype instance Arbitrary (Wrap String)
deriving newtype instance Arbitrary (Wrap Word)
deriving newtype instance Arbitrary (Wrap Word16)
deriving newtype instance Arbitrary (Wrap Word32)
deriving newtype instance Arbitrary (Wrap Word64)
deriving newtype instance Arbitrary (Wrap Word8)
instance Arbitrary (Wrap BS.Strict.ByteString) where
arbitrary = Wrap . BS.Strict.pack <$> arbitrary
instance Arbitrary (Wrap BS.Lazy.ByteString) where
arbitrary = Wrap . BS.Lazy.pack <$> arbitrary
#if !MIN_VERSION_bytestring(0,12,0)
instance Arbitrary (Wrap BS.Short.ShortByteString) where
arbitrary = Wrap . BS.Short.pack <$> arbitrary
#endif
instance Arbitrary (Wrap Text.Strict.Text) where
arbitrary = Wrap . Text.Strict.pack <$> arbitrary
instance Arbitrary (Wrap Text.Lazy.Text) where
arbitrary = Wrap . Text.Lazy.pack <$> arbitrary
-- | aeson >= 2.0.3.0 does define an 'Arbitrary' instance for 'Aeson.Value',
-- but it generates values that are too big, which cause the size sanity check
-- on the generator 'prop_showGenerated' to start to fail.
instance Arbitrary (Wrap Aeson.Value) where
arbitrary = QC.choose (0, 10) >>= fmap Wrap . go
where
go :: Int -> Gen Aeson.Value
go 0 = QC.oneof nonRecursive
go sz = QC.oneof (nonRecursive ++ recursive sz)
nonRecursive :: [Gen Aeson.Value]
nonRecursive = [
Aeson.String . Text.Strict.pack <$> arbitrary
, Aeson.Number . fromInteger <$> arbitrary
, Aeson.Bool <$> arbitrary
, return Aeson.Null
]
recursive :: Int -> [Gen Aeson.Value]
recursive sz = [
do n <- QC.choose (0, 5)
Aeson.Array . Vector.Boxed.fromList <$> replicateM n (go (sz `div` n))
, do n <- QC.choose (0, 5)
Aeson.object <$> replicateM n (
(Aeson..=)
<$> (fromString <$> fieldName)
<*> go (sz `div` n)
)
]
-- We're not interested in testing crazy values
fieldName :: Gen String
fieldName = QC.elements ["a", "b", "c"]
-- | Rather than trying to be clever here, we just generate a handful of
-- examples in different categories.
instance Arbitrary (Wrap SomeFun) where
arbitrary = fmap Wrap $ QC.elements [
-- Parametrically polymorphic function
fun (id :: Int -> Int)
, fun (const :: Int -> Bool -> Int)
-- Ad-hoc polymorphic function
, fun (negate :: Int -> Int)
, fun ((+) :: Int -> Int -> Int)
-- Partial application
, fun (const 1 :: Bool -> Int)
, fun ((+) 1 :: Int -> Int)
]
where
fun :: (a -> b) -> SomeFun
fun = unsafeCoerce
instance Arbitrary (Wrap SomeStorableVector) where
arbitrary = fmap Wrap $ QC.elements [
some $ Vector.Storable.fromList ([1, 2, 3] :: [Int])
, some $ Vector.Storable.fromList ("abc" :: String)
]
where
some :: Vector.Storable.Vector a -> SomeStorableVector
some = unsafeCoerce
instance Arbitrary (Wrap SomePrimitiveVector) where
arbitrary = fmap Wrap $ QC.elements [
some $ Vector.Primitive.fromList ([1, 2, 3] :: [Int])
, some $ Vector.Primitive.fromList ("abc" :: String)
]
where
some :: Vector.Primitive.Vector a -> SomePrimitiveVector
some = unsafeCoerce
instance Arbitrary (Wrap Prim.ByteArray) where
arbitrary = Wrap . IsList.fromList <$> arbitrary
{-------------------------------------------------------------------------------
For the mutable variables, we just use the one global example
-------------------------------------------------------------------------------}
instance Arbitrary (Wrap SomeSTRef) where
arbitrary = return $ Wrap exampleSTRef
instance Arbitrary (Wrap SomeTVar) where
arbitrary = return $ Wrap exampleTVar
instance Arbitrary (Wrap SomeMVar) where
arbitrary = return $ Wrap exampleMVar
instance Arbitrary (Wrap SomePrimArrayM) where
arbitrary = return $ Wrap examplePrimArrayM
instance Arbitrary (Wrap SomeStorableVectorM) where
arbitrary = return $ Wrap exampleStorableVectorM
instance Arbitrary (Wrap SomePrimitiveVectorM) where
arbitrary = return $ Wrap examplePrimitiveVectorM
instance Arbitrary (Wrap SomeMutableByteArray) where
arbitrary = return $ Wrap exampleMutableByteArray