module Test.Dahdit.Daytripper
  ( Cmp
  , expectCodec
  , expectCodecOk
  , expectCodecErr
  , expectBytes
  , expectText
  , expectStatic
  )
where

import Control.Monad.IO.Class (MonadIO (..))
import Dahdit (Binary, ByteCount (..), GetError, StaticByteSized (..), decodeEnd, encode)
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.Either (isLeft, isRight)
import Data.Proxy (Proxy (..))
import Data.Text (Text)
import Data.Text.Encoding qualified as TE
import Data.Word (Word8)
import PropUnit (MonadTest, assert, (===))
import Test.Daytripper (Expect, expectDuring, mkExpect)

type Cmp m a = Maybe a -> Either GetError a -> m ()

expectCodec :: (MonadTest m, MonadIO m, Binary a) => Cmp m a -> Expect m a ByteString (Either GetError a)
expectCodec :: forall (m :: * -> *) a.
(MonadTest m, MonadIO m, Binary a) =>
Cmp m a -> Expect m a ByteString (Either GetError a)
expectCodec = (a -> m ByteString)
-> (ByteString -> m (Either GetError a))
-> (Maybe a -> Either GetError a -> m ())
-> Expect m a ByteString (Either GetError a)
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b)
-> (b -> m c) -> (Maybe a -> c -> m ()) -> Expect m a b c
mkExpect a -> m ByteString
enc ByteString -> m (Either GetError a)
dec
 where
  enc :: a -> m ByteString
enc = IO ByteString -> m ByteString
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> m ByteString)
-> (a -> IO ByteString) -> a -> m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> IO ByteString
forall a z (m :: * -> *).
(Binary a, BinaryPutTarget z m) =>
a -> m z
encode
  dec :: ByteString -> m (Either GetError a)
dec = IO (Either GetError a) -> m (Either GetError a)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Either GetError a) -> m (Either GetError a))
-> (ByteString -> IO (Either GetError a))
-> ByteString
-> m (Either GetError a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Either GetError a, ByteCount) -> Either GetError a)
-> IO (Either GetError a, ByteCount) -> IO (Either GetError a)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Either GetError a, ByteCount) -> Either GetError a
forall a b. (a, b) -> a
fst (IO (Either GetError a, ByteCount) -> IO (Either GetError a))
-> (ByteString -> IO (Either GetError a, ByteCount))
-> ByteString
-> IO (Either GetError a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> IO (Either GetError a, ByteCount)
forall a z (m :: * -> *).
(Binary a, BinaryGetTarget z m) =>
z -> m (Either GetError a, ByteCount)
decodeEnd

expectCodecOk :: (MonadTest m, MonadIO m, Binary a, Eq a, Show a) => Expect m a ByteString (Either GetError a)
expectCodecOk :: forall (m :: * -> *) a.
(MonadTest m, MonadIO m, Binary a, Eq a, Show a) =>
Expect m a ByteString (Either GetError a)
expectCodecOk = Cmp m a -> Expect m a ByteString (Either GetError a)
forall (m :: * -> *) a.
(MonadTest m, MonadIO m, Binary a) =>
Cmp m a -> Expect m a ByteString (Either GetError a)
expectCodec ((Either GetError a -> m ())
-> (a -> Either GetError a -> m ()) -> Cmp m a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Bool -> m ()
forall (m :: * -> *). (MonadTest m, HasCallStack) => Bool -> m ()
assert (Bool -> m ())
-> (Either GetError a -> Bool) -> Either GetError a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either GetError a -> Bool
forall a b. Either a b -> Bool
isRight) (\a
a Either GetError a
x -> Either GetError a
x Either GetError a -> Either GetError a -> m ()
forall (m :: * -> *) a.
(MonadTest m, Eq a, Show a, HasCallStack) =>
a -> a -> m ()
=== a -> Either GetError a
forall a b. b -> Either a b
Right a
a))

expectCodecErr :: (MonadTest m, MonadIO m, Binary a) => Expect m a ByteString (Either GetError a)
expectCodecErr :: forall (m :: * -> *) a.
(MonadTest m, MonadIO m, Binary a) =>
Expect m a ByteString (Either GetError a)
expectCodecErr = Cmp m a -> Expect m a ByteString (Either GetError a)
forall (m :: * -> *) a.
(MonadTest m, MonadIO m, Binary a) =>
Cmp m a -> Expect m a ByteString (Either GetError a)
expectCodec ((Either GetError a -> m ()) -> Cmp m a
forall a b. a -> b -> a
const (Bool -> m ()
forall (m :: * -> *). (MonadTest m, HasCallStack) => Bool -> m ()
assert (Bool -> m ())
-> (Either GetError a -> Bool) -> Either GetError a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Either GetError a -> Bool
forall a b. Either a b -> Bool
isLeft))

expectBytes :: (MonadTest m) => [Word8] -> Expect m a ByteString c -> Expect m a ByteString c
expectBytes :: forall (m :: * -> *) a c.
MonadTest m =>
[Word8] -> Expect m a ByteString c -> Expect m a ByteString c
expectBytes [Word8]
ws = (Maybe a -> ByteString -> m ())
-> Expect m a ByteString c -> Expect m a ByteString c
forall (m :: * -> *) a b c.
Monad m =>
(Maybe a -> b -> m ()) -> Expect m a b c -> Expect m a b c
expectDuring (\Maybe a
_ ByteString
bs -> ByteString
bs ByteString -> ByteString -> m ()
forall (m :: * -> *) a.
(MonadTest m, Eq a, Show a, HasCallStack) =>
a -> a -> m ()
=== [Word8] -> ByteString
BS.pack [Word8]
ws)

expectText :: (MonadTest m) => Text -> Expect m a ByteString c -> Expect m a ByteString c
expectText :: forall (m :: * -> *) a c.
MonadTest m =>
Text -> Expect m a ByteString c -> Expect m a ByteString c
expectText Text
t = (Maybe a -> ByteString -> m ())
-> Expect m a ByteString c -> Expect m a ByteString c
forall (m :: * -> *) a b c.
Monad m =>
(Maybe a -> b -> m ()) -> Expect m a b c -> Expect m a b c
expectDuring (\Maybe a
_ ByteString
bs -> ByteString
bs ByteString -> ByteString -> m ()
forall (m :: * -> *) a.
(MonadTest m, Eq a, Show a, HasCallStack) =>
a -> a -> m ()
=== Text -> ByteString
TE.encodeUtf8 Text
t)

proxyBefore :: Expect m a b c -> Proxy a
proxyBefore :: forall (m :: * -> *) a b c. Expect m a b c -> Proxy a
proxyBefore Expect m a b c
_ = Proxy a
forall {k} (t :: k). Proxy t
Proxy

expectStatic :: (MonadTest m, StaticByteSized a) => Expect m a ByteString c -> Expect m a ByteString c
expectStatic :: forall (m :: * -> *) a c.
(MonadTest m, StaticByteSized a) =>
Expect m a ByteString c -> Expect m a ByteString c
expectStatic Expect m a ByteString c
ex =
  let len :: Int
len = ByteCount -> Int
unByteCount (Proxy a -> ByteCount
forall a. StaticByteSized a => Proxy a -> ByteCount
staticByteSize (Expect m a ByteString c -> Proxy a
forall (m :: * -> *) a b c. Expect m a b c -> Proxy a
proxyBefore Expect m a ByteString c
ex))
  in  (Maybe a -> ByteString -> m ())
-> Expect m a ByteString c -> Expect m a ByteString c
forall (m :: * -> *) a b c.
Monad m =>
(Maybe a -> b -> m ()) -> Expect m a b c -> Expect m a b c
expectDuring (\Maybe a
_ ByteString
bs -> ByteString -> Int
BS.length ByteString
bs Int -> Int -> m ()
forall (m :: * -> *) a.
(MonadTest m, Eq a, Show a, HasCallStack) =>
a -> a -> m ()
=== Int
len) Expect m a ByteString c
ex