packages feed

hspec 0.2.0 → 0.3.0

raw patch · 6 files changed

+243/−227 lines, 6 filesdep ~base

Dependency ranges changed: base

Files

Specs.hs view
@@ -1,16 +1,3 @@------------------------------------------------------------------------------------ Module      :  Specs--- Copyright   :  (c) Trystan Spangler 2011--- License     :  modified BSD------ Maintainer  : trystan.s@comcast.net--- Stability   : experimental--- Portability : portable------ |---------------------------------------------------------------------------------  module Specs where @@ -19,22 +6,23 @@ import Test.Hspec.HUnit () import System.IO import System.Environment-import Control.Monad (liftM)+import System.Exit import qualified Test.HUnit as HUnit  main :: IO () main = do   ar <- getArgs-  case ar of+  b <- case ar of     ["README"] -> withFile "README" WriteMode (\ h -> hPutStrLn h preable >> hHspec h specs)     [filename] -> withFile filename WriteMode (\ h -> hHspec h specs)-    _          -> hspec specs+    _          -> hspecB specs+  exitWith $ toExitCode b  preable :: String preable = unlines [     "hspec aims to be a simple, extendable, and useful tool for Behavior Driven Development in Haskell.", "",     "",-    "Step 1, write your specs",+    "Step 1, write descriptions and examples of your desired behavior",     "> specs = describe \"myabs\" [",     ">   it \"returns the original number when given a positive input\"",     ">     (myabs 1 == 1),",@@ -46,23 +34,33 @@     ">     (myabs 0 == 0)",     ">   ]",     "",-    "Step 2, write your dummy function",+    "Step 2, write whatever you are describing",     "> myabs n = undefined",     "",-    "Step 3, watch them fail",+    "Step 3, watch your examples fail",     "> hspec specs",     "myabs",-    " x returns the original number when given a positive input (Prelude.undefined)",-    " x returns a positive number when given a negative input (Prelude.undefined)",-    " x returns zero when given zero (Prelude.undefined)",+    " x returns the original number when given a positive input [1]",+    " x returns a positive number when given a negative input [2]",+    " x returns zero when given zero [3]",     "",+    "1) myabs returns the original number when given a positive input FAILED",+    "Prelude.undefined",+    "",+    "2) myabs returns a positive number when given a negative input FAILED",+    "Prelude.undefined",+    "",+    "3) myabs returns zero when given zero FAILED",+    "Prelude.undefined",+    "",     "Finished in 0.0002 seconds",     "",     "3 examples, 3 failures",     "",-    "Step 4, implement your requirements",-    "> myabs n = if n < 0 then negate n else n", "",-    "Step 5, watch them pass",+    "Step 4, implement your desired behavior",+    "> myabs n = if n < 0 then negate n else n",+    "",+    "Step 5, watch your examples pass",     "> hspec specs",     "myabs",     " - returns the original number when given a positive input",@@ -76,111 +74,141 @@     "",     "",     "",-    "Here's the report of hspec's specs:" ]+    "Here's the report of hspec's behavior:" ]  specs :: IO [Spec]-specs = let spec = Spec "Example" "example"-            testSpecs = [spec Success, spec (Fail ""), spec (Pending "")]-        in liftM concat $ sequence [+specs = do+  exampleSpecs <- describe "Example" [+    it "pass" (Success),+    it "fail 1" (Fail "fail message"),+    it "pending" (Pending "pending message"),+    it "fail 2" (HUnit.assertEqual "assertEqual test" 1 (2::Int)),+    it "exceptions" (undefined :: Bool),+    it "quickcheck" (property $ \ i -> i == (i+1::Integer))] -  describe "describe" [-    it "takes a description of what the requirements are for"-        ((=="Example") . name . head $ testSpecs),+  let report = pureHspec exampleSpecs -    it "groups requirements for what's being described"-        (all ((=="Example").name) testSpecs)-  ],-  describe "it" [-    it "takes a description of the requirement"-        (requirement (Spec "Example" "whatever" Success) == "whatever" ),+  -- uncomment the next line to aid in debugging+  --mapM_ putStrLn $ ["-- START example specs --"] ++ report ++ ["-- END example specs --"] -    it "takes an example of the requirement"-        (result (spec Success) == Success),+  -- the real specs+  descriptions [ -    it "can use a Bool, HUnit Test, QuickCheck property, or \"pending\" as an example"-        (True),+    describe "the \"describe\" function" [+        it "takes a description of what the behavior is for"+            ((=="Example") . name . head $ exampleSpecs), -    it "will treat exceptions as failures"-        (HUnit.TestCase $ do-          innerSpecs <- describe "" [ it "exceptions" (True && undefined)]-          let found = pureHspec innerSpecs !! 2-          HUnit.assertEqual (unlines $ pureHspec innerSpecs) " x exceptions (Prelude.undefined)" found),+        it "groups behaviors for what's being described"+            (all ((=="Example").name) exampleSpecs)+    ],+    describe "the \"it\" function" [+        it "takes a description of a desired behavior"+            (requirement (Spec "Example" "whatever" Success) == "whatever" ), -    it "allows failed examples to have details"-        (const True (Fail "details"))-  ],-  describe "Bool example" [-    it "is just an expression that evaluates to a Bool"-        (True)-  ],-  describe "HUnit example" [-    it "is specified with the HUnit \"TestCase\" data constructor"-        (HUnit.TestCase $ HUnit.assertBool "example" True),+        it "takes an example of that behavior"+            (result (Spec "Example" "whatever" Success) == Success), -    it "is the assumed example for IO() actions"-        (HUnit.assertBool "example" True),+        it "can use a Bool, HUnit Test, QuickCheck property, or \"pending\" as an example"+            (True), -    it "will show the assertion text if it fails"-        (HUnit.TestCase $ do-          innerSpecs <- describe "" [ it "fails" (HUnit.assertBool "trivial" False)]-          let found = pureHspec innerSpecs !! 2-          HUnit.assertEqual found " x fails (trivial)" found)-  ],-  describe "QuickCheck example" [-    it "is specified with the \"property\" function"-        (property $ \ b -> b || True)-  ],-  describe "pending example" [-    it "is specified with the \"pending\" function and an explanation"-        (pending "message" == Pending "message"),+        it "will treat exceptions as failures"+            (any (==" x exceptions [3]") report)+    ],+    describe "the \"hspec\" function" [+        it "displays a header for each thing being described"+            (any (=="Example") report), -    it "accepts a message to display in the report"-        (documentSpec (spec (Pending "t")) == " - example\n     # t")-  ],-  describe "hspec" [-    it "displays each thing being described as a header"-        (documentGroup [spec Success] !! 1 == "Example"),+        it "displays one row for each behavior"+            (HUnit.assertEqual "" 29 (length report)),+            -- 19 = group header + behaviors + blank lines + time + error messsages + pending message + example/failures footer -    it "displays one row for each requirement"-        (length (documentGroup testSpecs) == 5),+        it "displays a '-' for successfull examples"+            (any (==" - pass") report), -    it "displays a '-' for successfully implemented requirements"-        (documentSpec (spec Success) == " - example"),+        it "displays an 'x' for failed examples"+            (any (==" x fail 1 [1]") report), -    it "displays an 'x' for unsuccessfully implmented requirements"-        (documentSpec (spec $ Fail "whatever") == " x example (whatever)" ),+        it "displays a list of failed examples"+            (any (=="1) Example fail 1 FAILED") report), -    it "displays optional details for unsuccessfully implmented requirements"-        (documentSpec (spec $ Fail "whatever") == " x example (whatever)" ),+        it "displays available details for failed examples"+            (any (=="fail message") report), -    it "displays a '-' for requirements that are pending an example"-        (documentSpec (spec (Pending "pending")) == " - example\n     # pending" ),+        it "displays a '-' for pending examples"+            (any (==" - pending") report ), -    it "displays a '#' and an additional message for pending examples"-        (documentSpec (spec (Pending "pending")) == " - example\n     # pending" ),+        it "displays a '#' and an additional message for pending examples"+            (any (=="     # pending message") report ), -    it "can output to stdout"-        (True),+        it "summarizes the time it takes to finish"+            (any (=="Finished in 0.0000 seconds") (pureHspec exampleSpecs)), -    it "can output to stdout in color"-        (pending "TODO in the near future, perhaps using System.Console.ANSI?"),+        it "summarizes the number of examples and failures"+            (any (=="6 examples, 4 failures") (pureHspec exampleSpecs)), -    it "summarizes the time it takes to finish"-        (any (=="Finished in 0.0000 seconds") (pureHspec testSpecs)),+        it "outputs to stdout"+            (True)+    ],+    describe "Bool as an example" [+        it "is just an expression that evaluates to a Bool"+            (True)+    ],+    describe "HUnit TestCase as an example" [+        it "is specified with the HUnit \"TestCase\" data constructor"+            (HUnit.TestCase $ HUnit.assertBool "example" True), -    it "summarizes the number of examples and failures"-        (any (=="3 examples, 1 failure") (pureHspec testSpecs))-  ],-  describe "quantify (an internal function)" [-    it "returns an amount and a word given an amount and word"-        (quantify (1::Int) "thing" == "1 thing"),+        it "is the assumed example for IO() actions"+            (HUnit.assertBool "example" True), -    it "returns a singular word given the number 1"-        (quantify (1::Int) "thing" == "1 thing"),+        it "will show the failed assertion text if available (e.g. assertBool)"+            (HUnit.TestCase $ do+              innerSpecs <- describe "" [ it "" (HUnit.assertBool "trivial" False)]+              let innerReport = pureHspec innerSpecs+              HUnit.assertBool "should find assertion text" $ any (=="trivial") innerReport), -    it "returns a plural word given a number greater than 1"-        (quantify (2::Int) "thing" == "2 things"),+        it "will show the failed assertion expected and actual values if available (e.g. assertEqual)"+            (HUnit.TestCase $ do+              innerSpecs <- describe "" [ it "" (HUnit.assertEqual "trivial" (1::Int) 2)]+              let innerReport = pureHspec innerSpecs+              HUnit.assertBool "should find assertion text" $ any (=="trivial") innerReport+              HUnit.assertBool "should find 'expected: 1'" $ any (=="expected: 1") innerReport+              HUnit.assertBool "should find ' but got: 2'" $ any (==" but got: 2") innerReport)+    ],+    describe "QuickCheck property as an example" [+        it "is specified with the \"property\" function"+            (property $ \ b -> b || True), -    it "returns a plural word given the number 0"-        (quantify (0::Int) "thing" == "0 things")-  ]]+        it "will show what falsified it"+            (any (=="0") report)+        ],+    describe "pending as an example" [+        it "is specified with the \"pending\" function and an explanation"+            (pending "message" == Pending "message"),++        it "accepts a message to display in the report"+            (any (== "     # pending message") report)+        ],+    describe "hspecB" [+        it "returns true if no examples failed"+            (HUnit.TestCase $ do+              ss <- describe "" [it "" Success]+              HUnit.assertEqual "no errors" True (snd $ pureHspecB ss)),++        it "returns false if any examples failed"+            (HUnit.TestCase $ do+              ss <- describe "" [it "" (Fail "test")]+              HUnit.assertEqual "one error" False (snd $ pureHspecB ss))+    ],+    describe "quantify (an internal function)" [+        it "returns an amount and a word given an amount and word"+            (quantify (1::Int) "thing" == "1 thing"),++        it "returns a singular word given the number 1"+            (quantify (1::Int) "thing" == "1 thing"),++        it "returns a plural word given a number greater than 1"+            (quantify (2::Int) "thing" == "2 things"),++        it "returns a plural word given the number 0"+            (quantify (0::Int) "thing" == "0 things")+    ]]
hspec.cabal view
@@ -1,18 +1,21 @@ name: hspec-version: 0.2.0+version: 0.3.0 cabal-version: -any build-type: Custom license: BSD3 license-file: LICENSE-copyright: (c) Trystan Spangler 2011+copyright: (c) 2011 Trystan Spangler maintainer: trystan.s@comcast.net-build-depends: HUnit >= 1 && <= 2, QuickCheck >= 2.4.0.1 && <= 2.5, base >=4.2 && <=4.3+build-depends: HUnit >=1 && <=2, QuickCheck >=2.4.0.1 && <=2.5,+               base >=4 && <=5 stability: experimental homepage: https://github.com/trystan/hspec-package-url:-bug-reports:+package-url: https://github.com/trystan/hspec+bug-reports: mailto:trystan.s@comcast.net synopsis: Behavior Driven Development for Haskell description: Behavior Driven Development for Haskell+             .+             Hspec is based on the Ruby library RSpec - so much of what applies to RSpec also applies to Hspec. Hspec ties together /descriptions/ of behavior and /examples/ of that behavior. The examples can then be run as tests and the output summarises what needs to be implemented. category: Testing author: Trystan Spangler tested-with:@@ -32,7 +35,7 @@ pkgconfig-depends: frameworks: c-sources:-extensions:+extensions: FlexibleInstances extra-libraries: extra-lib-dirs: includes:
src/Test/Hspec.hs view
@@ -1,16 +1,4 @@------------------------------------------------------------------------------------ Module      :  Test.Hspec--- Copyright   :  (c) Trystan Spangler 2011--- License     :  modified------ Maintainer  : trystan.s@comcast.net--- Stability   : experimental--- Portability : portable--------------------------------------------------------------------------------- - -- | Hspec is a Behaviour-Driven Development tool for Haskell programmers. BDD is an approach -- to software development that combines Test-Driven Development, Domain Driven Design, and -- Acceptance Test-Driven Planning. Hspec helps you do the TDD part of that equation, focusing@@ -33,8 +21,8 @@ -- > main = hspec mySpecs -- -- Since the specs are often used to tell you what to implement, it's best to start with--- undefined functions. Once we have some specs, then you can implement each requirement--- one at a time, ensuring that each requirement is met and there is no undocumented behavior.+-- undefined functions. Once we have some specs, then you can implement each behavior+-- one at a time, ensuring that each behavior is met and there is no undocumented behavior. -- -- > unformatPhoneNumber :: String -> String -- > unformatPhoneNumber number = undefined@@ -42,21 +30,21 @@ -- > formatPhoneNumber :: String -> String -- > formatPhoneNumber number = undefined ----- The "describe" function takes a list of requirements and examples bound together with the "it" function+-- The "describe" function takes a list of behaviors and examples bound together with the "it" function -- -- > mySpecs = describe "unformatPhoneNumber" [ ----- A boolean expression can act as a requirement's example.+-- A boolean expression can act as a behavior's example. -- -- >   it "removes dashes, spaces, and parenthesies" -- >       (unformatPhoneNumber "(555) 555-1234" == "5555551234"), ----- The "pending" function marks a requirement as pending an example. It won't Fail.+-- The "pending" function marks a behavior as pending an example. The example doesn't count as failing. -- -- >   it "handles non-US phone numbers" -- >       (pending "need to look up how other cultures format phone numbers"), ----- An HUnit "Test" can act as a requirement's example. (must import @Test.Hspec.HUnit@)+-- An HUnit "Test" can act as a behavior's example. (must import @Test.Hspec.HUnit@) -- -- >   it "removes the \"ext\" prefix of the extension" -- >       (TestCase $ let expected = "5555551234135"@@ -73,7 +61,7 @@ -- -- The "property" function allows a QuickCheck property to act as an example. (must import @Test.Hspec.HUnit@) ----- >   it "can add and add remove formatting without changing the number"+-- >   it "can add and remove formatting without changing the number" -- >       (property $ forAll phoneNumber $ -- >         \ n -> unformatPhoneNumber (formatPhoneNumber n) == n) -- >   ]@@ -84,7 +72,12 @@ -- >   vectorOf nums (elements "0123456789") -- module Test.Hspec (-  Spec(), Result(), describe, it, pending, pureHspec, hHspec, hspec+  -- types+  Spec(), Result(),+  -- the main api+  describe, it, hspec, pending, descriptions,+  -- alternate "runner" functions+  hHspec, hspecX, hspecB, pureHspec, pureHspecB ) where  import Test.Hspec.Internal
src/Test/Hspec/HUnit.hs view
@@ -1,20 +1,8 @@-{-# OPTIONS -XFlexibleInstances #-}------------------------------------------------------------------------------------ Module      :  Test.Hspec.HUnit--- Copyright   :  (c) Trystan Spangler 2011--- License     :  modified BSD------ Maintainer  : trystan.s@comcast.net--- Stability   : experimental--- Portability : portable----------------------------------------------------------------------------------+{-# OPTIONS -XFlexibleInstances -fno-warn-orphans #-} --- | Importing this module allows you to use an HUnit test case as an example--- for a requirement. You can use an explicit TestCase data constructor or--- use an IO() action. For an IO() action, any exception means the example+-- | Importing this module allows you to use an @HUnit@ test case as an example+-- for a behavior. You can use an explicit @TestCase@ data constructor or+-- use an @IO()@ action. For an @IO()@ action, any exception means the example -- failed; otherwise, it's successfull. -- -- > describe "cutTheDeck" [@@ -30,15 +18,17 @@  import Test.Hspec.Internal import qualified Test.HUnit as HU+import Data.List (intersperse)  instance SpecVerifier (IO ()) where-  it n t = it n (HU.TestCase t)+  it description example = it description (HU.TestCase example)  instance SpecVerifier HU.Test where-  it n t = do-    (counts, fails) <- HU.runTestText HU.putTextToShowS t-    let rows = lines (fails "")+  it description example = do+    (counts, fails) <- HU.runTestText HU.putTextToShowS example     if HU.errors counts + HU.failures counts == 0-      then return (n, Success)-      else return (n, Fail (rows !! 1))+      then return (description, Success)+      else return (description, Fail (details $ fails "")) +details :: String -> String+details = concat . intersperse "\n" . tail . init . lines
src/Test/Hspec/Internal.hs view
@@ -1,24 +1,14 @@ {-# OPTIONS -XFlexibleInstances #-}------------------------------------------------------------------------------------ Module      :  Test.Hspec.Internal--- Copyright   :  (c) Trystan Spangler 2011--- License     :  modified BSD------ Maintainer  : trystan.s@comcast.net--- Stability   : experimental--- Portability : portable--------------------------------------------------------------------------------- - module Test.Hspec.Internal where  import System.IO-import Data.List (groupBy)+import System.Exit+import Data.List (mapAccumL, groupBy, intersperse) import System.CPUTime (getCPUTime) import Text.Printf import Control.Exception+import Control.Monad (liftM)  -- | The result of running an example. data Result = Success | Fail String | Pending String@@ -29,9 +19,9 @@ data Spec = Spec {                  -- | What is being tested, usually the name of a type.                  name::String,-                 -- | The specific requirement being tested.+                 -- | The specific behavior being tested.                  requirement::String,-                 -- | The status of this requirement.+                 -- | The status of this behavior.                  result::Result }  @@ -44,12 +34,15 @@ -- >   ] -- describe :: String                -- ^ The name of what is being described, usually a function or type.-         -> [IO (String, Result)] -- ^ A list of requirements and examples, created by a list of 'it'.+         -> [IO (String, Result)] -- ^ A list of behaviors and examples, created by a list of 'it'.          -> IO [Spec] describe n ss = do   ss' <- sequence ss   return $ map (\ (req, res) -> Spec n req res) ss' +-- | Combine a list of descriptions.+descriptions :: [IO [Spec]] -> IO [Spec]+descriptions = liftM concat . sequence  -- | Evaluate a Result. Any exceptions (undefined, etc.) are treated as failures. safely :: Result -> IO Result@@ -58,9 +51,9 @@         failed e = return $ Fail (show (e :: SomeException))  --- | Anything that can be used as an example of a requirement.+-- | Anything that can be used as an example of a behavior. class SpecVerifier a where-  -- | Create a description and example of a requirement, a list of these+  -- | Create a description and example of a behavior, a list of these   -- is used by 'describe'. Once you know what you want to specify, use this.   --   -- > describe "closeEnough" [@@ -71,63 +64,69 @@   -- >     (not $ 1.001 `closeEnough` 1.003)   -- >   ]   ---  it :: String           -- ^ A description of this requirement.-     -> a                -- ^ A example for this requirement.-     -> IO (String, Result) -- ^ The combined description and result of the example.+  it :: String           -- ^ A description of this behavior.+     -> a                -- ^ An example for this behavior.+     -> IO (String, Result)   instance SpecVerifier Bool where-  it n b = do-    r <- safely (if b then Success else Fail "")-    return (n, r)+  it description example = do+    r <- safely (if example then Success else Fail "")+    return (description, r)  instance SpecVerifier Result where-  it n r = return (n, r)+  it description example = return (description, example)   -- | Declare an example as not successful or failing but pending some other work.--- If you want to track a requirement but don't expect it to succeed or fail yet, use this.+-- If you want to report on a behavior but don't have an example yet, use this. -- -- > describe "fancyFormatter" [ -- >   it "can format text in a way that everyone likes" -- >     (pending "waiting for clarification from the designers") -- >   ] ---pending :: String  -- ^ An explanation for why this requirement is pending.+pending :: String  -- ^ An explanation for why this behavior is pending.         -> Result pending = Pending   -- | Create a document of the given specs. documentSpecs :: [Spec] -> [String]-documentSpecs = concatMap documentGroup . groupBy (\ a b -> name a == name b)-+documentSpecs specs = lines $ unlines $ concat report ++ [""] ++ intersperse "" errors+  where organize = groupBy (\ a b -> name a == name b)+        (errors, report) = mapAccumL documentGroup [] $ organize specs  -- | Create a document of the given group of specs.-documentGroup :: [Spec] -> [String]-documentGroup specGroup = "" : name (head specGroup) : map documentSpec specGroup-+documentGroup :: [String] -> [Spec] -> ([String], [String])+documentGroup errors specGroup = (errors', "" : name (head specGroup) : report)+  where (errors', report) = mapAccumL documentSpec errors specGroup  -- | Create a document of the given spec.-documentSpec :: Spec -> String-documentSpec spec  = case result spec of-                Success    -> " - " ++ requirement spec-                Fail ""    -> " x " ++ requirement spec-                Fail s     -> " x " ++ requirement spec ++ " (" ++ s ++ ")"-                Pending s  -> " - " ++ requirement spec ++ "\n     # " ++ s+documentSpec :: [String] -> Spec -> ([String], String)+documentSpec errors spec = case result spec of+                Success    -> (errors, " - " ++ requirement spec)+                Fail s     -> (errors ++ [errorDetails s], " x " ++ requirement spec ++ errorTag)+                Pending s  -> (errors, " - " ++ requirement spec ++ "\n     # " ++ s)+    where errorTag = " [" ++ (show $ length errors + 1) ++ "]"+          errorDetails s  = concat [ show (length errors + 1), ") ", name spec,+                                     " ",  requirement spec, " FAILED",+                                     if null s then "" else "\n" ++ s ]   -- | Create a summary of how long it took to run the examples. timingSummary :: Double -> String timingSummary t = printf "Finished in %1.4f seconds" (t / (10.0^(12::Integer)) :: Double) +failedCount :: [Spec] -> Int+failedCount ss = length $ filter (isFailure.result) ss+  where+    isFailure (Fail _) = True+    isFailure _        = False  -- | Create a summary of how many specs exist and how many examples failed. successSummary :: [Spec] -> String-successSummary ss = quantify (length ss) "example" ++ ", " ++ quantify failed "failure"-    where failed = length $ filter (isFailure.result) ss-          isFailure (Fail _) = True-          isFailure _        = False+successSummary ss = quantify (length ss) "example" ++ ", " ++ quantify (failedCount ss) "failure"   -- | Create a document of the given specs.@@ -135,18 +134,37 @@ -- a description of each spec and don't need to know how long it tacks to check, -- use this. pureHspec :: [Spec]   -- ^ The specs you are interested in.-          -> [String] -- ^ A human-readable summary of the specs and which are unsuccessfully implemented.-pureHspec ss = documentSpecs ss ++ [ "", timingSummary 0, "", successSummary ss]+          -> [String]+pureHspec = fst . pureHspecB  +pureHspecB :: [Spec]   -- ^ The specs you are interested in.+          -> ([String], Bool)+pureHspecB ss = (report, failedCount ss == 0)+  where report = documentSpecs ss ++ [ "", timingSummary 0, "", successSummary ss]++ -- | Create a document of the given specs and write it to stdout. -- This does track how much time it took to check the examples. Use this if -- you want a description of each spec and do need to know how long it tacks -- to check the examples or want to write to stdout. hspec :: IO [Spec] -> IO ()-hspec = hHspec stdout+hspec ss = hspecB ss >> return () +-- | Same as 'hspec' except it returns a bool indicating if all examples ran without failures+hspecB :: IO [Spec] -> IO Bool+hspecB = hHspec stdout +-- | Same as 'hspec' except the program exits successfull if all examples ran without failures or+-- with an errorcode of 1 if any examples failed.+hspecX :: IO [Spec] -> IO a+hspecX ss = hspecB ss >>= exitWith . toExitCode++toExitCode :: Bool -> ExitCode+toExitCode True  = ExitSuccess+toExitCode False = ExitFailure 1++ -- | Create a document of the given specs and write it to the given handle. -- This does track how much time it took to check the examples. Use this if -- you want a description of each spec and do need to know how long it tacks@@ -156,21 +174,17 @@ -- hHspec :: Handle     -- ^ A handle for the stream you want to write to.        -> IO [Spec]  -- ^ The specs you are interested in.-       -> IO ()+       -> IO Bool hHspec h ss = do   t0 <- getCPUTime   ss' <- ss   mapM_ (hPutStrLn h) $ documentSpecs ss'   t1 <- getCPUTime   mapM_ (hPutStrLn h) [ "", timingSummary (fromIntegral $ t1 - t0), "", successSummary ss']-+  return $ failedCount ss' == 0   -- | Create a more readable display of a quantity of something. quantify :: Num a => a -> String -> String quantify 1 s = "1 " ++ s quantify n s = show n ++ " " ++ s ++ "s"----
src/Test/Hspec/QuickCheck.hs view
@@ -1,18 +1,6 @@------------------------------------------------------------------------------------ Module      :  Test.Hspec.QuickCheck--- Copyright   :  (c) Trystan Spangler 2011--- License     :  modified BSD------ Maintainer  : trystan.s@comcast.net--- Stability   : experimental--- Portability : portable--------------------------------------------------------------------------------- - -- | Importing this module allows you to use a QuickCheck property as an example--- for a requirement. Use the 'property' function to indicate a QuickCkeck property.+-- for a behavior. Use the 'property' function to indicate a QuickCkeck property. -- -- > describe "cutTheDeck" [ -- >   it "puts the first half of a list after the last half"@@ -37,10 +25,10 @@ property = QuickCheckProperty  instance QC.Testable t => SpecVerifier (QuickCheckProperty t) where-  it n (QuickCheckProperty p) = do-    r <- QC.quickCheckResult p+  it description (QuickCheckProperty prop) = do+    r <- QC.quickCheckResult prop     case r of-      QC.Success {}           -> return (n, Success)-      f@(QC.Failure {})       -> return (n, Fail (QC.reason f))-      g@(QC.GaveUp {})        -> return (n, Fail ("Gave up after " ++ quantify (QC.numTests g) "test" ))-      QC.NoExpectedFailure {} -> return (n, Fail ("No expected failure"))+      QC.Success {}           -> return (description, Success)+      f@(QC.Failure {})       -> return (description, Fail (QC.output f))+      g@(QC.GaveUp {})        -> return (description, Fail ("Gave up after " ++ quantify (QC.numTests g) "test" ))+      QC.NoExpectedFailure {} -> return (description, Fail ("No expected failure"))