on da62ada help sign in
248 lines 8.3 kB history raw
1-- |
2-- Module : Main
3-- Copyright : (c) 2019 Composewell Technologies
4--
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
8-- Portability : GHC
9--
11-- This is a common array test module that gets included in different
12-- Array test modules with the corresponding macro defined.
14import Foreign.Storable (Storable(..))
16import Test.Hspec.QuickCheck
17import Test.QuickCheck (Property, forAll, Gen, vectorOf, arbitrary, choose)
18import Test.QuickCheck.Monadic (monadicIO, assert, run)
19import Test.Hspec as H
21import Streamly.Prelude (SerialT)
22import Streamly.Test.Common (listEquals)
24import qualified Streamly.Prelude as S
25#ifdef TEST_SMALL_ARRAY
26import qualified Streamly.Internal.Data.SmallArray as A
27type Array = A.SmallArray
28#elif defined(TEST_ARRAY)
29import Data.Word(Word8)
31import qualified Streamly.Internal.Data.Array.Storable.Foreign as A
32import qualified Streamly.Internal.Data.Array.Storable.Foreign.Types as A
33import qualified Streamly.Internal.Data.Stream.IsStream as IP
34import qualified Streamly.Internal.Memory.ArrayStream as AS
35type Array = A.Array
36#elif defined(DATA_ARRAY_PRIM_PINNED)
37import qualified Streamly.Internal.Data.Array.Prim.Pinned as A
38import qualified Streamly.Internal.Data.Array.Prim.Pinned.Types as A
39import qualified Streamly.Internal.Data.Stream.IsStream as IP
40type Array = A.Array
41#elif defined(DATA_ARRAY_PRIM)
42import qualified Streamly.Internal.Data.Array.Prim as A
43import qualified Streamly.Internal.Data.Array.Prim.Types as A
44import qualified Streamly.Internal.Data.Stream.IsStream as IP
45type Array = A.Array
46#else
47import qualified Streamly.Internal.Data.Array as A
48type Array = A.Array
49#endif
51-- Coverage build takes too long with default number of tests
52maxTestCount :: Int
53#ifdef DEVBUILD
54maxTestCount = 100
55#else
56maxTestCount = 10
57#endif
59allocOverhead :: Int
60allocOverhead = 2 * sizeOf (undefined :: Int)
62-- XXX this should be in sync with the defaultChunkSize in Array code, or we
63-- should expose that and use that. For fast testing we could reduce the
64-- defaultChunkSize under CPP conditionals.
65--
66defaultChunkSize :: Int
67defaultChunkSize = 32 * k - allocOverhead
68 where k = 1024
70maxArrLen :: Int
71maxArrLen = defaultChunkSize * 8
73genericTestFrom ::
74 (Int -> SerialT IO Int -> IO (Array Int))
75 -> Property
76genericTestFrom arrFold =
77 forAll (choose (0, maxArrLen)) $ \len ->
78 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
79 monadicIO $ do
80 arr <- run $ arrFold len $ S.fromList list
81 assert (A.length arr == len)
83testLength :: Property
84testLength = genericTestFrom (\n -> S.fold (A.writeN n))
86testLengthFromStreamN :: Property
87testLengthFromStreamN = genericTestFrom A.fromStreamN
89#ifndef TEST_SMALL_ARRAY
90testLengthFromStream :: Property
91testLengthFromStream = genericTestFrom (const A.fromStream)
92#endif
94genericTestFromTo ::
95 (Int -> SerialT IO Int -> IO (Array Int))
96 -> (Array Int -> SerialT IO Int)
97 -> ([Int] -> [Int] -> Bool)
98 -> Property
99genericTestFromTo arrFold arrUnfold listEq =
100 forAll (choose (0, maxArrLen)) $ \len ->
101 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
102 monadicIO $ do
103 arr <- run $ arrFold len $ S.fromList list
104 xs <- run $ S.toList $ arrUnfold arr
105 assert (listEq xs list)
107testFoldNUnfold :: Property
108testFoldNUnfold =
109 genericTestFromTo (\n -> S.fold (A.writeN n)) (S.unfold A.read) (==)
111testFoldNToStream :: Property
112testFoldNToStream =
113 genericTestFromTo (\n -> S.fold (A.writeN n)) A.toStream (==)
115testFoldNToStreamRev :: Property
116testFoldNToStreamRev =
117 genericTestFromTo
118 (\n -> S.fold (A.writeN n))
119 A.toStreamRev
120 (\xs list -> xs == reverse list)
122testFromStreamNUnfold :: Property
123testFromStreamNUnfold = genericTestFromTo A.fromStreamN (S.unfold A.read) (==)
125testFromStreamNToStream :: Property
126testFromStreamNToStream = genericTestFromTo A.fromStreamN A.toStream (==)
128testFromListN :: Property
129testFromListN =
130 forAll (choose (0, maxArrLen)) $ \len ->
131 forAll (choose (0, len)) $ \n ->
132 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
133 monadicIO $ do
134 let arr = A.fromListN n list
135 xs <- run $ S.toList $ (S.unfold A.read) arr
136 listEquals (==) xs (take n list)
138#ifndef TEST_SMALL_ARRAY
139testFromStreamToStream :: Property
140testFromStreamToStream = genericTestFromTo (const A.fromStream) A.toStream (==)
142testFoldUnfold :: Property
143testFoldUnfold = genericTestFromTo (const (S.fold A.write)) (S.unfold A.read) (==)
145testFromList :: Property
146testFromList =
147 forAll (choose (0, maxArrLen)) $ \len ->
148 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
149 monadicIO $ do
150 let arr = A.fromList list
151 xs <- run $ S.toList $ (S.unfold A.read) arr
152 assert (xs == list)
153#endif
155#if defined(TEST_ARRAY) ||\
156 defined(DATA_ARRAY_PRIM) ||\
157 defined(DATA_ARRAY_PRIM_PINNED)
159testArraysOf :: Property
160testArraysOf =
161 forAll (choose (0, maxArrLen)) $ \len ->
162 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
163 monadicIO $ do
164 xs <- run
165 $ S.toList
166 $ S.concatUnfold A.read
167 $ arraysOf 240
168 $ S.fromList list
169 assert (xs == list)
170 where
171 arraysOf n = IP.chunksOf n (A.writeNUnsafe n)
173#endif
175#ifdef TEST_ARRAY
177lastN :: Int -> [a] -> [a]
178lastN n l = drop (length l - n) l
180testLastN :: Property
181testLastN =
182 forAll (choose (0, maxArrLen)) $ \len ->
183 forAll (choose (0, len)) $ \n ->
184 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
185 monadicIO $ do
186 xs <- run
187 $ fmap A.toList
188 $ S.fold (A.lastN n)
189 $ S.fromList list
190 assert (xs == lastN n list)
192testLastN_LN :: Int -> Int -> IO Bool
193testLastN_LN len n = do
194 let list = [1..len]
195 l1 <- fmap A.toList $ S.fold (A.lastN n) $ S.fromList list
196 let l2 = lastN n list
197 return $ l1 == l2
199-- Instead of hard coding 10000 here we can have maxStreamLength for operations
200-- that use stream of arrays.
201concatArrayW8 :: Property
202concatArrayW8 =
203 forAll (vectorOf 10000 (arbitrary :: Gen Word8))
204 $ \w8List -> do
205 let w8ArrList = A.fromList . (: []) <$> w8List
206 f2 <- S.toList $ AS.concat $ S.fromList w8ArrList
207 w8List `shouldBe` f2
209#endif
211main :: IO ()
212main =
213 hspec $
214 H.parallel $
215 modifyMaxSuccess (const maxTestCount) $ do
216 describe "Construction" $ do
217 prop "length . writeN n === n" testLength
218 prop "length . fromStreamN n === n" testLengthFromStreamN
219 prop "read . writeN === id " testFoldNUnfold
220 prop "toStream . writeN === id" testFoldNToStream
221 prop "toStreamRev . writeN === reverse" testFoldNToStreamRev
222 prop "read . fromStreamN === id" testFromStreamNUnfold
223 prop "toStream . fromStreamN === id" testFromStreamNToStream
224 prop "fromListN" testFromListN
226#ifndef TEST_SMALL_ARRAY
227 prop "length . fromStream === n" testLengthFromStream
228 prop "toStream . fromStream === id" testFromStreamToStream
229 prop "read . write === id" testFoldUnfold
230 prop "fromList" testFromList
231#endif
233#if defined(TEST_ARRAY) ||\
234 defined(DATA_ARRAY_PRIM) ||\
235 defined(DATA_ARRAY_PRIM_PINNED)
236 prop "arraysOf concats to original" testArraysOf
237#endif
239#ifdef TEST_ARRAY
240 prop "AS.concat . (A.fromList . (:[]) <$>) === id" $ concatArrayW8
241 describe "Fold" $ do
242 prop "lastN : 0 <= n <= len" $ testLastN
243 describe "lastN boundary conditions" $ do
244 it "lastN -1" (testLastN_LN 10 (-1) `shouldReturn` True)
245 it "lastN 0" (testLastN_LN 10 0 `shouldReturn` True)
246 it "lastN length" (testLastN_LN 10 10 `shouldReturn` True)
247 it "lastN (length + 1)" (testLastN_LN 10 11 `shouldReturn` True)
248#endif