gigaparsec-0.2.0.0: test/Text/Gigaparsec/CharTests.hs
{-# LANGUAGE OverloadedLists #-}
module Text.Gigaparsec.CharTests where
import Test.Tasty
import Test.Tasty.HUnit
import Control.Monad
import Data.Char
import Data.Map.Strict qualified as Map
import Text.Gigaparsec
import Text.Gigaparsec.Char
import Text.Gigaparsec.Internal.Require
import Text.Gigaparsec.Internal.Test
tests :: TestTree
tests = testGroup "Char"
[ satisfyTests
, charTests
, stringTests
, satisfyMapTests
, oneOfTests
, noneOfTests
, stringsTests
, trieTests
]
satisfyTests :: TestTree
satisfyTests = testGroup "satisfy should"
[ testCase "be pure if it cannot read" do
pureParse (satisfy (const False))
pureParseWith (satisfy (== 'a')) ""
pureParseWith (satisfy (== 'a')) "b"
, testCase "be impure otherwise" do impureParseWith (satisfy (== 'a')) "a"
, testCase "return the parsed character" do
testParse item "a" @?= Success 'a'
testParse item "ba" @?= Success 'b'
testParse item "\NUL" @?= Success '\NUL'
, testCase "fail otherwise" do
ensureFails (satisfy (== 'b')) ""
ensureFails item ""
ensureFails (satisfy (== 'b')) "a"
]
charTests :: TestTree
charTests = testGroup "char should"
[ testCase "be pure if it cannot read" do
pureParseWith (char 'a') ""
pureParseWith (char 'a') "b"
, testCase "be impure otherwise" do impureParseWith (char 'a') "a"
, testCase "return the parsed character" do testParse (char 'a') "a" @?= Success 'a'
, testCase "fail otherwise" do
ensureFails (char 'a') ""
ensureFails (char 'a') "b"
]
stringTests :: TestTree
stringTests = testGroup "string should"
[ testCase "reject the empty string" (throws @RequirementUnsatisfied (testParse (string "") "")) -- don't ask why `string ""` doesn't work all the time
, testCase "be pure if it cannot read at all" do
pureParseWith (string "abc") ""
pureParseWith (string "abc") "123"
, testCase "be impure if there is a partial read" do impureParseWith (string "abc") "abd"
, testCase "be impure if full read" do impureParseWith (string "abc") "abc"
, testCase "return the parsed string" do testParse (string "123") "123" @?= Success "123"
, testCase "fail otherwise" do
ensureFails (string "123") "124"
ensureFails (string "123") "12"
]
satisfyMapTests :: TestTree
satisfyMapTests = testGroup "satisfyMap should"
[ testCase "fail when invalid" do
ensureFails p ""
ensureFails p "a"
, testCase "succeed performing the mapping otherwise" do
testParse p "4" @?= Success 4
testParse p "9" @?= Success 9
]
where p = satisfyMap (\c -> digitToInt c <$ guard (isDigit c))
oneOfTests :: TestTree
oneOfTests = testGroup "oneOf should"
[ testCase "fail when given no characters" do
pureParse p
ensureFails p ""
ensureFails p "a"
, testCase "act like character given one character" do
pureParseWith q ""
pureParseWith q "b"
impureParseWith q "a"
testParse q "a" @?= Success 'a'
ensureFails q ""
ensureFails q "b"
, testCase "parse within a contiguous range" do
pureParseWith r ""
pureParseWith r "a"
forM_ @[] ['0'..'9'] $ \c -> do
impureParseWith r (pure c)
testParse r (pure c) @?= Success c
ensureFails r "a"
ensureFails r "\NUL"
ensureFails r ":"
ensureFails r "/"
, testCase "parse any other sets" do
pureParseWith s ""
pureParseWith s "a"
forM_ @[] ['.', ';', ',', ':'] $ \c -> do
impureParseWith s (pure c)
testParse s (pure c) @?= Success c
ensureFails s "a"
ensureFails s "\NUL"
]
where p = oneOf []
q = oneOf ['a']
r = oneOf ['0' .. '9']
s = oneOf ['.', ';', ',', ':']
noneOfTests :: TestTree
noneOfTests = testGroup "oneOf should"
[ testCase "act like item when given no characters" do
pureParseWith p ""
ensureFails p ""
testParse p "a" @?= Success 'a'
testParse p "\ACK" @?= Success '\ACK'
, testCase "accept all but a specific character" do
pureParseWith q ""
pureParseWith q "a"
impureParseWith q "b"
testParse q "5" @?= Success '5'
ensureFails q ""
ensureFails q "a"
, testCase "parse within a contiguous range" do
pureParseWith r ""
impureParseWith r "a"
forM_ @[] ['0'..'9'] $ \c -> do
pureParseWith r (pure c)
ensureFails r (pure c)
testParse r "a" @?= Success 'a'
testParse r "\NUL" @?= Success '\NUL'
testParse r ":" @?= Success ':'
testParse r "/" @?= Success '/'
, testCase "parse any other sets" do
pureParseWith s ""
impureParseWith s "a"
forM_ @[] ['.', ';', ',', ':'] $ \c -> do
pureParseWith s (pure c)
ensureFails s (pure c)
testParse s "a" @?= Success 'a'
testParse s "\NUL" @?= Success '\NUL'
]
where p = noneOf []
q = noneOf ['a']
r = noneOf ['0' .. '9']
s = noneOf ['.', ';', ',', ':']
stringsTests :: TestTree
stringsTests = testGroup "strings should"
[ testCase "reject any empty strings" do throws @RequirementUnsatisfied (strings ["abc", "323", ""])
, testCase "have longest match behaviour" do
testParse p "hello" @?= Success "hello"
testParse p "hell" @?= Success "hell"
testParse p "he" @?= Success "h"
testParse p "123" @?= Success "123"
testParse p "124" @?= Success "1"
, testCase "reject anything outside of the set" do
ensureFails p "543"
ensureFails p "good"
]
where p = strings ["hell", "hello", "h", "123", "1"]
trieTests :: TestTree
trieTests = testGroup "trie should"
[ testCase "reject any empty strings" do throws @RequirementUnsatisfied (trie' ["" --> unit])
, testCase "have longest match behaviour" do
testParse p "hello" @?= Success "hello"
testParse p "hell" @?= Success "hell"
testParse p "h" @?= Success "h"
testParse p "he" @?= Success "h"
testParse p "hi" @?= Success "hi"
testParse p "good" @?= Success "good"
testParse p "goodby" @?= Success "good"
testParse p "goodbye" @?= Success "goodbye"
, testCase "reject anything outside of the set" do
ensureFails p "543"
ensureFails p "god"
]
where p = trie'
[ "h" --> atomic (trie' [ "ell" --> trie' ["o" --> pure "hello"]
<|> pure "hell"
, "i" --> pure "hi"
])
<|> pure "h"
, "good" --> atomic (trie' ["bye" --> pure "goodbye"])
<|> pure "good"
]
infix 0 -->
(-->) = (,)
trie' = trie . Map.fromList