2{-# LANGUAGE TemplateHaskell #-}
4-- Required for Eq instance declaration of HigherOrderType
5{-# LANGUAGE UndecidableInstances #-}
7-- We are generating an orphan instance of Serialize for Identity.
8{-# OPTIONS_GHC -fno-warn-orphans #-}
11-- Module : Streamly.Test.Data.Serialize
12-- Copyright : (c) 2022 Composewell technologies
13-- License : BSD-3-Clause
14-- Maintainer : streamly@composewell.com
15-- Stability : experimental
18module Streamly.Test.Data.Serialize (main) where
20--------------------------------------------------------------------------------
22--------------------------------------------------------------------------------
24import System.Random (randomRIO)
25import Streamly.Internal.Data.Serialize (MutByteArray, newByteArray)
26import GHC.Generics (Generic)
27import Streamly.Data.Serialize (Serialize)
28import Streamly.Test.Data.Serialize.TH (genDatatype)
30import Data.Functor.Identity (Identity (..))
32import qualified Streamly.Internal.Data.Array as Array
33import qualified Streamly.Internal.Data.Serialize as Serialize
35import qualified Streamly.Test.Data.Serialize.CompatV0 as CompatV0
36import qualified Streamly.Test.Data.Serialize.CompatV1 as CompatV1
38import Test.Hspec.QuickCheck
42--------------------------------------------------------------------------------
43-- Serialize configuration
44--------------------------------------------------------------------------------
46#ifdef ENABLE_constructorTagAsString
47#define CONF_NAME "ENABLE_constructorTagAsString"
48#define CONF (Serialize.encodeConstrNames True Serialize.serializeConfig)
50#define CONF_NAME "DEFAULT"
51#define CONF Serialize.serializeConfig
54--------------------------------------------------------------------------------
56--------------------------------------------------------------------------------
61$(Serialize.deriveSerializeWith CONF [d|instance Serialize Unit|])
66$(Serialize.deriveSerializeWith CONF [d|instance Serialize The|])
68--------------------------------------------------------------------------------
70--------------------------------------------------------------------------------
72$(genDatatype "CustomDatatype" 15)
73$(Serialize.deriveSerializeWith CONF [d|instance Serialize CustomDatatype|])
75--------------------------------------------------------------------------------
76-- Types with functional parameters
77--------------------------------------------------------------------------------
79data HigherOrderType f =
85instance (Eq (f Int), Eq (f Char)) => Eq (HigherOrderType f) where
86 (==) a b = (field0 a == field0 b) && (field1 a == field1 b)
88instance (Show (f Int), Show (f Char)) => Show (HigherOrderType f) where
89 show a = "HigherOrderType " ++ show (field0 a) ++ " " ++ show (field1 a)
91$(Serialize.deriveSerializeWith CONF
92 [d|instance Serialize a => Serialize (Identity a)|])
93$(Serialize.deriveSerializeWith CONF
94 [d|instance Serialize (HigherOrderType Identity)|])
96--------------------------------------------------------------------------------
98--------------------------------------------------------------------------------
102 = Tree (BinTree a) (BinTree a)
104 deriving (Show, Read, Eq, Generic)
106$(Serialize.deriveSerializeWith
108 [d|instance Serialize a => Serialize (BinTree a)|])
110instance Arbitrary a => Arbitrary (BinTree a) where
111 arbitrary = oneof [Leaf <$> arbitrary, Tree <$> arbitrary <*> arbitrary]
113--------------------------------------------------------------------------------
115--------------------------------------------------------------------------------
117upgradeRec :: (a -> b) -> CompatV0.Rec a -> CompatV1.Rec b
120 { CompatV1.initialField = CompatV0.initialField val
121 , CompatV1.otherField = f (CompatV0.otherField val)
122 , CompatV1.theLastField = CompatV0.theLastField val
123 , CompatV1.aNewField = Nothing
126upgradeRiver :: CompatV0.River -> CompatV1.River
127upgradeRiver = read . show
129downgradeRec :: (a -> b) -> CompatV1.Rec a -> CompatV0.Rec b
132 { CompatV0.initialField = CompatV1.initialField val
133 , CompatV0.otherField = f (CompatV1.otherField val)
134 , CompatV0.theLastField = CompatV1.theLastField val
137downgradeRiver :: CompatV1.River -> CompatV0.River
138downgradeRiver = read . show
141 CompatV0.Rec (CompatV0.Rec CompatV0.River)
142 -> CompatV1.Rec (CompatV1.Rec CompatV1.River)
144testCompatibility v0 v1 = do
145 let upgradedV0 = upgradeRec (upgradeRec upgradeRiver) v0
146 downgradedV1 = downgradeRec (downgradeRec downgradeRiver) v1
149 peekAndVerify res upgradedV0
152 peekAndVerify res1 downgradedV1
154--------------------------------------------------------------------------------
156--------------------------------------------------------------------------------
159 forall a. Serialize.Serialize a
161 -> IO (MutByteArray, Int, Int)
163 let sz = Serialize.size 0 val
166 randomOff <- randomRIO (10, excessSize)
167 -- Use a proper slice to test instead of the array directly. This will catch
168 -- any hardcoded 0 offsets
169 let arrSize = sz + excessSize
170 serStartOff = randomOff
171 serEndOff = randomOff + sz
172 arr <- newByteArray arrSize
174 off1 <- Serialize.serialize serStartOff arr val
175 off1 `shouldBe` serEndOff
176 pure (arr, serStartOff, serEndOff)
179 forall a. (Eq a, Show a, Serialize.Serialize a)
180 => (MutByteArray, Int, Int)
183peekAndVerify (arr, serStartOff, serEndOff) val = do
184 (off2, val2) <- Serialize.deserialize serStartOff arr serEndOff
186 off2 `shouldBe` serEndOff
187 let slice = Array.Array arr serStartOff serEndOff
188 val `shouldBe` Serialize.decode slice
189 clonedSlice <- Array.clone slice
190 val `shouldBe` Serialize.decode clonedSlice
193 :: forall a. (Eq a, Show a, Serialize.Serialize a)
198 val `shouldBe` Serialize.decode (Serialize.encode val)
201 peekAndVerify res val
204 :: forall a. (Eq a, Show a, Serialize.Serialize a)
208testSerializeList sizeOfA val = do
210 let sz = Serialize.size 0 val
212 sz `shouldBe` sizeOfA
216--------------------------------------------------------------------------------
218--------------------------------------------------------------------------------
224 $ testSerializeList (8 + 4 * 8) ([1, 2, 3, 4] :: [Int])
225 it "Serialize [[Int]]"
228 ([[1], [1, 2], [1, 2, 3]] :: [[Int]])
230 describe "Edge Cases" $ do
231 it "Unit" $ roundtrip Unit
232 it "The" $ roundtrip $ The Unit 1 'a'
235 $ roundtrip $ HigherOrderType (Identity 5) (Identity 'e')
238 $ \(x :: Integer) -> roundtrip x
240 prop "([Integer], [Int])"
241 $ \(x :: ([Integer], [Int])) -> roundtrip x
244 $ \(x :: [Int]) -> roundtrip (Array.fromList x)
246 prop "Compatible Record"
247 $ \(a :: CompatV1.Rec (CompatV0.Rec CompatV1.River)) -> roundtrip a
250 $ \a b -> testCompatibility a b
253 $ prop "CustomDatatype"
254 $ \(x :: CustomDatatype) -> roundtrip x
257 $ prop "[CustomDatatype]"
258 $ \(x :: [CustomDatatype]) -> roundtrip x
261 $ prop "BinTree" $ \(x :: BinTree Int) -> roundtrip x
265 limitQC = modifyMaxSize (const 50)
267--------------------------------------------------------------------------------
269--------------------------------------------------------------------------------
272moduleName = "Data.Serialize." ++ CONF_NAME
275main = hspec $ H.parallel $ describe moduleName testCases
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list