|
Packit |
4b2029 |
{-# LANGUAGE FlexibleInstances #-}
|
|
Packit |
4b2029 |
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
Packit |
4b2029 |
{-# LANGUAGE UndecidableInstances #-}
|
|
Packit |
4b2029 |
{-# LANGUAGE OverloadedStrings #-}
|
|
Packit |
4b2029 |
module Data.Conduit.ZlibSpec (spec) where
|
|
Packit |
4b2029 |
|
|
Packit |
4b2029 |
import Test.Hspec
|
|
Packit |
4b2029 |
import Test.Hspec.QuickCheck (prop)
|
|
Packit |
4b2029 |
|
|
Packit |
4b2029 |
import qualified Data.Conduit as C
|
|
Packit |
4b2029 |
import qualified Data.Conduit.List as CL
|
|
Packit |
4b2029 |
import qualified Data.Conduit.Zlib as CZ
|
|
Packit |
4b2029 |
import Control.Monad.ST (runST)
|
|
Packit |
4b2029 |
import Data.Monoid
|
|
Packit |
4b2029 |
import qualified Data.ByteString as S
|
|
Packit |
4b2029 |
import qualified Data.ByteString.Lazy as L
|
|
Packit |
4b2029 |
import Data.ByteString.Char8 ()
|
|
Packit |
4b2029 |
import Data.ByteString.Lazy.Char8 ()
|
|
Packit |
4b2029 |
import Control.Monad.Trans.Resource (runExceptionT_)
|
|
Packit |
4b2029 |
import Control.Monad.Trans.Class
|
|
Packit |
4b2029 |
import Control.Monad.Catch.Pure
|
|
Packit |
4b2029 |
import Control.Monad.Base
|
|
Packit |
4b2029 |
import Control.Monad (replicateM_)
|
|
Packit |
4b2029 |
|
|
Packit |
4b2029 |
instance MonadBase base m => MonadBase base (CatchT m) where
|
|
Packit |
4b2029 |
liftBase = lift . liftBase
|
|
Packit |
4b2029 |
|
|
Packit |
4b2029 |
spec :: Spec
|
|
Packit |
4b2029 |
spec = describe "Data.Conduit.Zlib" $ do
|
|
Packit |
4b2029 |
prop "idempotent" $ \bss' -> runST $ do
|
|
Packit |
4b2029 |
let bss = map S.pack bss'
|
|
Packit |
4b2029 |
lbs = L.fromChunks bss
|
|
Packit |
4b2029 |
src = mconcat $ map (CL.sourceList . return) bss
|
|
Packit |
4b2029 |
outBss <- runExceptionT_ $ src C.$= CZ.gzip C.$= CZ.ungzip C.$$ CL.consume
|
|
Packit |
4b2029 |
return $ lbs == L.fromChunks outBss
|
|
Packit |
4b2029 |
prop "flush" $ \bss' -> do
|
|
Packit |
4b2029 |
let bss = map S.pack $ filter (not . null) bss'
|
|
Packit |
4b2029 |
bssC = concatMap (\bs -> [C.Chunk bs, C.Flush]) bss
|
|
Packit |
4b2029 |
src = mconcat $ map (CL.sourceList . return) bssC
|
|
Packit |
4b2029 |
outBssC <- src C.$= CZ.compressFlush 5 (CZ.WindowBits 31)
|
|
Packit |
4b2029 |
C.$= CZ.decompressFlush (CZ.WindowBits 31)
|
|
Packit |
4b2029 |
C.$$ CL.consume
|
|
Packit |
4b2029 |
outBssC `shouldBe` bssC
|
|
Packit |
4b2029 |
it "compressFlush large data" $ do
|
|
Packit |
4b2029 |
let content = L.pack $ map (fromIntegral . fromEnum) $ concat $ ["BEGIN"] ++ map show [1..100000 :: Int] ++ ["END"]
|
|
Packit |
4b2029 |
src = CL.sourceList $ map C.Chunk $ L.toChunks content
|
|
Packit |
4b2029 |
bssC <- src C.$$ CZ.compressFlush 5 (CZ.WindowBits 31) C.=$ CL.consume
|
|
Packit |
4b2029 |
let unChunk (C.Chunk x) = [x]
|
|
Packit |
4b2029 |
unChunk C.Flush = []
|
|
Packit |
4b2029 |
bss <- CL.sourceList bssC C.$$ CL.concatMap unChunk C.=$ CZ.ungzip C.=$ CL.consume
|
|
Packit |
4b2029 |
L.fromChunks bss `shouldBe` content
|
|
Packit |
4b2029 |
|
|
Packit |
4b2029 |
it "uncompressed after compressed" $ do
|
|
Packit |
4b2029 |
let c = "This data is stored compressed."
|
|
Packit |
4b2029 |
u = "This data isn't."
|
|
Packit |
4b2029 |
let src1 = do
|
|
Packit |
4b2029 |
C.yield c C.$= CZ.gzip
|
|
Packit |
4b2029 |
C.yield u
|
|
Packit |
4b2029 |
encoded <- src1 C.$$ CL.consume
|
|
Packit |
4b2029 |
let src2 = mapM_ C.yield encoded
|
|
Packit |
4b2029 |
(c', u') <- src2 C.$$ do
|
|
Packit |
4b2029 |
c' <- CZ.ungzip C.=$ CL.consume
|
|
Packit |
4b2029 |
u' <- CL.consume
|
|
Packit |
4b2029 |
return (S.concat c', S.concat u')
|
|
Packit |
4b2029 |
c' `shouldBe` c
|
|
Packit |
4b2029 |
u' `shouldBe` u
|
|
Packit |
4b2029 |
|
|
Packit |
4b2029 |
it "multiple compressed values" $ do
|
|
Packit |
4b2029 |
let s1 = "hello"
|
|
Packit |
4b2029 |
s2 = "world"
|
|
Packit |
4b2029 |
src = do
|
|
Packit |
4b2029 |
C.yield s1 C.$= CZ.gzip
|
|
Packit |
4b2029 |
C.yield s2 C.$= CZ.gzip
|
|
Packit |
4b2029 |
actual <- src C.$$ CZ.multiple CZ.ungzip C.=$ CL.consume
|
|
Packit |
4b2029 |
S.concat actual `shouldBe` S.concat [s1, s2]
|
|
Packit |
4b2029 |
|
|
Packit |
4b2029 |
it "single compressed, multiple uncompressed chunks" $ do
|
|
Packit |
4b2029 |
let s1 = "hello"
|
|
Packit |
4b2029 |
s2 = "there"
|
|
Packit |
4b2029 |
s3 = "world"
|
|
Packit |
4b2029 |
s1Z <- fmap S.concat $ C.yield s1 C.$= CZ.gzip C.$$ CL.consume
|
|
Packit |
4b2029 |
let src = do
|
|
Packit |
4b2029 |
C.yield $ S.append s1Z s2
|
|
Packit |
4b2029 |
C.yield s3
|
|
Packit |
4b2029 |
actual <- src C.$$ do
|
|
Packit |
4b2029 |
x <- fmap S.concat $ CZ.ungzip C.=$ CL.consume
|
|
Packit |
4b2029 |
y <- CL.consume
|
|
Packit |
4b2029 |
return (x, y)
|
|
Packit |
4b2029 |
actual `shouldBe` (s1, [s2, s3])
|
|
Packit |
4b2029 |
|
|
Packit |
4b2029 |
it "multiple, over 32k" $ do
|
|
Packit |
4b2029 |
let str = "One line"
|
|
Packit |
4b2029 |
cnt = 30000
|
|
Packit |
4b2029 |
src = replicateM_ cnt $ C.yield str C.$= CZ.gzip
|
|
Packit |
4b2029 |
actual <- fmap S.concat $ src C.$$ CZ.multiple CZ.ungzip C.=$ CL.consume
|
|
Packit |
4b2029 |
let expected = S.concat (replicate cnt str)
|
|
Packit |
4b2029 |
S.length actual `shouldBe` S.length expected
|
|
Packit |
4b2029 |
actual `shouldBe` expected
|