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