megaparsec-7.0.0: tests/Control/Monad/CombinatorsSpec.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE MultiWayIf #-}
module Control.Monad.CombinatorsSpec (spec) where
import Control.Monad.Combinators
import Data.List (intersperse)
import Data.Maybe (maybeToList, isNothing, fromJust)
import Test.Hspec
import Test.Hspec.Megaparsec
import Test.Hspec.Megaparsec.AdHoc
import Test.QuickCheck
import Text.Megaparsec.Char
#if !MIN_VERSION_base(4,11,0)
import Data.Monoid
#endif
spec :: Spec
spec = do
describe "count" $ do
it "works" . property $ \n x' -> do
let x = getNonNegative x'
p = count n (char 'x')
p' = count' n n (char 'x')
s = replicate x 'x'
prs_ p s `shouldBe` prs_ p' s
rightOrder (count 3 letterChar) "abc" "abc"
describe "count'" $ do
it "works" . property $ \m n x' -> do
let x = getNonNegative x'
p = count' m n (char 'x')
s = replicate x 'x'
if | n <= 0 || m > n ->
if x == 0
then prs_ p s `shouldParse` ""
else prs_ p s `shouldFailWith` err 0 (utok 'x' <> eeof)
| m <= x && x <= n ->
prs_ p s `shouldParse` s
| x < m ->
prs_ p s `shouldFailWith` err x (ueof <> etok 'x')
| otherwise ->
prs_ p s `shouldFailWith` err n (utok 'x' <> eeof)
rightOrder (count' 1 3 letterChar) "abc" "abc"
describe "endBy" $ do
it "works" . property $ \n' c -> do
let n = getNonNegative n'
p = endBy (char 'a') (char '-')
s = intersperse '-' (replicate n 'a') ++ [c]
if | c == 'a' && n == 0 ->
prs_ p s `shouldFailWith` err 1 (ueof <> etok '-')
| c == 'a' ->
prs_ p s `shouldFailWith` err (g n) (utok 'a' <> etok '-')
| c == '-' && n == 0 ->
prs_ p s `shouldFailWith` err 0 (utok '-' <> etok 'a'<> eeof)
| c /= '-' ->
prs_ p s `shouldFailWith` err (g n)
( utok c <>
(if n > 0 then etok '-' else eeof) <>
(if n == 0 then etok 'a' else mempty) )
| otherwise -> prs_ p s `shouldParse` replicate n 'a'
rightOrder (endBy letterChar (char ',')) "a,b,c," "abc"
describe "endBy1" $ do
it "works" . property $ \n' c -> do
let n = getNonNegative n'
p = endBy1 (char 'a') (char '-')
s = intersperse '-' (replicate n 'a') ++ [c]
if | c == 'a' && n == 0 ->
prs_ p s `shouldFailWith` err (1 :: Int) (ueof <> etok '-')
| c == 'a' ->
prs_ p s `shouldFailWith` err (g n) (utok 'a' <> etok '-')
| c == '-' && n == 0 ->
prs_ p s `shouldFailWith` err 0 (utok '-' <> etok 'a')
| c /= '-' ->
prs_ p s `shouldFailWith` err (g n)
( utok c <>
(if n > 0 then etok '-' else mempty) <>
(if n == 0 then etok 'a' else mempty) )
| otherwise -> prs_ p s `shouldParse` replicate n 'a'
rightOrder (endBy1 letterChar (char ',')) "a,b,c," "abc"
describe "manyTill" $ do
it "works" . property $ \a' b' c' -> do
let [a,b,c] = getNonNegative <$> [a',b',c']
p = (,) <$> manyTill letterChar (char 'c') <*> many letterChar
s = abcRow a b c
if c == 0
then prs_ p s `shouldFailWith` err (a + b)
(ueof <> etok 'c' <> elabel "letter")
else let (pre, post) = break (== 'c') s
in prs_ p s `shouldParse` (pre, drop 1 post)
rightOrder (manyTill letterChar (char 'd')) "abcd" "abc"
describe "someTill" $ do
it "works" . property $ \a' b' c' -> do
let [a,b,c] = getNonNegative <$> [a',b',c']
p = (,) <$> someTill letterChar (char 'c') <*> many letterChar
s = abcRow a b c
if | null s ->
prs_ p s `shouldFailWith` err 0 (ueof <> elabel "letter")
| c == 0 ->
prs_ p s `shouldFailWith` err (a + b)
(ueof <> etok 'c' <> elabel "letter")
| s == "c" ->
prs_ p s `shouldFailWith` err 1 (ueof <> etok 'c' <> elabel "letter")
| head s == 'c' ->
prs_ p s `shouldParse` ("c", drop 2 s)
| otherwise ->
let (pre, post) = break (== 'c') s
in prs_ p s `shouldParse` (pre, drop 1 post)
rightOrder (someTill letterChar (char 'd')) "abcd" "abc"
describe "sepBy" $ do
it "works" . property $ \n' c' -> do
let n = getNonNegative n'
c = fromJust c'
p = sepBy (char 'a') (char '-')
s = intersperse '-' (replicate n 'a') ++ maybeToList c'
if | isNothing c' ->
prs_ p s `shouldParse` replicate n 'a'
| c == 'a' && n == 0 ->
prs_ p s `shouldParse` "a"
| n == 0 ->
prs_ p s `shouldFailWith` err 0 (utok c <> etok 'a' <> eeof)
| c == '-' ->
prs_ p s `shouldFailWith` err (length s) (ueof <> etok 'a')
| otherwise ->
prs_ p s `shouldFailWith` err (g n) (utok c <> etok '-' <> eeof)
rightOrder (sepBy letterChar (char ',')) "a,b,c" "abc"
describe "sepBy1" $ do
it "works" . property $ \n' c' -> do
let n = getNonNegative n'
c = fromJust c'
p = sepBy1 (char 'a') (char '-')
s = intersperse '-' (replicate n 'a') ++ maybeToList c'
if | isNothing c' && n >= 1 ->
prs_ p s `shouldParse` replicate n 'a'
| isNothing c' ->
prs_ p s `shouldFailWith` err 0 (ueof <> etok 'a')
| c == 'a' && n == 0 ->
prs_ p s `shouldParse` "a"
| n == 0 ->
prs_ p s `shouldFailWith` err 0 (utok c <> etok 'a')
| c == '-' ->
prs_ p s `shouldFailWith` err (length s) (ueof <> etok 'a')
| otherwise ->
prs_ p s `shouldFailWith` err (g n) (utok c <> etok '-' <> eeof)
rightOrder (sepBy1 letterChar (char ',')) "a,b,c" "abc"
describe "sepEndBy" $ do
it "works" . property $ \n' c' -> do
let n = getNonNegative n'
c = fromJust c'
p = sepEndBy (char 'a') (char '-')
a = replicate n 'a'
s = intersperse '-' (replicate n 'a') ++ maybeToList c'
if | isNothing c' ->
prs_ p s `shouldParse` a
| c == 'a' && n == 0 ->
prs_ p s `shouldParse` "a"
| n == 0 ->
prs_ p s `shouldFailWith` err 0 (utok c <> etok 'a' <> eeof)
| c == '-' ->
prs_ p s `shouldParse` a
| otherwise ->
prs_ p s `shouldFailWith` err (g n) (utok c <> etok '-' <> eeof)
rightOrder (sepEndBy letterChar (char ',')) "a,b,c," "abc"
describe "sepEndBy1" $ do
it "works" . property $ \n' c' -> do
let n = getNonNegative n'
c = fromJust c'
p = sepEndBy1 (char 'a') (char '-')
a = replicate n 'a'
s = intersperse '-' (replicate n 'a') ++ maybeToList c'
if | isNothing c' && n >= 1 ->
prs_ p s `shouldParse` a
| isNothing c' ->
prs_ p s `shouldFailWith` err 0 (ueof <> etok 'a')
| c == 'a' && n == 0 ->
prs_ p s `shouldParse` "a"
| n == 0 ->
prs_ p s `shouldFailWith` err 0 (utok c <> etok 'a')
| c == '-' ->
prs_ p s `shouldParse` a
| otherwise ->
prs_ p s `shouldFailWith` err (g n) (utok c <> etok '-' <> eeof)
rightOrder (sepEndBy1 letterChar (char ',')) "a,b,c," "abc"
describe "skipMany" $
it "works" . property $ \c n' a -> do
let p = skipMany (char c) *> string a
n = getNonNegative n'
p' = many (char c) >> string a
s = replicate n c ++ a
prs_ p s `shouldBe` prs_ p' s
describe "skipSome" $
it "works" . property $ \c n' a -> do
let p = skipSome (char c) *> string a
n = getNonNegative n'
p' = some (char c) >> string a
s = replicate n c ++ a
prs_ p s `shouldBe` prs_ p' s
describe "skipCount" $
it "works" . property $ \c n' a -> do
let p = skipCount n (char c) *> string a
n = getNonNegative n'
p' = count n (char c) *> string a
s = replicate n c ++ a
prs_ p s `shouldBe` prs_ p' s
describe "skipManyTill" $
it "works" . property $ \c n' a -> c /= a ==> do
let p = skipManyTill (char c) (char a)
n = getNonNegative n'
s = replicate n c ++ [a]
prs_ p s `shouldParse` a
describe "skipSomeTill" $
it "works" . property $ \c n' a -> c /= a ==> do
let p = skipSomeTill (char c) (char a)
n = getNonNegative n'
s = replicate n c ++ [a]
if n == 0
then prs_ p s `shouldFailWith` err 0 (utok a <> etok c)
else prs_ p s `shouldParse` a
----------------------------------------------------------------------------
-- Helpers
g :: Int -> Int
g x = x + if x > 0 then x - 1 else 0