{-# LANGUAGE CPP #-} {-# LANGUAGE NegativeLiterals #-} {-# LANGUAGE OverloadedStrings #-} module Pinch.Internal.ParserSpec (spec) where #if __GLASGOW_HASKELL__ < 709 import Control.Applicative #endif import Data.Either (isLeft) import Data.Word (Word8) import Test.Hspec import Test.Hspec.QuickCheck import Test.QuickCheck import qualified Data.ByteString as B import Pinch.Arbitrary import qualified Pinch.Internal.Parser as P parse :: [Word8] -> P.Parser a -> Either String a parse s p = P.runParser p (B.pack s) parseCases :: (Show a, Eq a) => P.Parser a -> [([Word8], a)] -> Expectation parseCases parser = mapM_ . uncurry $ \bytes expected -> (bytes `parse` parser) `shouldBe` Right expected spec :: Spec spec = describe "Parser" $ do it "can succeed" $ P.runParser (return 42) "" `shouldBe` Right (42 :: Int) it "can fail" $ (P.runParser (fail "great sadness") "" :: Either String ()) `shouldBe` Left "great sadness" it "can parse 8-bit integers" $ parseCases P.int8 [ ([0x01], 1) , ([0x05], 5) , ([0x7f], 127) , ([0xff], -1) , ([0x80], -128) ] it "can parse 16-bit integers" $ parseCases P.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 parse 32-bit integers" $ parseCases P.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 parse 64-bit integers" $ parseCases P.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 parse 64-bit little endian integers" $ parseCases P.int64LE [ ([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 1) , ([0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00], 4294967295) , ([0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00], 1099511627775) , ([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00], 281474976710655) , ([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00], 72057594037927935) , ([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f], 9223372036854775807) , ([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], -1) , ([0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff], -4294967296) , ([0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff], -1099511627776) , ([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff], -281474976710656) , ([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff], -72057594037927936) , ([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80], -9223372036854775808) ] it "can parse doubles" $ parseCases P.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) ] it "can parse little endian doubles" $ parseCases P.doubleLE [ ([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 0.0) , ([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f], 1.0) , ([0x38, 0xdf, 0x06, 0x00, 0x00, 0x00, 0xf0, 0x3f], 1.0000000001) , ([0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xf1, 0x3f], 1.1) , ([0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0xf1, 0xbf], -1.1) , ([0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40], 3.141592653589793) , ([0x38, 0xdf, 0x06, 0x00, 0x00, 0x00, 0xf0, 0xbf], -1.0000000001) ] describe "take" $ do prop "returns the requested number of bytes" $ \n (SomeByteString bs) -> B.length bs >= n ==> (B.length <$> P.runParser (P.take n) bs) === Right n prop "fails when input is too short" $ \n (SomeByteString bs) -> B.length bs < n ==> isLeft (P.runParser (P.take n) bs)