hspec-expectations-lens 0.2.0.0 → 0.2.1.0
raw patch · 5 files changed
+217/−43 lines, 5 files
Files
- CHANGELOG.md +6/−0
- README.lhs +144/−0
- README.md +0/−6
- hspec-expectations-lens.cabal +3/−3
- src/Test/Hspec/Expectations/Lens.hs +64/−34
CHANGELOG.md view
@@ -1,3 +1,9 @@+0.2.1.0+=======++ * Add a `shouldPerform` expectation+ * Improve expectations' error messages+ 0.2.0.0 =======
+ README.lhs view
@@ -0,0 +1,144 @@+hspec-expectations-lens+=======================+[](http://hackage.haskell.org/package/hspec-expectations-lens)+[](http://travis-ci.org/supki/hspec-expectations-lens)++hspec-expectations-lens is a set of expectations for [Hspec][hspec]+with a [lens][lens]-compatible interface++This README is a literate haskell file which contains a Hspec spec.+You can run it with `runhaskell`; result is something akin to:+++```shell+% runhaskell README.lhs++shouldHave+ - checks targets exist+ - looks as deep into structure as you want+ - replaces 'shouldBe'+ - checks a bigger part of the structure for equality+ - checks the whole structure for equality++shouldNotHave+ - is the opposite of 'shouldHave'++shouldView+ - gets a single target verbatim+ - combines multiple targets using Monoid instance++shouldList+ - combines multiple targets into list++shouldPreview+ - gets the first target++shouldPerform+ - performs an action and gets the first target++shouldThrow+ - looks into the 'error' call+ - looks into the division by zero+```++Expectations+------------++We start with pragmas, module declaration, and imports we use later.++> {-# LANGUAGE ExtendedDefaultRules #-} -- this is only neccessary because we don't like annotations+>+> module Main (main) where+>+> import Control.Lens+> import Data.List.Lens+> import Control.Exception (evaluate)+> import Control.Exception.Lens (_ErrorCall, _DivideByZero)+> import Test.Hspec.Lens+>+> main :: IO ()+> main = hspec $ do++hspec-expectations-lens expectations form several groups. First one contains `shouldHave`+and `shouldNotHave` combinators—they check whether a `Fold` you give them has (or doesn't have)+any targets in the structure.++> describe "shouldHave" $ do+> it "checks targets exist" $+> Right (Just (Left 'a')) `shouldHave` _Right++We can look arbitrarily deep into the structure; for instance, `_Right._Just._Left`+would also work here:++> it "looks as deep into structure as you want" $+> Right (Just (Left 'a')) `shouldHave` _Right._Just++Finally, `shouldHave` can happily be used as a replacement for a vanilla `shouldBe`.++> it "replaces 'shouldBe'" $+> Right (Just (Left 'a')) `shouldHave` _Right._Just._Left.only 'a'+>+> it "checks a bigger part of the structure for equality" $+> Right (Just (Left 'a')) `shouldHave` _Right._Just.only (Left 'a')+>+> it "checks the whole structure for equality" $+> Right (Just (Left 'a')) `shouldHave` only (Right (Just (Left 'a')))++`shouldNotHave` is the opposite of `shouldHave` as its name implies, it checks+whether a `Fold` does not have any targets in the structure.++> describe "shouldNotHave" $+> it "is the opposite of 'shouldHave'" $+> Right (Just (Left 'a')) `shouldNotHave` _Left++Next group of expectations is those of them that actually care about the result+of looking into the structure. It consists of `shouldView`, `shouldPreview`,+`shouldList`, and `shouldPerform`. They derive names from `view`, `preview`, `toListOf`,+and `perform` `combinators from the lens package.++`shouldView` works similarly to `view`, no big surprises here. If a `Fold` is actually+a `Getter`, you just get its target:++> describe "shouldView" $ do+> it "gets a single target verbatim" $+> (1, (((1, 7), 8), 2, (3, 4), 5, 7)) `shouldView` 7 `through` _2._1._1._2++(`through` is just a fancy name for `id`; it helps to avoid parentheses)++Otherwise, if `Fold` has multiple targets, they are combined using `Monoid` instance+for the target type (and it better have one):++> it "combines multiple targets using Monoid instance" $+> [("foo", 1), ("bar", 2), ("baz", 3)] `shouldView` "foobarbaz" `through` folded._1++`shouldList` is like `toListOf`, that is, it combines its targets into the list:++> describe "shouldList" $+> it "combines multiple targets into list" $+> [("foo", 1), ("bar", 2), ("baz", 3)] `shouldList` [1, 2, 3] `through` folded._2++`shouldPreview` is like `preview` in that it only cares about the first target:++> describe "shouldPreview" $+> it "gets the first target" $+> [1..10] `shouldPreview` 10 `through` reversed.folded++`shouldPerform` performs the action and looks into the first target of the result.++> describe "shouldPerform" $+> it "performs an action and gets the first target" $+> readFile "README.lhs" `shouldPerform` 99 `through` to lines.folded.prefixed ">".to length++The last combinator, which does not really belong to any of the previous groups,+is `shouldThrow`. It uses composable selectors to determine which+exception was thrown:++> describe "shouldThrow" $ do+> it "looks into the 'error' call" $+> error "foo" `shouldThrow` _ErrorCall.only "foo"+>+> it "looks into the division by zero" $+> evaluate (1 `div` 0) `shouldThrow` _DivideByZero++ [hspec]: http://hspec.github.io/+ [lens]: https://github.com/ekmett/lens/
− README.md
@@ -1,6 +0,0 @@-hspec-expectations-lens-======-[](http://hackage.haskell.org/package/hspec-expectations-lens)-[](http://travis-ci.org/supki/hspec-expectations-lens)--Hspec expectations for the lens stuff
hspec-expectations-lens.cabal view
@@ -1,5 +1,5 @@ name: hspec-expectations-lens-version: 0.2.0.0+version: 0.2.1.0 synopsis: Hspec expectations for the lens stuff description: Package adds hspec expectations (@\`shouldX\`@ things)@@ -13,7 +13,7 @@ build-type: Simple extra-source-files: CHANGELOG.md- README.md+ README.lhs cabal-version: >= 1.10 source-repository head@@ -22,7 +22,7 @@ source-repository this type: git- tag: 0.2.0.0+ tag: 0.2.1.0 location: https://github.com/supki/hspec-expectations-lens library
src/Test/Hspec/Expectations/Lens.hs view
@@ -7,10 +7,12 @@ , shouldPreview , shouldList , shouldThrow+ , shouldPerform , through ) where import Control.Lens+import Control.Monad import Control.Exception (SomeException) import Control.Exception.Lens import Data.Monoid (Any(..), All(..), First(..), Endo(..))@@ -19,11 +21,17 @@ import Text.Printf (printf) -infixl 1 `shouldHave`, `shouldNotHave`, `shouldView`, `shouldPreview`, `shouldList`, `shouldThrow`, `through`+infixl 1 `shouldHave`, `shouldNotHave`+infixl 1 `shouldView`, `shouldPreview`, `shouldList`+infixl 1 `shouldThrow`+infixl 1 `shouldPerform`+infixl 1 `through` --- | @x \`shouldHave\` l@ sets the expectation that 'Fold' @l@ has--- non-zero number of targets in @x@+-- | @s \`shouldHave\` l@ sets the expectation that 'Fold' @l@ has+-- non-zero number of targets in the structure @s@ --+-- > s `shouldBe` t ≡ s `shouldHave` only t+-- -- @ -- shouldHave :: 'Show' s => s -> 'Getter' s a -> 'Expectation' -- shouldHave :: 'Show' s => s -> 'Fold' s a -> 'Expectation'@@ -33,12 +41,12 @@ -- shouldHave :: 'Show' s => s -> 'Prism'' s a -> 'Expectation' -- @ shouldHave :: Show s => s -> Getting Any s a -> Expectation-x `shouldHave` f = assertBool msg (has f x)+s `shouldHave` l = assertBool msg (has l s) where- msg = printf "Supplied Fold has zero targets for %s" (show x)+ msg = printf "This Fold has zero targets for %s" (show s) --- | @x \`shouldNotHave\` l@ sets the expectation that 'Fold' @l@--- has zero targets in @x@+-- | @s \`shouldNotHave\` l@ sets the expectation that 'Fold' @l@+-- has exactly zero targets in the structue @s@ -- -- @ -- shouldNotHave :: 'Show' s => s -> 'Getter' s a -> 'Expectation'@@ -49,12 +57,12 @@ -- shouldNotHave :: 'Show' s => s -> 'Prism'' s a -> 'Expectation' -- @ shouldNotHave :: Show s => s -> Getting All s a -> Expectation-x `shouldNotHave` f = assertBool msg (hasn't f x)+s `shouldNotHave` l = assertBool msg (hasn't l s) where- msg = printf "Supplied Fold has non-zero targets for %s" (show x)+ msg = printf "This Fold has non-zero targets for %s" (show s) --- | @x \`shouldView\` y \`through\` l@ sets the expectation that--- you can see @y@ in @x@ though a 'Getter' @l@+-- | @s \`shouldView\` t \`through\` l@ sets the expectation that+-- you can see target @t@ in the structure @s@ though a 'Getter' @l@ -- -- @ -- shouldView :: ('Show' s, 'Show' a, 'Eq' a) => s -> a -> 'Getter' s a -> 'Expectation'@@ -65,12 +73,13 @@ -- shouldView :: ('Data.Monoid.Monoid' m, 'Show' s, 'Show' a, 'Eq' a) => s -> a -> 'Prism'' s m -> 'Expectation' -- @ shouldView :: (Show s, Show a, Eq a) => s -> a -> Getting a s a -> Expectation-(x `shouldView` y) l = assertBool msg (view l x == y)- where- msg = printf "Can't view %s from %s through supplied Getter" (show y) (show x)+(s `shouldView` t) l =+ let r = view l s in+ unless (r == t) $+ assertFailure (printf "Resulted in %s, but expected %s" (show r) (show t)) --- | @x \`shouldPreview\` y \`through\` l@ sets the expectation that--- you can list @y@ in @x@ first though a 'Fold' @l@+-- | @s \`shouldPreview\` t \`through\` l@ sets the expectation that+-- you @y@ is the first target of the 'Fold' @l@ in @s@ -- -- @ -- shouldPreview :: ('Show' s, 'Show' a, 'Eq' a) => s -> a -> 'Getter' s a -> 'Expectation'@@ -81,12 +90,15 @@ -- shouldPreview :: ('Show' s, 'Show' a, 'Eq' a) => s -> a -> 'Prism'' s a -> 'Expectation' -- @ shouldPreview :: (Show s, Show a, Eq a) => s -> a -> Getting (First a) s a -> Expectation-(x `shouldPreview` y) l = assertBool msg (preview l x == Just y)- where- msg = printf "Can't preview %s from %s through supplied Fold" (show y) (show x)+(s `shouldPreview` t) l =+ case preview l s of+ Nothing ->+ assertFailure (printf "No targets, but expected %s" (show t))+ Just r -> unless (r == t) $+ assertFailure (printf "Resulted in %s, but expected %s" (show r) (show t)) --- | @x \`shouldList\` ys \`through\` l@ sets the expectation that--- you can list @ys@ in @x@ though a 'Fold' @l@+-- | @s \`shouldList\` ts \`through\` l@ sets the expectation that+-- @ts@ is a list of the Fold @l@ targets in @x@ -- -- @ -- shouldList :: ('Show' s, 'Show' a, 'Eq' a) => s -> [a] -> 'Getter' s a -> 'Expectation'@@ -97,29 +109,47 @@ -- shouldList :: ('Show' s, 'Show' a, 'Eq' a) => s -> [a] -> 'Prism'' s a -> 'Expectation' -- @ shouldList :: (Show s, Show a, Eq a) => s -> [a] -> Getting (Endo [a]) s a -> Expectation-(x `shouldList` y) l = assertBool msg (toListOf l x == y)- where- msg = printf "Can't list %s from %s through supplied Fold" (show y) (show x)+(s `shouldList` t) l =+ let r = toListOf l s in+ unless (r == t) $+ assertFailure (printf "Resulted in %s, but expected %s" (show r) (show t)) --- | @x \`shouldthrow\` l@ sets the expectation that--- @x@ throws an exception catchable with a 'Fold' @l@+-- | @a \`shouldThrow\` l@ sets the expectation that+-- @a@ throws an exception that 'Fold' @l@ can catch ----- /Note:/ name conflicts with 'Test.Hspec.Expectations.shouldThrow'+-- "Test.Hspec" exports 'Test.Hspec.Expectations.shouldThrow' too; it+-- only allows @e -> Bool@ selectors, which is less general and often less convenient -- -- @--- shouldThrow :: 'IO' a -> -> 'Getter' s b -> 'Expectation'--- shouldThrow :: 'IO' a -> -> 'Fold' s b -> 'Expectation'--- shouldThrow :: 'IO' a -> -> 'Lens'' s b -> 'Expectation'--- shouldThrow :: 'IO' a -> -> 'Iso'' s b -> 'Expectation'--- shouldThrow :: 'IO' a -> -> 'Traversal'' s b -> 'Expectation'--- shouldThrow :: 'IO' a -> -> 'Prism'' s b -> 'Expectation'+-- shouldThrow :: 'IO' a -> 'Getter' s b -> 'Expectation'+-- shouldThrow :: 'IO' a -> 'Fold' s b -> 'Expectation'+-- shouldThrow :: 'IO' a -> 'Lens'' s b -> 'Expectation'+-- shouldThrow :: 'IO' a -> 'Iso'' s b -> 'Expectation'+-- shouldThrow :: 'IO' a -> 'Traversal'' s b -> 'Expectation'+-- shouldThrow :: 'IO' a -> 'Prism'' s b -> 'Expectation' -- @ shouldThrow :: IO a -> Getting (First b) SomeException b -> Expectation x `shouldThrow` l = do r <- trying l x case r of Left _ -> return ()- Right _ -> assertFailure "Couldn't catch any exceptions with the supplied Fold"+ Right _ -> assertFailure "Couldn't catch any exceptions"++-- | @a \`shouldPerform\` t \`through\` l@ sets the expectation that @t@ is+-- a target of the 'MonadicFold' @l@ applied to the result of action @a@+--+-- @+-- shouldPerform :: ('Show' a, 'Eq' a) => 'IO' s -> a -> 'Action' 'IO' s a -> 'Expectation'+-- shouldPerform :: ('Show' a, 'Eq' a) => 'IO' s -> a -> 'MonadicFold' 'IO' s a -> 'Expectation'+-- @+shouldPerform :: (Show a, Eq a) => IO s -> a -> Acting IO (Leftmost a) s s a b -> Expectation+(x `shouldPerform` t) l = do+ r <- x ^!? acts.l+ case r of+ Nothing ->+ assertFailure (printf "No targets, but expected %s" (show t))+ Just r' -> unless (r' == t) $+ assertFailure (printf "Resulted in %s, but expected %s" (show r') (show t)) -- | A helper to fight parentheses --