hspec-megaparsec (empty) → 0.1.0
raw patch · 7 files changed
+403/−0 lines, 7 filesdep +basedep +hspecdep +hspec-expectationssetup-changed
Dependencies added: base, hspec, hspec-expectations, hspec-megaparsec, megaparsec
Files
- CHANGELOG.md +3/−0
- LICENSE.md +28/−0
- README.md +20/−0
- Setup.hs +6/−0
- Test/Hspec/Megaparsec.hs +190/−0
- hspec-megaparsec.cabal +82/−0
- tests/Main.hs +74/−0
+ CHANGELOG.md view
@@ -0,0 +1,3 @@+## Hspec Megaparsec 0.1.0++* Initial release.
+ LICENSE.md view
@@ -0,0 +1,28 @@+Copyright © 2016 Mark Karpov++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 Mark Karpov nor the names of 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 “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 HOLDERS 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.
+ README.md view
@@ -0,0 +1,20 @@+# Hspec Megaparsec++[](http://opensource.org/licenses/BSD-3-Clause)+[](https://hackage.haskell.org/package/hspec-megaparsec)+[](http://stackage.org/nightly/package/hspec-megaparsec)+[](https://travis-ci.org/mrkkrp/hspec-megaparsec)+[](https://coveralls.io/github/mrkkrp/hspec-megaparsec?branch=master)++The package provides utilities for testing+[`Megaparsec`](https://hackage.haskell.org/package/megaparsec) parsers with with+[`Hspec`](https://hackage.haskell.org/package/hspec).++Consult Haddocks for usage, which should be trivial. Also see test suite of+this package.++## License++Copyright © 2016 Mark Karpov++Distributed under BSD 3 clause license.
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main (main) where++import Distribution.Simple++main :: IO ()+main = defaultMain
+ Test/Hspec/Megaparsec.hs view
@@ -0,0 +1,190 @@+-- |+-- Module : Test.Hspec.Megaparsec+-- Copyright : © 2016 Mark Karpov+-- License : BSD 3 clause+--+-- Maintainer : Mark Karpov <markkarpov@openmailbox.org>+-- Stability : experimental+-- Portability : portable+--+-- Utility functions for testing Megaparsec parsers with Hspec.++module Test.Hspec.Megaparsec+ ( -- * Basic expectations+ shouldParse+ , parseSatisfies+ , shouldSucceedOn+ , shouldFailOn+ -- * Testing of error messages+ , shouldFailWith+ -- * Incremental parsing+ , failsLeaving+ , succeedsLeaving+ , initialState )+where++import Control.Monad (unless)+import Test.Hspec.Expectations+import Text.Megaparsec+import Text.Megaparsec.Pos (initialPos, defaultTabWidth)++----------------------------------------------------------------------------+-- Basic expectations++-- | Create an expectation by saying what the result should be.+--+-- > parse letterChar "" "x" `shouldParse` 'x'++shouldParse :: (Eq a, Show a)+ => Either ParseError a+ -- ^ Result of parsing as returned by function like 'parse'+ -> a -- ^ Desired result+ -> Expectation+r `shouldParse` v = case r of+ Left e -> expectationFailure $ "expected: " ++ show v +++ "\nbut parsing failed with error:\n" ++ showParseError e+ Right x -> unless (x == v) . expectationFailure $+ "expected: " ++ show v ++ "\nbut got: " ++ show x++-- | Create an expectation by saying that the parser should successfully+-- parse a value and that the value should satisfy some predicate.+--+-- > parse (many punctuationChar) "" "?!!" `parseSatisfies` ((== 3) . length)++parseSatisfies :: Show a+ => Either ParseError a+ -- ^ Result of parsing as returned by function like 'parse'+ -> (a -> Bool) -- ^ Predicate+ -> Expectation+r `parseSatisfies` p = case r of+ Left e -> expectationFailure $+ "expected a parsed value to check against the predicate" +++ "\nbut parsing failed with error:\n" ++ showParseError e+ Right x -> unless (p x) . expectationFailure $+ "the value did not satisfy the predicate: " ++ show x++-- | Check that a parser fails on some given input.+--+-- > parse (char 'x') "" `shouldFailOn` "a"++shouldFailOn :: (Show a, Stream s t)+ => (s -> Either ParseError a)+ -- ^ Parser that takes stream and produces result or error message+ -> s -- ^ Input that the parser should fail on+ -> Expectation+p `shouldFailOn` s = shouldFail (p s)++-- | Check that a parser succeeds on some given input.+--+-- > parse (char 'x') "" `shouldSucceedOn` "x"++shouldSucceedOn :: (Show a, Stream s t)+ => (s -> Either ParseError a)+ -- ^ Parser that takes stream and produces result or error message+ -> s -- ^ Input that the parser should succeed on+ -> Expectation+p `shouldSucceedOn` s = shouldSucceed (p s)++----------------------------------------------------------------------------+-- Testing of error messages++-- | Create an expectation that parser should fail producing certain+-- 'ParseError'. Use functions from "Text.Megaparsec.Error" to construct+-- parse errors to check against. See "Text.Megaparsec.Pos" for functions to+-- construct textual positions.+--+-- > parse (char 'x') "" "b" `shouldFailWith`+-- > newErrorMessages [Unexpected "'b'", Expected "'x'"] (initialPos "")++shouldFailWith :: Show a+ => Either ParseError a+ -> ParseError+ -> Expectation+r `shouldFailWith` e = case r of+ Left e' -> unless (e == e') . expectationFailure $+ "the parser is expected to fail with:\n" ++ showParseError e +++ "but it failed with:\n" ++ showParseError e+ Right v -> expectationFailure $+ "the parser is expected to fail, but it parsed: " ++ show v++----------------------------------------------------------------------------+-- Incremental parsing++-- | Check that a parser fails and leaves certain part of input+-- unconsumed. Use it with functions like 'runParser'' and 'runParserT''+-- that support incremental parsing.+--+-- > runParser' (many (char 'x') <* eof) (initialState "xxa")+-- > `failsLeaving` "xxa"+--+-- See also: 'initialState'.++failsLeaving :: (Show a, Eq s, Show s, Stream s t)+ => (State s, Either ParseError a)+ -- ^ Parser that takes stream and produces result along with actual+ -- state information+ -> s -- ^ Part of input that should be left unconsumed+ -> Expectation+(st,r) `failsLeaving` s =+ shouldFail r >> checkUnconsumed s (stateInput st)++-- | Check that a parser succeeds and leaves certain part of input+-- unconsumed. Use it with functions like 'runParser'' and 'runParserT''+-- that support incremental parsing.+--+-- > runParser' (many (char 'x')) (initialState "xxa")+-- > `succeedsLeaving` "a"+--+-- See also: 'initialState'.++succeedsLeaving :: (Show a, Eq s, Show s, Stream s t)+ => (State s, Either ParseError a)+ -- ^ Parser that takes stream and produces result along with actual+ -- state information+ -> s -- ^ Part of input that should be left unconsumed+ -> Expectation+(st,r) `succeedsLeaving` s =+ shouldSucceed r >> checkUnconsumed s (stateInput st)++-- | Given input for parsing, construct initial state for parser (that is,+-- with empty file name, default tab width and position at 1 line and 1+-- column).++initialState :: Stream s t => s -> State s+initialState s = State s (initialPos "") defaultTabWidth++----------------------------------------------------------------------------+-- Helpers++-- | Expectation that argument is result of a failed parser.++shouldFail :: Show a => Either ParseError a -> Expectation+shouldFail r = case r of+ Left _ -> return ()+ Right v -> expectationFailure $+ "the parser is expected to fail, but it parsed: " ++ show v++-- | Expectation that argument is result of a succeeded parser.++shouldSucceed :: Show a => Either ParseError a -> Expectation+shouldSucceed r = case r of+ Left e -> expectationFailure $+ "the parser is expected to succeed, but it failed with:\n" +++ showParseError e+ Right _ -> return ()++-- | Compare two streams for equality and in the case of mismatch report it.++checkUnconsumed :: (Eq s, Show s, Stream s t)+ => s -- ^ Expected unconsumed input+ -> s -- ^ Actual unconsumed input+ -> Expectation+checkUnconsumed e a = unless (e == a) . expectationFailure $+ "the parser is expected to leave unconsumed input: " ++ show e +++ "\nbut it left this: " ++ show a++-- | Render parse error in a way that is suitable for inserting it in test+-- suite report.++showParseError :: ParseError -> String+showParseError = unlines . fmap (" " ++) . lines . show
+ hspec-megaparsec.cabal view
@@ -0,0 +1,82 @@+--+-- Cabal configuration for ‘hspec-megaparsec’.+--+-- Copyright © 2016 Mark Karpov+--+-- 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 Mark Karpov nor the names of 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 “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 HOLDERS 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.++name: hspec-megaparsec+version: 0.1.0+cabal-version: >= 1.10+license: BSD3+license-file: LICENSE.md+author: Mark Karpov <markkarpov@opmbx.org>+maintainer: Mark Karpov <markkarpov@opmbx.org>+homepage: https://github.com/mrkkrp/hspec-megaparsec+bug-reports: https://github.com/mrkkrp/hspec-megaparsec/issues+category: Testing, Parsing+synopsis: Utility functions for testing Megaparsec parsers with Hspec+build-type: Simple+description: Utility functions for testing Megaparsec parsers with Hspec.+extra-source-files: CHANGELOG.md+ , README.md++flag dev+ description: Turn on development settings.+ manual: True+ default: False++library+ build-depends: base >= 4.6 && < 5+ , hspec-expectations >= 0.5+ , megaparsec >= 4.2+ exposed-modules: Test.Hspec.Megaparsec+ if flag(dev)+ ghc-options: -Wall -Werror+ else+ ghc-options: -Wall+ default-language: Haskell2010++test-suite tests+ main-is: Main.hs+ hs-source-dirs: tests+ type: exitcode-stdio-1.0+ if flag(dev)+ ghc-options: -Wall -Werror+ else+ ghc-options: -Wall+ build-depends: base >= 4.6 && < 5+ , hspec >= 2.0+ , hspec-expectations >= 0.5+ , hspec-megaparsec >= 0.1+ , megaparsec >= 4.2+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/mrkkrp/hspec-megaparsec.git
+ tests/Main.hs view
@@ -0,0 +1,74 @@+--+-- Hspec Megaparsec tests.+--+-- Copyright © 2016 Mark Karpov+--+-- 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 Mark Karpov nor the names of 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 “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 HOLDERS 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.++{-# LANGUAGE CPP #-}++module Main (main) where++import Test.Hspec+import Test.Hspec.Megaparsec+import Text.Megaparsec+import Text.Megaparsec.Error (newErrorMessages)+import Text.Megaparsec.Pos (initialPos)++#if !MIN_VERSION_base(4,8,0)+import Control.Applicative ((<*))+#endif++-- | Toy tests, just an example of usage.++main :: IO ()+main = hspec $ do+ describe "shouldParse" $+ it "works" $+ parse letterChar "" "x" `shouldParse` 'x'+ describe "parseSatisfies" $+ it "works" $+ parse (many punctuationChar) "" "?!!" `parseSatisfies` ((== 3) . length)+ describe "shouldFailOn" $+ it "works" $+ parse (char 'x') "" `shouldFailOn` "a"+ describe "shouldSucceedOn" $+ it "works" $+ parse (char 'x') "" `shouldSucceedOn` "x"+ describe "shouldFailWith" $+ it "works" $+ parse (char 'x') "" "b" `shouldFailWith`+ newErrorMessages [Unexpected "'b'", Expected "'x'"] (initialPos "")+ describe "failsLeaving" $+ it "works" $+ runParser' (many (char 'x') <* eof) (initialState "xxa")+ `failsLeaving` "xxa"+ describe "succeedsLeaving" $+ it "works" $+ runParser' (many (char 'x')) (initialState "xxa")+ `succeedsLeaving` "a"