packages feed

streamly-0.11.0: test/Streamly/Test/Data/Array/Stream.hs

module Main (main) where

import Data.Word (Word8)
import Streamly.Test.Common (listEquals, chooseInt)
import Test.Hspec (hspec, describe, shouldBe)
import Test.Hspec.QuickCheck
import Test.QuickCheck (forAll, Property, vectorOf, Gen, Arbitrary (arbitrary))
import Test.QuickCheck.Monadic (assert, monadicIO, run)

import qualified Streamly.Internal.Data.Array as Array
import qualified Streamly.Internal.Data.Fold as Fold
import qualified Streamly.Internal.Data.Parser as Parser
import qualified Streamly.Internal.Data.Stream as Stream
import qualified Test.Hspec as Hspec

import Prelude hiding (sequence)

#if MIN_VERSION_QuickCheck(2,14,0)

import Test.QuickCheck (chooseAny)

#else

import System.Random (Random(random))
import Test.QuickCheck.Gen (Gen(MkGen))

-- | Generates a random element over the natural range of `a`.
chooseAny :: Random a => Gen a
chooseAny = MkGen (\r _ -> let (x,_) = random r in x)

#endif

maxTestCount :: Int
maxTestCount = 100

chunksOf :: Monad m
    => Int -> Fold.Fold m a b -> Stream.Stream m a -> Stream.Stream m b
chunksOf n f = Stream.foldMany (Fold.take n f)

parseBreak :: Property
parseBreak = do
    let len = 200
    -- ls = input list (stream)
    -- clen = chunk size
    -- tlen = parser take size
    forAll
        ((,,)
            <$> vectorOf len (chooseAny :: Gen Int)
            <*> chooseInt (1, len)
            <*> chooseInt (0, len))
        $ \(ls, clen, tlen) ->
            monadicIO $ do
                (ls1, str) <-
                    let input =
                            Stream.toStreamK
                                $ chunksOf
                                clen (Array.createOf clen) (Stream.fromList ls)
                        parser = Parser.fromFold (Fold.take tlen Fold.toList)
                     in run $ Array.parseBreak (Array.toParserK parser) input
                ls2 <- run $ Stream.fold Fold.toList (Array.concat $ Stream.fromStreamK str)
                case ls1 of
                    Right x -> listEquals (==) (x ++ ls2) ls
                    Left _ -> assert False

splitOnSuffix :: Word8 -> [Word8] -> [[Word8]] -> IO ()
splitOnSuffix sep inp out = do
    res <-
        Stream.fold Fold.toList
            $ Array.compactEndByByte_ sep
            $ chunksOf 2 (Array.createOf 2) $ Stream.fromList inp
    fmap Array.toList res `shouldBe` out

-------------------------------------------------------------------------------
-- Main
-------------------------------------------------------------------------------

moduleName :: String
moduleName = "Data.Array.Stream"

-- Instead of hard coding 10000 here we can have maxStreamLength for operations
-- that use stream of arrays.

concatArrayW8 :: Property
concatArrayW8 =
    forAll (vectorOf 10000 (arbitrary :: Gen Word8))
        $ \w8List -> do
              let w8ArrList = Array.fromList . (: []) <$> w8List
              f2 <- Stream.fold Fold.toList $ Array.concat $ Stream.fromList w8ArrList
              w8List `shouldBe` f2


main :: IO ()
main =
    hspec $
    Hspec.parallel $
    modifyMaxSuccess (const maxTestCount) $ do
        describe moduleName $ do
            describe "Stream parsing" $ do
                prop "parseBreak" parseBreak
                prop "concatArrayW8" concatArrayW8
            describe "splifOnSuffix" $ do
                Hspec.it "splitOnSuffix 0 [1, 2, 0, 4, 0, 5, 6]"
                       $ splitOnSuffix 0 [1, 2, 0, 4, 0, 5, 6]
                                         [[1, 2], [4], [5, 6]]
                Hspec.it "splitOnSuffix 0 [1, 2, 0, 4, 0, 5, 6, 0]"
                       $ splitOnSuffix 0 [1, 2, 0, 4, 0, 5, 6, 0]
                                         [[1, 2], [4], [5, 6]]
                Hspec.it "splitOnSuffix 0 [0, 1, 2, 0, 4, 0, 5, 6]"
                       $ splitOnSuffix 0 [0, 1, 2, 0, 4, 0, 5, 6]
                                         [[], [1, 2], [4], [5, 6]]