packages feed

streamly-0.10.0: test/Streamly/Test/Data/Unbox/TH.hs

{-# LANGUAGE TemplateHaskell #-}

-- |
-- Module      : Streamly.Test.Data.Unbox.TH
-- Copyright   : (c) 2022 Composewell technologies
-- License     : BSD-3-Clause
-- Maintainer  : streamly@composewell.com
-- Stability   : experimental
-- Portability : GHC

module Streamly.Test.Data.Unbox.TH (main) where

--------------------------------------------------------------------------------
-- Imports
--------------------------------------------------------------------------------

import Data.Proxy (Proxy(..))
import Streamly.Internal.Data.MutByteArray
import qualified Streamly.Internal.Data.MutByteArray as MBA

import Test.Hspec as H

--------------------------------------------------------------------------------
-- Test helpers
--------------------------------------------------------------------------------

testSerialization ::
       forall a. (Eq a, Show a, Unbox a)
    => a
    -> IO ()
testSerialization val = do
    arr <- MBA.new (sizeOf (Proxy :: Proxy a))
    pokeAt 0 arr val
    peekAt 0 arr `shouldReturn` val

-- Size is also implicitly tested while serializing and deserializing.
checkSizeOf :: forall a. Unbox a => Proxy a -> Int -> IO ()
checkSizeOf _ sz = sizeOf (Proxy :: Proxy a) `shouldBe` sz

checkSizeOfNew :: forall a. Unbox a => String -> Proxy a -> Int -> Spec
checkSizeOfNew tag proxy expectation =
    it ("checkSizeOf " ++ tag) $ checkSizeOf proxy expectation

data CustomDataType1 =
    CustomDataType1
    deriving (Show, Eq)

data CustomDataType2
    = CDT2Constructor1
    | CDT2Constructor2
    | CDT2Constructor3
    deriving (Show, Eq)

data CustomDataType3 a b c
    = CDT3Constructor1 a
    | CDT3Constructor2 a b
    | CDT3Constructor3 a b c
    deriving (Show, Eq)

data CustomDataType4 a b
    = CDT4Constructor1
    | CDT4Constructor2 Bool
    | CDT4Constructor3 Bool b
    deriving (Show, Eq)

$(deriveUnbox [d|instance Unbox CustomDataType1|])
$(deriveUnbox [d|instance Unbox CustomDataType2|])
$(deriveUnbox
    [d|instance (Unbox a, Unbox b, Unbox c) => Unbox (CustomDataType3 a b c)|])
$(deriveUnbox [d|instance Unbox b => Unbox (CustomDataType4 a b)|])

--------------------------------------------------------------------------------
-- CPP helpers
--------------------------------------------------------------------------------

#define CHECK_SIZE(type, expectation) \
 it "checkSizeOf type" $ checkSizeOf (Proxy :: Proxy type) expectation

--------------------------------------------------------------------------------
-- Tests
--------------------------------------------------------------------------------

testCustomDatatype1TH :: Spec
testCustomDatatype1TH = do
    it "CustomDataType1" $ testSerialization CustomDataType1

    CHECK_SIZE(CustomDataType1, 1)

testCustomDatatype2TH :: Spec
testCustomDatatype2TH = do
    it "CustomDataType2 1" $ testSerialization CDT2Constructor1
    it "CustomDataType2 2" $ testSerialization CDT2Constructor2
    it "CustomDataType2 3" $ testSerialization CDT2Constructor3

    CHECK_SIZE(CustomDataType2, 1)

testCustomDatatype3TH :: Spec
testCustomDatatype3TH = do
    it "CustomDataType3 1"
           $ testSerialization
                 (CDT3Constructor1 3 :: CustomDataType3 Int Bool Double)
    it "CustomDataType3 2"
           $ testSerialization
                 (CDT3Constructor2 3 False :: CustomDataType3 Int Bool Double)
    it "CustomDataType3 3"
           $ testSerialization (CDT3Constructor3 (3 :: Int) False (5 :: Double))

    checkSizeOfNew
        "CustomDataType3"
        (Proxy :: Proxy (CustomDataType3 Int Bool Double))
        (1 + sizeOf (Proxy :: Proxy Int)
           + sizeOf (Proxy :: Proxy Bool)
           + sizeOf (Proxy :: Proxy Double))

testCustomDatatype4TH :: Spec
testCustomDatatype4TH = do
    it "CustomDataType4 1"
           $ testSerialization (CDT4Constructor1 :: CustomDataType4 a Int)
    it "CustomDataType4 2"
           $ testSerialization
                 (CDT4Constructor2 True :: CustomDataType4 a Int)
    it "CustomDataType4 3"
           $ testSerialization (CDT4Constructor3 False (5 :: Int))

    checkSizeOfNew
        "CustomDataType4"
        (Proxy :: Proxy (CustomDataType4 a Int))
        (1 + sizeOf (Proxy :: Proxy Bool) + sizeOf (Proxy :: Proxy Int))

testCases :: Spec
testCases = do

    testCustomDatatype1TH
    testCustomDatatype2TH
    testCustomDatatype3TH
    testCustomDatatype4TH

--------------------------------------------------------------------------------
-- Main function
--------------------------------------------------------------------------------

moduleName :: String
moduleName = "Data.Unboxed.TH"

main :: IO ()
main = hspec $ H.parallel $ describe moduleName testCases