From fe2df6f7d63272ac147911c1573550bed1d38a37 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Tue, 6 Feb 2024 13:05:38 -0600 Subject: [PATCH] Implement tests --- src/Data/HexString.hs | 36 ++++++++++++++++-------------------- test/Data/HexStringSpec.hs | 28 ++++++++++++++-------------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/Data/HexString.hs b/src/Data/HexString.hs index 79e3682..467552f 100644 --- a/src/Data/HexString.hs +++ b/src/Data/HexString.hs @@ -8,9 +8,7 @@ module Data.HexString ( HexString(..) , hexString - , fromBinary - , toBinary - , fromBytes + , fromRawBytes , toBytes , fromText , toText @@ -23,7 +21,7 @@ import Data.Aeson import Data.Word (Word8) import qualified Data.ByteString as BS -import qualified Data.ByteString.Base16 as BS16 (decodeLenient, encode) +import qualified Data.ByteString.Base16 as BS16 (decode, decodeLenient, encode) import qualified Data.ByteString.Lazy as BSL import Data.Structured @@ -39,11 +37,14 @@ import qualified Generics.SOP as SOP -- are valid hex characters. newtype HexString = HexString { hexBytes :: BS.ByteString - } deriving stock (Eq, Prelude.Show, GHC.Generic) + } deriving stock (Eq, GHC.Generic) deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo) deriving anyclass (Data.Structured.Show) deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct HexString +instance Prelude.Show HexString where + show = T.unpack . toText + instance FromJSON HexString where parseJSON = withText "HexString" $ pure . hexString . TE.encodeUtf8 @@ -54,37 +55,32 @@ instance ToJSON HexString where -- hexadecimal characters. hexString :: BS.ByteString -> HexString hexString bs = - let isValidHex :: Word8 -> Bool - isValidHex c - | (48 <= c) && (c < 58) = True - | (97 <= c) && (c < 103) = True - | otherwise = False - in if BS.all isValidHex bs - then HexString bs - else error ("Not a valid hex string: " ++ Prelude.show bs) + case BS16.decode bs of + Right s -> HexString s + Left e -> error e -- | Converts a 'B.Binary' to a 'HexString' value fromBinary :: B.Binary a => a -> HexString -fromBinary = hexString . BS16.encode . BSL.toStrict . B.encode +fromBinary = HexString . BSL.toStrict . B.encode -- | Converts a 'HexString' to a 'B.Binary' value toBinary :: B.Binary a => HexString -> a -toBinary (HexString bs) = B.decode . BSL.fromStrict . BS16.decodeLenient $ bs +toBinary (HexString bs) = (B.decode . BSL.fromStrict) bs -- | Reads a 'BS.ByteString' as raw bytes and converts to hex representation. We -- cannot use the instance Binary of 'BS.ByteString' because it provides -- a leading length, which is not what we want when dealing with raw bytes. -fromBytes :: BS.ByteString -> HexString -fromBytes = hexString . BS16.encode +fromRawBytes :: BS.ByteString -> HexString +fromRawBytes = HexString -- | Access to the raw bytes in a 'BS.ByteString' format. toBytes :: HexString -> BS.ByteString -toBytes (HexString bs) = BS16.decodeLenient bs +toBytes (HexString bs) = bs -- | Reads a human-readable hex string into a `HexString` fromText :: T.Text -> HexString -fromText = hexString . BS16.decodeLenient . TE.encodeUtf8 +fromText = hexString . TE.encodeUtf8 -- | Access to a 'T.Text' representation of the 'HexString' toText :: HexString -> T.Text -toText (HexString bs) = TE.decodeUtf8 bs +toText (HexString bs) = (TE.decodeUtf8 . BS16.encode) bs diff --git a/test/Data/HexStringSpec.hs b/test/Data/HexStringSpec.hs index 93b4b90..a8d6673 100644 --- a/test/Data/HexStringSpec.hs +++ b/test/Data/HexStringSpec.hs @@ -1,27 +1,27 @@ +{-# LANGUAGE OverloadedStrings #-} + module Data.HexStringSpec where -import Data.HexString ( hexString - , fromBytes - , toBytes ) +import Data.HexString (fromRawBytes, fromText, hexString, toBytes, toText) import qualified Data.ByteString.Char8 as BS8 -import Test.Hspec +import Test.Hspec spec :: Spec spec = do describe "when constructing a hex string" $ do - it "should accept strings that fall within a valid range" $ - hexString (BS8.pack "0123456789abcdef") `shouldBe` hexString (BS8.pack "0123456789abcdef") - it "should reject strings outside the range" $ do - putStrLn (show (hexString (BS8.pack "/"))) `shouldThrow` anyErrorCall - putStrLn (show (hexString (BS8.pack ":"))) `shouldThrow` anyErrorCall - putStrLn (show (hexString (BS8.pack "`"))) `shouldThrow` anyErrorCall - putStrLn (show (hexString (BS8.pack "g"))) `shouldThrow` anyErrorCall - + print (hexString (BS8.pack "/")) `shouldThrow` anyErrorCall + print (hexString (BS8.pack ":")) `shouldThrow` anyErrorCall + print (hexString (BS8.pack "`")) `shouldThrow` anyErrorCall + print (hexString (BS8.pack "g")) `shouldThrow` anyErrorCall describe "when interpreting a hex string" $ do it "should convert the hex string properly when interpreting as bytes" $ - toBytes (hexString (BS8.pack "ffff")) `shouldBe` BS8.pack "\255\255" + toBytes (hexString "ffff") `shouldBe` BS8.pack "\255\255" it "should convert bytes to the proper hex string" $ - fromBytes (BS8.pack "\255\255") `shouldBe` hexString (BS8.pack "ffff") + fromRawBytes (BS8.pack "\255\255") `shouldBe` hexString (BS8.pack "ffff") + it "should convert the hex string to text" $ + toText (hexString "ffff") `shouldBe` "ffff" + it "should read text into the hex string" $ + fromText "ffff" `shouldBe` hexString (BS8.pack "ffff")