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 +137/−109
- hspec.cabal +9/−6
- src/Test/Hspec.hs +13/−20
- src/Test/Hspec/HUnit.hs +12/−22
- src/Test/Hspec/Internal.hs +65/−51
- src/Test/Hspec/QuickCheck.hs +7/−19
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"))