on 00a2f7b help sign in
246 lines 8.2 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 qualified Streamly.Prelude as S
23#ifdef TEST_SMALL_ARRAY
24import qualified Streamly.Internal.Data.SmallArray as A
25type Array = A.SmallArray
26#elif defined(TEST_ARRAY)
27import Data.Word(Word8)
29import qualified Streamly.Internal.Data.Array.Storable.Foreign as A
30import qualified Streamly.Internal.Data.Array.Storable.Foreign.Types as A
31import qualified Streamly.Internal.Data.Stream.IsStream as IP
32import qualified Streamly.Internal.Memory.ArrayStream as AS
33type Array = A.Array
34#elif defined(DATA_ARRAY_PRIM_PINNED)
35import qualified Streamly.Internal.Data.Array.Prim.Pinned as A
36import qualified Streamly.Internal.Data.Array.Prim.Pinned.Types as A
37import qualified Streamly.Internal.Data.Stream.IsStream as IP
38type Array = A.Array
39#elif defined(DATA_ARRAY_PRIM)
40import qualified Streamly.Internal.Data.Array.Prim as A
41import qualified Streamly.Internal.Data.Array.Prim.Types as A
42import qualified Streamly.Internal.Data.Stream.IsStream as IP
43type Array = A.Array
44#else
45import qualified Streamly.Internal.Data.Array as A
46type Array = A.Array
47#endif
49-- Coverage build takes too long with default number of tests
50maxTestCount :: Int
51#ifdef DEVBUILD
52maxTestCount = 100
53#else
54maxTestCount = 10
55#endif
57allocOverhead :: Int
58allocOverhead = 2 * sizeOf (undefined :: Int)
60-- XXX this should be in sync with the defaultChunkSize in Array code, or we
61-- should expose that and use that. For fast testing we could reduce the
62-- defaultChunkSize under CPP conditionals.
63--
64defaultChunkSize :: Int
65defaultChunkSize = 32 * k - allocOverhead
66 where k = 1024
68maxArrLen :: Int
69maxArrLen = defaultChunkSize * 8
71genericTestFrom ::
72 (Int -> SerialT IO Int -> IO (Array Int))
73 -> Property
74genericTestFrom arrFold =
75 forAll (choose (0, maxArrLen)) $ \len ->
76 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
77 monadicIO $ do
78 arr <- run $ arrFold len $ S.fromList list
79 assert (A.length arr == len)
81testLength :: Property
82testLength = genericTestFrom (\n -> S.fold (A.writeN n))
84testLengthFromStreamN :: Property
85testLengthFromStreamN = genericTestFrom A.fromStreamN
87#ifndef TEST_SMALL_ARRAY
88testLengthFromStream :: Property
89testLengthFromStream = genericTestFrom (const A.fromStream)
90#endif
92genericTestFromTo ::
93 (Int -> SerialT IO Int -> IO (Array Int))
94 -> (Array Int -> SerialT IO Int)
95 -> ([Int] -> [Int] -> Bool)
96 -> Property
97genericTestFromTo arrFold arrUnfold listEq =
98 forAll (choose (0, maxArrLen)) $ \len ->
99 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
100 monadicIO $ do
101 arr <- run $ arrFold len $ S.fromList list
102 xs <- run $ S.toList $ arrUnfold arr
103 assert (listEq xs list)
105testFoldNUnfold :: Property
106testFoldNUnfold =
107 genericTestFromTo (\n -> S.fold (A.writeN n)) (S.unfold A.read) (==)
109testFoldNToStream :: Property
110testFoldNToStream =
111 genericTestFromTo (\n -> S.fold (A.writeN n)) A.toStream (==)
113testFoldNToStreamRev :: Property
114testFoldNToStreamRev =
115 genericTestFromTo
116 (\n -> S.fold (A.writeN n))
117 A.toStreamRev
118 (\xs list -> xs == reverse list)
120testFromStreamNUnfold :: Property
121testFromStreamNUnfold = genericTestFromTo A.fromStreamN (S.unfold A.read) (==)
123testFromStreamNToStream :: Property
124testFromStreamNToStream = genericTestFromTo A.fromStreamN A.toStream (==)
126testFromListN :: Property
127testFromListN =
128 forAll (choose (0, maxArrLen)) $ \len ->
129 forAll (choose (0, len)) $ \n ->
130 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
131 monadicIO $ do
132 let arr = A.fromListN n list
133 xs <- run $ S.toList $ (S.unfold A.read) arr
134 assert (xs == take n list)
136#ifndef TEST_SMALL_ARRAY
137testFromStreamToStream :: Property
138testFromStreamToStream = genericTestFromTo (const A.fromStream) A.toStream (==)
140testFoldUnfold :: Property
141testFoldUnfold = genericTestFromTo (const (S.fold A.write)) (S.unfold A.read) (==)
143testFromList :: Property
144testFromList =
145 forAll (choose (0, maxArrLen)) $ \len ->
146 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
147 monadicIO $ do
148 let arr = A.fromList list
149 xs <- run $ S.toList $ (S.unfold A.read) arr
150 assert (xs == list)
151#endif
153#if defined(TEST_ARRAY) ||\
154 defined(DATA_ARRAY_PRIM) ||\
155 defined(DATA_ARRAY_PRIM_PINNED)
157testArraysOf :: Property
158testArraysOf =
159 forAll (choose (0, maxArrLen)) $ \len ->
160 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
161 monadicIO $ do
162 xs <- run
163 $ S.toList
164 $ S.concatUnfold A.read
165 $ arraysOf 240
166 $ S.fromList list
167 assert (xs == list)
168 where
169 arraysOf n = IP.chunksOf n (A.writeNUnsafe n)
171#endif
173#ifdef TEST_ARRAY
175lastN :: Int -> [a] -> [a]
176lastN n l = drop (length l - n) l
178testLastN :: Property
179testLastN =
180 forAll (choose (0, maxArrLen)) $ \len ->
181 forAll (choose (0, len)) $ \n ->
182 forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
183 monadicIO $ do
184 xs <- run
185 $ fmap A.toList
186 $ S.fold (A.lastN n)
187 $ S.fromList list
188 assert (xs == lastN n list)
190testLastN_LN :: Int -> Int -> IO Bool
191testLastN_LN len n = do
192 let list = [1..len]
193 l1 <- fmap A.toList $ S.fold (A.lastN n) $ S.fromList list
194 let l2 = lastN n list
195 return $ l1 == l2
197-- Instead of hard coding 10000 here we can have maxStreamLength for operations
198-- that use stream of arrays.
199concatArrayW8 :: Property
200concatArrayW8 =
201 forAll (vectorOf 10000 (arbitrary :: Gen Word8))
202 $ \w8List -> do
203 let w8ArrList = A.fromList . (: []) <$> w8List
204 f2 <- S.toList $ AS.concat $ S.fromList w8ArrList
205 w8List `shouldBe` f2
207#endif
209main :: IO ()
210main =
211 hspec $
212 H.parallel $
213 modifyMaxSuccess (const maxTestCount) $ do
214 describe "Construction" $ do
215 prop "length . writeN n === n" testLength
216 prop "length . fromStreamN n === n" testLengthFromStreamN
217 prop "read . writeN === id " testFoldNUnfold
218 prop "toStream . writeN === id" testFoldNToStream
219 prop "toStreamRev . writeN === reverse" testFoldNToStreamRev
220 prop "read . fromStreamN === id" testFromStreamNUnfold
221 prop "toStream . fromStreamN === id" testFromStreamNToStream
222 prop "fromListN" testFromListN
224#ifndef TEST_SMALL_ARRAY
225 prop "length . fromStream === n" testLengthFromStream
226 prop "toStream . fromStream === id" testFromStreamToStream
227 prop "read . write === id" testFoldUnfold
228 prop "fromList" testFromList
229#endif
231#if defined(TEST_ARRAY) ||\
232 defined(DATA_ARRAY_PRIM) ||\
233 defined(DATA_ARRAY_PRIM_PINNED)
234 prop "arraysOf concats to original" testArraysOf
235#endif
237#ifdef TEST_ARRAY
238 prop "AS.concat . (A.fromList . (:[]) <$>) === id" $ concatArrayW8
239 describe "Fold" $ do
240 prop "lastN : 0 <= n <= len" $ testLastN
241 describe "lastN boundary conditions" $ do
242 it "lastN -1" (testLastN_LN 10 (-1) `shouldReturn` True)
243 it "lastN 0" (testLastN_LN 10 0 `shouldReturn` True)
244 it "lastN length" (testLastN_LN 10 10 `shouldReturn` True)
245 it "lastN (length + 1)" (testLastN_LN 10 11 `shouldReturn` True)
246#endif