packages feed

tasty-checklist 1.0.2.0 → 1.0.3.0

raw patch · 4 files changed

+123/−8 lines, 4 filesdep ~doctestPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: doctest

API changes (from Hackage documentation)

+ Test.Tasty.Checklist: [Observe] :: Eq d => Text -> (i -> d) -> d -> (d -> d -> String) -> DerivedVal i d
+ Test.Tasty.Checklist: multiLineDiff :: Text -> Text -> String

Files

CHANGELOG.md view
@@ -1,5 +1,12 @@ # Revision history for tasty-checklist +## 1.0.3.0 -- 2021-08-13+  * Bump doctest upper constraints (contributed by Felix Yan)+  * Added missing doctest source+  * Added `Observe` to `DerivedVal` to allow using a user-supplied+    observation function on failure.+  * Added `multiLineDiff` helper function+ ## 1.0.2.0 -- 2021-07-25   * Added `Got` specifier for simpler specification of boolean     `DerivedVal` than using `Val`.
src/Test/Tasty/Checklist.hs view
@@ -46,13 +46,14 @@   -- $checkValues   -- $setup   , checkValues-  , DerivedVal(Val, Got)+  , DerivedVal(Val, Got, Observe)   -- * Error reporting   , CheckResult   , ChecklistFailures   -- * Displaying tested values   , TestShow(testShow)   , testShowList+  , multiLineDiff   ) where @@ -158,10 +159,14 @@  check :: (CanCheck, TestShow a, MonadIO m)       => Text -> (a -> Bool) -> a -> m ()-check what eval val = do+check = checkShow testShow++checkShow :: (CanCheck, MonadIO m)+          => (a -> String) -> Text -> (a -> Bool) -> a -> m ()+checkShow showit what eval val = do   r <- liftIO $ evaluate (eval val)   unless r $ do-    let chk = CheckFailed what $ T.pack $ testShow val+    let chk = CheckFailed what $ T.pack $ showit val     liftIO $ modifyIORef ?checker (chk:)  @@ -279,6 +284,10 @@         ti = T.pack (testShow got)         tv = T.pack (testShow v)     in check msg (v ==) r+  (Observe txt fld v observationReport) ->+    let r = fld got+        msg = txt <> " observation failure"+    in checkShow (observationReport v) msg (v ==) r   (Got txt fld) ->     let r = fld got         msg = txt <> " on input <<" <> ti <> ">>"@@ -287,6 +296,9 @@  -- | Each entry in the 'Data.Parameterized.Context.Assignment' list -- for 'checkValues' should be one of these 'DerivedVal' values.+--+-- The @i@ type parameter is the input type, and the @d@ is the value+-- derived from that input type.  data DerivedVal i d where @@ -296,7 +308,7 @@   -- not obtained.   Val :: (TestShow d, Eq d) => Text -> (i -> d) -> d -> DerivedVal i d -  -- | Got allow specification of a description string and an+  -- | Got allows specification of a description string and an   -- extraction function.  The 'checkValues' function will add a   -- Failure if the extraction result is False.   --@@ -304,12 +316,22 @@   --   Got :: Text -> (i -> Bool) -> DerivedVal i Bool +  -- | Observe performs the same checking as Val except the TestShow+  -- information for the actual and expected values are not as useful+  -- (e.g. they are lengthy, multi-line, or gibberish) so instead this+  -- allows the specification of a function that will take the+  -- supplied expected value and the result of the extraction function+  -- (the actual), respectively, and generate its own description of+  -- the failure.+  --+  Observe :: (Eq d) => Text -> (i -> d) -> d -> (d -> d -> String) -> DerivedVal i d+ ----------------------------------------------------------------------  -- | The 'TestShow' class is defined to provide a way for the various -- data objects tested by this module to be displayed when tests fail. -- The default 'testShow' will use a 'Show' instance, but this can be--- overridden if there are alternate ways t o display a particular+-- overridden if there are alternate ways to display a particular -- object (e.g. pretty-printing, etc.)  class TestShow v where@@ -337,3 +359,37 @@  testShowList :: TestShow v => [v] -> String testShowList  l = "[ " <> (List.intercalate ", " (testShow <$> l)) <> " ]"+++-- | The multiLineDiff is another helper function that can be used to+-- format a line-by-line difference display of two Text+-- representations.  This is provided as a convenience function to+-- help format large text regions for easier comparison.++multiLineDiff :: T.Text -> T.Text -> String+multiLineDiff expected actual =+  let dl (e,a) = if e == a then db e else de " ↱" e <> "\n    " <> da " ↳" a+      db b = "|        > " <> b+      de m e = "|" <> m <> "expect> " <> e+      da m a = "|" <> m <> "actual> " <> a+      el = T.lines expected+      al = T.lines actual+      addnum :: Int -> T.Text -> T.Text+      addnum n l = let nt = T.pack (show n)+                       nl = T.length nt+                   in T.take (4 - nl) "    " <> nt <> l+      banner = "MISMATCH between "+               <> T.pack (show $ length el) <> " expected and "+               <> T.pack (show $ length al) <> " actual"+      diffReport = fmap (uncurry addnum) $+                   zip [1..] $ concat $+                   -- Highly simplistic "diff" output assumes+                   -- correlated lines: added or removed lines just+                   -- cause everything to shown as different from that+                   -- point forward.+                   [ fmap dl $ zip el al+                   , fmap (de "∌ ") $ drop (length al) el+                   , fmap (da "∹ ") $ drop (length el) al+                   ]+      details = banner : diffReport+  in if expected == actual then "<no difference>" else T.unpack (T.unlines details)
tasty-checklist.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.2 name:               tasty-checklist-version:            1.0.2.0+version:            1.0.3.0 synopsis:           Check multiple items during a tasty test description:    Allows the test to check a number of items during a test and@@ -69,7 +69,7 @@   main-is:          DocTestChecklist.hs   build-depends: base                , HUnit-               , doctest >= 0.10 && < 0.17+               , doctest >= 0.10 && < 0.19                , parameterized-utils                , tasty                , tasty-checklist
test/TestChecklist.hs view
@@ -1,13 +1,16 @@+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}  module Main where  import Data.Parameterized.Context ( pattern Empty, pattern (:>) )+import qualified Data.Text as T import Test.Tasty+import Test.Tasty.Checklist import Test.Tasty.ExpectedFailure import Test.Tasty.HUnit-import Test.Tasty.Checklist   main :: IO ()@@ -112,6 +115,32 @@           :> Val "the answer" answer 19          ) +       ----------------------------------------++       , testCase "Compare identical multi-line results" $+         withChecklist "multi-line" $+         let result = fmap (T.replace " " " ") soliloquy+         in result `checkValues`+            (Empty+             :> Val "length" length (length soliloquy)+             :> Val "word count" (length . T.words . T.unlines) 114+             :> Observe "unchanged" id soliloquy+              (\expect actual ->+                 multiLineDiff (T.unlines expect) (T.unlines actual))+            )++       , expectFailBecause "there are changes" $+         testCase "Compare changed multi-line results" $+         withChecklist "multi-line" $+         let result = fmap (T.replace "  " " ") soliloquy+         in result `checkValues`+            (Empty+             :> Val "length" length (length soliloquy)+             :> Val "word count" (length . T.words . T.unlines) 113+             :> Observe "unchanged" id soliloquy+              (\expect actual ->+                 multiLineDiff (T.unlines expect) (T.unlines actual))+            )        ]  ----------------------------------------------------------------------@@ -151,3 +180,26 @@  instance TestShow Opaque where   testShow = display+++----------------------------------------------------------------------++soliloquy :: [T.Text]+soliloquy =+  [ "To be, or not to be--that is the question:"+  , "Whether 'tis nobler in the mind to suffer"+  , "The slings and arrows of outrageous fortune"+  , "Or to take arms against a sea of troubles"+  , "And by opposing end them.  To die, to sleep--"+  , "No more--and by a sleep to say we end"+  , "The heartache, and the thousand natural shocks"+  , "That flesh is heir to. 'Tis a consummation"+  , "Devoutly to be wished.  To die, to sleep--"+  , "To sleep--perchance to dream: ay, there's the rub,"+  , "For in that sleep of death what dreams may come"+  , "When we have shuffled off this mortal coil,"+  , "Must give us pause.  There's the respect"+  , "That makes calamity of so long life."+  ]++instance TestShow [T.Text] where testShow = show . T.unlines