mirror of
https://github.com/composewell/streamly.git
synced 2024-09-11 19:47:10 +03:00
Add test cases for Data.Fold/Array, FileSystem.Handle
Added the following test cases to Data.Fold: drain, drainBy, mean, stdDev, variance, mconcat, foldMap, foldMapM, lookup, mapM, teeWithLength, teeWithMax, distribute, partition, unzip Added the following test cases to Data.Array.Storable.Foreign * fromList and fromListN Added FileSystem.Handle module
This commit is contained in:
parent
2e0a445514
commit
0bd1586175
@ -168,6 +168,7 @@ extra-source-files:
|
||||
test/Streamly/Test/Data/Array/Storable/Foreign.hs
|
||||
test/Streamly/Test/Data/Parser/ParserD.hs
|
||||
test/Streamly/Test/FileSystem/Event.hs
|
||||
test/Streamly/Test/FileSystem/Handle.hs
|
||||
test/Streamly/Test/Prelude.hs
|
||||
test/Streamly/Test/Prelude/*.hs
|
||||
test/Streamly/Test/Unicode/Stream.hs
|
||||
|
@ -16,12 +16,10 @@ import Foreign.Storable (Storable(..))
|
||||
import Test.Hspec.QuickCheck
|
||||
import Test.QuickCheck (Property, forAll, Gen, vectorOf, arbitrary, choose)
|
||||
import Test.QuickCheck.Monadic (monadicIO, assert, run)
|
||||
|
||||
import Test.Hspec as H
|
||||
|
||||
import Streamly.Prelude (SerialT)
|
||||
import qualified Streamly.Prelude as S
|
||||
|
||||
#ifdef TEST_SMALL_ARRAY
|
||||
import qualified Streamly.Internal.Data.SmallArray as A
|
||||
type Array = A.SmallArray
|
||||
@ -125,12 +123,31 @@ testFromStreamNUnfold = genericTestFromTo A.fromStreamN (S.unfold A.read) (==)
|
||||
testFromStreamNToStream :: Property
|
||||
testFromStreamNToStream = genericTestFromTo A.fromStreamN A.toStream (==)
|
||||
|
||||
testFromListN :: Property
|
||||
testFromListN =
|
||||
forAll (choose (0, maxArrLen)) $ \len ->
|
||||
forAll (choose (0, len)) $ \n ->
|
||||
forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
|
||||
monadicIO $ do
|
||||
let arr = A.fromListN n list
|
||||
xs <- run $ S.toList $ (S.unfold A.read) arr
|
||||
assert (xs == take n list)
|
||||
|
||||
#ifndef TEST_SMALL_ARRAY
|
||||
testFromStreamToStream :: Property
|
||||
testFromStreamToStream = genericTestFromTo (const A.fromStream) A.toStream (==)
|
||||
|
||||
testFoldUnfold :: Property
|
||||
testFoldUnfold = genericTestFromTo (const (S.fold A.write)) (S.unfold A.read) (==)
|
||||
|
||||
testFromList :: Property
|
||||
testFromList =
|
||||
forAll (choose (0, maxArrLen)) $ \len ->
|
||||
forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
|
||||
monadicIO $ do
|
||||
let arr = A.fromList list
|
||||
xs <- run $ S.toList $ (S.unfold A.read) arr
|
||||
assert (xs == list)
|
||||
#endif
|
||||
|
||||
#if defined(TEST_ARRAY) ||\
|
||||
@ -202,10 +219,13 @@ main =
|
||||
prop "toStreamRev . writeN === reverse" testFoldNToStreamRev
|
||||
prop "read . fromStreamN === id" testFromStreamNUnfold
|
||||
prop "toStream . fromStreamN === id" testFromStreamNToStream
|
||||
prop "First N elements of a list" testFromListN
|
||||
|
||||
#ifndef TEST_SMALL_ARRAY
|
||||
prop "length . fromStream === n" testLengthFromStream
|
||||
prop "toStream . fromStream === id" testFromStreamToStream
|
||||
prop "read . write === id" testFoldUnfold
|
||||
prop "From a list" testFromList
|
||||
#endif
|
||||
|
||||
#if defined(TEST_ARRAY) ||\
|
||||
|
@ -1,16 +1,31 @@
|
||||
module Main (main) where
|
||||
|
||||
import Prelude hiding
|
||||
(maximum, minimum, elem, notElem, null, product, sum, head, last)
|
||||
import Data.Semigroup (Sum(..), getSum)
|
||||
import Test.QuickCheck
|
||||
( Gen
|
||||
, Property
|
||||
, arbitrary
|
||||
, choose
|
||||
, forAll
|
||||
, listOf
|
||||
, listOf1
|
||||
, property
|
||||
, vectorOf
|
||||
, withMaxSuccess
|
||||
)
|
||||
import Prelude hiding
|
||||
(maximum, minimum, elem, notElem, null, product, sum, head, last)
|
||||
import Streamly.Test.Common (checkListEqual)
|
||||
import Prelude hiding (maximum, minimum, elem, notElem, null, product, sum, head, last)
|
||||
import Test.QuickCheck.Monadic (monadicIO, assert, run)
|
||||
|
||||
import qualified Streamly.Internal.Data.Fold as F
|
||||
import qualified Streamly.Prelude as S
|
||||
import qualified Streamly.Data.Fold as FL
|
||||
|
||||
import Test.Hspec as H
|
||||
import Test.Hspec.QuickCheck
|
||||
import Test.QuickCheck
|
||||
(Property, property, forAll, Gen, vectorOf, arbitrary, choose, listOf)
|
||||
import Test.QuickCheck.Monadic (monadicIO, assert, run)
|
||||
|
||||
maxStreamLen :: Int
|
||||
maxStreamLen = 1000
|
||||
@ -43,75 +58,75 @@ rollingHashFirstN =
|
||||
b <- run $ S.fold (F.rollingHashFirstN n) $ S.fromList vec
|
||||
assert $ a == b
|
||||
|
||||
|
||||
head :: [Int] -> Expectation
|
||||
head ls = S.fold FL.head (S.fromList ls) `shouldReturn` headl ls
|
||||
where
|
||||
headl [] = Nothing
|
||||
headl (x:_) = Just x
|
||||
|
||||
where
|
||||
|
||||
headl [] = Nothing
|
||||
headl (x:_) = Just x
|
||||
|
||||
length :: [Int] -> Expectation
|
||||
length ls = S.fold FL.length (S.fromList ls) `shouldReturn` Prelude.length ls
|
||||
|
||||
|
||||
sum :: [Int] -> Expectation
|
||||
sum ls = S.fold FL.sum (S.fromList ls) `shouldReturn` foldl (+) 0 ls
|
||||
|
||||
|
||||
product :: [Int] -> Expectation
|
||||
product ls = S.fold FL.product (S.fromList ls) `shouldReturn` foldl (*) 1 ls
|
||||
|
||||
|
||||
lesser :: (a -> a -> Ordering) -> a -> a -> a
|
||||
lesser f x y = if f x y == LT then x else y
|
||||
|
||||
|
||||
greater :: (a -> a -> Ordering) -> a -> a -> a
|
||||
greater f x y = if f x y == GT then x else y
|
||||
|
||||
|
||||
foldMaybe :: (b -> a -> b) -> b -> [a] -> Maybe b
|
||||
foldMaybe f acc ls =
|
||||
case ls of
|
||||
[] -> Nothing
|
||||
_ -> Just (foldl f acc ls)
|
||||
|
||||
case ls of
|
||||
[] -> Nothing
|
||||
_ -> Just (foldl f acc ls)
|
||||
|
||||
maximumBy :: (Ord a, Show a) => a -> (a -> a -> Ordering) -> [a] -> Expectation
|
||||
maximumBy genmin f ls = S.fold (FL.maximumBy f) (S.fromList ls) `shouldReturn` foldMaybe (greater f) genmin ls
|
||||
|
||||
maximumBy genmin f ls =
|
||||
S.fold (FL.maximumBy f) (S.fromList ls)
|
||||
`shouldReturn`
|
||||
foldMaybe (greater f) genmin ls
|
||||
|
||||
maximum :: (Show a, Ord a) => a -> [a] -> Expectation
|
||||
maximum genmin ls = S.fold FL.maximum (S.fromList ls) `shouldReturn` foldMaybe (greater compare) genmin ls
|
||||
|
||||
maximum genmin ls =
|
||||
S.fold FL.maximum (S.fromList ls)
|
||||
`shouldReturn` foldMaybe (greater compare) genmin ls
|
||||
|
||||
minimumBy :: (Ord a, Show a) => a -> (a -> a -> Ordering) -> [a] -> Expectation
|
||||
minimumBy genmax f ls = S.fold (FL.minimumBy f) (S.fromList ls) `shouldReturn` foldMaybe (lesser f) genmax ls
|
||||
|
||||
minimumBy genmax f ls =
|
||||
S.fold (FL.minimumBy f) (S.fromList ls)
|
||||
`shouldReturn` foldMaybe (lesser f) genmax ls
|
||||
|
||||
minimum :: (Show a, Ord a) => a -> [a] -> Expectation
|
||||
minimum genmax ls = S.fold FL.minimum (S.fromList ls) `shouldReturn` foldMaybe (lesser compare) genmax ls
|
||||
|
||||
minimum genmax ls =
|
||||
S.fold FL.minimum (S.fromList ls)
|
||||
`shouldReturn` foldMaybe (lesser compare) genmax ls
|
||||
|
||||
toList :: [Int] -> Expectation
|
||||
toList ls = S.fold FL.toList (S.fromList ls) `shouldReturn` ls
|
||||
|
||||
|
||||
safeLast :: [a] -> Maybe a
|
||||
safeLast [] = Nothing
|
||||
safeLast (x:[]) = Just x
|
||||
safeLast (_:xs) = safeLast xs
|
||||
|
||||
|
||||
last :: [String] -> Expectation
|
||||
last ls = S.fold FL.last (S.fromList ls) `shouldReturn` safeLast ls
|
||||
|
||||
mapMaybe :: [Int] -> Expectation
|
||||
mapMaybe ls =
|
||||
(let f = F.mapMaybe (\x -> if even x then Just x else Nothing) FL.toList
|
||||
in S.fold f (S.fromList ls))
|
||||
`shouldReturn` filter even ls
|
||||
let maybeEven x =
|
||||
if even x
|
||||
then Just x
|
||||
else Nothing
|
||||
f = F.mapMaybe maybeEven FL.toList
|
||||
in S.fold f (S.fromList ls) `shouldReturn` filter even ls
|
||||
|
||||
nth :: Int -> [a] -> Maybe a
|
||||
nth idx (x:xs) = if idx == 0
|
||||
@ -121,48 +136,52 @@ nth idx (x:xs) = if idx == 0
|
||||
else nth (idx - 1) xs
|
||||
nth _ [] = Nothing
|
||||
|
||||
|
||||
index :: Int -> [String] -> Expectation
|
||||
index idx ls = let x = S.fold (FL.index idx) (S.fromList ls)
|
||||
in x `shouldReturn` (nth idx ls)
|
||||
|
||||
|
||||
find :: (Show a, Eq a) => (a -> Bool) -> [a] -> Expectation
|
||||
find f ls = do
|
||||
let x = S.fold (FL.findIndex f) (S.fromList ls)
|
||||
y <- x
|
||||
case y of
|
||||
Nothing -> S.fold (FL.find f) (S.fromList ls) `shouldReturn` Nothing
|
||||
Just idx -> S.fold (FL.any f) (S.fromList $ take idx ls) `shouldReturn` False
|
||||
|
||||
y <- S.fold (FL.findIndex f) (S.fromList ls)
|
||||
case y of
|
||||
Nothing ->
|
||||
let fld = S.fold (FL.find f) (S.fromList ls)
|
||||
in fld `shouldReturn` Nothing
|
||||
Just idx ->
|
||||
let fld = S.fold (FL.any f) (S.fromList $ take idx ls)
|
||||
in fld `shouldReturn` False
|
||||
|
||||
neg :: (a -> Bool) -> a -> Bool
|
||||
neg f x = if f x == True then False else True
|
||||
|
||||
findIndex :: (a -> Bool) -> [a] -> Expectation
|
||||
findIndex f ls = do
|
||||
let x = S.fold (FL.findIndex f) (S.fromList ls)
|
||||
y <- x
|
||||
case y of
|
||||
Nothing -> S.fold (FL.all $ neg f) (S.fromList ls) `shouldReturn` True
|
||||
Just idx -> if idx == 0
|
||||
then S.fold (FL.all f) (S.fromList []) `shouldReturn` True
|
||||
else S.fold (FL.all f) (S.fromList $ (take idx ls)) `shouldReturn` False
|
||||
y <- S.fold (FL.findIndex f) (S.fromList ls)
|
||||
case y of
|
||||
Nothing ->
|
||||
let fld = S.fold (FL.all $ neg f) (S.fromList ls)
|
||||
in fld `shouldReturn` True
|
||||
Just idx -> if idx == 0
|
||||
then
|
||||
S.fold (FL.all f) (S.fromList []) `shouldReturn` True
|
||||
else
|
||||
S.fold (FL.all f) (S.fromList $ (take idx ls))
|
||||
`shouldReturn`
|
||||
False
|
||||
|
||||
predicate :: Int -> Bool
|
||||
predicate x = if x * x < 100 then True else False
|
||||
|
||||
elemIndex :: Int -> [Int] -> Expectation
|
||||
elemIndex elm ls = do
|
||||
let x = S.fold (FL.elemIndex elm) (S.fromList ls)
|
||||
y <- x
|
||||
case y of
|
||||
Nothing -> S.fold (FL.any (\z -> if z == elm
|
||||
then True
|
||||
else False)) (S.fromList ls) `shouldReturn` False
|
||||
Just idx -> S.fold (FL.any (\z -> if z == elm
|
||||
then True
|
||||
else False)) (S.fromList $ (take idx ls)) `shouldReturn` False
|
||||
y <- S.fold (FL.elemIndex elm) (S.fromList ls)
|
||||
case y of
|
||||
Nothing ->
|
||||
let fld = S.fold (FL.any (== elm)) (S.fromList ls)
|
||||
in fld `shouldReturn` False
|
||||
Just idx ->
|
||||
let fld = S.fold (FL.any (== elm)) (S.fromList $ (take idx ls))
|
||||
in fld `shouldReturn` False
|
||||
|
||||
null :: [Int] -> Expectation
|
||||
null ls = S.fold FL.null (S.fromList ls) `shouldReturn` case ls of
|
||||
@ -170,36 +189,26 @@ null ls = S.fold FL.null (S.fromList ls) `shouldReturn` case ls of
|
||||
_ -> False
|
||||
elem :: Int -> [Int] -> Expectation
|
||||
elem elm ls = do
|
||||
let x = S.fold (FL.elem elm) (S.fromList ls)
|
||||
y <- x
|
||||
S.fold (FL.any (\z -> if z == elm
|
||||
then True
|
||||
else False)) (S.fromList ls) `shouldReturn` y
|
||||
|
||||
y <- S.fold (FL.elem elm) (S.fromList ls)
|
||||
let fld = S.fold (FL.any (== elm)) (S.fromList ls)
|
||||
fld `shouldReturn` y
|
||||
|
||||
notElem :: Int -> [Int] -> Expectation
|
||||
notElem elm ls = do
|
||||
let x = S.fold (FL.notElem elm) (S.fromList ls)
|
||||
y <- x
|
||||
S.fold (FL.any (\z -> if z == elm
|
||||
then True
|
||||
else False)) (S.fromList ls) `shouldReturn` (if y == True
|
||||
then False
|
||||
else True)
|
||||
|
||||
y <- S.fold (FL.notElem elm) (S.fromList ls)
|
||||
let fld = S.fold (FL.any (== elm)) (S.fromList ls)
|
||||
fld `shouldReturn` not y
|
||||
|
||||
all :: (a -> Bool) -> [a] -> Expectation
|
||||
all f ls = S.fold (FL.all f) (S.fromList ls) `shouldReturn` Prelude.and (map f ls)
|
||||
|
||||
all f ls =
|
||||
S.fold (FL.all f) (S.fromList ls) `shouldReturn` Prelude.and (map f ls)
|
||||
|
||||
any :: (a -> Bool) -> [a] -> Expectation
|
||||
any f ls = S.fold (FL.any f) (S.fromList ls) `shouldReturn` Prelude.any f ls
|
||||
|
||||
|
||||
and :: [Bool] -> Expectation
|
||||
and ls = S.fold FL.and (S.fromList ls) `shouldReturn` Prelude.and ls
|
||||
|
||||
|
||||
or :: [Bool] -> Expectation
|
||||
or ls = S.fold FL.or (S.fromList ls) `shouldReturn` Prelude.or ls
|
||||
|
||||
@ -230,6 +239,181 @@ sliceSepByMax =
|
||||
Right xs -> checkListEqual xs ys
|
||||
Left _ -> property False
|
||||
|
||||
chooseFloat :: (Float, Float) -> Gen Float
|
||||
chooseFloat = choose
|
||||
|
||||
drain :: [Int] -> Expectation
|
||||
drain ls = S.fold FL.drain (S.fromList ls) `shouldReturn` ()
|
||||
|
||||
drainBy :: [Int] -> Expectation
|
||||
drainBy ls = S.fold (FL.drainBy return) (S.fromList ls) `shouldReturn` ()
|
||||
|
||||
mean :: Property
|
||||
mean =
|
||||
forAll (listOf1 (chooseFloat (-100.0, 100.0)))
|
||||
$ \ls0 -> withMaxSuccess 1000 $ monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
v1 <- run $ S.fold FL.mean (S.fromList ls)
|
||||
let v2 = (foldl (+) 0 ls) / fromIntegral (Prelude.length ls)
|
||||
assert (abs (v1 - v2) < 0.0001)
|
||||
|
||||
stdDev :: Property
|
||||
stdDev =
|
||||
forAll (listOf1 (chooseFloat (-100.0, 100.0)))
|
||||
$ \ls0 -> withMaxSuccess 1000 $ monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
v1 <- run $ S.fold FL.stdDev (S.fromList ls)
|
||||
let avg = (foldl (+) 0 ls) / fromIntegral (Prelude.length ls)
|
||||
se = (foldl (+) 0 (map (\x -> (x - avg) * (x - avg)) ls))
|
||||
sd = sqrt $ se / fromIntegral (Prelude.length ls)
|
||||
assert (abs (v1 - sd) < 0.0001 )
|
||||
|
||||
variance :: Property
|
||||
variance =
|
||||
forAll (listOf1 (chooseFloat (-100.0, 100.0)))
|
||||
$ \ls0 -> withMaxSuccess 1000 $ monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
v1 <- run $ S.fold FL.variance (S.fromList ls)
|
||||
let avg = (foldl (+) 0 ls) / fromIntegral (Prelude.length ls)
|
||||
se = (foldl (+) 0 (map (\x -> (x - avg) * (x - avg)) ls))
|
||||
vr = se / fromIntegral (Prelude.length ls)
|
||||
assert (abs (v1 - vr) < 0.01 )
|
||||
|
||||
mconcat :: Property
|
||||
mconcat =
|
||||
forAll (listOf1 (chooseInt (intMin, intMax)))
|
||||
$ \ls0 -> monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
v1 <- run $ S.fold FL.mconcat (S.map Sum $ S.fromList ls)
|
||||
let v2 = (foldl (+) 0 ls)
|
||||
assert (getSum v1 == v2)
|
||||
|
||||
foldMap :: Property
|
||||
foldMap =
|
||||
forAll (listOf1 (chooseInt (intMin, intMax)))
|
||||
$ \ls0 -> monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
v1 <- run $ S.fold (FL.foldMap Sum) $ S.fromList ls
|
||||
let v2 = (foldl (+) 0 ls)
|
||||
assert (getSum v1 == v2)
|
||||
|
||||
foldMapM :: Property
|
||||
foldMapM =
|
||||
forAll (listOf1 (chooseInt (intMin, intMax)))
|
||||
$ \ls0 -> monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
v1 <- run $ S.fold (FL.foldMapM (return . Sum)) $ S.fromList ls
|
||||
let v2 = (foldl (+) 0 ls)
|
||||
assert (getSum v1 == v2)
|
||||
|
||||
lookup :: Property
|
||||
lookup =
|
||||
forAll (chooseInt (1, 15))
|
||||
$ \key0 ->monadicIO $ action key0
|
||||
|
||||
where
|
||||
|
||||
action key = do
|
||||
let ls = [(1, "first"), (2, "second"), (3, "third"), (4, "fourth")
|
||||
, (5, "fifth"), (6, "fifth+first"), (7, "fifth+second")
|
||||
, (8, "fifth+third"), (9, "fifth+fourth")
|
||||
, (10, "fifth+fifth")]
|
||||
v1 <- run $ S.fold (FL.lookup key) $ S.fromList ls
|
||||
let v2 = Prelude.lookup key ls
|
||||
assert (v1 == v2)
|
||||
|
||||
mapM :: Property
|
||||
mapM =
|
||||
forAll (listOf1 (chooseInt (intMin, intMax)))
|
||||
$ \ls0 -> monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
let addLen x = return $ x + Prelude.length ls
|
||||
fld = FL.mapM addLen FL.sum
|
||||
v2 = foldl (+) (Prelude.length ls) ls
|
||||
v1 <- run $ S.fold fld $ S.fromList ls
|
||||
assert (v1 == v2)
|
||||
|
||||
teeWithLength :: Property
|
||||
teeWithLength =
|
||||
forAll (listOf1 (chooseInt (intMin, intMax)))
|
||||
$ \ls0 -> monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
v1 <- run $ S.fold (FL.tee FL.sum FL.length) $ S.fromList ls
|
||||
let v2 = foldl (+) 0 ls
|
||||
v3 = Prelude.length ls
|
||||
assert (v1 == (v2, v3))
|
||||
|
||||
teeWithMax :: Property
|
||||
teeWithMax =
|
||||
forAll (listOf1 (chooseInt (intMin, intMax)))
|
||||
$ \ls0 -> monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
v1 <- run $ S.fold (FL.tee FL.sum FL.maximum) $ S.fromList ls
|
||||
let v2 = foldl (+) 0 ls
|
||||
v3 = foldMaybe (greater compare) intMin ls
|
||||
assert (v1 == (v2, v3))
|
||||
|
||||
distribute :: Property
|
||||
distribute =
|
||||
forAll (listOf1 (chooseInt (intMin, intMax)))
|
||||
$ \ls0 -> monadicIO $ action ls0
|
||||
|
||||
where
|
||||
|
||||
action ls = do
|
||||
v1 <- run $ S.fold (FL.distribute [FL.sum, FL.length]) $ S.fromList ls
|
||||
let v2 = foldl (+) 0 ls
|
||||
v3 = Prelude.length ls
|
||||
assert (v1 == [v2, v3])
|
||||
|
||||
partition :: Property
|
||||
partition =
|
||||
monadicIO $ do
|
||||
v1 :: (Int, [String]) <-
|
||||
run
|
||||
$ S.fold (FL.partition FL.sum FL.toList)
|
||||
$ S.fromList
|
||||
[Left 1, Right "abc", Left 3, Right "xy", Right "pp2"]
|
||||
let v2 = (4,["abc","xy","pp2"])
|
||||
assert (v1 == v2)
|
||||
|
||||
unzip :: Property
|
||||
unzip =
|
||||
monadicIO $ do
|
||||
v1 :: (Int, [String]) <-
|
||||
run
|
||||
$ S.fold (FL.unzip FL.sum FL.toList)
|
||||
$ S.fromList [(1, "aa"), (2, "bb"), (3, "cc")]
|
||||
let v2 = (6, ["aa", "bb", "cc"])
|
||||
assert (v1 == v2)
|
||||
|
||||
main :: IO ()
|
||||
main = hspec $
|
||||
describe "Fold s" $ do
|
||||
@ -259,3 +443,18 @@ main = hspec $
|
||||
prop "ltake" ltake
|
||||
prop "sliceSepBy" sliceSepBy
|
||||
prop "sliceSepByMax" sliceSepByMax
|
||||
prop "drain" Main.drain
|
||||
prop "drainBy" Main.drainBy
|
||||
prop "mean" Main.mean
|
||||
prop "stdDev" Main.stdDev
|
||||
prop "variance" Main.variance
|
||||
prop "mconcat" Main.mconcat
|
||||
prop "foldMap" Main.foldMap
|
||||
prop "foldMapM" Main.foldMapM
|
||||
prop "lookup" Main.lookup
|
||||
prop "mapM" Main.mapM
|
||||
prop "teeWithLength" Main.teeWithLength
|
||||
prop "teeWithMax" Main.teeWithMax
|
||||
prop "distribute" Main.distribute
|
||||
prop "partition" Main.partition
|
||||
prop "unzip" Main.unzip
|
||||
|
165
test/Streamly/Test/FileSystem/Handle.hs
Normal file
165
test/Streamly/Test/FileSystem/Handle.hs
Normal file
@ -0,0 +1,165 @@
|
||||
-- |
|
||||
-- Module : Streamly.Test.FileSystem.Handle
|
||||
-- Copyright : (c) 2020 Composewell technologies
|
||||
-- License : BSD-3-Clause
|
||||
-- Maintainer : streamly@composewell.com
|
||||
-- Stability : experimental
|
||||
-- Portability : GHC
|
||||
|
||||
module Streamly.Test.FileSystem.Handle (main) where
|
||||
|
||||
import Data.Functor.Identity (runIdentity)
|
||||
import Data.Word (Word8)
|
||||
import Foreign.Storable (Storable(..))
|
||||
import Streamly.Internal.Data.Stream.IsStream (IsStream, SerialT)
|
||||
import System.FilePath ((</>))
|
||||
import System.IO
|
||||
( Handle
|
||||
, IOMode(..)
|
||||
, SeekMode(..)
|
||||
, hClose
|
||||
, hFlush
|
||||
, hSeek
|
||||
, openFile
|
||||
)
|
||||
import System.IO.Temp (withSystemTempDirectory)
|
||||
import Test.QuickCheck (Property, forAll, Gen, vectorOf, choose)
|
||||
import Test.QuickCheck.Monadic (monadicIO, assert, run)
|
||||
|
||||
import Streamly.FileSystem.Handle as FH
|
||||
import Test.Hspec as H
|
||||
import Test.Hspec.QuickCheck
|
||||
|
||||
import qualified Streamly.Data.Fold as FL
|
||||
import qualified Streamly.Internal.Data.Stream.IsStream as S
|
||||
import qualified Streamly.Internal.Data.Array.Storable.Foreign as A
|
||||
import qualified Streamly.Internal.Unicode.Stream as U
|
||||
|
||||
allocOverhead :: Int
|
||||
allocOverhead = 2 * sizeOf (undefined :: Int)
|
||||
|
||||
defaultChunkSize :: Int
|
||||
defaultChunkSize = 32 * k - allocOverhead
|
||||
where k = 1024
|
||||
|
||||
maxArrLen :: Int
|
||||
maxArrLen = defaultChunkSize * 8
|
||||
|
||||
maxTestCount :: Int
|
||||
maxTestCount = 10
|
||||
|
||||
chooseWord8 :: (Word8, Word8) -> Gen Word8
|
||||
chooseWord8 = choose
|
||||
|
||||
utf8ToString :: A.Array Word8 -> String
|
||||
utf8ToString = runIdentity . S.toList . U.decodeUtf8' . A.toStream
|
||||
|
||||
testData :: String
|
||||
testData = "This is the test data for FileSystem.Handle ??`!@#$%^&*~~))`]"
|
||||
|
||||
testDataLarge :: String
|
||||
testDataLarge = concat $ replicate 6000 testData
|
||||
|
||||
executor :: (Handle -> (SerialT IO Char)) -> IO (SerialT IO Char)
|
||||
executor f =
|
||||
withSystemTempDirectory "fs_handle" $ \fp -> do
|
||||
let fpath = fp </> "tmp_read.txt"
|
||||
writeFile fpath testDataLarge
|
||||
h <- openFile fpath ReadMode
|
||||
return $ f h
|
||||
|
||||
readFromHandle :: IO (SerialT IO Char)
|
||||
readFromHandle =
|
||||
let f = U.decodeUtf8 . S.unfold FH.read
|
||||
in executor f
|
||||
|
||||
readWithBufferFromHandle :: IO (SerialT IO Char)
|
||||
readWithBufferFromHandle =
|
||||
let f1 = (\h -> (1024, h))
|
||||
f2 = U.decodeUtf8 . S.unfold FH.readWithBufferOf . f1
|
||||
in executor f2
|
||||
|
||||
readChunksFromHandle :: IO (SerialT IO Char)
|
||||
readChunksFromHandle =
|
||||
let f = U.decodeUtf8 . S.concatMap (A.toStream) . S.unfold FH.readChunks
|
||||
in executor f
|
||||
|
||||
readChunksWithBuffer :: IO (SerialT IO Char)
|
||||
readChunksWithBuffer =
|
||||
let f1 = (\h -> (1024, h))
|
||||
f2 =
|
||||
U.decodeUtf8
|
||||
. S.concatMap (A.toStream)
|
||||
. S.unfold FH.readChunksWithBufferOf
|
||||
. f1
|
||||
in executor f2
|
||||
|
||||
testRead :: (IsStream t) => IO (t IO Char) -> Property
|
||||
testRead fn = monadicIO $ do
|
||||
let v2 = (S.fromList testDataLarge)
|
||||
v1 <- run $ fn
|
||||
res <- run $ S.eqBy (==) v1 v2
|
||||
assert (res)
|
||||
|
||||
testWrite :: (Handle -> FL.Fold IO Word8 ()) -> Property
|
||||
testWrite hfold =
|
||||
forAll (choose (0, maxArrLen)) $ \len ->
|
||||
forAll (vectorOf len $ chooseWord8 (0, 255)) $ \list0 ->
|
||||
monadicIO $ do
|
||||
res <- run $ go list0
|
||||
assert res
|
||||
|
||||
where
|
||||
|
||||
go list =
|
||||
withSystemTempDirectory "fs_handle" $ \fp -> do
|
||||
let fpathWrite = fp </> "tmp_write.txt"
|
||||
writeFile fpathWrite ""
|
||||
h <- openFile fpathWrite ReadWriteMode
|
||||
hSeek h AbsoluteSeek 0
|
||||
S.fold (hfold h) $ S.fromList list
|
||||
hFlush h
|
||||
hSeek h AbsoluteSeek 0
|
||||
ls <- S.toList $ S.unfold FH.read h
|
||||
hClose h
|
||||
return (ls == list)
|
||||
|
||||
testWriteWithChunk :: Property
|
||||
testWriteWithChunk =
|
||||
monadicIO $ do
|
||||
res <- run $ go
|
||||
assert res
|
||||
|
||||
where
|
||||
|
||||
go =
|
||||
withSystemTempDirectory "fs_handle" $ \fp -> do
|
||||
let fpathRead = fp </> "tmp_read.txt"
|
||||
fpathWrite = fp </> "tmp_write.txt"
|
||||
writeFile fpathRead testDataLarge
|
||||
writeFile fpathWrite ""
|
||||
hr <- openFile fpathRead ReadMode
|
||||
hw <- openFile fpathWrite ReadWriteMode
|
||||
hSeek hw AbsoluteSeek 0
|
||||
S.fold (FH.writeChunks hw)
|
||||
$ S.unfold FH.readChunksWithBufferOf (1024, hr)
|
||||
hFlush hw
|
||||
hSeek hw AbsoluteSeek 0
|
||||
ls <- S.toList $ S.unfold FH.read hw
|
||||
let arr = A.fromList ls
|
||||
return (testDataLarge == utf8ToString arr)
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
hspec $
|
||||
H.parallel $
|
||||
modifyMaxSuccess (const maxTestCount) $ do
|
||||
describe "Read" $ do
|
||||
prop "testRead" $ testRead readFromHandle
|
||||
prop "testReadWithBuffer" $ testRead readWithBufferFromHandle
|
||||
prop "testReadChunks" $ testRead readChunksFromHandle
|
||||
prop "testReadChunksWithBuffer" $ testRead readChunksWithBuffer
|
||||
describe "Write" $ do
|
||||
prop "testWrite" $ testWrite FH.write
|
||||
prop "testWriteWithBufferOf" $ testWrite $ FH.writeWithBufferOf 1024
|
||||
prop "testWriteWithChunk" $ testWriteWithChunk
|
@ -330,3 +330,9 @@ test-suite FileSystem.Event
|
||||
main-is: Streamly/Test/FileSystem/Event.hs
|
||||
if os(darwin)
|
||||
buildable: False
|
||||
|
||||
test-suite FileSystem.Handle
|
||||
import: test-options
|
||||
type: exitcode-stdio-1.0
|
||||
main-is: Streamly/Test/FileSystem/Handle.hs
|
||||
ghc-options: -main-is Streamly.Test.FileSystem.Handle.main
|
||||
|
Loading…
Reference in New Issue
Block a user