hspec 1.1.3 → 1.2.0
raw patch · 16 files changed
+362/−345 lines, 16 filesdep +doctestdep +hspecdep +hspec-discoverdep ~HUnitdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: doctest, hspec, hspec-discover
Dependency ranges changed: HUnit, base
API changes (from Hackage documentation)
- Test.Hspec: descriptions :: Specs -> Specs
- Test.Hspec: hspecX :: Specs -> IO a
- Test.Hspec.Core: SpecExample :: String -> a -> SpecTree a
- Test.Hspec.Core: SpecGroup :: String -> [SpecTree a] -> SpecTree a
- Test.Hspec.Core: data SpecTree a
- Test.Hspec.Core: descriptions :: Specs -> Specs
- Test.Hspec.Core: failedCount :: [EvaluatedSpec] -> Int
- Test.Hspec.Core: failure :: [EvaluatedSpec] -> Bool
- Test.Hspec.Core: hspecX :: Specs -> IO a
- Test.Hspec.Core: isFailure :: Result -> Bool
- Test.Hspec.Core: safeEvaluateExample :: AnyExample -> IO Result
- Test.Hspec.Core: success :: [EvaluatedSpec] -> Bool
- Test.Hspec.Core: type AnyExample = IO Result
- Test.Hspec.Core: type EvaluatedSpec = SpecTree Result
- Test.Hspec.Core: type UnevaluatedSpec = Spec
- Test.Hspec.Monadic: descriptions :: [Spec] -> Spec
- Test.Hspec.Monadic: hspecX :: Spec -> IO a
- Test.Hspec.Monadic: type Spec = SpecM ()
- Test.Hspec.Monadic: type Specs = SpecM ()
- Test.Hspec.Runner: describe :: String -> [Spec] -> Spec
- Test.Hspec.Runner: it :: Example a => String -> a -> Spec
+ Test.Hspec: Summary :: Int -> Int -> Summary
+ Test.Hspec: data Summary
+ Test.Hspec: summaryExamples :: Summary -> Int
+ Test.Hspec: summaryFailures :: Summary -> Int
+ Test.Hspec.Core: Summary :: Int -> Int -> Summary
+ Test.Hspec.Core: data Summary
+ Test.Hspec.Core: summaryExamples :: Summary -> Int
+ Test.Hspec.Core: summaryFailures :: Summary -> Int
+ Test.Hspec.Monadic: Summary :: Int -> Int -> Summary
+ Test.Hspec.Monadic: data Summary
+ Test.Hspec.Monadic: summaryExamples :: Summary -> Int
+ Test.Hspec.Monadic: summaryFailures :: Summary -> Int
+ Test.Hspec.Runner: Summary :: Int -> Int -> Summary
+ Test.Hspec.Runner: data Summary
+ Test.Hspec.Runner: instance Eq Summary
+ Test.Hspec.Runner: instance Monoid Summary
+ Test.Hspec.Runner: instance Show Summary
+ Test.Hspec.Runner: summaryExamples :: Summary -> Int
+ Test.Hspec.Runner: summaryFailures :: Summary -> Int
- Test.Hspec: hHspec :: Handle -> Specs -> IO [EvaluatedSpec]
+ Test.Hspec: hHspec :: Handle -> Specs -> IO Summary
- Test.Hspec: hspec :: Specs -> IO [EvaluatedSpec]
+ Test.Hspec: hspec :: Specs -> IO ()
- Test.Hspec.Core: hHspec :: Handle -> Specs -> IO [EvaluatedSpec]
+ Test.Hspec.Core: hHspec :: Handle -> Specs -> IO Summary
- Test.Hspec.Core: hspec :: Specs -> IO [EvaluatedSpec]
+ Test.Hspec.Core: hspec :: Specs -> IO ()
- Test.Hspec.Core: quantify :: (Show a, Num a, Eq a) => a -> String -> String
+ Test.Hspec.Core: quantify :: Int -> String -> String
- Test.Hspec.Monadic: hHspec :: Handle -> Spec -> IO [EvaluatedSpec]
+ Test.Hspec.Monadic: hHspec :: Handle -> Spec -> IO Summary
- Test.Hspec.Monadic: hspec :: Spec -> IO [EvaluatedSpec]
+ Test.Hspec.Monadic: hspec :: Spec -> IO ()
- Test.Hspec.Runner: hHspec :: Handle -> Specs -> IO [EvaluatedSpec]
+ Test.Hspec.Runner: hHspec :: Handle -> Specs -> IO Summary
- Test.Hspec.Runner: hHspecWithFormat :: Formatter -> Bool -> Handle -> Specs -> IO [EvaluatedSpec]
+ Test.Hspec.Runner: hHspecWithFormat :: Formatter -> Bool -> Handle -> Specs -> IO Summary
- Test.Hspec.Runner: hspec :: Specs -> IO [EvaluatedSpec]
+ Test.Hspec.Runner: hspec :: Specs -> IO ()
Files
- Specs.hs +0/−158
- Test/Hspec.hs +14/−2
- Test/Hspec/Core.hs +100/−42
- Test/Hspec/Formatters.hs +4/−3
- Test/Hspec/Formatters/Internal.hs +2/−1
- Test/Hspec/HUnit.hs +4/−5
- Test/Hspec/Internal.hs +19/−33
- Test/Hspec/Monadic.hs +42/−21
- Test/Hspec/Pending.hs +14/−0
- Test/Hspec/QuickCheck.hs +6/−6
- Test/Hspec/Runner.hs +48/−31
- example/NonMonadic.hs +23/−0
- example/Spec.hs +21/−0
- hspec.cabal +58/−34
- test/Spec.hs +1/−9
- test/doctests.hs +6/−0
− Specs.hs
@@ -1,158 +0,0 @@-{-# OPTIONS_GHC -fno-warn-deprecations #-}-module Main (main) where--import Test.Hspec.ShouldBe (Specs, describe, it, hspecX)--import qualified Test.Hspec as H-import Test.Hspec hiding (Specs, describe, it, hspecX)-import Test.Hspec.Runner (hHspecWithFormat)-import Test.Hspec.Internal (SpecTree(..), Spec(..), Result(..), quantify)-import Test.Hspec.Formatters-import Test.Hspec.QuickCheck-import Test.Hspec.HUnit ()-import Test.HUnit-import System.IO-import System.IO.Silently-import Data.List (isPrefixOf)-import qualified Test.HUnit as HUnit--main :: IO ()-main = specs >>= hspecX--specs :: IO Specs-specs = do- let testSpecs = [H.describe "Example" [- H.it "success" (Success),- H.it "fail 1" (Fail "fail message"),- H.it "pending" (pending "pending message"),- H.it "fail 2" (HUnit.assertEqual "assertEqual test" 1 (2::Int)),- H.it "exceptions" (undefined :: Bool),- H.it "quickcheck" (property $ \ i -> i == (i+1::Integer))]- ]-- (reportContents, exampleSpecs) <- capture $ hHspecWithFormat specdoc False stdout testSpecs- (silentReportContents, _) <- capture $ hHspecWithFormat silent False stdout testSpecs- (progressReportContents, _) <- capture $ hHspecWithFormat progress False stdout testSpecs- (failed_examplesReportContents, _) <- capture $ hHspecWithFormat failed_examples False stdout testSpecs-- let report = lines reportContents-- return $ do- describe "the \"describe\" function" $ do- it "takes a description of what the behavior is for" $- case exampleSpecs of- [SpecGroup "Example" _] -> True- _ -> False-- it "groups behaviors for what's being described" $- case exampleSpecs of- [SpecGroup _ xs] -> length xs == 6- _ -> False-- describe "a nested description" $ do- it "has it's own specs"- (True)-- describe "the \"it\" function" $ do- it "takes a description of a desired behavior" $- case unSpec $ H.it "whatever" Success of- SpecExample requirement _ -> requirement == "whatever"- _ -> False-- it "takes an example of that behavior" $ do- case unSpec $ H.it "whatever" Success of- SpecExample _ example -> do- r <- example- r @?= Success- SpecGroup _ _ -> assertFailure "unexpected SpecGroup"-- it "can use a Bool, HUnit Test, QuickCheck property, or \"pending\" as an example"- (True)-- it "will treat exceptions as failures"- (any (==" - exceptions FAILED [3]") report)-- describe "the \"hspec\" function" $ do- it "displays a header for each thing being described"- (any (=="Example") report)-- it "displays one row for each behavior"- (HUnit.assertEqual "" 29 (length report))-- it "displays a row for each successfull, failed, or pending example"- (any (==" - success") report && any (==" - fail 1 FAILED [1]") report)-- it "displays a detailed list of failed examples"- (any (=="1) Example fail 1 FAILED") report)-- it "displays a '#' with an additional message for pending examples"- (any (==" # PENDING: pending message") report )-- it "summarizes the time it takes to finish"- (any ("Finished in " `isPrefixOf`) report)-- it "summarizes the number of examples and failures"- (any (=="6 examples, 4 failures") report)-- it "outputs failed examples in red, pending in yellow, and successful in green"- (True)-- describe "Bool as an example" $ do- it "is just an expression that evaluates to a Bool"- (True)-- describe "HUnit TestCase as an example" $ do- it "is specified with the HUnit \"TestCase\" data constructor"- (HUnit.TestCase $ HUnit.assertBool "example" True)-- it "is the assumed example for IO() actions"- (HUnit.assertBool "example" True)-- it "will show the failed assertion text if available (e.g. assertBool)" $ do- (innerReport, _) <- capture $ hspec $ [H.describe "" [ H.it "" (HUnit.assertBool "trivial" False)]]- HUnit.assertBool "should find assertion text" $ any (=="trivial") (lines innerReport)-- it "will show the failed assertion expected and actual values if available (e.g. assertEqual)" $ do- (innerReportContents, _) <- capture $ hspec $ [H.describe "" [ H.it "" (HUnit.assertEqual "trivial" (1::Int) 2)]]- let innerReport = lines innerReportContents- 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" $ do- it "is specified with the \"property\" function"- (property $ \ b -> b || True)-- it "will show what falsified it"- (any (=="0") report)-- describe "pending as an example" $ do- it "is specified with the \"pending\" function and an explanation" True-- it "accepts a message to display in the report" True-- describe "the \"hHspecWithFormat\" function" $ do- it "can use the \"silent\" formatter to show no output"- (null silentReportContents)-- it "can use the \"progress\" formatter to show '..F...FF.F' style output"- (HUnit.assertEqual "" ".F.FFF" (head $ lines progressReportContents))-- it "can use the \"specdoc\" formatter to show all examples (default)"- (HUnit.assertEqual "" "Example" (lines reportContents !! 1))-- it "can use the \"failed_examples\" formatter to show only failed examples"- (HUnit.assertEqual "" "1) Example fail 1 FAILED" (lines failed_examplesReportContents !! 1))-- describe "quantify (an internal function)" $ do- 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")
Test/Hspec.hs view
@@ -1,3 +1,4 @@+{-# OPTIONS_HADDOCK prune #-} -- | -- Hspec is a Behaviour-Driven Development tool for Haskell programmers. BDD is -- an approach to software development that combines Test-Driven Development,@@ -34,14 +35,25 @@ -- * Running a spec , hspec , hspecB-, hspecX , hHspec+, Summary (..) --- * Deprecated functions+++++-- deprecated functions , descriptions+, hspecX+++ ) where import Test.Hspec.Core+++ -- $intro --
Test/Hspec/Core.hs view
@@ -1,8 +1,27 @@-{-# OPTIONS_GHC -fno-warn-deprecations #-}+{-# OPTIONS_HADDOCK prune #-} -- |--- This module contains the core types, constructors, classes, instances, and--- utility functions common to hspec.+-- 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 on the documentation and design+-- aspects of TDD.+--+-- Hspec (and the preceding intro) are based on the Ruby library RSpec. Much of+-- what applies to RSpec also applies to Hspec. Hspec ties together+-- /descriptions/ of behavior and /examples/ of that behavior. The examples can+-- also be run as tests and the output summarises what needs to be implemented.+--+-- NOTE: There is a monadic and a non-monadic API. This is the documentation+-- for the non-monadic API. The monadic API is more stable, so you may prefer+-- it over this one. For documentation on the monadic API look at+-- "Test.Hspec.Monadic".+ module Test.Hspec.Core (+++-- * Introduction+-- $intro+ -- * Types Spec , Specs@@ -17,29 +36,19 @@ -- * Running a spec , hspec , hspecB-, hspecX , hHspec+, Summary (..) -- * Internals-, SpecTree (..)-, EvaluatedSpec-, Result (..) , quantify+, Result (..) --- * Deprecated types and functions--- | The following types and functions are deprecated and will be removed with--- the next release.------ If you still need any of those, please open an issue and describe your use--- case: <https://github.com/hspec/hspec/issues>+-- deprecated stuff , descriptions+, hspecX , AnyExample , safeEvaluateExample , UnevaluatedSpec-, success-, failure-, isFailure-, failedCount ) where import Test.Hspec.Internal hiding (safeEvaluateExample)@@ -47,36 +56,85 @@ import Test.Hspec.Pending import Test.Hspec.Runner +-- $intro+--+-- The three functions you'll use the most are 'hspecX', 'describe', and 'it'.+-- Here is an example of functions that format and unformat phone numbers and+-- the specs for them.+--+-- > import Test.Hspec+-- > import Test.Hspec.QuickCheck+-- > import Test.Hspec.HUnit ()+-- > import Test.QuickCheck+-- > import Test.HUnit+-- >+-- > main = hspecX 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 behavior one at a time, ensuring that each behavior is met+-- and there is no undocumented behavior.+--+-- > unformatPhoneNumber :: String -> String+-- > unformatPhoneNumber number = undefined+-- >+-- > formatPhoneNumber :: String -> String+-- > formatPhoneNumber number = undefined+--+-- 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 behavior's example.+--+-- > it "removes dashes, spaces, and parenthesies" $+-- > unformatPhoneNumber "(555) 555-1234" == "5555551234"+-- > ,+--+-- 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.HUnit.Test' can act as a behavior's example. (must import+-- "Test.Hspec.HUnit")+--+-- > it "removes the \"ext\" prefix of the extension" $ TestCase $ do+-- > let expected = "5555551234135"+-- > actual = unformatPhoneNumber "(555) 555-1234 ext 135"+-- > expected @?= actual+-- > ,+--+-- An @IO()@ action is treated like an HUnit 'TestCase'. (must import+-- "Test.Hspec.HUnit")+--+-- > it "converts letters to numbers" $ do+-- > let expected = "6862377"+-- > actual = unformatPhoneNumber "NUMBERS"+-- > actual @?= expected+-- > ,+--+-- The 'property' function allows a QuickCheck property to act as an example.+-- (must import "Test.Hspec.QuickCheck")+--+-- > it "can add and remove formatting without changing the number" $ property $+-- > forAll phoneNumber $ \n -> unformatPhoneNumber (formatPhoneNumber n) == n+-- > ]]+-- >+-- > phoneNumber :: Gen String+-- > phoneNumber = do+-- > n <- elements [7,10,11,12,13,14,15]+-- > vectorOf n (elements "0123456789")+ {-# DEPRECATED UnevaluatedSpec "use Spec instead" #-} type UnevaluatedSpec = Spec --- | DEPRECATED: This is no longer needed (it's just an alias for `id` now).+{-# DEPRECATED descriptions "this is no longer needed, and will be removed in a future release" #-} descriptions :: Specs -> Specs descriptions = id-{-# DEPRECATED descriptions "this is no longer needed, and will be removed in a future release" #-}--{-# DEPRECATED success "This will be removed with the next major release. If you still need this, raise your voice!" #-}-success :: [EvaluatedSpec] -> Bool-success = not . failure--{-# DEPRECATED failure "This will be removed with the next major release. If you still need this, raise your voice!" #-}-failure :: [EvaluatedSpec] -> Bool-failure = any p- where- p (SpecGroup _ xs) = any p xs- p (SpecExample _ x) = isFailure x--{-# DEPRECATED isFailure "This will be removed with the next major release. If you still need this, raise your voice!" #-}-isFailure :: Result -> Bool-isFailure (Fail _) = True-isFailure _ = False--{-# DEPRECATED failedCount "This will be removed with the next major release. If you still need this, raise your voice!" #-}-failedCount :: [EvaluatedSpec] -> Int-failedCount = sum . map count- where- count (SpecGroup _ xs) = sum (map count xs)- count (SpecExample _ x) = if isFailure x then 1 else 0 {-# DEPRECATED AnyExample "This will be removed with the next major release. If you still need this, raise your voice!" #-} type AnyExample = IO Result
Test/Hspec/Formatters.hs view
@@ -43,6 +43,7 @@ import Data.List (intersperse) import Text.Printf import Control.Monad (unless)+import Control.Applicative -- We use an explicit import list for "Test.Hspec.Formatters.Internal", to make -- sure, that we only use the public API to implement formatters.@@ -134,12 +135,12 @@ defaultFooter :: FormatM () defaultFooter = do- cpuTime <- getCPUTime- time <- getRealTime++ writeLine =<< printf "Finished in %1.4f seconds, used %1.4f seconds of CPU time" <$> getRealTime <*> getCPUTime+ fails <- getFailCount total <- getTotalCount (if fails == 0 then withSuccessColor else withFailColor) $ do- writeLine $ printf "Finished in %1.4f seconds, used %1.4f seconds of CPU time" time cpuTime writeLine "" write $ quantify total "example" ++ ", " writeLine $ quantify fails "failure"
Test/Hspec/Formatters/Internal.hs view
@@ -32,6 +32,7 @@ import qualified System.IO as IO import System.IO (Handle) import Control.Monad (when)+import Control.Applicative import Control.Exception (bracket_) import System.Console.ANSI import Control.Monad.Trans.State hiding (gets, modify)@@ -72,7 +73,7 @@ totalCount s = successCount s + pendingCount s + failCount s newtype FormatM a = FormatM (StateT FormatterState IO a)- deriving (Functor, Monad)+ deriving (Functor, Applicative, Monad) runFormatM :: Bool -> Handle -> FormatM a -> IO a runFormatM useColor handle (FormatM action) = do
Test/Hspec/HUnit.hs view
@@ -23,8 +23,7 @@ -- > it "gives the original list, if applied twice" $ TestCase $ -- > (reverse . reverse) [1, 2, 3] @?= [1, 2, 3] ---module Test.Hspec.HUnit (-) where+module Test.Hspec.HUnit () where import System.IO.Silently import Test.Hspec.Core@@ -41,6 +40,6 @@ then Success else Fail (details $ fails "") return r--details :: String -> String-details = concat . intersperse "\n" . tail . init . lines+ where+ details :: String -> String+ details = concat . intersperse "\n" . tail . init . lines
Test/Hspec/Internal.hs view
@@ -1,9 +1,6 @@-{-# LANGUAGE FlexibleInstances #-} module Test.Hspec.Internal (- SpecTree (..)-, Spec (..)+ Spec (..) , Specs-, EvaluatedSpec , Example (..) , safeEvaluateExample , Result (..)@@ -16,37 +13,21 @@ where import Control.Exception-import qualified Test.Hspec.Pending as Pending +-- | A list of specs. type Specs = [Spec]-type EvaluatedSpec = SpecTree Result -- | The result of running an example. data Result = Success | Pending (Maybe String) | Fail String deriving (Eq, Show) -newtype Spec = Spec {unSpec :: SpecTree (IO Result)}---- IMPORTANT: Remove this warnings and remove -fno-warn-deprecations from the--- following modules/files when making SpecGroup abstract.------ * Spec.hs--- * Test.Hspec.Runner--- * Test.Hspec.Core----{-# WARNING SpecExample "This will be removed from the public interface with the next major release. If you need this, raise your voice!" #-}-{-# WARNING SpecGroup "This will be removed from the public interface with the next major release. If you need this, raise your voice!" #-}- -- | Internal representation of a spec.------ This will be made abstract with the next release. If you still need access--- to any constructors, open an issue and describe your use case:--- <https://github.com/hspec/hspec/issues>-data SpecTree a = SpecGroup String [SpecTree a]- | SpecExample String a+data Spec = SpecGroup String [Spec]+ | SpecExample String (IO Result) +-- | The @describe@ function combines a list of specs into a larger spec. describe :: String -> [Spec] -> Spec-describe str specs = Spec . SpecGroup str $ map unSpec specs+describe = SpecGroup safeEvaluateExample :: IO Result -> IO Result safeEvaluateExample action = do@@ -70,7 +51,7 @@ -- > ] -- it :: Example a => String -> a -> Spec-it requirement' = Spec . SpecExample requirement' . evaluateExample+it requirement = SpecExample requirement . evaluateExample -- | A type class for examples. --@@ -88,13 +69,18 @@ instance Example Result where evaluateExample r = r `seq` return r -instance Example Pending.Pending where- evaluateExample (Pending.Pending reason) = evaluateExample (Pending reason)--instance Example (String -> Pending.Pending) where- evaluateExample _ = evaluateExample (Pending.Pending Nothing)- -- | Create a more readable display of a quantity of something.-quantify :: (Show a, Num a, Eq a) => a -> String -> String+--+-- Examples:+--+-- >>> quantify 0 "example"+-- "0 examples"+--+-- >>> quantify 1 "example"+-- "1 example"+--+-- >>> quantify 2 "example"+-- "2 examples"+quantify :: Int -> String -> String quantify 1 s = "1 " ++ s quantify n s = show n ++ " " ++ s ++ "s"
Test/Hspec/Monadic.hs view
@@ -1,11 +1,17 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# OPTIONS_HADDOCK prune #-}+{-# OPTIONS_GHC -fno-warn-deprecations #-} -- |--- There is a monadic and a non-monadic API. This is the documentation for the--- monadic API. The monadic API is suitable for most use cases, and it is more--- stable than the non-monadic API.------ For documentation on the non-monadic API look at "Test.Hspec".+-- 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 on the documentation and design+-- aspects of TDD. --+-- Hspec (and the preceding intro) are based on the Ruby library RSpec. Much of+-- what applies to RSpec also applies to Hspec. Hspec ties together+-- /descriptions/ of behavior and /examples/ of that behavior. The examples can+-- also be run as tests and the output summarises what needs to be implemented. module Test.Hspec.Monadic ( -- * Introduction -- $intro@@ -23,22 +29,24 @@ -- * Running a spec , hspec , hspecB-, hspecX , hHspec+, Summary (..) -- * Interface to the non-monadic API , runSpecM , fromSpecList --- * Deprecated types and functions-, descriptions+-- deprecated stuff , Specs+, descriptions+, hspecX ) where import System.IO-import Test.Hspec.Core (EvaluatedSpec, Example)+import Test.Hspec.Core (Example) import qualified Test.Hspec.Core as Core import qualified Test.Hspec.Runner as Runner+import Test.Hspec.Runner (Summary (..)) import Test.Hspec.Pending (Pending) import qualified Test.Hspec.Pending as Pending @@ -122,15 +130,16 @@ newtype SpecM a = SpecM (Writer [Core.Spec] a) deriving Monad --- | Create a document of the given specs and write it to stdout.-hspec :: Spec -> IO [EvaluatedSpec]+-- | Create a document of the given spec and write it to stdout.+--+-- Exit the program with `exitSuccess` if all examples passed, with+-- `exitFailure` otherwise.+hspec :: Spec -> IO () hspec = Runner.hspec . runSpecM --- | Use in place of `hspec` to also exit the program with an @ExitCode@-hspecX :: Spec -> IO a-hspecX = Runner.hspecX . runSpecM---- | Use in place of hspec to also give a @Bool@ success indication+-- | Create a document of the given spec and write it to stdout.+--+-- Return `True` if all examples passed, `False` otherwise. hspecB :: Spec -> IO Bool hspecB = Runner.hspecB . runSpecM @@ -138,7 +147,7 @@ -- -- > writeReport filename specs = withFile filename WriteMode (\h -> hHspec h specs) ---hHspec :: Handle -> Spec -> IO [EvaluatedSpec]+hHspec :: Handle -> Spec -> IO Summary hHspec h = Runner.hHspec h . runSpecM -- | Convert a monadic spec into a non-monadic spec.@@ -149,12 +158,21 @@ fromSpecList :: [Core.Spec] -> Spec fromSpecList = SpecM . tell +-- | The @describe@ function combines a list of specs into a larger spec. describe :: String -> Spec -> Spec describe label action = SpecM . tell $ [Core.describe label (runSpecM action)] +-- | An alias for `describe`. context :: String -> Spec -> Spec context = describe +-- |+-- Create a set of specifications for a specific type being described. Once+-- you know what you want specs for, use this.+--+-- > describe "abs" $ do+-- > it "returns a positive number given a negative number" $+-- > abs (-1) == 1 it :: Example v => String -> v -> Spec it label action = (SpecM . tell) [Core.it label action] @@ -174,10 +192,13 @@ pending :: String -> Pending pending = Pending.pending --- | DEPRECATED: Use `sequence_` instead.+{-# DEPRECATED Specs "use Spec instead" #-}+type Specs = SpecM ()++{-# DEPRECATED descriptions "use sequence_ instead" #-} descriptions :: [Spec] -> Spec descriptions = sequence_-{-# DEPRECATED descriptions "use sequence_ instead" #-} --- | DEPRECATED: Use `Spec` instead-type Specs = SpecM ()+{-# DEPRECATED hspecX "use hspec instead" #-}+hspecX :: Spec -> IO a+hspecX = Runner.hspecX . runSpecM
Test/Hspec/Pending.hs view
@@ -1,6 +1,20 @@+{-# LANGUAGE FlexibleInstances #-} module Test.Hspec.Pending where +import qualified Test.Hspec.Internal as Internal+import Test.Hspec.Internal (Example(..))++-- NOTE: This is defined in a separate packages, because it clashes with+-- Result.Pending.++-- | A pending example. newtype Pending = Pending (Maybe String)++instance Example Pending where+ evaluateExample (Pending reason) = evaluateExample (Internal.Pending reason)++instance Example (String -> Pending) where+ evaluateExample _ = evaluateExample (Pending Nothing) -- | A pending example. --
Test/Hspec/QuickCheck.hs view
@@ -36,9 +36,9 @@ instance Example QC.Property where evaluateExample p = do r <- silence $ QC.quickCheckResult p- let r' = case r of- QC.Success {} -> Success- f@(QC.Failure {}) -> Fail (QC.output f)- g@(QC.GaveUp {}) -> Fail ("Gave up after " ++ quantify (QC.numTests g) "test" )- QC.NoExpectedFailure {} -> Fail ("No expected failure")- return r'+ return $+ case r of+ QC.Success {} -> Success+ f@(QC.Failure {}) -> Fail (QC.output f)+ QC.GaveUp {QC.numTests = n} -> Fail ("Gave up after " ++ quantify n "test" )+ QC.NoExpectedFailure {} -> Fail ("No expected failure")
Test/Hspec/Runner.hs view
@@ -1,11 +1,24 @@-{-# OPTIONS_GHC -fno-warn-deprecations #-} -- | This module contains the runners that take a set of specs, evaluate their examples, and -- report to a given handle. -- module Test.Hspec.Runner (- Specs, hspec, hspecX, hspecB, hHspec, hHspecWithFormat, describe, it, toExitCode+ Specs+, hspec+, hspecB+, hHspec+, hHspecWithFormat+, toExitCode++, Summary (..)++-- * Deprecated functions+, hspecX ) where +import Control.Monad (unless, (>=>))+import Control.Applicative+import Data.Monoid+ import Test.Hspec.Internal import Test.Hspec.Formatters import Test.Hspec.Formatters.Internal@@ -13,13 +26,13 @@ import System.Exit -- | Evaluate and print the result of checking the spec examples.-runFormatter :: Formatter -> Spec -> FormatM EvaluatedSpec-runFormatter formatter = go 0 [] . unSpec+runFormatter :: Formatter -> Spec -> FormatM ()+runFormatter formatter = go 0 [] where+ go :: Int -> [String] -> Spec -> FormatM () go nesting groups (SpecGroup group xs) = do exampleGroupStarted formatter nesting group- ys <- mapM (go (succ nesting) (group : groups)) xs- return (SpecGroup group ys)+ mapM_ (go (succ nesting) (group : groups)) xs go nesting groups (SpecExample requirement e) = do result <- liftIO $ safeEvaluateExample e case result of@@ -34,7 +47,6 @@ Pending reason -> do increasePendingCount examplePending formatter nesting requirement reason- return (SpecExample requirement result) failureDetails :: [String] -> String -> String -> Int -> String failureDetails groups requirement err i =@@ -48,49 +60,54 @@ _ -> concatMap (++ " - ") (reverse groups) --- | Use in place of `hspec` to also exit the program with an @ExitCode@+-- | Create a document of the given specs and write it to stdout.+--+-- Exit the program with `exitSuccess` if all examples passed, with+-- `exitFailure` otherwise.+hspec :: Specs -> IO ()+hspec = hspecB >=> (`unless` exitFailure)++{-# DEPRECATED hspecX "use hspec instead" #-} hspecX :: Specs -> IO a-hspecX ss = hspecB ss >>= exitWith . toExitCode+hspecX = hspecB >=> exitWith . toExitCode --- | Use in place of hspec to also give a @Bool@ success indication+-- | Create a document of the given specs and write it to stdout.+--+-- Return `True` if all examples passed, `False` otherwise. hspecB :: Specs -> IO Bool-hspecB ss = success `fmap` hspec ss+hspecB = fmap success . hHspec stdout where- success :: [EvaluatedSpec] -> Bool- success = not . failure-- failure :: [EvaluatedSpec] -> Bool- failure = any p- where- p (SpecGroup _ xs) = any p xs- p (SpecExample _ x) = isFailure x-- isFailure :: Result -> Bool- isFailure (Fail _) = True- isFailure _ = False---- | Create a document of the given specs and write it to stdout.-hspec :: Specs -> IO [EvaluatedSpec]-hspec = hHspec stdout+ success :: Summary -> Bool+ success s = summaryFailures s == 0 -- | Create a document of the given specs and write it to the given handle. -- -- > writeReport filename specs = withFile filename WriteMode (\h -> hHspec h specs) ---hHspec :: Handle -> Specs -> IO [EvaluatedSpec]+hHspec :: Handle -> Specs -> IO Summary hHspec h specs = do useColor <- hIsTerminalDevice h hHspecWithFormat specdoc useColor h specs -- | Create a document of the given specs and write it to the given handle. -- THIS IS LIKELY TO CHANGE-hHspecWithFormat :: Formatter -> Bool -> Handle -> Specs -> IO [EvaluatedSpec]+hHspecWithFormat :: Formatter -> Bool -> Handle -> Specs -> IO Summary hHspecWithFormat formatter useColor h ss = runFormatM useColor h $ do- specList <- mapM (runFormatter formatter) ss+ mapM_ (runFormatter formatter) ss failedFormatter formatter footerFormatter formatter- return specList+ Summary <$> getTotalCount <*> getFailCount toExitCode :: Bool -> ExitCode toExitCode True = ExitSuccess toExitCode False = ExitFailure 1++-- | Summary of a test run.+data Summary = Summary {+ summaryExamples :: Int+, summaryFailures :: Int+} deriving (Eq, Show)++instance Monoid Summary where+ mempty = Summary 0 0+ (Summary x1 x2) `mappend` (Summary y1 y2) = Summary (x1 + y1) (x2 + y2)
+ example/NonMonadic.hs view
@@ -0,0 +1,23 @@+module Main (main, spec) where++import Test.Hspec.Core+import Test.Hspec.HUnit ()+import Test.Hspec.QuickCheck+import Test.HUnit++shouldBe :: (Show a, Eq a) => a -> a -> Assertion+actual `shouldBe` expected = actual @?= expected++main :: IO ()+main = hspec spec++spec :: Specs+spec = [+ describe "reverse" [+ it "reverses a list" $ do+ reverse [1 :: Int, 2, 3] `shouldBe` [3, 2, 1]++ , it "gives the original list, if applied twice" $ property $+ \(xs) -> reverse (reverse xs) == (xs :: [Int])+ ]+ ]
+ example/Spec.hs view
@@ -0,0 +1,21 @@+module Main (main, spec) where++import Test.Hspec.Monadic+import Test.Hspec.HUnit ()+import Test.Hspec.QuickCheck+import Test.HUnit++shouldBe :: (Show a, Eq a) => a -> a -> Assertion+actual `shouldBe` expected = actual @?= expected++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+ describe "reverse" $ do+ it "reverses a list" $ do+ reverse [1 :: Int, 2, 3] `shouldBe` [3, 2, 1]++ it "gives the original list, if applied twice" $ property $+ \xs -> reverse (reverse xs) == (xs :: [Int])
hspec.cabal view
@@ -1,26 +1,26 @@-name: hspec-version: 1.1.3-cabal-version: >= 1.8-build-type: Simple-license: BSD3-license-file: LICENSE-copyright: (c) 2011 Trystan Spangler-category: Testing-author: Trystan Spangler-maintainer: trystan.s@comcast.net-stability: experimental-bug-reports: https://github.com/hspec/hspec/issues-homepage: http://hspec.github.com/-synopsis: Behavior Driven Development for Haskell-description: Behavior Driven Development for Haskell- .- Hspec is roughly based on the Ruby library RSpec. However,- Hspec is just a framework for running HUnit and QuickCheck- tests. Compared to other options, it provides a much nicer- syntax that makes tests very easy to read.- .- New to Hspec? Start with the introductory documentation:- <http://hspec.github.com/>+name: hspec+version: 1.2.0+license: BSD3+license-file: LICENSE+copyright: (c) 2011 Trystan Spangler+author: Trystan Spangler+maintainer: trystan.s@comcast.net+build-type: Simple+cabal-version: >= 1.8+category: Testing+stability: experimental+bug-reports: https://github.com/hspec/hspec/issues+homepage: http://hspec.github.com/+synopsis: Behavior Driven Development for Haskell+description: Behavior Driven Development for Haskell+ .+ Hspec is roughly based on the Ruby library RSpec. However,+ Hspec is just a framework for running HUnit and QuickCheck+ tests. Compared to other options, it provides a much nicer+ syntax that makes tests very easy to read.+ .+ Start with the introductory documentation:+ <http://hspec.github.com/> source-repository head type: git@@ -71,21 +71,45 @@ , HUnit >= 1 && <= 2 , QuickCheck >= 2.4.0.1 && <= 2.5 , hspec-shouldbe+ , hspec-discover --- this should be merged with spec-test-suite old-spec+test-suite doctests+ main-is:+ doctests.hs type: exitcode-stdio-1.0+ ghc-options:+ -Wall -Werror -threaded+ hs-source-dirs:+ test+ build-depends:+ base+ , doctest >= 0.7++test-suite example+ type:+ exitcode-stdio-1.0 main-is:- Specs.hs+ Spec.hs+ hs-source-dirs:+ example ghc-options: -Wall -Werror build-depends:- base >= 4 && <= 5- , silently >= 1.1.1 && < 2- , ansi-terminal == 0.5.5- , time < 1.5- , transformers >= 0.2.0 && < 0.4.0- , HUnit >= 1 && <= 2- , QuickCheck >= 2.4.0.1 && <= 2.5- , hspec-shouldbe+ base+ , hspec+ , HUnit++test-suite example-non-monadic+ type:+ exitcode-stdio-1.0+ main-is:+ NonMonadic.hs+ hs-source-dirs:+ example+ ghc-options:+ -Wall -Werror+ build-depends:+ base+ , hspec+ , HUnit
test/Spec.hs view
@@ -1,9 +1,1 @@-module Main (main) where--import Test.Hspec.ShouldBe--import qualified Test.Hspec.MonadicSpec--main :: IO ()-main = hspecX $ do- describe "Test.Hspec.Monadic" Test.Hspec.MonadicSpec.spec+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/doctests.hs view
@@ -0,0 +1,6 @@+module Main where++import Test.DocTest++main :: IO ()+main = doctest ["Test/Hspec/Internal.hs"]