{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module MessageProps ( encodeDecodeMessage ) where import Data.Attoparsec.ByteString.Char8 import Data.ByteString.Char8 (ByteString) import Test.QuickCheck import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as LBS import Network.Nats.Types (Sid) import Network.Nats.Message.Message (Message (..), ProtocolError (..)) import Network.Nats.Message.Parser (parseMessage) import Network.Nats.Message.Writer (writeMessage) -- | Arbitrary instance for ProtocolError. instance Arbitrary ProtocolError where arbitrary = elements [ minBound .. ] -- | Arbitrary instance for Message. instance Arbitrary Message where arbitrary = oneof [ arbitraryInfo , arbitraryConnect , arbitraryMsg , arbitraryPub , arbitrarySub , arbitraryUnsub , arbitraryPingPong , arbitraryOk , arbitraryErr ] -- | Arbitrary generation of Info messages. arbitraryInfo :: Gen Message arbitraryInfo = INFO <$> perhaps valueString <*> perhaps valueString <*> perhaps valueString <*> perhaps valueString <*> perhaps posInt <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> perhaps posInt -- | Arbitrary generation of Connect messages. arbitraryConnect :: Gen Message arbitraryConnect = CONNECT <$> arbitrary <*> arbitrary <*> arbitrary <*> perhaps valueString <*> perhaps valueString <*> perhaps valueString <*> perhaps valueString <*> perhaps valueString <*> perhaps valueString -- | Arbitrary generation of Msg messages. arbitraryMsg :: Gen Message arbitraryMsg = MSG <$> alnumString <*> sid <*> perhaps alnumString <*> payloadString -- | Arbitrary generation of Pub messages. arbitraryPub :: Gen Message arbitraryPub = PUB <$> alnumString <*> perhaps alnumString <*> payloadString -- | Arbitrary generation of Sub messages. arbitrarySub :: Gen Message arbitrarySub = SUB <$> alnumString <*> perhaps alnumString <*> sid -- | Arbitrary generation of Sub messages. arbitraryUnsub :: Gen Message arbitraryUnsub = UNSUB <$> sid <*> perhaps posInt -- | Arbitrary generation of Ping/Pong messages. arbitraryPingPong :: Gen Message arbitraryPingPong = oneof [ pure PING, pure PONG ] -- | Arbitrary generation of Ok messages. arbitraryOk :: Gen Message arbitraryOk = pure OK -- | Arbitrary generation of Err messages. arbitraryErr :: Gen Message arbitraryErr = ERR <$> arbitrary -- | Test by write a Message to ByteString, and parse it back again. encodeDecodeMessage :: Message -> Bool encodeDecodeMessage msg = let asByteString = LBS.toStrict $ writeMessage msg in verify (parse parseMessage asByteString) where verify :: IResult ByteString Message -> Bool verify result = case result of (Done _ msg2) -> msg == msg2 (Partial g) -> verify (g "") _ -> False -- | Generate Maybe's for the tailor made generators. perhaps :: Gen a -> Gen (Maybe a) perhaps gen = oneof [ return Nothing, Just <$> gen ] -- | Generate a ByteString which not contains any quote characters. valueString :: Gen ByteString valueString = BS.pack <$> listOf (elements selection) where selection :: [Char] selection = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ "+-_!?*(){} " payloadString :: Gen LBS.ByteString payloadString = LBS.pack <$> listOf arbitrary -- | Generate a non-empty ByteString which is plain alphanumeric. alnumString :: Gen ByteString alnumString = BS.pack <$> listOf1 (elements selection) where selection :: [Char] selection = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] -- | Generate a positive integer. Can be max size of Int. posInt :: Gen Int posInt = choose (0, maxBound) -- | Generate a Sid sid :: Gen Sid sid = choose (0, maxBound)