packages feed

TLT 0.4.0.0 → 0.5.0.0

raw patch · 6 files changed

+182/−80 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Test.TLT: noUncaught_ :: MonadTLTExcept m e nt ne => String -> m a -> m ()
+ Test.TLT.Class: noUncaught_ :: MonadTLTExcept m e nt ne => String -> m a -> m ()
- Test.TLT: noUncaught :: MonadTLTExcept m e nt ne => String -> m a -> m ()
+ Test.TLT: noUncaught :: (MonadTLTExcept m e nt ne, Show e) => String -> m a -> m ()
- Test.TLT.Class: noUncaught :: MonadTLTExcept m e nt ne => String -> m a -> m ()
+ Test.TLT.Class: noUncaught :: (MonadTLTExcept m e nt ne, Show e) => String -> m a -> m ()

Files

ChangeLog.md view
@@ -1,5 +1,10 @@ # Changelog for TLT +- 0.5.0 :: Add a variation of @noUncaught@ to disguish @Show@ and+  non-@Show@ exception types in TLT failure reporting.+  +  Various improvement to the documentation.+ - 0.4.0 :: Adding a class, instance declarations, and functions for   inspecting exceptions thrown from an `ExceptT` transformer layer.   
README.md view
@@ -84,12 +84,39 @@ terms of organizing the output you see in the final report of tests run. -Finally, it is straightforward to write new `Assertion`s for-project-specific test criteria: they are simply functions returning-monadic values.  There are several functions in the final section of-this document which transform pure predicates into `Assertion`s, or-which transform one form of `Assertion` into another.+It is straightforward to write new `Assertion`s for project-specific+test criteria: they are simply functions returning monadic values.+There are several functions in the final section of this document+which transform pure predicates into `Assertion`s, or which transform+one form of `Assertion` into another. +There are also special forms for validating the normal termination of+computations including an `ExceptT` monad transformer layer:++ - `noUncaught` and `noUncaught_` each take an `ExceptT` computation+   (which may itself contain additional TLT tests) as an argument, and+   expects that computation to finish without finding an uncaught+   exception thrown from it.  The `noUncaught` function requires the+   exception type to be an instance of `Show`; the `noUncaught_`+   function operates on any exception.++ - `uncaught` also takes an `ExceptT` computation as an argument, but+   does expects it to throw an uncaught exception.  This computation+   may contain additional TLT tests, but it should be noted that any+   tests which would have been executed after a `throwE` will either+   be executed, nor be recorded for test result reporting.++ - `uncaughtWith` is like `uncaught`, but takes an additional function+   argument which receives the thrown exception for additional+   examination.+   +These three functions generally require a declaration of an instance+of `MonadTLTExcept` for the monadic type under test.  This class+decribes the relationship among the overall monad stack, the `ExceptT`+layer with it, and the TLT transformer within the `ExceptT` layer.+With these inclusion requirements, these functions do require a more+specific monad stack structure than the rest of TLT.+ # Examples  These examples are from the sample executables and test suite of@@ -221,3 +248,47 @@ from the executions of the `MnT`s for assembly into an overall test declaration. +## Testing with exceptions++These tests will pass:++    do+      noUncaught "extest1" $ do+        "6 is 6 as pure assertion" ~: 6 @==- 6+        "7 is 7 as pure assertion" ~: 7 @==- 7+      uncaught "extest2" $ do+        "8 is 8 as pure assertion" ~: 8 @==- 8+        throwE "Boom"+        "9 is 9 as pure assertion" ~: 9 @==- 9+      uncaughtWith "extest3"+	    (do "10 is 10 as pure assertion" ~: 10 @==- 10+            throwE "Boom"+            11 is 11 as pure assertion" ~: 11 @==- 11) h+        (\e -> "The exception should be \"Boom\""+                 ~: "Boom" @==- e)++This test will fail because it expects no thrown exceptions, but does+observe one:++    noUncaught "extest1x" $ do+      "6 is 6 as pure assertion" ~: 6 @==- 6+      throwE "Boom"+      "7 is 7 as pure assertion" ~: 7 @==- 7++This test will fail because it expects a thrown exception, but the+subcomputation ends normally:++    uncaught "extest2x" $ do+      "8 is 8 as pure assertion" ~: 8 @==- 8+      "9 is 9 as pure assertion" ~: 9 @==- 9++Finally, this test will record an error +against `"The exception should be \"Boom\""`,+although no error will be logged against `"extest3x"`+since only the absence of an exception would be logged at that point.++    uncaughtWith "extest3x"+	  (do throwE "Bang"+          "10 is 10 as pure assertion" ~: 10 @==- 10+          "11 is 11 as pure assertion" ~: 11 @==- 11)+	  (\e -> lift ("The exception should be \"Boom\"" ~: "Boom" @==- e)
TLT.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.35.0. -- -- see: https://github.com/sol/hpack  name:           TLT-version:        0.4.0.0+version:        0.5.0.0 synopsis:       Testing in monads and transformers without explicit specs description:    A quick-and-dirty unit test system without test specifications, motivated by easy examination of intermediate results of computations in monad transformers.  See the GitHub repository <https://github.com/jphmrst/TLT/> for documentation, or the Haddock page for additional examples. category:       Test@@ -42,7 +42,7 @@   build-depends:       STMonadTrans >=0.4.6 && <0.5     , ansi-terminal >=0.11.1 && <0.12-    , base (>=4.14.1 && <4.15) || (>=4.15.1 && <4.16) || (>=4.16.0 && <4.17)+    , base >=4.14.1 && <4.15 || >=4.15.1 && <4.16 || >=4.16.0 && <4.17     , free >=5.1.7 && <5.2     , mtl >=2.2.2 && <2.3     , resourcet >=1.2.4 && <1.3@@ -60,7 +60,7 @@       STMonadTrans >=0.4.6 && <0.5     , TLT     , ansi-terminal >=0.11.1 && <0.12-    , base (>=4.14.1 && <4.15) || (>=4.15.1 && <4.16) || (>=4.16.0 && <4.17)+    , base >=4.14.1 && <4.15 || >=4.15.1 && <4.16 || >=4.16.0 && <4.17     , free >=5.1.7 && <5.2     , mtl >=2.2.2 && <2.3     , resourcet >=1.2.4 && <1.3@@ -79,7 +79,7 @@       STMonadTrans >=0.4.6 && <0.5     , TLT     , ansi-terminal >=0.11.1 && <0.12-    , base (>=4.14.1 && <4.15) || (>=4.15.1 && <4.16) || (>=4.16.0 && <4.17)+    , base >=4.14.1 && <4.15 || >=4.15.1 && <4.16 || >=4.16.0 && <4.17     , free >=5.1.7 && <5.2     , mtl >=2.2.2 && <2.3     , resourcet >=1.2.4 && <1.3
src/Test/TLT.hs view
@@ -146,8 +146,13 @@   -- first argument of each is a @TLT@ monad of tests which has been   -- declared to take an `ExceptT` layer.   ---  --  [`noUncaught`]: Asserts that /no/ uncaught exceptions should be-  --  thrown from its argument computation, and fails if one is.+  --  [`noUncaught` and `noUncaught_`]: Both assert that /no/ uncaught+  --  exceptions should be thrown from its argument computation, and+  --  fails if one is.  The `noUncaught_` function accepts any type of+  --  exception, but cannot report any details about them except that+  --  /something/ was thrown.  The `noUncaught` function demands that+  --  the exception type be of class `Show`, and does report exception+  --  details in the case of failure.   --   --  [`uncaught`]: Asserts that an uncaught exception /should/ be   --  thrown from its argument computation, and fails if none are@@ -167,7 +172,7 @@   -- functions, are all below.    -- * The TLT transformer-  TLT, MonadTLT, liftTLT,+  TLT, MonadTLT(liftTLT),   -- ** Session options   reportAllTestResults, setExitAfterFailDisplay, @@ -193,8 +198,8 @@   -- *** Binary assertions   liftAssertion2Pure, assertion2PtoM, liftAssertion2M,   -- * Dealing with exceptions in an `ExceptT` layer-  MonadTLTExcept, liftTLTExcept, runToExcept,-  noUncaught, uncaught, uncaughtWith+  MonadTLTExcept(liftTLTExcept, runToExcept),+  noUncaught, noUncaught_, uncaught, uncaughtWith    ) where 
src/Test/TLT/Class.hs view
@@ -96,6 +96,66 @@ instance (MonadTLT m n, Monoid w) => MonadTLT (WS.WriterT w m) n where   liftTLT = lift . liftTLT +{- ----------------------------------------------------------------- -}++-- |Execute the tests specified in a `TLT` monad without output+-- side-effects, returning the final options and result reports.+--+-- This function is primarily useful when calling TLT from some other+-- package.  If you are using TLT itself as your test framework, and+-- wishing to see its human-oriented output directly, consider using+-- `Test.TLT.tlt` instead.+runTLT :: Monad m => TLT m r -> m (TLTopts, [TestResult])+runTLT (TLT t) = do+  (_, (opts, resultsBuf)) <- runStateT t $ (defaultOpts, Top 0 0 [])+  return (opts, closeTRBuf resultsBuf)++-- |This function controls whether `Test.TLT.tlt` will report only+-- tests which fail, suppressing any display of tests which pass, or+-- else report the results of all tests.  The default is the former:+-- the idea is that no news should be good news, with the programmer+-- bothered only with problems which need fixing.+reportAllTestResults :: MonadTLT m n => Bool -> m ()+reportAllTestResults b = liftTLT $ TLT $ do+  (opts, tr) <- get+  put $ (opts `withShowPasses` b, tr)++-- |This function controls whether the main `Test.TLT.tlt` executable+-- should exit after displaying test results which include at least+-- one failing test.  By default, it will exit in this situation.  The+-- idea is that a test suite can be broken into parts when it makes+-- sense to run the latter parts only when the former parts all pass.+setExitAfterFailDisplay :: MonadTLT m n => Bool -> m ()+setExitAfterFailDisplay b = liftTLT $ TLT $ do+  (opts, tr) <- get+  put $ (opts `withExitAfterFail` b, tr)++-- |Report a failure.  Useful in pattern-matching cases which are+-- entirely not expected.+tltFail :: MonadTLT m n => String -> String -> m ()+desc `tltFail` detail = liftTLT $ TLT $ do+  (opts, before) <- get+  let after = addResult before $ Test desc [Asserted detail]+  put (opts, after)++-- |Report a success.  Useful in default cases.+tltPass :: MonadTLT m n => String -> m ()+tltPass desc = liftTLT $ TLT $ do+  (opts, before) <- get+  let after = addResult before $ Test desc []+  put (opts, after)++-- |Organize the tests in the given subcomputation as a separate group+-- within the test results we will report.+inGroup :: MonadTLT m n => String -> m a -> m a+inGroup name group = do+  (opts, before) <- liftTLT $ TLT get+  liftTLT $ TLT $ put $ (opts, Buf before 0 0 name [])+  result <- group+  (opts', after) <- liftTLT $ TLT $ get+  liftTLT $ TLT $ put $ (opts', popGroup after)+  return result+ {- --------------------------------------------------------------- -}  -- | Enabling TLT checking of the completion of computations with- or@@ -113,9 +173,16 @@ -- transformer layer. class (MonadTLT m nt, Monad m, MonadTLT ne nt) => MonadTLTExcept m e nt ne       | m -> e, m -> ne where+  -- | Encodes how an embedded `ExceptT` monad can be lifted to the+  -- top-level monad stack type @m@.   liftTLTExcept :: ExceptT e ne a -> m a+  -- | Runs the layers of the monad stack above the `ExceptT` layer,+  -- exposing that latter layer.  Serves as an inverse of+  -- `liftTLTExcept`.   runToExcept :: m a -> ExceptT e ne a +-- | The `ExceptT` instance is a base case; here the lift/run+-- functions are simply `id`. instance MonadTLT m nt => MonadTLTExcept (ExceptT e m) e nt m where   liftTLTExcept = id   runToExcept = id@@ -128,6 +195,8 @@   runToExcept = ??? -} +-- | We can infer general instances for other monad transformer types+-- when their @run@ function does not take some initializing argument. instance MonadTLTExcept m e nt ne => MonadTLTExcept (IdentityT m) e nt ne where   liftTLTExcept = lift . liftTLTExcept   runToExcept = runToExcept . runIdentityT@@ -172,72 +241,24 @@   runToExcept m = runToExcept $ do (res, _) <- WS.runWriterT m                                    return res --- |Execute the tests specified in a `TLT` monad without output--- side-effects, returning the final options and result reports.------ This function is primarily useful when calling TLT from some other--- package.  If you are using TLT itself as your test framework, and--- wishing to see its human-oriented output directly, consider using--- `Test.TLT.tlt` instead.-runTLT :: Monad m => TLT m r -> m (TLTopts, [TestResult])-runTLT (TLT t) = do-  (_, (opts, resultsBuf)) <- runStateT t $ (defaultOpts, Top 0 0 [])-  return (opts, closeTRBuf resultsBuf)---- |This function controls whether `Test.TLT.tlt` will report only--- tests which fail, suppressing any display of tests which pass, or--- else report the results of all tests.  The default is the former:--- the idea is that no news should be good news, with the programmer--- bothered only with problems which need fixing.-reportAllTestResults :: MonadTLT m n => Bool -> m ()-reportAllTestResults b = liftTLT $ TLT $ do-  (opts, tr) <- get-  put $ (opts `withShowPasses` b, tr)---- |This function controls whether the main `Test.TLT.tlt` executable--- should exit after displaying test results which include at least--- one failing test.  By default, it will exit in this situation.  The--- idea is that a test suite can be broken into parts when it makes--- sense to run the latter parts only when the former parts all pass.-setExitAfterFailDisplay :: MonadTLT m n => Bool -> m ()-setExitAfterFailDisplay b = liftTLT $ TLT $ do-  (opts, tr) <- get-  put $ (opts `withExitAfterFail` b, tr)---- |Report a failure.  Useful in pattern-matching cases which are--- entirely not expected.-tltFail :: MonadTLT m n => String -> String -> m ()-desc `tltFail` detail = liftTLT $ TLT $ do-  (opts, before) <- get-  let after = addResult before $ Test desc [Asserted detail]-  put (opts, after)---- |Report a success.  Useful in default cases.-tltPass :: MonadTLT m n => String -> m ()-tltPass desc = liftTLT $ TLT $ do-  (opts, before) <- get-  let after = addResult before $ Test desc []-  put (opts, after)---- |Organize the tests in the given subcomputation as a separate group--- within the test results we will report.-inGroup :: MonadTLT m n => String -> m a -> m a-inGroup name group = do-  (opts, before) <- liftTLT $ TLT get-  liftTLT $ TLT $ put $ (opts, Buf before 0 0 name [])-  result <- group-  (opts', after) <- liftTLT $ TLT $ get-  liftTLT $ TLT $ put $ (opts', popGroup after)-  return result+-- | Ensure that a computation in `ExceptT` completes without an+-- uncaught exception.+noUncaught_ :: MonadTLTExcept m e nt ne => String -> m a -> m ()+noUncaught_ loc m = do+  let label = "No uncaught exception from " ++ loc+  liftTLTExcept $ catchE (do runToExcept m+                             tltPass label)+                         (\_ -> label `tltFail` "Uncaught exception")  -- | Ensure that a computation in `ExceptT` completes without an -- uncaught exception.-noUncaught :: MonadTLTExcept m e nt ne => String -> m a -> m ()+noUncaught :: (MonadTLTExcept m e nt ne, Show e) => String -> m a -> m () noUncaught loc m = do   let label = "No uncaught exception from " ++ loc   liftTLTExcept $ catchE (do runToExcept m                              tltPass label)-                         (\_ -> label `tltFail` "Uncaught exception")+                         (\ex -> label `tltFail`+                                   ("Uncaught exception: " ++ show ex))  -- | Ensure that a computation in `ExceptT` does throw an uncaught -- exception, allowing further testing of the exception.
test/Passing.hs view
@@ -94,9 +94,9 @@     "8 is 8 as pure assertion" ~: 8 @==- 8     throwE "Boom"     "9 is 9 as pure assertion" ~: 9 @==- 9-  uncaughtWith "extest3" (do "10 is 10 as pure assertion" ~: 10 @==- 10-                             throwE "Boom"-                             "11 is 11 as pure assertion" ~: 11 @==- 11) h--  where h :: String -> ExceptT String (TLT IO) ()-        h e = "The exception should be \"Boom\"" ~: "Boom" @==- e+  uncaughtWith "extest3"+    (do "10 is 10 as pure assertion" ~: 10 @==- 10+        throwE "Boom"+        "11 is 11 as pure assertion" ~: 11 @==- 11)+    (\e -> "The exception should be \"Boom\""+             ~: "Boom" @==- e)