packages feed

pinch-0.1.0.0: tests/Pinch/Internal/BuilderSpec.hs

{-# LANGUAGE NegativeLiterals  #-}
{-# LANGUAGE OverloadedStrings #-}
module Pinch.Internal.BuilderSpec (spec) where

import Control.Arrow           (second)
import Data.ByteString         (ByteString)
import Data.ByteString.Builder (toLazyByteString)
import Data.ByteString.Lazy    (toStrict)
import Data.Int                (Int64)
import Data.Word               (Word8)
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck

import qualified Data.ByteString as B

import Pinch.Arbitrary
import Pinch.Internal.Builder (Build)

import qualified Pinch.Internal.Builder as BB

run :: Build -> (Int64, ByteString)
run = second (toStrict . toLazyByteString) . BB.run


encodeCases
    :: (a -> Build) -> [([Word8], a)] -> Expectation
encodeCases encode = mapM_ . uncurry $ \bytes a -> do
    let (size, encoded) = run (encode a)
        expected = B.pack bytes
    encoded `shouldBe` expected
    fromIntegral size `shouldBe` B.length expected


spec :: Spec
spec = describe "Builder" $ do

    it "can encode 8-bit integers" $
        encodeCases BB.int8
            [ ([0x01], 1)
            , ([0x05], 5)
            , ([0x7f], 127)
            , ([0xff], -1)
            , ([0x80], -128)
            ]

    it "can encode 16-bit integers" $
        encodeCases BB.int16
            [ ([0x00, 0x01], 1)
            , ([0x00, 0xff], 255)
            , ([0x01, 0x00], 256)
            , ([0x01, 0x01], 257)
            , ([0x7f, 0xff], 32767)
            , ([0xff, 0xff], -1)
            , ([0xff, 0xfe], -2)
            , ([0xff, 0x00], -256)
            , ([0xff, 0x01], -255)
            , ([0x80, 0x00], -32768)
            ]

    it "can encode 32-bit integers" $
        encodeCases BB.int32
            [ ([0x00, 0x00, 0x00, 0x01], 1)
            , ([0x00, 0x00, 0x00, 0xff], 255)
            , ([0x00, 0x00, 0xff, 0xff], 65535)
            , ([0x00, 0xff, 0xff, 0xff], 16777215)
            , ([0x7f, 0xff, 0xff, 0xff], 2147483647)
            , ([0xff, 0xff, 0xff, 0xff], -1)
            , ([0xff, 0xff, 0xff, 0x00], -256)
            , ([0xff, 0xff, 0x00, 0x00], -65536)
            , ([0xff, 0x00, 0x00, 0x00], -16777216)
            , ([0x80, 0x00, 0x00, 0x00], -2147483648)
            ]

    it "can encode 64-bit integers" $
        encodeCases BB.int64
            [ ([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], 1)
            , ([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff], 4294967295)
            , ([0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff], 1099511627775)
            , ([0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 281474976710655)
            , ([0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 72057594037927935)
            , ([0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 9223372036854775807)
            , ([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], -1)
            , ([0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00], -4294967296)
            , ([0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00], -1099511627776)
            , ([0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], -281474976710656)
            , ([0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], -72057594037927936)
            , ([0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], -9223372036854775808)
            ]

    it "can encode doubles" $
        encodeCases BB.double
            [ ([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 0.0)
            , ([0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 1.0)
            , ([0x3f, 0xf0, 0x00, 0x00, 0x00, 0x06, 0xdf, 0x38], 1.0000000001)
            , ([0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a], 1.1)
            , ([0xbf, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a], -1.1)
            , ([0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18], 3.141592653589793)
            , ([0xbf, 0xf0, 0x00, 0x00, 0x00, 0x06, 0xdf, 0x38], -1.0000000001)
            ]

    prop "can encode bytestrings" $ \(SomeByteString bs) ->
        run (BB.byteString bs) === (fromIntegral $ B.length bs, bs)

    it "can join multiple operations using (>>)" $
        encodeCases (\(a, b) -> BB.int16 a >> BB.byteString b)
            [ ( [0x12, 0x34, 0x61, 0x62, 0x63, 0x64]
              , (4660, "abcd")
              )
            , ( [0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f]
              , (0, "hello")
              )
            ]

    it "can join multiple operations using (>>=)" $
        encodeCases (\(a, b) -> BB.int16 a >>= \() -> BB.byteString b)
            [ ( [0x12, 0x34, 0x61, 0x62, 0x63, 0x64]
              , (4660, "abcd")
              )
            , ( [0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f]
              , (0, "hello")
              )
            ]