hspec 1.2.0.1 → 1.3.0
raw patch · 11 files changed
+283/−184 lines, 11 filesdep +directorydep +filepathdep +hspec-expectationsdep −hspec-discoverdep −hspec-shouldbedep ~QuickChecknew-component:exe:hspec-discoverPVP ok
version bump matches the API change (PVP)
Dependencies added: directory, filepath, hspec-expectations, hspec-meta
Dependencies removed: hspec-discover, hspec-shouldbe
Dependency ranges changed: QuickCheck
API changes (from Hackage documentation)
- Test.Hspec: Summary :: Int -> Int -> Summary
- Test.Hspec: data Spec
- Test.Hspec: data Summary
- Test.Hspec: hHspec :: Handle -> Specs -> IO Summary
- Test.Hspec: hspecB :: Specs -> IO Bool
- Test.Hspec: summaryExamples :: Summary -> Int
- Test.Hspec: summaryFailures :: Summary -> Int
- Test.Hspec: type Specs = [Spec]
+ Test.Hspec: context :: String -> Spec -> Spec
- Test.Hspec: describe :: String -> [Spec] -> Spec
+ Test.Hspec: describe :: String -> Spec -> Spec
- Test.Hspec: hspec :: Specs -> IO ()
+ Test.Hspec: hspec :: Spec -> IO ()
- Test.Hspec: it :: Example a => String -> a -> Spec
+ Test.Hspec: it :: Example v => String -> v -> Spec
Files
- hspec-discover/example/Spec.hs +1/−0
- hspec-discover/integration-test/empty/Spec.hs +1/−0
- hspec-discover/src/Main.hs +8/−0
- hspec-discover/src/Run.hs +161/−0
- hspec-discover/test/Spec.hs +1/−0
- hspec.cabal +70/−12
- src/Test/Hspec.hs +36/−65
- src/Test/Hspec/Core.hs +4/−15
- src/Test/Hspec/Internal.hs +0/−6
- src/Test/Hspec/Monadic.hs +0/−85
- test/Spec.hs +1/−1
+ hspec-discover/example/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ hspec-discover/integration-test/empty/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ hspec-discover/src/Main.hs view
@@ -0,0 +1,8 @@+module Main (main) where++import System.Environment++import Run (run)++main :: IO ()+main = getArgs >>= run
+ hspec-discover/src/Run.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+-- | A preprocessor that finds and combines specs.+module Run where+import Control.Monad+import Control.Applicative+import Data.List+import Data.String+import Data.Function+import System.Environment+import System.Exit+import System.IO+import System.Directory+import System.FilePath hiding (combine)++instance IsString ShowS where+ fromString = showString++run :: [String] -> IO ()+run args_ = case args_ of+ src : _ : dst : args -> do+ nested <- case args of+ [] -> return False+ ["--nested"] -> return True+ _ -> exit+ specs <- findSpecs src+ writeFile dst (mkSpecModule src nested specs)+ _ -> exit+ where+ exit = do+ name <- getProgName+ hPutStrLn stderr ("usage: " ++ name ++ " SRC CUR DST [--nested]")+ exitFailure++mkSpecModule :: FilePath -> Bool -> [SpecNode] -> String+mkSpecModule src nested nodes =+ ( "{-# LINE 1 " . shows src . " #-}"+ . showString "module Main where\n"+ . showString "import Test.Hspec\n"+ . importList nodes+ . showString "main :: IO ()\n"+ . showString "main = hspec $ "+ . format nodes+ ) "\n"+ where+ format+ | nested = formatSpecsNested+ | otherwise = formatSpecs++-- | Generate imports for a list of specs.+importList :: [SpecNode] -> ShowS+importList = go ""+ where+ go :: ShowS -> [SpecNode] -> ShowS+ go current = foldr (.) "" . map (f current)+ f current (SpecNode name inhabited children) = this . go (current . showString name . ".") children+ where+ this+ | inhabited = "import qualified " . current . showString name . "Spec\n"+ | otherwise = id++-- | Combine a list of strings with (>>).+sequenceS :: [ShowS] -> ShowS+sequenceS = foldr (.) "" . intersperse " >> "++-- | Convert a list of specs to code.+formatSpecs :: [SpecNode] -> ShowS+formatSpecs xs+ | null xs = "return ()"+ | otherwise = sequenceS (map formatSpec xs)++-- | Convert a spec to code.+formatSpec :: SpecNode -> ShowS+formatSpec = sequenceS . go ""+ where+ go :: String -> SpecNode -> [ShowS]+ go current (SpecNode name inhabited children) = addThis $ concatMap (go (current ++ name ++ ".")) children+ where+ addThis :: [ShowS] -> [ShowS]+ addThis+ | inhabited = ("describe " . shows (current ++ name) . " " . showString (current ++ name ++ "Spec.spec") :)+ | otherwise = id++-- | Convert a list of specs to code.+--+-- Hierarchical modules are mapped to nested specs.+formatSpecsNested :: [SpecNode] -> ShowS+formatSpecsNested xs+ | null xs = "return ()"+ | otherwise = sequenceS (map formatSpecNested xs)++-- | Convert a spec to code.+--+-- Hierarchical modules are mapped to nested specs.+formatSpecNested :: SpecNode -> ShowS+formatSpecNested = go ""+ where+ go current (SpecNode name inhabited children) = "describe " . shows name . " (" . specs . ")"+ where+ specs :: ShowS+ specs = (sequenceS . addThis . map (go (current . showString name . "."))) children+ addThis+ | inhabited = ((current . showString name . "Spec.spec") :)+ | otherwise = id++data SpecNode = SpecNode String Bool [SpecNode]+ deriving (Eq, Show)++specNodeName :: SpecNode -> String+specNodeName (SpecNode name _ _) = name++specNodeInhabited :: SpecNode -> Bool+specNodeInhabited (SpecNode _ inhabited _) = inhabited++specNodeChildren :: SpecNode -> [SpecNode]+specNodeChildren (SpecNode _ _ children) = children++getFilesAndDirectories :: FilePath -> IO ([FilePath], [FilePath])+getFilesAndDirectories dir = do+ c <- filter (`notElem` ["..", "."]) <$> getDirectoryContents dir+ dirs <- filterM (doesDirectoryExist . (dir </>)) c+ files <- filterM (doesFileExist . (dir </>)) c+ return (dirs, files)++-- | Find specs relative to given source file.+--+-- The source file itself is not considered.+findSpecs :: FilePath -> IO [SpecNode]+findSpecs src = do+ let (dir, file) = splitFileName src+ (dirs, files) <- getFilesAndDirectories dir+ go dir (dirs, filter (/= file) files)+ where+ go :: FilePath -> ([FilePath], [FilePath]) -> IO [SpecNode]+ go base (dirs, files) = do+ nestedSpecs <- forM dirs $ \d -> do+ let dir = base </> d+ SpecNode d False <$> (getFilesAndDirectories dir >>= go dir)+ (return . filterSpecs . combineSpecs) (specsFromFiles files ++ nestedSpecs)+ where+ specsFromFiles = map (\x -> SpecNode (stripSuffix x) True []) . filter (isSuffixOf suffix)+ where+ suffix = "Spec.hs"+ stripSuffix = reverse . drop (length suffix) . reverse++ -- remove empty leafs+ filterSpecs :: [SpecNode] -> [SpecNode]+ filterSpecs = filter (\x -> specNodeInhabited x || (not . null . specNodeChildren) x)++ -- sort specs, and merge nodes with the same name+ combineSpecs :: [SpecNode] -> [SpecNode]+ combineSpecs = foldr f [] . sortBy (compare `on` specNodeName)+ where+ f x@(SpecNode n1 _ _) (y@(SpecNode n2 _ _):acc) | n1 == n2 = x `combine` y : acc+ f x acc = x : acc++ x `combine` y = SpecNode name inhabited children+ where+ name = specNodeName x+ inhabited = specNodeInhabited x || specNodeInhabited y+ children = specNodeChildren x ++ specNodeChildren y
+ hspec-discover/test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-meta-discover #-}
hspec.cabal view
@@ -1,10 +1,9 @@ name: hspec-version: 1.2.0.1+version: 1.3.0 license: BSD3 license-file: LICENSE-copyright: (c) 2011 Trystan Spangler-author: Trystan Spangler-maintainer: trystan.s@comcast.net+copyright: (c) 2011-2012 Trystan Spangler, (c) 2011-2012 Simon Hengel, (c) 2011 Greg Weber+maintainer: Simon Hengel <sol@typeful.net> build-type: Simple cabal-version: >= 1.8 category: Testing@@ -39,14 +38,15 @@ , transformers >= 0.2.0 && < 0.4.0 , HUnit >= 1 && <= 2 , QuickCheck >= 2.4.0.1 && <= 2.5+ , hspec-expectations exposed-modules: Test.Hspec- , Test.Hspec.Core- , Test.Hspec.Monadic- , Test.Hspec.Runner- , Test.Hspec.Formatters- , Test.Hspec.HUnit- , Test.Hspec.QuickCheck+ Test.Hspec.Core+ Test.Hspec.Monadic+ Test.Hspec.Runner+ Test.Hspec.Formatters+ Test.Hspec.HUnit+ Test.Hspec.QuickCheck other-modules: Test.Hspec.Pending Test.Hspec.Internal@@ -69,8 +69,8 @@ , transformers >= 0.2.0 && < 0.4.0 , HUnit >= 1 && <= 2 , QuickCheck >= 2.4.0.1 && <= 2.5- , hspec-shouldbe- , hspec-discover+ , hspec-expectations+ , hspec-meta test-suite doctests main-is:@@ -112,3 +112,61 @@ base , hspec , HUnit++-- hspec-discover+executable hspec-discover+ ghc-options:+ -Wall+ hs-source-dirs:+ hspec-discover/src+ main-is:+ Main.hs+ other-modules:+ Run+ build-depends:+ base >= 4 && <= 5+ , filepath+ , directory++test-suite hspec-discover-spec+ type:+ exitcode-stdio-1.0+ ghc-options:+ -Wall -Werror+ hs-source-dirs:+ hspec-discover/src+ , hspec-discover/test+ main-is:+ Spec.hs+ 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
src/Test/Hspec.hs view
@@ -1,59 +1,42 @@ {-# 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,--- 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 is a framework for /Behavior-Driven Development (BDD)/ in Haskell. 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 {-# WARNING "This module will re-export Test.Hspec.Monadic in the future. Either use Test.Hspec.Core as a drop-in replacement, or migrate your code to the monadic API!" #-} (+-- also be run as tests and the output summarizes what needs to be implemented.+module Test.Hspec ( -- * Introduction -- $intro -- * Types Spec-, Specs , Example , Pending +-- * Setting expectations+, module Test.Hspec.Expectations+ -- * Defining a spec , describe+, context , it , pending -- * Running a spec , hspec-, hspecB-, hHspec-, Summary (..)-------- deprecated functions-, descriptions-, hspecX--- ) where -import Test.Hspec.Core---+import Test.Hspec.Monadic+import Test.Hspec.HUnit ()+import Test.Hspec.QuickCheck ()+import Test.Hspec.Expectations -- $intro --@@ -62,12 +45,11 @@ -- the specs for them. -- -- > import Test.Hspec--- > import Test.Hspec.QuickCheck--- > import Test.Hspec.HUnit () -- > import Test.QuickCheck -- > import Test.HUnit -- >--- > main = hspec mySpecs+-- > main :: IO ()+-- > main = hspec spec -- -- 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@@ -75,53 +57,42 @@ -- and there is no undocumented behavior. -- -- > unformatPhoneNumber :: String -> String--- > unformatPhoneNumber number = undefined+-- > unformatPhoneNumber = undefined -- > -- > formatPhoneNumber :: String -> String--- > formatPhoneNumber number = undefined+-- > formatPhoneNumber = undefined -- -- The 'describe' function takes a list of behaviors and examples bound -- together with the 'it' function ----- > mySpecs = [describe "unformatPhoneNumber" [+-- > spec :: Spec+-- > spec = do+-- > describe "unformatPhoneNumber" $ do ----- A boolean expression can act as a behavior's example.+-- A `Bool` can be used as an example. ----- > it "removes dashes, spaces, and parenthesies" $--- > unformatPhoneNumber "(555) 555-1234" == "5555551234"--- > ,+-- > 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"--- > ,+-- > 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")+-- An HUnit 'Test.HUnit.Lang.Assertion' can be used as an example. ----- > it "removes the \"ext\" prefix of the extension" $ TestCase $ do--- > let expected = "5555551234135"--- > actual = unformatPhoneNumber "(555) 555-1234 ext 135"--- > expected @?= actual--- > ,+-- > it "converts letters to numbers" $ do+-- > let expected = "6862377"+-- > actual = unformatPhoneNumber "NUMBERS"+-- > actual @?= expected ----- 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")+-- A QuickCheck 'Test.QuickCheck.Property' can be used as an example. ----- > it "can add and remove formatting without changing the number" $ property $--- > forAll phoneNumber $ \n -> unformatPhoneNumber (formatPhoneNumber n) == n--- > ]]+-- > it "can add and remove formatting without changing the number" $ property $+-- > forAll phoneNumber $ \n -> unformatPhoneNumber (formatPhoneNumber n) == n -- > -- > phoneNumber :: Gen String -- > phoneNumber = do
src/Test/Hspec/Core.hs view
@@ -1,21 +1,9 @@ {-# 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,--- 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".-+-- "Test.Hspec". module Test.Hspec.Core ( @@ -68,7 +56,8 @@ -- > import Test.QuickCheck -- > import Test.HUnit -- >--- > main = hspec mySpecs+-- > main :: IO ()+-- > main = hspec spec -- -- 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@@ -84,7 +73,7 @@ -- The 'describe' function takes a list of behaviors and examples bound -- together with the 'it' function ----- > mySpecs = [describe "unformatPhoneNumber" [+-- > spec = [describe "unformatPhoneNumber" [ -- -- A boolean expression can act as a behavior's example. --
src/Test/Hspec/Internal.hs view
@@ -54,12 +54,6 @@ it requirement = SpecExample requirement . evaluateExample -- | A type class for examples.------ To use an HUnit `Test.HUnit.Test` or an `Test.HUnit.Assertion` as an example--- you need to import "Test.Hspec.HUnit".------ To use a QuickCheck `Test.QuickCheck.Property` as an example you need to--- import "Test.Hspec.QuickCheck". class Example a where evaluateExample :: a -> IO Result
src/Test/Hspec/Monadic.hs view
@@ -1,20 +1,7 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# OPTIONS_HADDOCK prune #-} {-# OPTIONS_GHC -fno-warn-deprecations #-}--- |--- 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 -- * Types Spec , Example@@ -52,78 +39,6 @@ import Control.Monad.Trans.Writer (Writer, execWriter, tell) --- $intro------ The three functions you'll use the most are 'hspec', 'describe', and 'it'.--- Here is an example of functions that format and unformat phone numbers and--- the specs for them.------ > import Test.Hspec.Monadic--- > import Test.Hspec.QuickCheck--- > import Test.Hspec.HUnit ()--- > import Test.QuickCheck--- > import Test.HUnit--- >--- > 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 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" $ do------ 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")--- type Spec = SpecM ()
test/Spec.hs view
@@ -1,1 +1,1 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover #-}+{-# OPTIONS_GHC -F -pgmF hspec-meta-discover #-}