packer-0.1.3: Tests/Tests.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
import Test.Framework (defaultMain, testGroup)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Test.Framework.Providers.HUnit (testCase)
import Test.QuickCheck
import Test.HUnit
import Control.Applicative ((<$>))
import Control.Monad
import Control.Exception
import qualified Data.ByteString as B
import Data.Packer
import Data.Word
--instance Arbitrary a where
endiannessCases :: [ (String, (Word64 -> Packing ()), Unpacking Word64, B.ByteString, Word64) ]
endiannessCases =
[ ("16LE", putWord16LE . fromIntegral, (fromIntegral <$> getWord16LE), B.pack [1,2], 0x0201)
, ("16BE", putWord16BE . fromIntegral, (fromIntegral <$> getWord16BE), B.pack [2,1], 0x0201)
, ("32LE", putWord32LE . fromIntegral, (fromIntegral <$> getWord32LE), B.pack [1,2,3,4], 0x04030201)
, ("32BE", putWord32BE . fromIntegral, (fromIntegral <$> getWord32BE), B.pack [4,3,2,1], 0x04030201)
, ("64LE", putWord64LE . fromIntegral, (fromIntegral <$> getWord64LE), B.pack [1,2,3,4,5,6,7,8], 0x0807060504030201)
, ("64BE", putWord64BE . fromIntegral, (fromIntegral <$> getWord64BE), B.pack [8,7,6,5,4,3,2,1], 0x0807060504030201)
]
toEndianCase (n, pAct, gAct, bs, v) =
[ testCase ("put" ++ n) (runPacking 8 (pAct v) @=? bs)
, testCase ("get" ++ n) (runUnpacking gAct bs @=? v)
]
data DataAtom = W8 Word8
| W16 Word16
| W16BE Word16
| W16LE Word16
| W32 Word32
| W32BE Word32
| W32LE Word32
| W64 Word64
| W64BE Word64
| W64LE Word64
| Bytes B.ByteString
deriving (Show,Eq)
newtype DataStream = DataStream [DataAtom]
deriving (Show,Eq)
arbitraryBS =
choose (0,257)
>>= \sz -> replicateM sz (fromIntegral <$> (choose (0,255) :: Gen Int))
>>= return . B.pack
instance Arbitrary DataAtom where
arbitrary = oneof
[ W8 <$> arbitrary
, W16 <$> arbitrary
, W16BE <$> arbitrary
, W16LE <$> arbitrary
, W32 <$> arbitrary
, W32BE <$> arbitrary
, W32LE <$> arbitrary
, W64 <$> arbitrary
, W64BE <$> arbitrary
, W64LE <$> arbitrary
, Bytes <$> arbitraryBS
]
instance Arbitrary DataStream where
arbitrary = choose (0,2048)
>>= \sz -> replicateM sz arbitrary
>>= return . DataStream
packDataStream (DataStream atoms) = runPacking (foldl sumLen 0 atoms) (mapM_ process atoms)
where process :: DataAtom -> Packing ()
process (W8 w) = putWord8 w
process (W16 w) = putWord16 w
process (W32 w) = putWord32 w
process (W64 w) = putWord64 w
process (W16LE w) = putWord16LE w
process (W32LE w) = putWord32LE w
process (W64LE w) = putWord64LE w
process (W16BE w) = putWord16BE w
process (W32BE w) = putWord32BE w
process (W64BE w) = putWord64BE w
process (Bytes b) = putBytes b
sumLen a (W8 _) = a + 1
sumLen a (W16 _) = a + 2
sumLen a (W16LE _) = a + 2
sumLen a (W16BE _) = a + 2
sumLen a (W32 _) = a + 4
sumLen a (W32LE _) = a + 4
sumLen a (W32BE _) = a + 4
sumLen a (W64 _) = a + 8
sumLen a (W64LE _) = a + 8
sumLen a (W64BE _) = a + 8
sumLen a (Bytes b) = a + B.length b
unpackDataStream :: DataStream -> B.ByteString -> DataStream
unpackDataStream (DataStream atoms) bs = DataStream $ runUnpacking (mapM process atoms) bs
where process :: DataAtom -> Unpacking DataAtom
process (W8 _) = W8 <$> getWord8
process (W16 _) = W16 <$> getWord16
process (W32 _) = W32 <$> getWord32
process (W64 _) = W64 <$> getWord64
process (W16LE _) = W16LE <$> getWord16LE
process (W32LE _) = W32LE <$> getWord32LE
process (W64LE _) = W64LE <$> getWord64LE
process (W16BE _) = W16BE <$> getWord16BE
process (W32BE _) = W32BE <$> getWord32BE
process (W64BE _) = W64BE <$> getWord64BE
process (Bytes b) = Bytes <$> getBytes (B.length b)
assertException msg filterE act =
handleJust filterE (\_ -> return ()) (evaluate act >> assertFailure (msg ++ " didn't raise the proper exception"))
main :: IO ()
main = defaultMain
[ testGroup "serialization"
[ testGroup "basic cases"
[ testCase "packing 4 bytes" (runPacking 4 (mapM_ putWord8 [1,2,3,4]) @=? B.pack [1,2,3,4])
, testCase "packing out of bounds" (assertException "packing" (\(OutOfBoundPacking _ _) -> Just ())
(runPacking 1 (mapM_ putWord8 [1,2])))
, testCase "unpacking out of bounds" (assertException "unpacking" (\(OutOfBoundUnpacking _ _) -> Just ())
(runUnpacking (mapM_ (\_ -> getWord8 >> return ()) [1,2]) (B.singleton 1)))
, testCase "unpacking set pos before" (assertException "unpacking position" (\(OutOfBoundUnpacking _ _) -> Just ())
(runUnpacking (unpackSetPosition 2) (B.singleton 1)))
, testCase "unpacking set pos after" (assertException "unpacking position" (\(OutOfBoundUnpacking _ _) -> Just ())
(runUnpacking (unpackSetPosition (-1)) (B.singleton 1)))
, testCase "unpacking isolate" (runUnpacking (isolate 2 (getBytes 2) >>= \i -> getWord8 >>= \r -> return (i,r)) (B.pack [1,2,3]) @=? (B.pack [1,2], 3))
, testCase "unpacking isolate out of bounds" $
assertException "unpacking isolate" (\(OutOfBoundUnpacking _ _) -> Just ())
(runUnpacking (isolate 2 (getBytes 3)) (B.pack [1,2,3]))
, testCase "unpacking isolate not consumed" $
assertException "unpacking isolate" (\(IsolationNotFullyConsumed _ _) -> Just ())
(runUnpacking (isolate 3 (getBytes 2)) (B.pack [1,2,3]))
]
, testGroup "endianness cases" $ concatMap toEndianCase endiannessCases
, testProperty "unpacking.packing=id" (\ds -> unpackDataStream ds (packDataStream ds) == ds)
]
]