snap-core-0.2.13: test/suite/Snap/Iteratee/Tests.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Snap.Iteratee.Tests
( tests ) where
import qualified Control.Exception as E
import Control.Exception hiding (try, assert)
import Control.Monad
import Control.Monad.Identity
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy.Char8 as L
import Data.Monoid
import Data.Int
import Data.IORef
import Data.Iteratee.WrappedByteString
import Data.Word
import Prelude hiding (drop, take)
import Test.Framework
import Test.Framework.Providers.QuickCheck2
import Test.QuickCheck
import qualified Test.QuickCheck.Monadic as QC
import Test.QuickCheck.Monadic hiding (run)
import Test.Framework.Providers.HUnit
import qualified Test.HUnit as H
import Snap.Iteratee
import Snap.Test.Common ()
instance Arbitrary Int64 where
arbitrary = arbitraryBoundedIntegral
shrink = shrinkIntegral
liftQ :: forall a m . (Monad m) => m a -> PropertyM m a
liftQ = QC.run
expectException :: IO a -> PropertyM IO ()
expectException m = do
e <- liftQ $ E.try m
case e of
Left (z::SomeException) -> (show z) `seq` return ()
Right _ -> fail "expected exception, didn't get one"
tests :: [Test]
tests = [ testEnumBS
, testEnumLBS
, testBuffer
, testBuffer2
, testBuffer3
, testBuffer4
, testBufferChain
, testBufferChainEscape
, testUnsafeBuffer
, testUnsafeBuffer2
, testUnsafeBuffer3
, testUnsafeBuffer4
, testUnsafeBuffer5
, testTakeExactly1
, testTakeExactly2
, testTakeExactly3
, testTakeNoMoreThan1
, testTakeNoMoreThan2
, testTakeNoMoreThan3
, testCountBytes
, testCountBytes2
]
testEnumBS :: Test
testEnumBS = testProperty "enumBS" prop
where
prop :: S.ByteString -> Bool
prop s = (S.concat $ L.toChunks $ fromWrap $ runIdentity (run iter)) == s
where
iter = runIdentity $ enumBS s stream2stream
testEnumLBS :: Test
testEnumLBS = testProperty "enumLBS" prop
where
prop :: L.ByteString -> Bool
prop s = fromWrap (runIdentity (run iter)) == s
where
iter = runIdentity $ enumLBS s stream2stream
testBuffer :: Test
testBuffer = testProperty "testBuffer" $
monadicIO $ forAllM arbitrary prop
where
prop s = do
pre (s /= L.empty)
(i,_) <- liftQ $ bufferIteratee stream2stream
iter <- liftQ $ enumLBS s' i
x <- liftQ $ run iter
QC.assert $ fromWrap x == s'
where
s' = L.take 20000 $ L.cycle s
testBuffer2 :: Test
testBuffer2 = testCase "testBuffer2" prop
where
prop = do
(i,_) <- bufferIteratee $ drop 4 >> stream2stream
s <- enumLBS "abcdefgh" i >>= run >>= return . fromWrap
H.assertEqual "s == 'efgh'" "efgh" s
testBuffer3 :: Test
testBuffer3 = testProperty "testBuffer3" $
monadicIO $ forAllM arbitrary prop
where
prop s = do
pre (s /= L.empty)
(i,_) <- liftQ $ bufferIteratee (ss >>= \x -> drop 1 >> return x)
iter <- liftQ $ enumLBS s' i
x <- liftQ $ run iter
QC.assert $ fromWrap x == (L.take 19999 s')
where
s' = L.take 20000 $ L.cycle s
ss = joinI $ take 19999 stream2stream
testBuffer4 :: Test
testBuffer4 = testProperty "testBuffer4" $
monadicIO $ forAllM arbitrary prop
where
prop s = do
(i,_) <- liftQ $ bufferIteratee (stream2stream >> throwErr (Err "foo"))
i' <- liftQ $ enumLBS s i
expectException $ run i'
(j,_) <- liftQ $ bufferIteratee (throwErr (Err "foo") >> stream2stream)
j' <- liftQ $ enumLBS s j
expectException $ run j'
k <- liftQ $ enumErr "foo" j
expectException $ run k
testBufferChain :: Test
testBufferChain = testProperty "testBufferChain" $
monadicIO $ forAllM arbitrary prop
where
prop s = do
pre (s /= L.empty)
(j,_) <- liftQ $ bufferIteratee stream2stream
(i,_) <- liftQ $ bufferIteratee j
iter <- liftQ $ enumLBS s' i
x <- liftQ $ run iter
QC.assert $ fromWrap x == s'
where
s' = L.take 20000 $ L.cycle s
testBufferChainEscape :: Test
testBufferChainEscape = testProperty "testBufferChainEscape" $
monadicIO $ forAllM arbitrary prop
where
prop s = do
pre (s /= L.empty)
(j,esc) <- liftQ $ bufferIteratee stream2stream
(i,_) <- liftQ $ bufferIteratee j
liftQ $ writeIORef esc True
iter <- liftQ $ enumLBS s' i
x <- liftQ $ run iter
QC.assert $ fromWrap x == s'
where
s' = L.take 20000 $ L.cycle s
copyingStream2stream :: Iteratee IO (WrappedByteString Word8)
copyingStream2stream = IterateeG (step mempty)
where
step acc (Chunk (WrapBS ls))
| S.null ls = return $ Cont (IterateeG (step acc)) Nothing
| otherwise = do
let !ls' = S.copy ls
let !bs' = WrapBS $! ls'
return $ Cont (IterateeG (step (acc `mappend` bs')))
Nothing
step acc str = return $ Done acc str
bufferAndRun :: Iteratee IO a -> L.ByteString -> IO a
bufferAndRun ii s = do
i <- unsafeBufferIteratee ii
iter <- enumLBS s i
run iter
testUnsafeBuffer :: Test
testUnsafeBuffer = testProperty "testUnsafeBuffer" $
monadicIO $ forAllM arbitrary prop
where
prop s = do
pre $ s /= L.empty
x <- liftQ $ bufferAndRun copyingStream2stream s'
assert $ fromWrap x == s'
where
s' = L.take 20000 $ L.cycle s
testUnsafeBuffer2 :: Test
testUnsafeBuffer2 = testCase "testUnsafeBuffer2" prop
where
prop = do
i <- unsafeBufferIteratee $ drop 4 >> copyingStream2stream
s <- enumLBS "abcdefgh" i >>= run >>= return . fromWrap
H.assertEqual "s == 'efgh'" "efgh" s
testUnsafeBuffer3 :: Test
testUnsafeBuffer3 = testProperty "testUnsafeBuffer3" $
monadicIO $ forAllM arbitrary prop
where
prop s = do
pre $ s /= L.empty
x <- liftQ $ bufferAndRun (ss >>= \x -> drop 1 >> return x) s'
assert $ fromWrap x == (L.take 19999 s')
where
s' = L.take 20000 $ L.cycle s
ss = joinI $ take 19999 copyingStream2stream
testUnsafeBuffer4 :: Test
testUnsafeBuffer4 = testProperty "testUnsafeBuffer4" $
monadicIO $ forAllM arbitrary prop
where
prop s = do
i <- liftQ $
unsafeBufferIteratee (copyingStream2stream >> throwErr (Err "foo"))
i' <- liftQ $ enumLBS s i
expectException $ run i'
j <- liftQ $
unsafeBufferIteratee (throwErr (Err "foo") >> copyingStream2stream)
j' <- liftQ $ enumLBS s j
expectException $ run j'
k <- liftQ $ enumErr "foo" j
expectException $ run k
testUnsafeBuffer5 :: Test
testUnsafeBuffer5 = testProperty "testUnsafeBuffer5" $
monadicIO $ forAllM arbitrary prop
where
prop s = do
pre $ s /= L.empty
x <- liftQ $ bufferAndRun copyingStream2stream s
assert $ fromWrap x == s
testTakeExactly1 :: Test
testTakeExactly1 = testProperty "short stream" $
monadicIO $ forAllM arbitrary prop
where
prop :: L.ByteString -> PropertyM IO ()
prop s = do
expectException $ doIter >>= run >>= return . fromWrap
where
doIter = enumLBS s (joinI (takeExactly (n+1) stream2stream))
n = fromIntegral $ L.length s
testTakeExactly2 :: Test
testTakeExactly2 = testProperty "exact stream" $
monadicIO $ forAllM arbitrary prop
where
prop :: L.ByteString -> PropertyM IO ()
prop s = do
e <- liftQ $ doIter >>= run >>= return . fromWrap
assert $ e == s
where
doIter = enumLBS s (joinI (takeExactly n stream2stream))
n = fromIntegral $ L.length s
testTakeExactly3 :: Test
testTakeExactly3 = testProperty "long stream" $
monadicIO $ forAllM arbitrary prop
where
prop :: L.ByteString -> PropertyM IO ()
prop s = do
e <- liftQ $ doIter >>= run >>= return . fromWrap
assert $ e == L.take (fromIntegral n) s
where
doIter = enumLBS s (joinI (takeExactly n stream2stream))
n = fromIntegral $ L.length s
testTakeNoMoreThan1 :: Test
testTakeNoMoreThan1 = testProperty "takeNoMore: short stream" $
monadicIO $ forAllM arbitrary prop
where
prop :: L.ByteString -> PropertyM IO ()
prop s = do
s' <- liftQ $ doIter >>= run >>= return . fromWrap
assert $ s == s'
where
doIter = enumLBS s (joinI (takeNoMoreThan (n+1) stream2stream))
n = fromIntegral $ L.length s
testTakeNoMoreThan2 :: Test
testTakeNoMoreThan2 = testProperty "takeNoMore: exact stream" $
monadicIO $ forAllM arbitrary prop
where
prop :: L.ByteString -> PropertyM IO ()
prop s = do
e <- liftQ $ doIter >>= run >>= return . fromWrap
assert $ e == s
where
doIter = enumLBS (L.concat ["", s])
(joinI (takeNoMoreThan n stream2stream))
n = fromIntegral $ L.length s
testTakeNoMoreThan3 :: Test
testTakeNoMoreThan3 = testProperty "takeNoMoreLong" $
monadicIO $ forAllM arbitrary prop
where
prop :: (Int64,L.ByteString) -> PropertyM IO ()
prop (m,s) = do
v <- liftQ $ enumLBS "" (joinI (takeNoMoreThan 0 stream2stream)) >>= run
assert $ fromWrap v == ""
if (L.null s || m == 0)
then liftQ $ do
!_ <- doIter >>= run
return ()
else expectException $ doIter >>= run >>= return . fromWrap
where
doIter = enumLBS s (joinI (takeNoMoreThan (n-abs m) stream2stream))
n = L.length s
testCountBytes :: Test
testCountBytes = testProperty "count bytes" $
monadicIO $ forAllM arbitrary prop
where
prop :: L.ByteString -> PropertyM IO ()
prop s = do
(!_,n1) <- f (countBytes (return ()))
(!_,n2) <- f (countBytes stream2stream)
assert $ n1 == 0
assert $ n2 == n
expectException $ g erriter
expectException $ enumEof erriter >>= run
where
erriter = countBytes $ throwErr $ Err "foo"
g iter = enumLBS s iter >>= run
f = liftQ . g
n = L.length s
testCountBytes2 :: Test
testCountBytes2 = testProperty "count bytes" $
monadicIO $ forAllM arbitrary prop
where
prop :: L.ByteString -> PropertyM IO ()
prop s = do
pre $ L.length s > 4
(n1,s') <- f iter
assert $ n1 == 4
assert $ fromWrap s' == L.drop 4 s
where
f i = liftQ $ enumLBS s i >>= run
iter = do
(!_,m) <- countBytes $ drop' 4
x <- stream2stream
return (m,x)