hspec-attoparsec (empty) → 0.1.0.0
raw patch · 6 files changed
+307/−0 lines, 6 filesdep +attoparsecdep +basedep +bytestringsetup-changed
Dependencies added: attoparsec, base, bytestring, hspec, hspec-expectations, text
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- hspec-attoparsec.cabal +51/−0
- src/Test/Hspec/Attoparsec.hs +125/−0
- src/Test/Hspec/Attoparsec/Source.hs +98/−0
- tests/Spec.hs +1/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Alp Mestanogullari++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Alp Mestanogullari nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ hspec-attoparsec.cabal view
@@ -0,0 +1,51 @@+name: hspec-attoparsec+version: 0.1.0.0+synopsis: Utility functions for testing your attoparsec parsers with hspec+description: This package provides some helper functions for testing attoparsec parsers with hspec.+ .+ See the documentation in @Test.Hspec.Attoparsec@ for examples, or this package's own test suite.+homepage: http://github.com/alpmestan/hspec-attoparsec+Bug-reports: https://github.com/alpmestan/hspec-attoparsec/issues+license: BSD3+license-file: LICENSE+author: Alp Mestanogullari+maintainer: alpmestan@gmail.com+copyright: 2014 Alp Mestanogullari+category: Testing, Parsing+build-type: Simple+cabal-version: >=1.10++library+ exposed-modules: Test.Hspec.Attoparsec,+ Test.Hspec.Attoparsec.Source+ build-depends: base >=4 && <5,+ attoparsec >= 0.10,+ hspec-expectations >= 0.5,+ bytestring >= 0.8,+ text >= 1.0+ hs-source-dirs: src+ default-language: Haskell2010+ ghc-options: -Wall++test-suite spec+ type:+ exitcode-stdio-1.0+ ghc-options:+ -Wall+ hs-source-dirs:+ src, tests+ main-is:+ Spec.hs+ build-depends:+ base == 4.*+ , text >= 1.0+ , bytestring >= 0.8+ , hspec+ , hspec-expectations >= 0.5+ , attoparsec >= 0.10+ default-language:+ Haskell2010++source-repository head+ type: git+ location: http://github.com/alpmestan/hspec-attoparsec.git
+ src/Test/Hspec/Attoparsec.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE OverloadedStrings #-}+-- |+-- Module : Test.Hspec.Attoparsec+-- Copyright : (c) 2014 Alp Mestanogullari+-- License : BSD3+-- Maintainer : alpmestan@gmail.com+-- Stability : experimental+-- +-- Utility functions for testing @attoparsec@ parsers, each one providing+-- an example of how to use it.+module Test.Hspec.Attoparsec+ ( -- * Equality-based combinator+ shouldParse++ , -- * Predicate-based combinator+ parseSatisfies++ , -- * Inspecting the result+ shouldSucceedOn+ , shouldFailOn++ , -- * Inspecting unconsumed input+ leavesUnconsumed++ , -- * The 'Source' class, connecting parsers and inputs+ Source(..)++ , -- * The 'Leftover' class, letting us inspect unconsumed input+ Leftover(..)+ ) where++import Control.Monad (when)+import Data.Either (isLeft, isRight)+import Test.Hspec.Attoparsec.Source+import Test.Hspec.Expectations++-- | Create an expectation by saying what the result should be.+-- Intended to be used with '~>' as follows:+--+-- > "<!-- foo -->" ~> htmlCommentParser+-- > `shouldParse` TagComment " foo "+shouldParse :: (Eq a, Show a) => Either String a -> a -> Expectation+res `shouldParse` expectedVal =+ either (expectationFailure . errmsg)+ checkEquality+ res++ where errmsg err = " expected: " ++ show expectedVal+ ++ "\n but parsing failed with error: " ++ err++ checkEquality parsedVal =+ when (parsedVal /= expectedVal) $+ expectationFailure $ " expected: " ++ show expectedVal+ ++ "\n but got: " ++ show parsedVal++-- | Create an expectation by saying that the parser should successfully+-- parse a value and that this value should satisfy some predicate.+-- +-- This can fail if the parsing doesn't succeed or if it succeeds but+-- the value doesn't match the predicate.+--+-- > ">>>" ~> many (char '>')+-- > `parseSatisfies` ((==3) . length)+parseSatisfies :: Show a => Either String a -> (a -> Bool) -> Expectation+parseSatisfies res predicate =+ either (expectationFailure . errmsg)+ checkPred+ res++ where errmsg err = " expected a parsed value to check against the predicate"+ ++ "\n but parsing failed with error: " ++ err++ checkPred value =+ when (not $ predicate value) $+ expectationFailure $ + " the following value did not match the predicate: \n"+ ++ " " ++ show value++-- | Check that a parser fails on some given input+--+-- > char 'x' `shouldFailOn` "a"+shouldFailOn :: (Source p s s' r, Show a)+ => p s' a+ -> s+ -> Expectation+parser `shouldFailOn` string =+ (string ~> parser) `shouldSatisfy` isLeft++-- | Check that a parser succeeds on some given input+--+-- > char 'x' `shouldSucceedOn` "x"+shouldSucceedOn :: (Source p s s' r, Show a)+ => p s' a+ -> s+ -> Expectation+parser `shouldSucceedOn` string =+ (string ~> parser) `shouldSatisfy` isRight++-- | Checking that the given parser succeeds+-- and yields the given part of the input unconsumed.+-- Intended to be used in conjunction with '~?>'+--+-- > ("xa" :: Text) ~?> char 'x'+-- > `leavesUnconsumed` "a"+leavesUnconsumed :: (Source p s s' r, Leftover r s)+ => r a+ -> s+ -> Expectation+leavesUnconsumed res str+ | unconsumed == Nothing && str /= "" =+ expectationFailure $ + " expected the parser to leave the following unconsumed: " ++ show str+ ++ "\n but got no leftover"+ | otherwise = + case unconsumed of+ Just str' -> + when (str /= str') $+ expectationFailure $ + " expected the parser to leave the following unconsumed: " ++ show str+ ++ "\n but got: " ++ show str'+ Nothing -> expectationFailure $+ " expected the parser to leave the following unconsumed: " ++ show str+ ++ "\n but got no unconsumed input"++ where unconsumed = leftover res
+ src/Test/Hspec/Attoparsec/Source.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE MultiParamTypeClasses,+ TypeSynonymInstances,+ FlexibleInstances,+ FunctionalDependencies #-}+-- |+-- Module : Test.Hspec.Attoparsec.Source+-- Copyright : (c) 2014 Alp Mestanogullari+-- License : BSD3+-- Maintainer : alpmestan@gmail.com+-- Stability : experimental+-- +-- A 'Source' class that ties parser types and input types to+-- give you a uniform interface for testing your parsers,+-- without caring about the input type.+module Test.Hspec.Attoparsec.Source where ++import qualified Data.Attoparsec.ByteString as AB+import qualified Data.ByteString as B++import qualified Data.Attoparsec.ByteString.Lazy as ALB+import qualified Data.ByteString.Lazy as LB++import qualified Data.Attoparsec.Text as AT+import qualified Data.Text as T++import qualified Data.Attoparsec.Text.Lazy as ALT+import qualified Data.Text.Lazy as LT++import qualified Data.Attoparsec.Types as Atto++import Data.String (IsString)++-- | A class where each instance will just teach+-- how to get an Either or the specific result +-- type associated to the parser for the given+-- input type.+class (Eq string, Show string, IsString string)+ => Source parser string string' result | string -> parser, string -> result, string -> string' where+ -- | Feed some input to a parser and extract the result+ -- as either a failure 'String' or an actually parsed value.+ -- Can be read as /fed to/.+ -- + -- > -- "<a ...>" fed to an HTML parser + -- > "<a href=\"/foo\">Go to foo</a>" ~> htmlParser :: Either String a+ (~>) :: string -> parser string' a -> Either String a++ -- | Feed some input to a parser and extract it as the+ -- appropriate result type from that module.+ -- + -- This is not currently useful in the library per se,+ -- but is used in test-suites directly where we generally only deal+ -- with one concrete set of parser, input and result types.+ -- This lets us inspect the result in any way we want, e.g+ -- in conjunction with @shouldSatisfy@ or a custom hspec combinator.+ (~?>) :: string -> parser string' a -> result a++instance Source Atto.Parser B.ByteString B.ByteString AB.Result where+ t ~> p = AB.parseOnly p t++ t ~?> p = AB.parse p t++instance Source Atto.Parser LB.ByteString B.ByteString ALB.Result where+ t ~> p = ALB.eitherResult $ t ~?> p++ t ~?> p = ALB.parse p t++instance Source Atto.Parser T.Text T.Text AT.Result where+ t ~> p = AT.parseOnly p t++ t ~?> p = AT.parse p t++instance Source Atto.Parser LT.Text T.Text ALT.Result where+ t ~> p = ALT.eitherResult $ t ~?> p++ t ~?> p = ALT.parse p t++-- | Class for generically inspecting unconsumed input+class Leftover r s | r -> s where+ -- | Get the unconsumed input from the result of a parser+ -- + -- Returns 'Nothing' if the unconsumed input is ""+ leftover :: r a -> Maybe s++instance Leftover AB.Result B.ByteString where+ leftover (AB.Done t _) = Just t+ leftover _ = Nothing++instance Leftover ALB.Result LB.ByteString where+ leftover (ALB.Done t _) = Just t+ leftover _ = Nothing++instance Leftover AT.Result T.Text where+ leftover (AT.Done t _) = Just t+ leftover _ = Nothing++instance Leftover ALT.Result LT.Text where+ leftover (ALT.Done t _) = Just t+ leftover _ = Nothing
+ tests/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}