packages feed

tasty-hunit 0.9.2 → 0.10

raw patch · 5 files changed

+156/−55 lines, 5 filesdep +call-stackPVP ok

version bump matches the API change (PVP)

Dependencies added: call-stack

API changes (from Hackage documentation)

- Test.Tasty.HUnit: instance IsTest TestCase
- Test.Tasty.HUnit: instance Typeable TestCase
+ Test.Tasty.HUnit: infix 1 @?
+ Test.Tasty.HUnit: instance Test.Tasty.Core.IsTest Test.Tasty.HUnit.TestCase
+ Test.Tasty.HUnit: type HasCallStack = ?callStack :: CallStack
- Test.Tasty.HUnit: (@=?) :: (Eq a, Show a) => a -> a -> Assertion
+ Test.Tasty.HUnit: (@=?) :: (Eq a, Show a, HasCallStack) => a -> a -> Assertion
- Test.Tasty.HUnit: (@?) :: AssertionPredicable t => t -> String -> Assertion
+ Test.Tasty.HUnit: (@?) :: (AssertionPredicable t) => t -> String -> Assertion
- Test.Tasty.HUnit: (@?=) :: (Eq a, Show a) => a -> a -> Assertion
+ Test.Tasty.HUnit: (@?=) :: (Eq a, Show a, HasCallStack) => a -> a -> Assertion
- Test.Tasty.HUnit: HUnitFailure :: String -> HUnitFailure
+ Test.Tasty.HUnit: HUnitFailure :: (Maybe SrcLoc) -> String -> HUnitFailure
- Test.Tasty.HUnit: assertBool :: String -> Bool -> Assertion
+ Test.Tasty.HUnit: assertBool :: HasCallStack => String -> Bool -> Assertion
- Test.Tasty.HUnit: assertEqual :: (Eq a, Show a) => String -> a -> a -> Assertion
+ Test.Tasty.HUnit: assertEqual :: (Eq a, Show a, HasCallStack) => String -> a -> a -> Assertion
- Test.Tasty.HUnit: assertFailure :: String -> Assertion
+ Test.Tasty.HUnit: assertFailure :: HasCallStack => String -> IO a
- Test.Tasty.HUnit: assertString :: String -> Assertion
+ Test.Tasty.HUnit: assertString :: HasCallStack => String -> Assertion

Files

CHANGELOG.md view
@@ -1,6 +1,13 @@ Changes ======= +Version 0.10+------------++* Make `assertFailure`'s return type polymorphic+* When a test fails, print the source location of the failing assertion+* Deprecate `Assertable`, `AssertionPredicate`, `AssertionPredicable`, `(@?)`+ Version 0.9.2 ------------- 
Test/Tasty/HUnit.hs view
@@ -1,10 +1,63 @@--- | Unit testing support for tasty, inspired by the HUnit package+-- | Unit testing support for tasty, inspired by the HUnit package.+--+-- Here's an example (a single tasty test case consisting of three+-- assertions):+--+-- >import Test.Tasty+-- >import Test.Tasty.HUnit+-- >+-- >main = defaultMain $+-- >  testCase "Example test case" $ do+-- >    -- assertion no. 1 (passes)+-- >    2 + 2 @?= 4+-- >    -- assertion no. 2 (fails)+-- >    assertBool "the list is not empty" $ null [1]+-- >    -- assertion no. 3 (would have failed, but won't be executed because+-- >    -- the previous assertion has already failed)+-- >    "foo" @?= "bar" {-# LANGUAGE TypeFamilies, DeriveDataTypeable #-} module Test.Tasty.HUnit-  ( testCase+  (+    -- * Constructing test cases+    testCase   , testCaseInfo   , testCaseSteps-  , module Test.Tasty.HUnit.Orig+    -- * Constructing assertions+  , assertFailure+  , assertBool+  , assertEqual+  , (@=?)+  , (@?=)+    -- * Data types+  , Assertion+  , HUnitFailure(..)+    -- * Accurate location for domain-specific assertion functions+    -- | It is common to define domain-specific assertion functions based+    -- on the standard ones, e.g.+    --+    -- > assertNonEmpty = assertBool "List is empty" . not . null+    --+    -- The problem is that if a test fails, tasty-hunit will point to the+    -- definition site of @assertNonEmpty@ as the source of failure, not+    -- its use site.+    --+    -- To correct this, add a 'HasCallStack' constraint (re-exported from+    -- this module) to your function:+    --+    -- > assertNonEmpty :: HasCallStack => [a] -> Assertion+    -- > assertNonEmpty = assertBool "List is empty" . not . null+    --+    , HasCallStack+    -- * Deprecated functions and types+    -- | These definitions come from HUnit, but I don't see why one would+    -- need them. If you have a valid use case for them, please contact me+    -- or file an issue for tasty. Otherwise, they will eventually be+    -- removed.+  , assertString+  , Assertable(..)+  , AssertionPredicate+  , AssertionPredicable(..)+  , (@?)   ) where  import Test.Tasty.Providers@@ -13,9 +66,10 @@ import Test.Tasty.HUnit.Steps  import Data.Typeable+import Data.CallStack (HasCallStack) import Control.Exception --- | Create a 'Test' for a HUnit 'Assertion'+-- | Turn an 'Assertion' into a tasty test case testCase :: TestName -> Assertion -> TestTree testCase name = singleTest name . TestCase . (fmap (const "")) @@ -49,6 +103,6 @@     return $       case hunitResult of         Right info -> testPassed info-        Left (HUnitFailure message) -> testFailed message+        Left (HUnitFailure mbloc message) -> testFailed $ prependLocation mbloc message    testOptions = return []
Test/Tasty/HUnit/Orig.hs view
@@ -1,4 +1,8 @@ {-# LANGUAGE DeriveDataTypeable, FlexibleInstances, TypeSynonymInstances #-}++-- required for HasCallStack by different versions of GHC+{-# LANGUAGE ConstraintKinds, FlexibleContexts #-}+ -- | This is the code copied from the original hunit package (v. 1.2.5.2). -- with minor modifications module Test.Tasty.HUnit.Orig where@@ -6,13 +10,17 @@ import qualified Control.Exception as E import Control.Monad import Data.Typeable (Typeable)+import Data.CallStack  -- Interfaces -- ---------- --- | When an assertion is evaluated, it will output a message if and only if the--- assertion fails.  +-- | An assertion is simply an 'IO' action. Assertion failure is indicated+-- by throwing an exception, typically 'HUnitFailure'. --+-- Instead of throwing the exception directly, you should use+-- functions like 'assertFailure' and 'assertBool'.+-- -- Test cases are composed of a sequence of one or more assertions.  type Assertion = IO ()@@ -21,55 +29,104 @@ -- other assertions can be expressed with the form: -- -- @---    if conditionIsMet ---        then IO () +--    if conditionIsMet+--        then return () --        else assertFailure msg--- @ +-- @ -assertFailure :: String -- ^ A message that is displayed with the assertion failure -              -> Assertion-assertFailure msg = E.throwIO (HUnitFailure msg)+assertFailure+  :: HasCallStack+  => String -- ^ A message that is displayed with the assertion failure+  -> IO a+assertFailure msg = E.throwIO (HUnitFailure location msg)+  where+    location :: Maybe SrcLoc+    location = case reverse callStack of+      (_, loc) : _ -> Just loc+      [] -> Nothing  -- Conditional Assertion Functions -- -------------------------------  -- | Asserts that the specified condition holds.-assertBool :: String    -- ^ The message that is displayed if the assertion fails-           -> Bool      -- ^ The condition-           -> Assertion+assertBool+  :: HasCallStack+  => String    -- ^ The message that is displayed if the assertion fails+  -> Bool      -- ^ The condition+  -> Assertion assertBool msg b = unless b (assertFailure msg) --- | Signals an assertion failure if a non-empty message (i.e., a message--- other than @\"\"@) is passed.-assertString :: String    -- ^ The message that is displayed with the assertion failure -             -> Assertion-assertString s = unless (null s) (assertFailure s)- -- | Asserts that the specified actual value is equal to the expected value.--- The output message will contain the prefix, the expected value, and the +-- The output message will contain the prefix, the expected value, and the -- actual value.---  +-- -- If the prefix is the empty string (i.e., @\"\"@), then the prefix is omitted -- and only the expected and actual values are output.-assertEqual :: (Eq a, Show a) => String -- ^ The message prefix -                              -> a      -- ^ The expected value -                              -> a      -- ^ The actual value-                              -> Assertion+assertEqual+  :: (Eq a, Show a, HasCallStack)+  => String -- ^ The message prefix+  -> a      -- ^ The expected value+  -> a      -- ^ The actual value+  -> Assertion assertEqual preface expected actual =   unless (actual == expected) (assertFailure msg)  where msg = (if null preface then "" else preface ++ "\n") ++              "expected: " ++ show expected ++ "\n but got: " ++ show actual +-- | Asserts that the specified actual value is equal to the expected value+--   (with the expected value on the left-hand side).+(@=?)+  :: (Eq a, Show a, HasCallStack)+  => a -- ^ The expected value+  -> a -- ^ The actual value+  -> Assertion+expected @=? actual = assertEqual "" expected actual +-- | Asserts that the specified actual value is equal to the expected value+--   (with the actual value on the left-hand side).+(@?=)+  :: (Eq a, Show a, HasCallStack)+  => a -- ^ The actual value+  -> a -- ^ The expected value+  -> Assertion+actual @?= expected = assertEqual "" expected actual++-- | Exception thrown by 'assertFailure' etc.+data HUnitFailure = HUnitFailure (Maybe SrcLoc) String+    deriving (Eq, Show, Typeable)+instance E.Exception HUnitFailure++prependLocation :: Maybe SrcLoc -> String -> String+prependLocation mbloc s =+  case mbloc of+    Nothing -> s+    Just loc -> srcLocFile loc ++ ":" ++ show (srcLocStartLine loc) ++ ":\n" ++ s++----------------------------------------------------------------------+--                          DEPRECATED CODE+----------------------------------------------------------------------++{-# DEPRECATED assertString "Why not use assertBool instead?" #-}+{-# DEPRECATED Assertable, AssertionPredicate, AssertionPredicable, (@?)+   "This class or function seems dubious. If you have a good use case for it, please create an issue for tasty. Otherwise, it may be removed in a future version." #-}++-- | Signals an assertion failure if a non-empty message (i.e., a message+-- other than @\"\"@) is passed.+assertString+  :: HasCallStack+  => String    -- ^ The message that is displayed with the assertion failure+  -> Assertion+assertString s = unless (null s) (assertFailure s)+ -- Overloaded `assert` Function -- ----------------------------  -- | Allows the extension of the assertion mechanism. ----- Since an 'Assertion' can be a sequence of @Assertion@s and @IO@ actions, +-- Since an 'Assertion' can be a sequence of @Assertion@s and @IO@ actions, -- there is a fair amount of flexibility of what can be achieved.  As a rule, -- the resulting @Assertion@ should be the body of a 'TestCase' or part of--- a @TestCase@; it should not be used to assert multiple, independent +-- a @TestCase@; it should not be used to assert multiple, independent -- conditions. -- -- If more complex arrangements of assertions are needed, 'Test's and@@ -111,13 +168,13 @@ -- 2. Read data from a file, evaluate conditions. -- -- 3. Clean up the file.--- +-- -- 4. Assert that the side effects of the read operation meet certain conditions. -- -- 5. Assert that the conditions evaluated in step 2 are met. type AssertionPredicate = IO Bool --- | Used to signify that a data type can be converted to an assertion +-- | Used to signify that a data type can be converted to an assertion -- predicate. class AssertionPredicable t  where assertionPredicate :: t -> AssertionPredicate@@ -141,21 +198,3 @@                                 -> Assertion predi @? msg = assertionPredicate predi >>= assertBool msg --- | Asserts that the specified actual value is equal to the expected value---   (with the expected value on the left-hand side).-(@=?) :: (Eq a, Show a) => a -- ^ The expected value-                        -> a -- ^ The actual value-                        -> Assertion-expected @=? actual = assertEqual "" expected actual---- | Asserts that the specified actual value is equal to the expected value---   (with the actual value on the left-hand side).-(@?=) :: (Eq a, Show a) => a -- ^ The actual value-                        -> a -- ^ The expected value-                        -> Assertion-actual @?= expected = assertEqual "" expected actual---- | Exception thrown by 'assertFailure' etc.-data HUnitFailure = HUnitFailure String-    deriving (Show, Typeable)-instance E.Exception HUnitFailure
Test/Tasty/HUnit/Steps.hs view
@@ -5,6 +5,7 @@ import Control.Exception import Data.IORef import Data.Typeable (Typeable)+import Prelude  -- Silence AMP import warnings import Test.Tasty.HUnit.Orig import Test.Tasty.Providers @@ -28,14 +29,14 @@          Right {} -> testPassed (unlines msgs) -        Left (HUnitFailure errMsg) -> testFailed $+        Left (HUnitFailure mbloc errMsg) -> testFailed $           if null msgs             then               errMsg             else               -- Indent the error msg w.r.t. step messages               unlines $-                msgs ++ map ("  " ++) (lines errMsg)+                msgs ++ map ("  " ++) (lines . prependLocation mbloc $ errMsg)    testOptions = return [] 
tasty-hunit.cabal view
@@ -2,14 +2,14 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                tasty-hunit-version:             0.9.2+version:             0.10 synopsis:            HUnit support for the Tasty test framework. description:         HUnit support for the Tasty test framework. license:             MIT license-file:        LICENSE author:              Roman Cheplyaka <roma@ro-che.info> maintainer:          Roman Cheplyaka <roma@ro-che.info>-homepage:            http://documentup.com/feuerbach/tasty+homepage:            https://github.com/feuerbach/tasty bug-reports:         https://github.com/feuerbach/tasty/issues -- copyright:            category:            Testing@@ -27,7 +27,7 @@   other-modules:       Test.Tasty.HUnit.Orig                        Test.Tasty.HUnit.Steps   other-extensions:    TypeFamilies, DeriveDataTypeable-  build-depends:       base ==4.*, tasty >= 0.8+  build-depends:       base ==4.*, tasty >= 0.8, call-stack   -- hs-source-dirs:         default-language:    Haskell2010   ghc-options: -Wall