packages feed

daytripper 0.1.0 → 0.2.0

raw patch · 3 files changed

+45/−23 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Test.Daytripper: expectAssertBool :: MonadExpect m => String -> Bool -> m ()
+ Test.Daytripper: expectAssertFailure :: MonadExpect m => String -> m ()
- Test.Daytripper: expectAfter :: Monad m => (a -> b -> c -> m ()) -> Expect m a b c -> Expect m a b c
+ Test.Daytripper: expectAfter :: Monad m => (Maybe a -> b -> c -> m ()) -> Expect m a b c -> Expect m a b c
- Test.Daytripper: expectBefore :: Monad m => (a -> m ()) -> Expect m a b c -> Expect m a b c
+ Test.Daytripper: expectBefore :: Monad m => (Maybe a -> m ()) -> Expect m a b c -> Expect m a b c
- Test.Daytripper: expectDuring :: Monad m => (a -> b -> m ()) -> Expect m a b c -> Expect m a b c
+ Test.Daytripper: expectDuring :: Monad m => (Maybe a -> b -> m ()) -> Expect m a b c -> Expect m a b c
- Test.Daytripper: mkExpect :: (MonadExpect m, Eq (f a), Show (f a), Applicative f) => (a -> m b) -> (b -> m (f a)) -> Expect m a b (f a)
+ Test.Daytripper: mkExpect :: MonadExpect m => (a -> m b) -> (b -> m c) -> (Maybe a -> c -> m ()) -> Expect m a b c

Files

daytripper.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           daytripper-version:        0.1.0+version:        0.2.0 synopsis:       Helpers for round-trip tests description:    Please see the README on GitHub at <https://github.com/ejconlon/daytripper#readme> homepage:       https://github.com/ejconlon/daytripper#readme
src/Test/Daytripper.hs view
@@ -16,7 +16,7 @@   ) where -import Control.Monad (void)+import Control.Monad (unless, void) import Data.ByteString (ByteString) import Data.ByteString qualified as BS import Data.Foldable (for_)@@ -31,7 +31,7 @@ import Test.Falsify.Property qualified as FP import Test.Tasty (TestName, TestTree, askOption, defaultIngredients, defaultMainWithIngredients, includingOptions) import Test.Tasty.Falsify (testProperty)-import Test.Tasty.HUnit (testCase, (@?=))+import Test.Tasty.HUnit (assertBool, assertFailure, testCase, (@?=)) import Test.Tasty.Ingredients (Ingredient) import Test.Tasty.Options (IsOption (..), OptionDescription (..), safeRead) @@ -40,14 +40,20 @@ class MonadFail m => MonadExpect m where   expectLiftIO :: IO a -> m a   expectAssertEq :: (Eq a, Show a) => a -> a -> m ()+  expectAssertFailure :: String -> m ()+  expectAssertBool :: String -> Bool -> m ()+  expectAssertBool s b = unless b (expectAssertFailure s)  instance MonadExpect IO where   expectLiftIO = id   expectAssertEq = (@?=)+  expectAssertFailure = assertFailure+  expectAssertBool = assertBool  instance MonadExpect Property where   expectLiftIO = pure . unsafePerformIO   expectAssertEq x y = FP.assert (FR.eq FR..$ ("LHS", x) FR..$ ("RHS", y))+  expectAssertFailure = FP.testFailed  -- | A general type of test expectation. Captures two stages of processing an input, -- first encoding, then decoding. The monad is typically something implementing@@ -55,31 +61,35 @@ -- The input is possibly missing, in which case we test decoding only. type Expect m a b c = Either b a -> m (b, m c) +eitherMay :: Either b a -> Maybe a+eitherMay = either (const Nothing) Just+ -- | Assert something before processing (before encoding and before decoding)-expectBefore :: Monad m => (a -> m ()) -> Expect m a b c -> Expect m a b c-expectBefore f ex i = for_ i f >> ex i+expectBefore :: Monad m => (Maybe a -> m ()) -> Expect m a b c -> Expect m a b c+expectBefore f ex i = f (eitherMay i) >> ex i  -- | Assert something during processing (after encoding and before decoding)-expectDuring :: Monad m => (a -> b -> m ()) -> Expect m a b c -> Expect m a b c-expectDuring f ex i = ex i >>= \p@(b, _) -> p <$ for_ i (`f` b)+expectDuring :: Monad m => (Maybe a -> b -> m ()) -> Expect m a b c -> Expect m a b c+expectDuring f ex i = ex i >>= \p@(b, _) -> p <$ f (eitherMay i) b  -- | Asserting something after processing (after encoding and after decoding)-expectAfter :: Monad m => (a -> b -> c -> m ()) -> Expect m a b c -> Expect m a b c-expectAfter f ex i = ex i >>= \(b, end) -> end >>= \c -> (b, pure c) <$ for_ i (\a -> f a b c)+expectAfter :: Monad m => (Maybe a -> b -> c -> m ()) -> Expect m a b c -> Expect m a b c+expectAfter f ex i = ex i >>= \(b, end) -> end >>= \c -> (b, pure c) <$ f (eitherMay i) b c --- | One way of definining expectations from a pair of encode/decode functions.--- Generalizes decoding in 'Maybe' or 'Either'.+-- | A way of definining expectations from a pair of encode/decode functions and+-- a comparison function. mkExpect-  :: (MonadExpect m, Eq (f a), Show (f a), Applicative f)+  :: MonadExpect m   => (a -> m b)-  -> (b -> m (f a))-  -> Expect m a b (f a)-mkExpect f g i = do+  -> (b -> m c)+  -> (Maybe a -> c -> m ())+  -> Expect m a b c+mkExpect f g h i = do   b <- either pure f i   pure . (b,) $ do-    fa <- g b-    for_ i (expectAssertEq fa . pure)-    pure fa+    c <- g b+    h (either (const Nothing) Just i) c+    pure c  -- | Simple way to run an expectation, ignoring the intermediate value. runExpect :: Monad m => Expect m a b c -> a -> m c
test/Main.hs view
@@ -8,11 +8,14 @@  import Data.ByteString (ByteString) import Data.ByteString qualified as BS+import Data.Maybe (isJust, isNothing) import Test.Daytripper (Expect, MonadExpect (..), daytripperMain, mkExpect, mkFileRT, mkPropRT, mkUnitRT, testRT) import Test.Falsify.Generator qualified as Gen import Test.Tasty (testGroup) -expec :: MonadExpect m => Expect m ByteString ByteString (Maybe ByteString)+type Cmp m = Maybe ByteString -> Maybe ByteString -> m ()++expec :: MonadExpect m => Cmp m -> Expect m ByteString ByteString (Maybe ByteString) expec = mkExpect enc dec  where   enc a = pure (a <> a)@@ -23,14 +26,23 @@             then Just a             else Nothing +expecOk, expecFail :: MonadExpect m => Expect m ByteString ByteString (Maybe ByteString)+expecOk =+  expec $+    maybe+      (expectAssertBool "expected Just" . isJust)+      (\a mc -> expectAssertEq mc (Just a))+expecFail = expec (const (expectAssertBool "expected Nothing" . isNothing))+ main :: IO () main =   daytripperMain $     testGroup "Daytripper" $       fmap         testRT-        [ mkPropRT "prop" expec (Gen.choose (pure "a") (pure "b"))-        , mkUnitRT "unit" expec "a"-        , mkFileRT "file just" expec "testdata/b.txt" (Just "b")-        , mkFileRT "file nothing" expec "testdata/c.txt" Nothing+        [ mkPropRT "prop" expecOk (Gen.choose (pure "a") (pure "b"))+        , mkUnitRT "unit" expecOk "a"+        , mkFileRT "file just" expecOk "testdata/b.txt" (Just "b")+        , mkFileRT "file nothing" expecOk "testdata/c.txt" Nothing+        , mkFileRT "file fail" expecFail "testdata/x.txt" Nothing         ]