packages feed

hspec 1.4.2 → 1.4.2.1

raw patch · 34 files changed

+1012/−33 lines, 34 filesdep −hspec-metadep ~HUnitdep ~QuickCheckPVP ok

version bump matches the API change (PVP)

Dependencies removed: hspec-meta

Dependency ranges changed: HUnit, QuickCheck

API changes (from Hackage documentation)

Files

− hspec-discover/example/Spec.hs
@@ -1,1 +0,0 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
− hspec-discover/integration-test/empty/Spec.hs
@@ -1,1 +0,0 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ hspec-discover/test-data/empty-dir/Foo/Bar/Baz/.placeholder view
+ hspec-discover/test-data/nested-spec/Foo/Bar/BazSpec.hs view
+ hspec-discover/test-data/nested-spec/Foo/BarSpec.hs view
+ hspec-discover/test-data/nested-spec/FooSpec.hs view
+ hspec-discover/test-data/no-intermediate-specs/Foo/Bar/BazSpec.hs view
+ hspec-discover/test-data/prefix-name/Foo/BazSpec.hs view
+ hspec-discover/test-data/prefix-name/FooBar/BazSpec.hs view
+ hspec-discover/test-data/prefix-name/FooBarSpec.hs view
+ hspec-discover/test-data/prefix-name/FooSpec.hs view
+ hspec-discover/test-data/several-specs/BarSpec.hs view
+ hspec-discover/test-data/several-specs/BazSpec.hs view
+ hspec-discover/test-data/several-specs/FooSpec.hs view
+ hspec-discover/test-data/single-spec-nested/Foo/BarSpec.hs view
+ hspec-discover/test-data/single-spec/FooSpec.hs view
+ hspec-discover/test-data/single-spec/Spec.hs view
+ hspec-discover/test/RunSpec.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE OverloadedStrings #-}+module RunSpec (main, spec) where++import           Test.Hspec.Meta++import           Run++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "findSpecs" $ do+    context "when specs are not nested" $ do+      it "finds a single spec" $ do+        findSpecs "hspec-discover/test-data/single-spec/Spec.hs" `shouldReturn` [SpecNode "Foo" True []]++      it "finds several specs" $ do+        findSpecs "hspec-discover/test-data/several-specs/Spec.hs" `shouldReturn` [SpecNode "Bar" True [], SpecNode "Baz" True [], SpecNode "Foo" True []]++    context "when specs are nested" $ do+      it "finds a single spec" $ do+        findSpecs "hspec-discover/test-data/single-spec-nested/Spec.hs" `shouldReturn` [SpecNode "Foo" False [SpecNode "Bar" True []]]++      it "properly groups nested specs" $ do+        findSpecs "hspec-discover/test-data/nested-spec/Spec.hs" `shouldReturn` [SpecNode "Foo" True [SpecNode "Bar" True [SpecNode "Baz" True []]]]++    context "given a nested spec, without specs at the intermediate nodes" $ do+      it "finds a single spec" $ do+        findSpecs "hspec-discover/test-data/no-intermediate-specs/Spec.hs" `shouldReturn` [SpecNode "Foo" False [SpecNode "Bar" False [SpecNode "Baz" True []]]]++    context "given a nested specs, with specs at the intermediate nodes" $ do+      context "with two top-level specs, where one spec name is a prefix of the other" $ do+        it "properly sorts specs" $ do+          findSpecs "hspec-discover/test-data/prefix-name/Spec.hs" `shouldReturn`+            [SpecNode "Foo" True [SpecNode "Baz" True []], SpecNode "FooBar" True [SpecNode "Baz" True []]]++    context "when there are no specs" $ do+      it "returns an empty list" $ do+        findSpecs "hspec-discover/test-data/empty-dir/Spec.hs" `shouldReturn` []++  describe "formatSpec" $ do+    it "generates code for a spec" $+      formatSpec (SpecNode "Foo" True []) "" `shouldBe` "describe \"Foo\" FooSpec.spec"++    it "generates code for a nested spec" $+      formatSpec (SpecNode "Foo" True [SpecNode "Bar" True [SpecNode "Baz" True []]]) "" `shouldBe`+        "describe \"Foo\" FooSpec.spec >> describe \"Foo.Bar\" Foo.BarSpec.spec >> describe \"Foo.Bar.Baz\" Foo.Bar.BazSpec.spec"++  describe "formatSpecs" $ do+    it "generates code for a list of specs" $ do+      formatSpecs [SpecNode "Bar" True [], SpecNode "Baz" True [], SpecNode "Foo" True []] "" `shouldBe`+        "describe \"Bar\" BarSpec.spec >> describe \"Baz\" BazSpec.spec >> describe \"Foo\" FooSpec.spec"++    it "generates code for an empty list" $ do+      formatSpecs [] "" `shouldBe`+        "return ()"++  describe "formatSpecNested" $ do+    it "generates code for a spec" $+      formatSpecNested (SpecNode "Foo" True []) "" `shouldBe` "describe \"Foo\" (FooSpec.spec)"++    it "generates code for a nested spec" $+      formatSpecNested (SpecNode "Foo" True [SpecNode "Bar" True [SpecNode "Baz" True []]]) "" `shouldBe`+        "describe \"Foo\" (FooSpec.spec >> describe \"Bar\" (Foo.BarSpec.spec >> describe \"Baz\" (Foo.Bar.BazSpec.spec)))"++  describe "formatSpecsNested" $ do+    it "generates code for a list of specs" $ do+      formatSpecsNested [SpecNode "Bar" True [], SpecNode "Baz" True [], SpecNode "Foo" True []] "" `shouldBe`+        "describe \"Bar\" (BarSpec.spec) >> describe \"Baz\" (BazSpec.spec) >> describe \"Foo\" (FooSpec.spec)"++    it "generates code for an empty list" $ do+      formatSpecsNested [] "" `shouldBe`+        "return ()"++  describe "importList" $ do+    it "generates imports for a spec" $ do+      importList [SpecNode "Foo" True []] "" `shouldBe` "import qualified FooSpec\n"++    it "generates imports for a nested spec" $+      importList [SpecNode "Foo" True [SpecNode "Bar" True [SpecNode "Baz" True []]]] "" `shouldBe`+        "import qualified FooSpec\nimport qualified Foo.BarSpec\nimport qualified Foo.Bar.BazSpec\n"++    it "generates imports for a list of specs" $ do+      importList [SpecNode "Bar" True [], SpecNode "Baz" True [], SpecNode "Foo" True []] "" `shouldBe`+        "import qualified BarSpec\nimport qualified BazSpec\nimport qualified FooSpec\n"++    it "generates imports for a nested spec that has no specs at the intermediate nodes" $ do+      importList [SpecNode "Foo" False [SpecNode "Bar" False [SpecNode "Baz" True []]]] "" `shouldBe`+        "import qualified Foo.Bar.BazSpec\n"
hspec-discover/test/Spec.hs view
@@ -1,1 +1,5 @@-{-# OPTIONS_GHC -F -pgmF hspec-meta-discover #-}+{-# LINE 1 "hspec-discover/test/Spec.hs" #-}module Main where+import Test.Hspec+import qualified RunSpec+main :: IO ()+main = hspec $ describe "Run" RunSpec.spec
+ hspec-discover/test/Test/Hspec/Meta.hs view
@@ -0,0 +1,2 @@+module Test.Hspec.Meta (module Test.Hspec) where+import Test.Hspec
hspec.cabal view
@@ -1,5 +1,5 @@ name:             hspec-version:          1.4.2+version:          1.4.2.1 license:          BSD3 license-file:     LICENSE copyright:        (c) 2011-2012 Trystan Spangler, (c) 2011-2012 Simon Hengel, (c) 2011 Greg Weber@@ -20,6 +20,24 @@                   .                   The Hspec Manual is at <http://hspec.github.com/>. +-- find hspec-discover/test-data/ -type f+extra-source-files:+  hspec-discover/test-data/single-spec/FooSpec.hs+  hspec-discover/test-data/single-spec/Spec.hs+  hspec-discover/test-data/single-spec-nested/Foo/BarSpec.hs+  hspec-discover/test-data/nested-spec/FooSpec.hs+  hspec-discover/test-data/nested-spec/Foo/Bar/BazSpec.hs+  hspec-discover/test-data/nested-spec/Foo/BarSpec.hs+  hspec-discover/test-data/several-specs/BarSpec.hs+  hspec-discover/test-data/several-specs/FooSpec.hs+  hspec-discover/test-data/several-specs/BazSpec.hs+  hspec-discover/test-data/empty-dir/Foo/Bar/Baz/.placeholder+  hspec-discover/test-data/prefix-name/FooSpec.hs+  hspec-discover/test-data/prefix-name/Foo/BazSpec.hs+  hspec-discover/test-data/prefix-name/FooBarSpec.hs+  hspec-discover/test-data/prefix-name/FooBar/BazSpec.hs+  hspec-discover/test-data/no-intermediate-specs/Foo/Bar/BazSpec.hs+ source-repository head   type: git   location: https://github.com/hspec/hspec@@ -63,6 +81,20 @@       src, test   main-is:       Spec.hs+  other-modules:+      Mock+      Util+      Test.Hspec.Meta+      -- actual spec files+      Test.HspecSpec+      Test.Hspec.CompatSpec+      Test.Hspec.Core.TypeSpec+      Test.Hspec.FailureReportSpec+      Test.Hspec.FormattersSpec+      Test.Hspec.HUnitSpec+      Test.Hspec.QuickCheckSpec+      Test.Hspec.RunnerSpec+      Test.Hspec.UtilSpec   ghc-options:       -Wall -Werror   build-depends:@@ -76,7 +108,6 @@     , QuickCheck >= 2.4.0.1 && < 2.6     , hspec-expectations -    , hspec-meta     , process     , ghc-paths @@ -132,35 +163,12 @@     , hspec-discover/test   main-is:       Spec.hs+  other-modules:+      Test.Hspec.Meta+      -- actual spec files+      RunSpec   build-depends:       base >= 4 && <= 5     , filepath     , directory-    , hspec-meta--test-suite hspec-discover-example-  type:-      exitcode-stdio-1.0-  ghc-options:-      -Wall -Werror-  hs-source-dirs:-      hspec-discover/example-  main-is:-      Spec.hs-  build-depends:-      base >= 4 && <= 5-    , hspec-    , QuickCheck--test-suite hspec-discover-integration-test-empty-  type:-      exitcode-stdio-1.0-  ghc-options:-      -Wall -Werror-  hs-source-dirs:-      hspec-discover/integration-test/empty-  main-is:-      Spec.hs-  build-depends:-      base >= 4 && <= 5     , hspec
+ test/Mock.hs view
@@ -0,0 +1,15 @@+module Mock where++import           Control.Applicative+import           Data.IORef++newtype Mock = Mock (IORef Int)++newMock :: IO Mock+newMock = Mock <$> newIORef 0++mockAction :: Mock -> IO ()+mockAction (Mock ref) = modifyIORef ref succ++mockCounter  :: Mock -> IO Int+mockCounter  (Mock ref) = readIORef ref
test/Spec.hs view
@@ -1,1 +1,13 @@-{-# OPTIONS_GHC -F -pgmF hspec-meta-discover #-}+{-# LINE 1 "test/Spec.hs" #-}module Main where+import Test.Hspec+import qualified Test.HspecSpec+import qualified Test.Hspec.CompatSpec+import qualified Test.Hspec.Core.TypeSpec+import qualified Test.Hspec.FailureReportSpec+import qualified Test.Hspec.FormattersSpec+import qualified Test.Hspec.HUnitSpec+import qualified Test.Hspec.QuickCheckSpec+import qualified Test.Hspec.RunnerSpec+import qualified Test.Hspec.UtilSpec+main :: IO ()+main = hspec $ describe "Test.Hspec" Test.HspecSpec.spec >> describe "Test.Hspec.Compat" Test.Hspec.CompatSpec.spec >> describe "Test.Hspec.Core.Type" Test.Hspec.Core.TypeSpec.spec >> describe "Test.Hspec.FailureReport" Test.Hspec.FailureReportSpec.spec >> describe "Test.Hspec.Formatters" Test.Hspec.FormattersSpec.spec >> describe "Test.Hspec.HUnit" Test.Hspec.HUnitSpec.spec >> describe "Test.Hspec.QuickCheck" Test.Hspec.QuickCheckSpec.spec >> describe "Test.Hspec.Runner" Test.Hspec.RunnerSpec.spec >> describe "Test.Hspec.Util" Test.Hspec.UtilSpec.spec
+ test/Test/Hspec/CompatSpec.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE DeriveDataTypeable #-}+module Test.Hspec.CompatSpec (main, spec) where++import           Test.Hspec.Meta++import           Test.Hspec.Compat+import           Data.Typeable++data SomeType = SomeType+  deriving Typeable++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "showType" $ do+    it "shows fully qualified name of type" $ do+      showType SomeType `shouldBe` "Test.Hspec.CompatSpec.SomeType"
+ test/Test/Hspec/Core/TypeSpec.hs view
@@ -0,0 +1,65 @@+module Test.Hspec.Core.TypeSpec (main, spec) where++import           Test.Hspec.Meta+import           Test.QuickCheck++import           Test.QuickCheck.Property (morallyDubiousIOProperty)+import           Control.Exception (AsyncException(..), throwIO)+import qualified Test.Hspec.Core.Type as H+import qualified Test.Hspec.Pending as H (pending)++main :: IO ()+main = hspec spec++evaluateExample :: H.Example e => e -> IO H.Result+evaluateExample = H.evaluateExample H.defaultParams++spec :: Spec+spec = do+  describe "evaluateExample" $ do+    context "for Bool" $ do+      it "returns Success on True" $ do+        evaluateExample True `shouldReturn` H.Success++      it "returns Fail on False" $ do+        evaluateExample False `shouldReturn` H.Fail ""++      it "propagates exceptions" $ do+        evaluateExample (error "foobar" :: Bool) `shouldThrow` errorCall "foobar"++    context "for Expectation" $ do+      it "returns Success if all expectations hold" $ do+        evaluateExample (23 `shouldBe` (23 :: Int)) `shouldReturn` H.Success++      it "returns Fail if an expectation does not hold" $ do+        evaluateExample (23 `shouldBe` (42 :: Int)) `shouldReturn` H.Fail "expected: 42\n but got: 23"++      it "propagates exceptions" $ do+        evaluateExample (error "foobar" :: Expectation) `shouldThrow` errorCall "foobar"++    context "for Property" $ do+      it "returns Success if property holds" $ do+        evaluateExample (property $ \n -> n == (n :: Int)) `shouldReturn` H.Success++      it "returns Fail if property does not hold" $ do+        H.Fail _ <- evaluateExample $ property $ \n -> n /= (n :: Int)+        return ()++      it "shows what falsified it" $ do+        H.Fail r <- evaluateExample $ property $ \ n -> n == (n + 1 :: Int)+        lines r `shouldSatisfy` any (== "0")++      it "propagates UserInterrupt" $ do+        let p = morallyDubiousIOProperty (throwIO UserInterrupt >> return True)+        evaluateExample p `shouldThrow` (== UserInterrupt)++      it "propagates exceptions" $ do+        pending "this probaly needs a patch to QuickCheck"+        -- evaluateExample (property $ (error "foobar" :: Int -> Bool)) `shouldThrow` errorCall "foobar"++    context "for pending" $ do+      it "returns Pending" $ do+        evaluateExample (H.pending) `shouldReturn` H.Pending Nothing++      it "includes the optional reason" $ do+        evaluateExample (H.pending "foo") `shouldReturn` H.Pending (Just "foo")
+ test/Test/Hspec/FailureReportSpec.hs view
@@ -0,0 +1,40 @@+module Test.Hspec.FailureReportSpec (main, spec) where++import           Test.Hspec.Meta++import           System.IO+import           System.IO.Silently+import           Test.Hspec.FailureReport+import           GHC.Paths (ghc)+import           System.Process+import           System.Exit++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "writeFailureReport" $ do+    it "prints a warning on unexpected exceptions" $ do+      (r, ()) <- hCapture [stderr] $ writeFailureReport (error "some error")+      r `shouldBe` "WARNING: Could not write environment variable HSPEC_FAILURES (some error)\n"++  -- GHCi needs to keep the environment on :reload, so that we can store+  -- failures there.  Otherwise --re-run would not be very useful.  So we add a+  -- test for that.+  describe "GHCi" $ do+    it "keeps environment variables on :reload" $ do+      let flags = ["-v0", "--interactive", "-ignore-dot-ghci"]+      (Just hIn, Just hOut, Nothing, processHandle) <- createProcess $ (proc ghc flags) {+          std_in = CreatePipe+        , std_out = CreatePipe+        }+      hPutStrLn hIn "import System.SetEnv"+      hPutStrLn hIn "setEnv \"FOO\" \"bar\""+      hPutStrLn hIn ":reload"+      hPutStrLn hIn "import System.Environment"+      hPutStrLn hIn "getEnv \"FOO\""+      hClose hIn+      r <- hGetContents hOut+      length r `seq` r `shouldBe` "\"bar\"\n"+      waitForProcess processHandle `shouldReturn` ExitSuccess
+ test/Test/Hspec/FormattersSpec.hs view
@@ -0,0 +1,225 @@+{-# LANGUAGE CPP #-}+module Test.Hspec.FormattersSpec (main, spec) where++import           Test.Hspec.Meta++import           Util+import           System.IO.Silently (capture)+import qualified Test.Hspec as H+import qualified Test.Hspec.Core as H (Result(..))+import qualified Test.Hspec.Runner as H+import qualified Test.Hspec.Formatters as H++#ifndef mingw32_HOST_OS+import           System.Console.ANSI+#endif++main :: IO ()+main = hspec spec++testSpec :: H.Spec+testSpec = do+  H.describe "Example" $ do+    H.it "success"    (H.Success)+    H.it "fail 1"     (H.Fail "fail message")+    H.it "pending"    (H.pending "pending message")+    H.it "fail 2"     (H.Fail "")+    H.it "exceptions" (undefined :: H.Result)+    H.it "fail 3"     (H.Fail "")++spec :: Spec+spec = do+  describe "silent" $ do+    let runSpec = fmap fst . capture . H.hspecWith H.defaultConfig {H.configFormatter = H.silent}+    it "produces no output" $ do+      runSpec testSpec `shouldReturn` ""++  describe "failed_examples" $ do+    failed_examplesSpec H.failed_examples++  describe "progress" $ do+    let runSpec = capture__ . H.hspecWith H.defaultConfig {H.configFormatter = H.progress}++    it "produces '..F...FF.F' style output" $ do+      r <- runSpec testSpec+      head r `shouldBe` ".F.FFF"++    context "same as failed_examples" $ do+      failed_examplesSpec H.progress++  describe "specdoc" $ do+    let runSpec = capture__ . H.hspecWith H.defaultConfig {H.configFormatter = H.specdoc}++    it "displays a header for each thing being described" $ do+      _:x:_ <- runSpec testSpec+      x `shouldBe` "Example"++    it "displays one row for each behavior" $ do+      r <- runSpec $ do+        H.describe "List as a Monoid" $ do+          H.describe "mappend" $ do+            H.it "is associative" True+          H.describe "mempty" $ do+            H.it "is a left identity" True+            H.it "is a right identity" True+        H.describe "Maybe as a Monoid" $ do+          H.describe "mappend" $ do+            H.it "is associative" True+          H.describe "mempty" $ do+            H.it "is a left identity" True+            H.it "is a right identity" True+      normalizeSummary r `shouldBe` [+          ""+        , "List as a Monoid"+        , "  mappend"+        , "    - is associative"+        , ""+        , "  mempty"+        , "    - is a left identity"+        , "    - is a right identity"+        , ""+        , "Maybe as a Monoid"+        , "  mappend"+        , "    - is associative"+        , ""+        , "  mempty"+        , "    - is a left identity"+        , "    - is a right identity"+        , ""+        , "Finished in 0.0000 seconds"+        , "6 examples, 0 failures"+        ]++    it "prints an empty line before each group" $ do+      r <- runSpec $ do+        H.describe "foo" $ do+          H.it "example 1" True+          H.it "example 2" True+          H.describe "bar" $ do+            H.it "example 3" True+            H.it "example 4" True+      normalizeSummary r `shouldBe` [+          ""+        , "foo"+        , "  - example 1"+        , "  - example 2"+        , ""+        , "  bar"+        , "    - example 3"+        , "    - example 4"+        , ""+        , "Finished in 0.0000 seconds"+        , "4 examples, 0 failures"+        ]++    it "prints an empty line after each group" $ do+      r <- runSpec $ do+        H.describe "foo" $ do+          H.describe "bar" $ do+            H.it "example 1" True+            H.it "example 2" True+          H.it "example 3" True+          H.it "example 4" True+      normalizeSummary r `shouldBe` [+          ""+        , "foo"+        , "  bar"+        , "    - example 1"+        , "    - example 2"+        , ""+        , "  - example 3"+        , "  - example 4"+        , ""+        , "Finished in 0.0000 seconds"+        , "4 examples, 0 failures"+        ]++    it "outputs an empty line at the beginning (even for non-nested specs)" $ do+      r <- runSpec $ do+        H.it "example 1" True+        H.it "example 2" True+      normalizeSummary r `shouldBe` [+          ""+        , "- example 1"+        , "- example 2"+        , ""+        , "Finished in 0.0000 seconds"+        , "2 examples, 0 failures"+        ]++    it "displays a row for each successfull, failed, or pending example" $ do+      r <- runSpec testSpec+      r `shouldSatisfy` any (== "  - fail 1 FAILED [1]")+      r `shouldSatisfy` any (== "  - success")++    it "displays a '#' with an additional message for pending examples" $ do+      r <- runSpec testSpec+      r `shouldSatisfy` any (== "     # PENDING: pending message")++    it "outputs failed examples in red, pending in yellow, and successful in green" $ do+      pending++    context "same as failed_examples" $ do+      failed_examplesSpec H.progress++failed_examplesSpec :: H.Formatter -> Spec+failed_examplesSpec formatter = do+  let runSpec = capture__ . H.hspecWith H.defaultConfig {H.configFormatter = formatter}++  it "summarizes the time it takes to finish" $ do+    r <- runSpec (return ())+    normalizeSummary r `shouldSatisfy` any (== "Finished in 0.0000 seconds")++  context "displays a detailed list of failures" $ do+    it "prints all requirements that are not met" $ do+      r <- runSpec testSpec+      r `shouldSatisfy` any (== "1) Example fail 1 FAILED")++    it "prints the exception type for requirements that fail due to an uncaught exception" $ do+      r <- runSpec $ do+        H.it "foobar" (undefined :: Bool)+      r `shouldContain` [+          "1) foobar FAILED (uncaught exception)"+        , "GHC.Exception.ErrorCall (Prelude.undefined)"+        ]++    it "prints all descriptions when a nested requirement fails" $ do+      r <- runSpec $+        H.describe "foo" $ do+          H.describe "bar" $ do+            H.it "baz" False+      r `shouldSatisfy` any (== "1) foo.bar baz FAILED")++  it "summarizes the number of examples and failures" $ do+    r <- runSpec testSpec+    r `shouldSatisfy` any (== "6 examples, 4 failures, 1 pending")++  -- Windows has no support for ANSI escape codes.  The Console API is used for+  -- colorized output, hence the following tests do not work on Windows.+#ifndef mingw32_HOST_OS+  it "shows summary in green if there are no failures" $ do+    r <- capture__ $ H.hspecWith H.defaultConfig {H.configColorMode = H.ColorAlway} $ do+      H.it "foobar" True+    r `shouldSatisfy` any (== (green ++ "1 example, 0 failures" ++ reset))++  it "shows summary in yellow if there are pending examples" $ do+    r <- capture__ $ H.hspecWith H.defaultConfig {H.configColorMode = H.ColorAlway} $ do+      H.it "foobar" H.pending+    r `shouldSatisfy` any (== (yellow ++ "1 example, 0 failures, 1 pending" ++ reset))++  it "shows summary in red if there are failures" $ do+    r <- capture__ $ H.hspecWith H.defaultConfig {H.configColorMode = H.ColorAlway} $ do+      H.it "foobar" False+    r `shouldSatisfy` any (== (red ++ "1 example, 1 failure" ++ reset))++  it "shows summary in red if there are both failures and pending examples" $ do+    r <- capture__ $ H.hspecWith H.defaultConfig {H.configColorMode = H.ColorAlway} $ do+      H.it "foo" False+      H.it "bar" H.pending+    r `shouldSatisfy` any (== (red ++ "2 examples, 1 failure, 1 pending" ++ reset))+  where+    green  = setSGRCode [SetColor Foreground Dull Green]+    yellow = setSGRCode [SetColor Foreground Dull Yellow]+    red    = setSGRCode [SetColor Foreground Dull Red]+    reset  = setSGRCode [Reset]+#endif
+ test/Test/Hspec/HUnitSpec.hs view
@@ -0,0 +1,83 @@+module Test.Hspec.HUnitSpec (main, spec) where++import           Test.Hspec.Meta+import           Util (capture__)+import           Control.Applicative++import qualified Test.Hspec as H+import qualified Test.Hspec.Runner as H+import           Test.Hspec.Core.Type (SpecTree(..), runSpecM)+import           Test.Hspec.HUnit+import           Test.HUnit++main :: IO ()+main = hspec spec++-- SpecTree does not have an Eq nor a Show instance, hence we map it to `Tree`.+data Tree = Group String [Tree] | Example String+  deriving (Eq, Show)++shouldYield :: Test -> [Tree] -> Expectation+a `shouldYield` b = (convert . runSpecM . fromHUnitTest) a `shouldBe` b+  where+    convert :: [SpecTree] -> [Tree]+    convert = map go+      where+        go :: SpecTree -> Tree+        go x = case x of+          SpecGroup s xs  -> Group s (map go xs)+          SpecItem  s _   -> Example s++spec :: Spec+spec = do+  describe "fromHUnitTest" $ do+    let e = TestCase $ pure ()++    it "works for a TestCase" $ do+      e `shouldYield` [Example "<unlabeled>"]++    it "works for a labeled TestCase" $ do+      TestLabel "foo" e+        `shouldYield` [Example "foo"]++    it "works for a TestCase with nested labels" $ do+      (TestLabel "foo" . TestLabel "bar") e+        `shouldYield` [Group "foo" [Example "bar"]]++    it "works for a flat TestList" $ do+      TestList [e, e, e]+        `shouldYield` [Example "<unlabeled>", Example "<unlabeled>", Example "<unlabeled>"]++    it "works for a nested TestList" $ do+      (TestLabel "foo" . TestLabel "bar" . TestList) [TestLabel "one" e, TestLabel "two" e, TestLabel "three" e]+        `shouldYield` [Group "foo" [Group "bar" [Example "one", Example "two", Example "three"]]]++  describe "HUnit TestCase as an example (deprecated!)" $ do+    it "is specified with the HUnit `TestCase` data constructor" $ TestCase $ do+      runSpec $ do+        H.it "some behavior" (TestCase $ "foo" @?= "bar")+        H.it "some behavior" (TestCase $ "foo" @?= "foo")+      `shouldReturn` H.Summary 2 1++    it "is the assumed example for IO() actions" $ do+      runSpec $ do+        H.it "some behavior" ("foo" @?= "bar")+        H.it "some behavior" ("foo" @?= "foo")+      `shouldReturn` H.Summary 2 1++    it "will show the failed assertion text if available (e.g. assertBool)" $ do+      let assertionText = "some assertion text"+      r <- capture__ . runSpec $ do+        H.describe "foo" $ do+          H.it "bar" (assertFailure assertionText)+      r `shouldSatisfy` any (== assertionText)++    it "will show the failed assertion expected and actual values if available (e.g. assertEqual)" $ do+      r <- capture__ . runSpec $ do+        H.describe "foo" $ do+          H.it "bar" (assertEqual "trivial" (1::Int) 2)+      assertBool "should find assertion text" $ any (=="trivial") r+      assertBool "should find 'expected: 1'"  $ any (=="expected: 1") r+      assertBool "should find ' but got: 2'"  $ any (==" but got: 2") r+  where+    runSpec = H.hspecWith H.defaultConfig
+ test/Test/Hspec/Meta.hs view
@@ -0,0 +1,2 @@+module Test.Hspec.Meta (module Test.Hspec) where+import Test.Hspec
+ test/Test/Hspec/QuickCheckSpec.hs view
@@ -0,0 +1,19 @@+module Test.Hspec.QuickCheckSpec (main, spec) where++import           Test.Hspec.Meta++import qualified Test.Hspec as H+import qualified Test.Hspec.Runner as H+import qualified Test.Hspec.QuickCheck as H++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "prop" $ do+    it "is a shortcut to use properties as examples" $ do+      H.hspecWith H.defaultConfig $ do+        H.describe "read" $ do+          H.prop "is inverse to show" $ \x -> (read . show) x == (x :: Int)+      `shouldReturn` H.Summary 1 0
+ test/Test/Hspec/RunnerSpec.hs view
@@ -0,0 +1,214 @@+module Test.Hspec.RunnerSpec (main, spec) where++import           Test.Hspec.Meta+import           System.IO.Silently (hCapture, hSilence)+import           System.IO (stderr)+import           Control.Applicative+import           System.Environment (withArgs, withProgName, getArgs)+import           System.Exit+import qualified Control.Exception as E+import           Util+import           Mock+import           System.SetEnv+import           Test.Hspec.Util (getEnv)+import           Test.QuickCheck.Property (morallyDubiousIOProperty)++import qualified Test.Hspec.Runner as H+import qualified Test.Hspec as H (describe, it, pending)+import qualified Test.Hspec.Formatters as H (silent)++ignoreExitCode :: IO () -> IO ()+ignoreExitCode action = action `E.catch` \e -> let _ = e :: ExitCode in return ()++main :: IO ()+main = hspec spec++spec :: Spec+spec = do++  describe "hspec" $ do+    it "runs a spec" $ do+      H.hspec $ do+        H.it "foobar" True+      `shouldReturn` ()++    it "exits with exitFailure if not all examples pass" $ do+      H.hspec $ do+        H.it "foobar" False+      `shouldThrow` (== ExitFailure 1)++    it "suppresses output to stdout when evaluating examples" $ do+      r <- capture__ . H.hspec $ do+        H.it "foobar" $ do+          putStrLn "baz"+      r `shouldSatisfy` notElem "baz"++    it "prints an error message on unrecognized command-line options" $ do+      withProgName "myspec" . withArgs ["--foo"] $ do+        hSilence [stderr] (H.hspec $ pure ()) `shouldThrow` (== ExitFailure 1)+        fst `fmap` hCapture [stderr] (ignoreExitCode (H.hspec $ pure ())) `shouldReturn` unlines [+            "myspec: unrecognized option `--foo'"+          , "Try `myspec --help' for more information."+          ]++    it "does not leak command-line flags to examples" $ do+      withArgs ["--verbose"] $ do+        H.hspec $ do+          H.it "foobar" $ do+            getArgs `shouldReturn` []+        `shouldReturn` ()++    context "with --help" $ do+      let printHelp = withProgName "spec" . withArgs ["--help"] . H.hspec $ pure ()+      it "prints help" $ do+        r <- (capture__ . ignoreExitCode) printHelp+        r `shouldStartWith` ["Usage: spec [OPTION]..."]+        printHelp `shouldThrow` (== ExitSuccess)++      it "constrains lines to 80 characters" $ do+        r <- (capture__ . ignoreExitCode) printHelp+        r `shouldSatisfy` all ((<= 80) . length)+        r `shouldSatisfy` any ((78 <=) . length)++    context "with --verbose" $ do+      it "does not suppress output to stdout" $ do+        r <- capture__ . withArgs ["--verbose"] . H.hspec $ do+          H.it "foobar" $ do+            putStrLn "baz"+        r `shouldSatisfy` elem "baz"++    context "with --match" $ do+      it "only runs examples that match a given pattern" $ do+        e1 <- newMock+        e2 <- newMock+        e3 <- newMock+        withArgs ["-m", "/bar/example"] . H.hspec $ do+          H.describe "foo" $ do+            H.describe "bar" $ do+              H.it "example 1" $ mockAction e1+              H.it "example 2" $ mockAction e2+            H.describe "baz" $ do+              H.it "example 3" $ mockAction e3+        (,,) <$> mockCounter e1 <*> mockCounter e2 <*> mockCounter e3 `shouldReturn` (1, 1, 0)++      it "can be given multiple times" $ do+        e1 <- newMock+        e2 <- newMock+        e3 <- newMock+        withArgs ["-m", "foo", "-m", "baz"] . H.hspec $ do+          H.describe "foo" $ do+            H.it "example 1" $ mockAction e1+          H.describe "bar" $ do+            H.it "example 2" $ mockAction e2+          H.describe "baz" $ do+            H.it "example 3" $ mockAction e3+        (,,) <$> mockCounter e1 <*> mockCounter e2 <*> mockCounter e3 `shouldReturn` (1, 0, 1)++    context "with --maximum-generated-tests=n" $ do+      it "tries QuickCheck properties n times" $ do+        m <- newMock+        withArgs ["--maximum-generated-tests=23"] . H.hspec $ do+          H.it "foo" $ do+            morallyDubiousIOProperty (mockAction m >> pure True)+        mockCounter m `shouldReturn` 23++    context "with --print-cpu-time" $ do+      it "includes used CPU time in summary" $ do+        r <- capture_ $ withArgs ["--print-cpu-time"] (H.hspec $ pure ())+        (normalizeSummary . lines) r `shouldContain` ["Finished in 0.0000 seconds, used 0.0000 seconds of CPU time"]++    context "with --html" $ do+      it "produces HTML output" $ do+        r <- capture_ . withArgs ["--html"] . H.hspec $ do+          H.it "foo" True+        r `shouldContain` "</span>"++      it "marks successful examples with CSS class hspec-success" $ do+        r <- capture_ . withArgs ["--html"] . H.hspec $ do+          H.it "foo" True+        r `shouldContain` "<span class=\"hspec-success\">- foo\n</span>"++      it "marks pending examples with CSS class hspec-pending" $ do+        r <- capture_ . withArgs ["--html"] . H.hspec $ do+          H.it "foo" H.pending+        r `shouldContain` "<span class=\"hspec-pending\">- foo"++      it "marks failed examples with CSS class hspec-failure" $ do+        r <- capture_ . ignoreExitCode . withArgs ["--html"] . H.hspec $ do+          H.it "foo" False+        r `shouldContain` "<span class=\"hspec-failure\">- foo"++  describe "hspec (experimental features)" $ do+    it "stores a failure report in environment HSPEC_FAILURES" $ do+      ignoreExitCode . H.hspec $ do+        H.describe "foo" $ do+          H.describe "bar" $ do+            H.it "example 1" True+            H.it "example 2" False+        H.describe "baz" $ do+          H.it "example 3" False+      getEnv "HSPEC_FAILURES" `shouldReturn` Just "[([\"foo\",\"bar\"],\"example 2\"),([\"baz\"],\"example 3\")]"++    describe "with --re-run" $ do+      let runSpec = (capture__ . ignoreExitCode . H.hspec) $ do+            H.it "example 1" True+            H.it "example 2" False+            H.it "example 3" False+            H.it "example 4" True+            H.it "example 5" False++      it "re-runs examples that previously failed" $ do+        r0 <- runSpec+        r0 `shouldSatisfy` elem "5 examples, 3 failures"++        r1 <- withArgs ["-r"] runSpec+        r1 `shouldSatisfy` elem "3 examples, 3 failures"++      context "when there is no failure report in the environment" $ do+        it "runs everything" $ do+          unsetEnv "HSPEC_FAILURES"+          r <- hSilence [stderr] $ withArgs ["-r"] runSpec+          r `shouldSatisfy` elem "5 examples, 3 failures"++        it "prints a warning to stderr" $ do+          unsetEnv "HSPEC_FAILURES"+          r <- hCapture [stderr] $ withArgs ["-r"] runSpec+          fst r `shouldBe` "WARNING: Could not read environment variable HSPEC_FAILURES; `--re-run' is ignored!\n"++      context "when parsing of failure report fails" $ do+        it "runs everything" $ do+          setEnv "HSPEC_FAILURES" "some invalid report"+          r <- hSilence [stderr] $ withArgs ["-r"] runSpec+          r `shouldSatisfy` elem "5 examples, 3 failures"++        it "prints a warning to stderr" $ do+          setEnv "HSPEC_FAILURES" "some invalid report"+          r <- hCapture [stderr] $ withArgs ["-r"] runSpec+          fst r `shouldBe` "WARNING: Could not read environment variable HSPEC_FAILURES; `--re-run' is ignored!\n"++  describe "hspecWith" $ do+    it "returns a summary of the test run" $ do+      H.hspecWith H.defaultConfig $ do+        H.it "foo" True+        H.it "foo" False+        H.it "foo" False+        H.it "foo" True+        H.it "foo" True+      `shouldReturn` H.Summary 5 2++    it "treats uncaught exceptions as failure" $ do+      H.hspecWith H.defaultConfig  $ do+        H.it "foobar" (E.throwIO (E.ErrorCall "foobar") >> pure ())+      `shouldReturn` H.Summary 1 1++    it "uses the specdoc formatter by default" $ do+      _:r:_ <- capture__ . H.hspecWith H.defaultConfig $ do+        H.describe "Foo.Bar" $ do+          H.it "some example" True+      r `shouldBe` "Foo.Bar"++    it "can use a custom formatter" $ do+      r <- capture_ . H.hspecWith H.defaultConfig {H.configFormatter = H.silent} $ do+        H.describe "Foo.Bar" $ do+          H.it "some example" True+      r `shouldBe` ""
+ test/Test/Hspec/UtilSpec.hs view
@@ -0,0 +1,89 @@+module Test.Hspec.UtilSpec (main, spec) where++import           Test.Hspec.Meta++import qualified Control.Exception as E+import           Test.Hspec.Util++import           System.SetEnv++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "quantify" $ do+    it "returns an amount and a word given an amount and word" $ do+      quantify 1 "thing" `shouldBe` "1 thing"++    it "returns a singular word given the number 1" $ do+      quantify 1 "thing" `shouldBe` "1 thing"++    it "returns a plural word given a number greater than 1" $ do+      quantify 2 "thing" `shouldBe` "2 things"++    it "returns a plural word given the number 0" $ do+      quantify 0 "thing" `shouldBe` "0 things"++  describe "safeEvaluate" $ do+    it "returns Right on success" $ do+      Right e <- safeEvaluate (return 23 :: IO Int)+      e `shouldBe` 23++    it "returns Left on exception" $ do+      Left e <- safeEvaluate (E.throwIO E.DivideByZero :: IO Int)+      show e `shouldBe` "divide by zero"++    it "evaluates result to weak head normal form" $ do+      Left e <- safeEvaluate (return undefined)+      show e `shouldBe` "Prelude.undefined"++    it "re-throws AsyncException" $ do+      safeEvaluate (E.throwIO E.UserInterrupt :: IO Int) `shouldThrow` (== E.UserInterrupt)++  describe "filterPredicate" $ do+    it "tries to match a pattern against a path" $ do+      let p = filterPredicate "foo/bar/example 1"+      p (["foo", "bar"], "example 1") `shouldBe` True+      p (["foo", "bar"], "example 2") `shouldBe` False++    it "is ambiguous" $ do+      let p = filterPredicate "foo/bar/baz"+      p (["foo", "bar"], "baz") `shouldBe` True+      p (["foo"], "bar/baz") `shouldBe` True++    it "succeeds on a partial match" $ do+      let p = filterPredicate "bar/baz"+      p (["foo", "bar", "baz"], "example 1") `shouldBe` True++    it "succeeds with a pattern that matches the message give in the failure list" $ do+      let p = filterPredicate "ModuleA.ModuleB.foo does something"+      p (["ModuleA", "ModuleB", "foo"], "does something") `shouldBe` True++  describe "formatRequirement" $ do+    it "creates a sentence from a subject and a requirement" $ do+      formatRequirement (["reverse"], "reverses a list") `shouldBe` "reverse reverses a list"++    it "creates a sentence from a subject and a requirement when the subject consits of multiple words" $ do+      formatRequirement (["The reverse function"], "reverses a list") `shouldBe` "The reverse function reverses a list"++    it "returns the requirement if no subject is given" $ do+      formatRequirement ([], "reverses a list") `shouldBe` "reverses a list"++    it "inserts context separated by commas" $ do+      formatRequirement (["reverse", "when applied twice"], "reverses a list") `shouldBe` "reverse, when applied twice, reverses a list"++    it "joins components of a subject with a dot" $ do+      formatRequirement (["Data", "List", "reverse"], "reverses a list") `shouldBe` "Data.List.reverse reverses a list"++    it "properly handles context after a subject that consists of several components" $ do+      formatRequirement (["Data", "List", "reverse", "when applied twice"], "reverses a list") `shouldBe` "Data.List.reverse, when applied twice, reverses a list"++  describe "getEnv" $ do+    it "returns value of specified environment variable" $ do+      setEnv "FOO" "bar"+      getEnv "FOO" `shouldReturn` Just "bar"++    it "returns Nothing if specified environment variable is not set" $ do+      unsetEnv "FOO"+      getEnv "FOO" `shouldReturn` Nothing
+ test/Test/HspecSpec.hs view
@@ -0,0 +1,64 @@+module Test.HspecSpec (main, spec) where++import           Test.Hspec.Meta+import           Util (capture__)+import           Data.List (isPrefixOf)++import qualified Test.Hspec.Core.Type as H (defaultParams)+import           Test.Hspec.Core (SpecTree(..), Result(..), runSpecM)+import qualified Test.Hspec as H+import qualified Test.Hspec.Runner as H (hspecWith)+import           Test.Hspec.Runner (defaultConfig)++main :: IO ()+main = hspec spec++spec :: Spec+spec = do+  describe "pending" $ do+    it "specifies a pending example" $ do+      r <- runSpec $ do+        H.it "foo" H.pending+      r `shouldSatisfy` any (== "     # PENDING: No reason given")++    it "accepts an optional message, which is included in the report" $ do+      r <- runSpec $ do+        H.it "foo" $ do+          H.pending "for some reason"+      r `shouldSatisfy` any (== "     # PENDING: for some reason")++  describe "describe" $ do+    let testSpec = do+          H.describe "some subject" $ do+            H.it "foo" True+            H.it "bar" True+            H.it "baz" True+    it "takes a description of what the behavior is for" $ do+      r <- runSpec testSpec+      r `shouldSatisfy` any (== "some subject")++    it "groups behaviors for what's being described" $ do+      r <- filter (isPrefixOf "  - ") `fmap` runSpec testSpec+      length r `shouldBe` 3++    it "can be nested" $ do+      let [SpecGroup foo [SpecGroup bar [SpecItem baz _]]] = runSpecM $ do+            H.describe "foo" $ do+              H.describe "bar" $ do+                H.it "baz" True+      (foo, bar, baz) `shouldBe` ("foo", "bar", "baz")++  describe "it" $ do+    it "takes a description of a desired behavior" $ do+      let [SpecItem d _] = runSpecM (H.it "whatever" True)+      d `shouldBe` "whatever"++    it "takes an example of that behavior" $ do+      let [SpecItem _ e] = runSpecM (H.it "whatever" True)+      e H.defaultParams `shouldReturn` Success++    it "can use a Bool, HUnit Test, QuickCheck property, or `pending` as an example"+      pending+  where+    runSpec :: H.Spec -> IO [String]+    runSpec = capture__ . H.hspecWith defaultConfig
+ test/Util.hs view
@@ -0,0 +1,30 @@+module Util where++import           Data.List+import           Data.Char+import           Test.Hspec.Meta+import qualified System.IO.Silently as S++capture_ :: IO a -> IO String+capture_ = fmap fst . S.capture++capture__ :: IO a -> IO [String]+capture__ = fmap lines . capture_++shouldContain :: (Eq a, Show a) => [a] -> [a] -> Expectation+x `shouldContain` y = x `shouldSatisfy` isInfixOf y++shouldStartWith :: (Eq a, Show a) => [a] -> [a] -> Expectation+x `shouldStartWith` y = x `shouldSatisfy` isPrefixOf y++shouldEndWith :: (Eq a, Show a) => [a] -> [a] -> Expectation+x `shouldEndWith` y = x `shouldSatisfy` isSuffixOf y++-- replace times in summary with zeroes+normalizeSummary :: [String] -> [String]+normalizeSummary xs = map f xs+  where+    f x | "Finished in " `isPrefixOf` x = map g x+        | otherwise = x+    g x | isNumber x = '0'+        | otherwise  = x