packages feed

cereal-io-streams-0.0.1.0: test/Main.hs

{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell   #-}
module Main
    ( main
    ) where

-------------------------------------------------------------------------------
import           Control.Exception        hiding (assert)
import qualified Data.ByteString          as BS
import           Data.DeriveTH
import           Data.Monoid
import           Data.Serialize
import           GHC.Generics
import           System.IO.Streams        hiding (map)
import qualified System.IO.Streams        as Streams
import           Test.QuickCheck.Monadic
import           Test.Tasty
import           Test.Tasty.HUnit         hiding (assert)
import           Test.Tasty.QuickCheck

import Control.Monad
import qualified Data.ByteString.Lazy          as LBS
import qualified Data.ByteString.Char8          as BS8
import qualified Control.Monad.State as MS
-------------------------------------------------------------------------------
import           System.IO.Streams.Cereal
-------------------------------------------------------------------------------


main :: IO ()
main = defaultMain testSuite


testSuite :: TestTree
testSuite = testGroup "cereal-io-streams"
  [
    testProperty "serialization roundtrips Foo" prop_roundtrip_Foo

  , testProperty "serialization roundtrips Foo unpredictable chunking" prop_roundtrip_Foo_chunking

  , testCase "partial input" test_partial
  , testCase "excess preceding input" test_excess_head
  , testCase "excess remaining input left in stream" test_excess_tail
  ]


-------------------------------------------------------------------------------
prop_roundtrip_Foo = monadicIO $ do
    a   <- (pick arbitrary :: PropertyM IO Foo)
    res <- run $
      getFromStream get =<< putToStream (put a)
    assert $ a == res


-------------------------------------------------------------------------------
prop_roundtrip_Foo_chunking = monadicIO $ do
    as   <- (pick arbitrary :: PropertyM IO [Foo])
    Positive csize <- pick arbitrary
    res <- run $ do
      lbs <- fmap (LBS.fromChunks . rechunk csize . mconcat) . Streams.toList =<< putEachStream put =<< Streams.fromList as
      is <- fromLazyByteString lbs
      Streams.toList =<< getEachStream get is
    assert $ as == res


-------------------------------------------------------------------------------
test_partial = do
  let s = mutatePut $ BS.drop 1
  assertGetException $ getFromStream (get :: Get Foo) =<< fromByteString s

-------------------------------------------------------------------------------
test_excess_tail = do
  let s = mutatePut $ (<> "extra")
  inS <- fromByteString s
  getFromStream (get :: Get Foo) inS
  remainder <- smappend inS
  remainder @?= "extra"

-------------------------------------------------------------------------------
smappend = Streams.fold mappend mempty

-------------------------------------------------------------------------------
test_excess_head = do
  let s = mutatePut $ ("extra" <>)
  assertGetException $ getFromStream (get :: Get Foo) =<< fromByteString s


-------------------------------------------------------------------------------
mutatePut f = f $ runPut $ put $ Foo 42 "yup"


-------------------------------------------------------------------------------
rechunk :: Int -> BS.ByteString -> [BS.ByteString]
rechunk n bs = fst $ MS.execState go ([], bs)
  where
    go :: MS.State ([BS.ByteString], BS.ByteString) ()
    go = do
      (chunks, rmning) <- MS.get
      unless (BS.null rmning) $ do
        let (chunk, rmning') = BS.splitAt n rmning
        MS.put (chunks ++ [chunk], rmning')
        go


-------------------------------------------------------------------------------
assertGetException a = do
  res <- try a
  case res of
    Left (GetException _) -> return ()
    (Right r)             -> assertFailure $ "Expected a GetException but got " ++ show r


-------------------------------------------------------------------------------
data Foo = Foo Int String deriving (Generic,Show,Eq)

instance Serialize Foo
$(derive makeArbitrary ''Foo)