packstream-0.1.0.1: test/Spec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE CPP #-}
import Test.Hspec
import Data.Text (Text)
import qualified Data.Text as T (unpack)
import Data.ByteString (ByteString)
import qualified Data.ByteString as B (pack, unpack, take, empty)
import Data.ByteString.Lazy (toStrict, fromStrict)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M (empty, fromList)
#if !MIN_VERSION_base(4, 13, 0)
import Control.Monad.Fail (MonadFail)
#endif
import Data.PackStream (PackStreamValue (..), Value(..), (=:), unpackFail)
import Data.PackStream.Internal.Hex (Hex(..))
main :: IO ()
main = hspec $ do serializeSpec
parseSpec
serializeSpec :: Spec
serializeSpec =
describe "Serializer" $ do
it "packs ()" $
hex (pack ()) `shouldBe` "C0"
it "packs Bool" $ do
hex (pack False) `shouldBe` "C2"
hex (pack True) `shouldBe` "C3"
it "packs Int" $ do
hex (pack (1::Int)) `shouldBe` "01"
hex (pack (42::Int)) `shouldBe` "2A"
hex (pack (32767::Int)) `shouldBe` "C97FFF"
hex (pack (-32768::Int)) `shouldBe` "C98000"
hex (pack (9223372036854775807::Int)) `shouldBe` "CB7FFFFFFFFFFFFFFF"
hex (pack (-9223372036854775808::Int)) `shouldBe` "CB8000000000000000"
it "packs Integer" $ do
hex (pack (1::Integer)) `shouldBe` "01"
hex (pack (42::Integer)) `shouldBe` "2A"
hex (pack (1234::Integer)) `shouldBe` "C904D2"
hex (pack (32767::Integer)) `shouldBe` "C97FFF"
hex (pack (-32768::Integer)) `shouldBe` "C98000"
hex (pack (-9223372036854775808::Integer)) `shouldBe` "CB8000000000000000"
it "packs Double" $ do
hex (pack (6.283185307179586::Double)) `shouldBe` "C1401921FB54442D18"
hex (pack (-1.1::Double)) `shouldBe` "C1BFF199999999999A"
it "packs ByteString" $ do
hex (pack B.empty) `shouldBe` "CC00"
hex (pack (B.pack [1, 2, 3])) `shouldBe` "CC03010203"
B.take 12 (hex (pack (B.pack [1 .. 255]))) `shouldBe` "CCFF01020304"
B.take 14 (hex (pack (B.pack [0 .. 255]))) `shouldBe` "CD010000010203"
it "packs Text" $ do
hex (pack (""::Text)) `shouldBe` "80"
hex (pack ("ABCDE"::Text)) `shouldBe` "854142434445"
hex (pack ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"::Text)) `shouldBe` "D01A4142434445464748494A4B4C4D4E4F505152535455565758595A"
hex (pack ("Größenmaßstäbe"::Text)) `shouldBe` "D0124772C3B6C39F656E6D61C39F7374C3A46265"
it "packs []" $ do
hex (pack ([]::[Int])) `shouldBe` "90"
hex (pack [1::Int, 2, 3]) `shouldBe` "93010203"
hex (pack [I 1, F (-1.1), T "", B False]) `shouldBe` "9401C1BFF199999999999A80C2"
hex (pack [1::Int .. 32]) `shouldBe` "D4200102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20"
B.take 14 (hex (pack [0::Int .. 255])) `shouldBe` "D5010000010203"
it "packs Map" $ do
hex (pack (M.empty::Map Text Int)) `shouldBe` "A0"
hex (pack (M.fromList ["A" =: True, "B" =: False])) `shouldBe` "A28141C38142C2"
hex (pack (M.fromList ["A" =: (1::Int), "B" =: ("ABCDE"::Text)])) `shouldBe` "A28141018142854142434445"
hex (pack bigMap) `shouldBe` bigMapBS
parseSpec :: Spec
parseSpec =
describe "Parser" $ do
it "parses ()" $ do
v <- prepareData "C0" >>= unpackFail :: IO ()
v `shouldBe` ()
it "parses Bool" $ do
t <- prepareData "C3" >>= unpackFail :: IO Bool
t `shouldBe` True
f <- prepareData "C2" >>= unpackFail :: IO Bool
f `shouldBe` False
it "parses Int" $ do
u1 <- prepareData "01" >>= unpackFail :: IO Int
u1 `shouldBe` 1
u42 <- prepareData "2A" >>= unpackFail :: IO Int
u42 `shouldBe` 42
u32767 <- prepareData "C97FFF" >>= unpackFail :: IO Int
u32767 `shouldBe` 32767
umin <- prepareData "CB8000000000000000" >>= unpackFail :: IO Int
umin `shouldBe` (-9223372036854775808)
it "parses Integer" $ do
u1 <- prepareData "01" >>= unpackFail :: IO Integer
u1 `shouldBe` 1
u42 <- prepareData "2A" >>= unpackFail :: IO Integer
u42 `shouldBe` 42
u1234 <- prepareData "C97FFF" >>= unpackFail :: IO Integer
u1234 `shouldBe` 32767
umin <- prepareData "CB8000000000000000" >>= unpackFail :: IO Integer
umin `shouldBe` (-9223372036854775808)
it "parses Double" $ do
uf <- prepareData "C1BFF199999999999A" >>= unpackFail :: IO Double
uf `shouldBe` (-1.1)
us <- prepareData "C1401921FB54442D18" >>= unpackFail :: IO Double
us `shouldBe` 6.283185307179586
it "parses ByteString" $ do
uemp <- prepareData "CC00" >>= unpackFail :: IO ByteString
B.unpack uemp `shouldBe` []
usmall <- prepareData "CC03010203" >>= unpackFail :: IO ByteString
B.unpack usmall `shouldBe` [1, 2, 3]
u255 <- unpackFail (B.pack $ [0xCC, 0xFF] ++ [1 .. 255]) :: IO ByteString
B.unpack u255 `shouldBe` [1 .. 255]
u256 <- unpackFail (B.pack $ [0xCD, 0x01, 0x00] ++ [0 .. 255]) :: IO ByteString
B.unpack u256 `shouldBe` [0 .. 255]
it "parses Text" $ do
uemp <- prepareData "80" >>= unpackFail :: IO Text
T.unpack uemp `shouldBe` ""
usmall <- prepareData "854142434445" >>= unpackFail :: IO Text
T.unpack usmall `shouldBe` "ABCDE"
ubig <- prepareData "D01A4142434445464748494A4B4C4D4E4F505152535455565758595A" >>= unpackFail :: IO Text
T.unpack ubig `shouldBe` "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
uutf <- prepareData "D0124772C3B6C39F656E6D61C39F7374C3A46265" >>= unpackFail :: IO Text
uutf `shouldBe` "Größenmaßstäbe"
it "parses []" $ do
uemp <- prepareData "90" >>= unpackFail :: IO [Bool]
uemp `shouldBe` []
usmall <- prepareData "9401C1BFF199999999999A80C2" >>= unpackFail :: IO [Value]
usmall `shouldBe` [I 1, F (-1.1), T "", B False]
ubig <- prepareData "D4200102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20" >>= unpackFail :: IO [Int]
ubig `shouldBe` [1 .. 32]
it "parses Map" $ do
uemp <- prepareData "A0" >>= unpackFail :: IO (Map Text Int)
uemp `shouldBe` M.empty
usmall <- prepareData "A28141018142854142434445" >>= unpackFail :: IO (Map Text Value)
usmall `shouldBe` M.fromList ["A" =: (1::Int), "B" =: ("ABCDE"::Text)]
ubig <- prepareData bigMapBS >>= unpackFail :: IO (Map Text Int)
ubig `shouldBe` bigMap
-- Helper
prepareData :: MonadFail m => ByteString -> m ByteString
prepareData = (toStrict <$>) . unhex . fromStrict
bigMap :: Map Text Int
bigMap = M.fromList [ ("A", 1), ("B", 2), ("C", 3), ("D", 4), ("E", 5)
, ("F", 6), ("G", 7), ("H", 8), ("I", 9), ("J", 10)
, ("K", 11), ("L", 12), ("M", 13), ("N", 14), ("O", 15)
, ("P", 16), ("Q", 17), ("R", 18), ("S", 19), ("T", 20)
, ("U", 21), ("V", 22), ("W", 23), ("X", 24), ("Y", 25)
, ("Z", 26)]
bigMapBS :: ByteString
bigMapBS = "D81A814101814202814303814404814505814606814707814808814909814A0A814B0B814C0C814D0D814E0E814F0F815010815111815212815313815414815515815616815717815818815919815A1A"