packages feed

streamly-0.11.0: test/Streamly/Test/Data/Parser/Common.hs

{-# Language NoMonoLocalBinds #-}
-- XXX We are using head/tail at one place
#if __GLASGOW_HASKELL__ >= 908
{-# OPTIONS_GHC -Wno-x-partial #-}
#endif
module Streamly.Test.Data.Parser.Common (main) where

import Control.Applicative ((<|>))
import Control.Exception (displayException, try, evaluate, SomeException)
import Data.List (isSuffixOf)
import Streamly.Internal.Data.MutByteArray (Unbox)
import Streamly.Test.Common (listEquals, checkListEqual, chooseInt)
import Streamly.Internal.Data.Parser (ParseErrorPos(..))
import Test.QuickCheck
       (arbitrary, forAll, elements, Property, property, listOf,
        vectorOf, Gen, (.&&.), ioProperty)
import Test.QuickCheck.Monadic (monadicIO, assert, run, PropertyM)

import Prelude hiding (sequence)

import qualified Control.Monad.Fail as Fail
import qualified Data.List as List
import qualified Prelude
import qualified Streamly.Internal.Data.Stream as S
import qualified Streamly.Internal.Data.Array as A
import qualified Streamly.Internal.Data.Array.Generic as GA
import qualified Streamly.Internal.Data.Fold as FL
import qualified Streamly.Internal.Data.Parser as P
import qualified Streamly.Internal.Data.ParserK as PK
import qualified Streamly.Internal.Data.StreamK as K

import Test.Hspec
import Test.Hspec.QuickCheck

#if MIN_VERSION_QuickCheck(2,14,0)

import Test.QuickCheck (chooseAny)
import Control.Monad.Identity (Identity(runIdentity, Identity))

#else

import System.Random (Random(random))
import Test.QuickCheck.Gen (Gen(MkGen))

-- | Generates a random element over the natural range of `a`.
chooseAny :: Random a => Gen a
chooseAny = MkGen (\r _ -> let (x,_) = random r in x)

#endif

min_value :: Int
min_value = 0

mid_value :: Int
mid_value = 5000

max_value :: Int
max_value = 10000

max_length :: Int
max_length = 1000

-- Accumulator Tests

-- TODO: Replace ParserTestCase_Temp with ParserTestCase in all the test cases.

type ParserTestCase a m b c =
        (P.Parser a m b -> [a] -> m (Either ParseErrorPos b, [a])) -> c

type ParserTestCase_Temp a m b c =
        forall t. ([a] -> t)
        -> (P.Parser a m b -> t -> m (Either ParseErrorPos b))
        -> c

fromFold :: ParserTestCase Int IO Int Property
fromFold consumer =
    forAll (listOf $ chooseInt (min_value, max_value)) $ \ls ->
        ioProperty $ do
        (s1, rest) <- consumer (P.fromFold FL.sum) ls
        o2 <- S.fold FL.sum (S.fromList ls)
        pure $ rest == [] &&
            case s1 of
                Right o1 -> o1 == o2
                Left _ -> False

fromPure :: ParserTestCase Int Identity Int Property
fromPure consumer =
    forAll (chooseInt (min_value, max_value)) $ \x ->
        case runIdentity $ consumer (P.fromPure x) [1 :: Int] of
            (Right r, rest) -> r == x && rest == [1 :: Int]
            (Left _, _) -> False

fromEffect :: ParserTestCase Int Identity Int Property
fromEffect consumer =
    forAll (chooseInt (min_value, max_value)) $ \x ->
        case runIdentity $ consumer (P.fromEffect $ return x) [1 :: Int] of
            (Right r, rest) -> r == x && rest == [1 :: Int]
            (Left _, _) -> False

die :: ParserTestCase Int Identity Int Property
die consumer =
    property $
    case runIdentity $ consumer (P.die "die test") [0 :: Int] of
        (Right _, _) -> False
        (Left _, rest) -> rest == [0 :: Int]

dieM :: ParserTestCase Int Identity Int Property
dieM consumer =
    property $
    case runIdentity $ consumer (P.dieM (Identity "die test")) [0 :: Int] of
        (Right _, _) -> False
        (Left _, rest) -> rest == [0 :: Int]

parserFail :: ParserTestCase Int Identity Int Property
parserFail consumer =
    property $
        case runIdentity $ consumer (Fail.fail err) [0 :: Int] of
            (Right _, _) -> False
            (Left (ParseErrorPos _ e), rest) -> err == e && rest == [0 :: Int]
    where
    err = "Testing MonadFail.fail."

-- Element Parser Tests

peekPass :: ParserTestCase Int Identity Int Property
peekPass consumer =
    forAll (chooseInt (1, max_length)) $ \list_length ->
        forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
            case runIdentity $ consumer P.peek ls of
                (Right head_value, rest) -> case ls of
                    head_ls : _ -> head_value == head_ls && rest == ls
                    _ -> False
                (Left _, _) -> False

peekFail :: ParserTestCase Int Identity Int Property
peekFail consumer =
    property (case runIdentity $ consumer P.peek [] of
        (Right _, _) -> False
        (Left _, rest) -> rest == [])

eofPass :: ParserTestCase_Temp Int Identity () Property
eofPass producer consumer =
    property (case runIdentity $ consumer P.eof (producer []) of
        Right _ -> True
        Left _ -> False)

eofFail :: ParserTestCase_Temp Int Identity () Property
eofFail producer consumer =
    forAll (chooseInt (1, max_length)) $ \list_length ->
        forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
            case runIdentity $ consumer P.eof (producer ls) of
                Right _ -> False
                Left _ -> True

satisfyPass :: ParserTestCase_Temp Int Identity Int Property
satisfyPass producer consumer =
    forAll (chooseInt (mid_value, max_value)) $ \first_element ->
        forAll (listOf (chooseInt (min_value, max_value))) $ \ls_tail ->
            let
                ls = first_element : ls_tail
                predicate = (>= mid_value)
            in
                case runIdentity $ consumer (P.satisfy predicate) (producer ls) of
                    Right r -> r == first_element
                    Left _ -> False

satisfy :: ParserTestCase_Temp Int Identity Int Property
satisfy producer consumer =
    forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
        case runIdentity $ consumer (P.satisfy predicate) (producer ls) of
            Right r -> case ls of
                [] -> False
                (x : _) -> predicate x && (r == x)
            Left _ -> case ls of
                [] -> True
                (x : _) -> not $ predicate x
        where
            predicate = (>= mid_value)

onePass :: ParserTestCase_Temp Int Identity Int Property
onePass producer consumer =
    forAll (chooseInt (1, max_value)) $ \int ->
        property (case runIdentity $ consumer P.one (producer [int]) of
            Right i -> i  == int
            Left _ -> False)

one :: ParserTestCase_Temp Int Identity Int Property
one producer consumer =
    property $
        case runIdentity $ consumer P.one (producer []) of
            Left _ -> True
            Right _ -> False

-- Sequence Parsers Tests
takeBetweenPass :: ParserTestCase_Temp Int Identity [Int] Property
takeBetweenPass producer consumer =
    forAll (chooseInt (min_value, max_value)) $ \m ->
        forAll (chooseInt (m, max_value)) $ \n ->
            forAll (chooseInt (m, max_value)) $ \list_length ->
                forAll (vectorOf list_length (chooseInt (min_value, max_value)))
                    $ \ls ->
                        case runIdentity $ consumer (P.takeBetween m n FL.toList)
                                (producer ls) of
                            Right parsed_list ->
                                let lpl = Prelude.length parsed_list
                                in checkListEqual parsed_list
                                    $ Prelude.take lpl ls
                            Left _ -> property False

takeBetween :: ParserTestCase_Temp Int Identity [Int] Property
takeBetween producer consumer =
    forAll (chooseInt (min_value, max_value)) $ \m ->
        forAll (chooseInt (min_value, max_value)) $ \n ->
            forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
                ioProperty $ go m n ls

    where

    go m n ls = do
        let inputLen = Prelude.length ls
        let p = P.takeBetween m n FL.toList
        eres <- try $ evaluate $ runIdentity $ consumer p (producer ls)
        pure $ case eres of
            Left (_ :: SomeException) -> m >= 0 && n >= 0 && m > n
            Right (Right xs) ->
                let parsedLen = Prelude.length xs
                in (inputLen >= m && parsedLen >= m && parsedLen <= n)
                       && (xs == Prelude.take parsedLen ls)
            Right (Left _) -> inputLen < m


take :: ParserTestCase_Temp Int Identity [Int] Property
take producer consumer =
    forAll (chooseInt (min_value, max_value)) $ \n ->
        forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
            case runIdentity $ consumer (P.fromFold $ FL.take n FL.toList) (producer ls) of
                Right parsed_list -> checkListEqual parsed_list (Prelude.take n ls)
                Left _ -> property False

takeEQPass :: ParserTestCase_Temp Int Identity [Int] Property
takeEQPass producer consumer =
    forAll (chooseInt (min_value, max_value)) $ \n ->
        forAll (chooseInt (n, max_value)) $ \list_length ->
            forAll (vectorOf list_length
                        (chooseInt (min_value, max_value))) $ \ls ->
                case runIdentity $ consumer (P.takeEQ n FL.toList) (producer ls) of
                    Right parsed_list ->
                        checkListEqual parsed_list (Prelude.take n ls)
                    Left _ -> property False

takeEQ :: ParserTestCase_Temp Int Identity [Int] Property
takeEQ producer consumer =
    forAll (chooseInt (min_value, max_value)) $ \n ->
        forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
            let
                list_length = Prelude.length ls
            in
                case runIdentity $ consumer (P.takeEQ n FL.toList) (producer ls) of
                    Right parsed_list ->
                        if n <= list_length
                        then checkListEqual parsed_list (Prelude.take n ls)
                        else property False
                    Left _ -> property (n > list_length)

takeGEPass :: ParserTestCase_Temp Int Identity [Int] Property
takeGEPass producer consumer =
    forAll (chooseInt (min_value, max_value)) $ \n ->
        forAll (chooseInt (n, max_value)) $ \list_length ->
            forAll (vectorOf list_length (chooseInt (min_value, max_value)))
                $ \ls ->
                    case runIdentity $ consumer (P.takeGE n FL.toList) (producer ls) of
                        Right parsed_list -> checkListEqual parsed_list ls
                        Left _ -> property False

takeGE :: ParserTestCase_Temp Int Identity [Int] Property
takeGE producer consumer =
    forAll (chooseInt (min_value, max_value)) $ \n ->
        forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
            let
                list_length = Prelude.length ls
            in
                case runIdentity $ consumer (P.takeGE n FL.toList) (producer ls) of
                    Right parsed_list ->
                        if n <= list_length
                        then checkListEqual parsed_list ls
                        else property False
                    Left _ -> property (n > list_length)

nLessThanEqual0 ::
       (  Int
       -> FL.Fold Identity Int [Int]
       -> P.Parser Int Identity [Int]
       )
    -> (Int -> [Int] -> [Int])
    -> ParserTestCase_Temp Int Identity [Int] Property
nLessThanEqual0 tk ltk producer consumer =
    forAll (elements [0, (-1)]) $ \n ->
        forAll (listOf arbitrary) $ \ls ->
            case runIdentity $ consumer (tk n FL.toList) (producer ls) of
                Right parsed_list -> checkListEqual parsed_list (ltk n ls)
                Left _ -> property False

takeProperties :: ParserTestCase_Temp Int Identity [Int] Spec
takeProperties producer consumer =
    describe "take combinators when n <= 0/" $ do
        prop "takeEQ n FL.toList = []" $
            nLessThanEqual0 P.takeEQ (\_ -> const []) producer consumer
        prop "takeGE n FL.toList xs = xs" $
            nLessThanEqual0 P.takeGE (\_ -> id) producer consumer

-- XXX lookAhead can't deal with EOF which in this case means when
-- n==list_length, this test will fail. So excluding that case for now.
lookAheadPass :: ParserTestCase_Temp Int Identity ([Int], [Int]) Property
lookAheadPass producer consumer =
    forAll (chooseInt (min_value, max_value)) $ \n ->
        let
            takeWithoutConsume = P.lookAhead $ P.fromFold $ FL.take n FL.toList
            parseTwice = do
                parsed_list_1 <- takeWithoutConsume
                parsed_list_2 <- takeWithoutConsume
                return (parsed_list_1, parsed_list_2)
        in
            forAll (chooseInt (n+1, max_value)) $ \list_length ->
                forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
                    case runIdentity $ consumer parseTwice (producer ls) of
                        Right (ls_1, ls_2) -> checkListEqual ls_1 ls_2 .&&. checkListEqual ls_1 (Prelude.take n ls)
                        Left _ -> property $ False

-- lookAheadFail :: ParserTestCase_Temp Int Identity Int Property
-- lookAheadFail producer consumer =
--     forAll (chooseInt (min_value + 1, max_value)) $ \n ->
--         let
--             takeWithoutConsume = P.lookAhead $ P.take n FL.toList
--             parseTwice = do
--                 parsed_list_1 <- takeWithoutConsume
--                 parsed_list_2 <- takeWithoutConsume
--                 return (parsed_list_1, parsed_list_2)
--         in
--             forAll (chooseInt (min_value, n - 1)) $ \list_length ->
--                 forAll (vectorOf list_length (chooseInt (min_value, max_value))) $ \ls ->
--                     case consumer parseTwice (producer ls) of
--                         Right _ -> False
--                         Left _ -> True

lookAhead :: ParserTestCase_Temp Int Identity ([Int], [Int]) Property
lookAhead producer consumer =
    forAll (chooseInt (min_value, max_value)) $ \n ->
        let
            takeWithoutConsume = P.lookAhead $ P.fromFold $ FL.take n FL.toList
            parseTwice = do
                parsed_list_1 <- takeWithoutConsume
                parsed_list_2 <- takeWithoutConsume
                return (parsed_list_1, parsed_list_2)
        in
            forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
                case runIdentity $ consumer parseTwice (producer ls) of
                    Right (ls_1, ls_2) -> checkListEqual ls_1 ls_2 .&&. checkListEqual ls_1 (Prelude.take n ls)
                    Left _ -> property ((list_length < n) || (list_length == n && n == 0))
                        where
                            list_length = Prelude.length ls

listTakeEndBy_ :: (a -> Bool) -> [a] -> ([a], [a])
listTakeEndBy_ predicate ls =
    case break predicate ls of
        (a, []) -> (a, [])
        (a, b) -> (a, tail b)

takeEndBy_ :: ParserTestCase Int Identity [Int] Property
takeEndBy_ consumer =
    forAll (listOf (chooseInt (min_value, max_value )))  $ \ls ->
        case runIdentity $ consumer (P.takeEndBy_ predicate prsr) ls of
            (Right parsed_list, rest) -> monadicIO $ do
                let (ls1, ls2) = listTakeEndBy_ predicate ls
                listEquals (==) parsed_list ls1
                listEquals (==) rest ls2
            _ -> property False
        where
            predicate = (>= 100)
            prsr = P.many (P.satisfy (const True)) FL.toList

takeEndByOrMax_ :: ParserTestCase Int Identity [Int] Property
takeEndByOrMax_ consumer =
    forAll (chooseInt (min_value, max_value)) $ \n ->
        forAll (listOf (chooseInt (0, 1))) $ \ls ->
            case runIdentity $ consumer (P.fromFold $ FL.takeEndBy_ predicate (FL.take n FL.toList)) ls of
                (Right parsed_list, rest) -> monadicIO $ do
                    let (lsa, lsb) = listTakeEndBy_ predicate ls
                        (ls1, ls2) = Prelude.splitAt n ls
                    if length lsa < length ls1
                    then do
                        listEquals (==) parsed_list lsa
                        listEquals (==) rest lsb
                    else do
                        listEquals (==) parsed_list ls1
                        listEquals (==) rest ls2
                _ -> property False
            where
                predicate = (== 1)

takeStartBy :: ParserTestCase Int Identity [Int] Property
takeStartBy consumer =
    forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
        let ls1 = 1:ls
        in
            case runIdentity $ consumer parser ls1 of
                (Right parsed_list, rest) ->
                  if not $ Prelude.null ls1
                  then
                    let (rls1, rls2) = Prelude.break predicate (tail ls1)
                    in monadicIO $ do
                           listEquals (==) parsed_list (head ls1 : rls1)
                           listEquals (==) rest rls2
                  else property $ Prelude.null parsed_list && Prelude.null rest
                _ -> property False
            where
                predicate = odd
                parser = P.takeBeginBy predicate FL.toList

takeWhile :: ParserTestCase Int Identity [Int] Property
takeWhile consumer =
    forAll (listOf (chooseInt (0, 1))) $ \ ls ->
        case runIdentity $ consumer (P.takeWhile predicate FL.toList) ls of
            (Right parsed_list, rest) -> monadicIO $ do
                let (ls1, ls2) = Prelude.span predicate ls
                listEquals (==) parsed_list ls1
                listEquals (==) rest ls2
            _ -> property False
        where
            predicate = (== 0)

takeP :: ParserTestCase Int Identity [Int] Property
takeP consumer =
    forAll
        ((,) <$> chooseInt (min_value, max_value)
             <*> listOf (chooseInt (0, 1)))
        $ \(takeNum, ls) ->
              case runIdentity $ consumer
                       (P.takeP takeNum (P.fromFold FL.toList)) ls of
                  (Right parsed_list, rest) -> monadicIO $ do
                      let (ls1, ls2) = Prelude.splitAt takeNum ls
                      listEquals (==) parsed_list ls1
                      listEquals (==) rest ls2
                  _ -> property False

takeWhile1 :: ParserTestCase Int Identity [Int] Property
takeWhile1 consumer =
    forAll (listOf (chooseInt (0, 1))) $ \ ls ->
        case runIdentity $ consumer (P.takeWhile1 predicate  FL.toList) ls of
            (Right parsed_list, rest) -> case ls of
                [] -> property False
                (x : _) ->
                    if predicate x
                    then monadicIO $ do
                        let (ls1, ls2) = span predicate ls
                        listEquals (==) parsed_list ls1
                        listEquals (==) rest ls2
                    else
                        property False
            (Left _, rest) -> monadicIO $ do
                listEquals (==) rest ls
                case ls of
                    [] -> assert True
                    (x : _) -> assert (not $ predicate x)
        where
            predicate = (== 0)

takeWhileP :: ParserTestCase Int Identity [Int] Property
takeWhileP consumer =
    forAll (listOf (chooseInt (0, 1))) $ \ls ->
        forAll (chooseInt (min_value, max_value)) $ \n ->
            let
                predicate = (== 1)

                prsr =
                    P.takeWhileP predicate
                        $ P.fromFold (FL.take n FL.toList)

                takeWhileTillLen maxLen prd list =
                    Prelude.take maxLen $ Prelude.takeWhile prd list
            in
                case runIdentity $ consumer prsr ls of
                    (Right parsed_list, rest) -> monadicIO $ do
                        let ls1 = takeWhileTillLen n predicate ls
                            ls2 = drop (length ls1) ls
                        listEquals (==) parsed_list ls1
                        listEquals (==) rest ls2
                    _ -> property False

{-
choice :: ParserTestCase_Temp Int Identity Int Property
choice producer consumer =
    forAll
        ((,,) <$> chooseInt (min_value, max_value)
             <*> chooseInt (min_value, max_value)
             <*> listOf (chooseInt (0, 1)))
        $ \(i, j, ls) ->
              case consumer (P.choice [parser i, parser j]) (producer ls) of
                  Right parsed_list ->
                      checkListEqual parsed_list $ take (min i j) ls
                  Left _ -> property False

    where

    parser i = P.fromFold (FL.take i FL.toList)
-}

groupBy :: ParserTestCase_Temp Int Identity [Int] Property
groupBy producer consumer =
    forAll (listOf (chooseInt (0, 1)))
        $ \ls ->
              case runIdentity $ consumer parser (producer ls) of
                  Right parsed -> checkListEqual parsed (groupByLF ls)
                  Left _ -> property False

    where

    cmp = (==)
    parser = P.groupBy cmp FL.toList
    groupByLF lst
        | null lst = []
        | otherwise = head $ List.groupBy cmp lst

groupByRolling :: ParserTestCase_Temp Int Identity [Int] Property
groupByRolling producer consumer =
    forAll (listOf (chooseInt (0, 1)))
        $ \ls ->
              case runIdentity $ consumer parser (producer ls) of
                  Right parsed -> checkListEqual parsed (groupByLF Nothing ls)
                  Left _ -> property False

    where

    cmp = (==)
    parser = P.groupBy cmp FL.toList
    groupByLF _ [] = []
    groupByLF Nothing (x:xs) = x : groupByLF (Just x) xs
    groupByLF (Just y) (x:xs) =
        if cmp y x
        then x : groupByLF (Just x) xs
        else []

wordBy :: ParserTestCase_Temp Char Identity [String] Property
wordBy producer consumer =
    forAll (listOf (elements [' ', 's']))
        $ \ls ->
              case runIdentity $ consumer parser (producer ls) of
                  Right parsed -> checkListEqual parsed (words' ls)
                  Left _ -> property False

    where

    predicate = (== ' ')
    parser = P.many (P.wordBy predicate FL.toList) FL.toList
    words' lst =
        let wrds = words lst
         in if wrds == [] && length lst > 0 then [""] else wrds

splitWith :: ParserTestCase_Temp Int Identity (Int, Int) Property
splitWith producer consumer =
    forAll (listOf (chooseInt (0, 1))) $ \ls ->
        case runIdentity $ consumer (P.splitWith (,) (P.satisfy (== 0)) (P.satisfy (== 1))) (producer ls) of
            Right (result_first, result_second) -> case ls of
                0 : 1 : _ -> (result_first == 0) && (result_second == 1)
                _ -> False
            Left _ -> case ls of
                0 : 1 : _ -> False
                _ -> True

splitWithFailLeft :: ParserTestCase_Temp Int Identity (Int, Int) Property
splitWithFailLeft producer consumer =
    property (case runIdentity $ consumer (P.splitWith (,) (P.die "die") (P.fromPure (1 :: Int))) (producer [1 :: Int]) of
        Right _ -> False
        Left _ -> True)

splitWithFailRight :: ParserTestCase_Temp Int Identity (Int, Int) Property
splitWithFailRight producer consumer =
    property (case runIdentity $ consumer (P.splitWith (,) (P.fromPure (1 :: Int)) (P.die "die")) (producer [1 :: Int]) of
        Right _ -> False
        Left _ -> True)

splitWithFailBoth :: ParserTestCase_Temp Int Identity (Int, Int) Property
splitWithFailBoth producer consumer =
    property (case runIdentity $ consumer (P.splitWith (,) (P.die "die") (P.die "die")) (producer [1 :: Int]) of
        Right _ -> False
        Left _ -> True)

-- teeWithPass :: ParserTestCase_Temp Int Identity Int Property
-- teeWithPass producer consumer =
--     forAll (chooseInt (min_value, max_value)) $ \n ->
--         forAll (listOf (chooseInt (0, 1))) $ \ls ->
--             let
--                 prsr = P.fromFold $ FL.take n FL.toList
--             in
--                 case consumer (P.teeWith (,) prsr prsr) (producer ls) of
--                     Right (ls_1, ls_2) -> checkListEqual (Prelude.take n ls) ls_1 .&&. checkListEqual ls_1 ls_2
--                     Left _ -> property False

-- teeWithFailLeft :: ParserTestCase_Temp Int Identity Int Property
-- teeWithFailLeft producer consumer =
--     property (case consumer (P.teeWith (,) (P.die "die") (P.fromPure (1 :: Int))) (producer [1 :: Int]) of
--         Right _ -> False
--         Left _ -> True)

-- teeWithFailRight :: ParserTestCase_Temp Int Identity Int Property
-- teeWithFailRight producer consumer =
--     property (case consumer (P.teeWith (,) (P.fromPure (1 :: Int)) (P.die "die")) (producer [1 :: Int]) of
--         Right _ -> False
--         Left _ -> True)

-- teeWithFailBoth :: ParserTestCase_Temp Int Identity Int Property
-- teeWithFailBoth producer consumer =
--     property (case consumer (P.teeWith (,) (P.die "die") (P.die "die")) (producer [1 :: Int]) of
--         Right _ -> False
--         Left _ -> True)

{-
deintercalate :: ParserTestCase_Temp Int Identity Int Property
deintercalate producer consumer =
    forAll (listOf (chooseAny :: Gen Int)) $ \ls ->
        case runIdentity $ consumer p (producer ls) of
            Right evenOdd -> evenOdd == List.partition even ls
            Left _ -> False

        where
            p1 = P.takeWhile even FL.toList
            p2 = P.takeWhile odd FL.toList
            partition =
                FL.tee (fmap concat $ FL.catLefts FL.toList)
                       (fmap concat $ FL.catRights FL.toList)
            p = P.deintercalate p1 p2 partition
-}

-- shortestPass :: ParserTestCase_Temp Int Identity Int Property
-- shortestPass producer consumer =
--     forAll (listOf (chooseInt(min_value, max_value))) $ \ls ->
--         let
--             half_mid_value = mid_value `Prelude.div` 2
--             prsr_1 = P.takeWhile (<= half_mid_value) FL.toList
--             prsr_2 = P.takeWhile (<= mid_value) FL.toList
--             prsr_shortest = P.shortest prsr_1 prsr_2
--         in
--             case consumer prsr_shortest (producer ls) of
--                 Right short_list -> checkListEqual short_list (Prelude.takeWhile (<= half_mid_value) ls)
--                 Left _ -> property False

-- shortestPassLeft :: ParserTestCase_Temp Int Identity Int Property
-- shortestPassLeft producer consumer =
--     property (case consumer (P.shortest (P.die "die") (P.fromPure (1 :: Int))) (producer [1 :: Int]) of
--         Right r -> r == 1
--         Left _ -> False)
--
-- shortestPassRight :: ParserTestCase_Temp Int Identity Int Property
-- shortestPassRight producer consumer =
--     property (case consumer (P.shortest (P.fromPure (1 :: Int)) (P.die "die")) (producer [1 :: Int]) of
--         Right r -> r == 1
--         Left _ -> False)

-- shortestFailBoth :: ParserTestCase_Temp Int Identity Int Property
-- shortestFailBoth producer consumer =
--     property
--         (case consumer
--                   (P.shortest (P.die "die") (P.die "die"))
--                   (producer [1 :: Int]) of
--              Right _ -> False
--              Left _ -> True)
--
-- longestPass :: ParserTestCase_Temp Int Identity Int Property
-- longestPass producer consumer =
--     forAll (listOf (chooseInt(min_value, max_value))) $ \ls ->
--         let
--             half_mid_value = mid_value `Prelude.div` 2
--             prsr_1 = P.takeWhile (<= half_mid_value) FL.toList
--             prsr_2 = P.takeWhile (<= mid_value) FL.toList
--             prsr_longest = P.longest prsr_1 prsr_2
--         in
--             case consumer prsr_longest (producer ls) of
--                 Right long_list -> long_list == Prelude.takeWhile (<= mid_value) ls
--                 Left _ -> False
--
-- longestPassLeft :: ParserTestCase_Temp Int Identity Int Property
-- longestPassLeft producer consumer =
--     property (case consumer (P.shortest (P.die "die") (P.fromPure (1 :: Int))) (producer [1 :: Int]) of
--         Right r -> r == 1
--         Left _ -> False)
--
-- longestPassRight :: ParserTestCase_Temp Int Identity Int Property
-- longestPassRight producer consumer =
--     property (case consumer (P.shortest (P.fromPure (1 :: Int)) (P.die "die")) (producer [1 :: Int]) of
--         Right r -> r == 1
--         Left _ -> False)
--
-- longestFailBoth :: ParserTestCase_Temp Int Identity Int Property
-- longestFailBoth producer consumer =
--     property
--         (case consumer (P.shortest (P.die "die") (P.die "die")) (producer [1 :: Int]) of
--         Right _ -> False
--         Left _ -> True)

many :: ParserTestCase_Temp Int Identity [Int] Property
many producer consumer =
    forAll (listOf (chooseInt (0, 1))) $ \ls ->
        let fldstp conL currL = return $ FL.Partial (conL ++ currL)
            concatFold = FL.Fold fldstp (return (FL.Partial [])) return return
            prsr =
                flip P.many concatFold
                    $ P.fromFold $ FL.takeEndBy_ (== 1) FL.toList
         in case runIdentity $ consumer prsr (producer ls) of
                Right res_list ->
                    checkListEqual res_list (Prelude.filter (== 0) ls)
                Left _ -> property False

many_empty :: ParserTestCase_Temp Int Identity [Int] Property
many_empty producer consumer =
    property (case runIdentity $ consumer (flip P.many FL.toList (P.die "die")) (producer [1 :: Int]) of
        Right res_list -> checkListEqual res_list ([] :: [Int])
        Left _ -> property False)

some :: ParserTestCase_Temp Int Identity [Int] Property
some producer consumer =
    forAll (listOf (chooseInt (0, 1))) $ \genLs ->
        let
            ls = 0 : genLs
            fldstp conL currL = return $ FL.Partial $ conL ++ currL
            concatFold = FL.Fold fldstp (return (FL.Partial [])) return return
            prsr =
                flip P.some concatFold
                    $ P.fromFold $ FL.takeEndBy_ (== 1) FL.toList
         in case runIdentity $ consumer prsr (producer ls) of
                Right res_list -> res_list == Prelude.filter (== 0) ls
                Left _ -> False

someFail :: ParserTestCase_Temp Int Identity [Int] Property
someFail producer consumer =
    property (case runIdentity $ consumer (P.some (P.die "die") FL.toList) (producer [1 :: Int]) of
        Right _ -> False
        Left _ -> True)

-------------------------------------------------------------------------------
-- Instances
-------------------------------------------------------------------------------

applicative :: ParserTestCase_Temp Int Identity ([Int], [Int]) Property
applicative producer consumer =
    forAll (listOf (chooseAny :: Gen Int)) $ \ list1 ->
        forAll (listOf (chooseAny :: Gen Int)) $ \ list2 ->
            let parser =
                    (,)
                        <$> P.fromFold (FL.take (length list1) FL.toList)
                        <*> P.fromFold (FL.take (length list2) FL.toList)
             in
                case runIdentity $ consumer parser (producer $ list1 ++ list2) of
                    Right (olist1, olist2) -> olist1 == list1 && olist2 == list2
                    Left _ -> False

sequence :: ParserTestCase_Temp Int IO [[Int]] Property
sequence producer consumer =
    forAll (vectorOf 11 (listOf (chooseAny :: Gen Int))) $ \ ins ->
        let p xs = P.fromFold (FL.take (length xs) FL.toList)
         in monadicIO $ do
                outs <- run $
                        consumer
                            (Prelude.sequence $ fmap p ins)
                            (producer $ concat ins)
                return $
                    case outs of
                        Right ls -> ls == ins
                        Left _ -> False

altEOF1 :: ParserTestCase_Temp Int (PropertyM IO) Int Property
altEOF1 producer consumer =
    monadicIO $ do
    s1 <- consumer
        (P.satisfy (> 0) <|> return 66)
        (producer ([]::[Int]))
    return $
        case s1 of
            Right x -> x == 66
            Left _ -> False

altEOF2 :: ParserTestCase_Temp Int (PropertyM IO) [Int] Property
altEOF2 producer consumer =
    monadicIO $ do
    s1 <- consumer
        ((P.takeEQ 2 FL.toList) <|> (P.takeEQ 1 FL.toList))
        (producer ([51]::[Int]))
    return $
        case s1 of
            Right x -> x == [51]
            Left _ -> False

monad :: ParserTestCase_Temp Int (PropertyM IO) ([Int], [Int]) Property
monad producer consumer =
    forAll (listOf (chooseAny :: Gen Int)) $ \ list1 ->
        forAll (listOf (chooseAny :: Gen Int)) $ \ list2 ->
            let parser = do
                    olist1 <- P.fromFold (FL.take (length list1) FL.toList)
                    olist2 <- P.fromFold (FL.take (length list2) FL.toList)
                    return (olist1, olist2)
             in monadicIO $ do
                    s <- consumer parser (producer $ list1 ++ list2)
                    return $
                        case s of
                            Right (olist1, olist2) -> olist1 == list1 && olist2 == list2
                            Left _ -> False

takeEndBy1 :: ParserTestCase_Temp Int Identity [Int] Property
takeEndBy1 producer consumer =
    forAll (listOf (chooseInt (0, 1))) $ \ls ->
        case runIdentity $ consumer (P.takeEndBy predicate prsr) (producer ls) of
            Right parsed_list ->
                checkListEqual
                parsed_list
                (takeWhileAndFirstFail (not . predicate) ls)
            Left _ -> property False
        where
            prsr = P.many (P.satisfy (const True)) FL.toList

            predicate = (== 1)

            takeWhileAndFirstFail prd (x : xs) =
                if prd x
                then x : takeWhileAndFirstFail prd xs
                else [x]
            takeWhileAndFirstFail _ [] = []

takeEndByEsc :: ParserTestCase_Temp Int Identity [Int] Property
takeEndByEsc producer consumer =
    forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
        let
            msg = "takeEndByEsc: trailing escape"

            isSep = even

            isEsc x = x `mod` 6 == 0

            prsr = P.takeEndByEsc isEsc isSep prsr0

                where

                prsr0 = P.many (P.satisfy (const True)) FL.toList

            escapeSep maybePrevEsc [] =
                case maybePrevEsc of
                    Nothing -> []
                    Just prevEsc -> [prevEsc]
            escapeSep maybePrevEsc (x : xs) =
                 case maybePrevEsc of
                    Nothing ->
                        if isEsc x
                        then escapeSep (Just x) xs
                        else
                            if isSep x
                            then [x]
                            else x : escapeSep Nothing xs
                    Just _ ->
                            x : escapeSep Nothing xs
        in
            case runIdentity $ consumer prsr (producer ls) of
                Right parsed_list -> checkListEqual parsed_list $ escapeSep Nothing ls
                Left err -> property (msg `isSuffixOf` displayException err)

takeFramedByEsc_ :: ParserTestCase_Temp Int Identity [Int] Property
takeFramedByEsc_ producer consumer =
    forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
        let
            isBegin = (== 0)

            isEnd = (== 1)

            isEsc = (== 2)

            prsr = P.takeFramedByEsc_ isEsc isBegin isEnd  FL.toList

            checkPass (x : xs) maybePrevEsc openMinusClose =
                case maybePrevEsc of
                    Nothing ->
                        if isEsc x
                        then checkPass xs (Just x) openMinusClose
                        else
                            if isBegin x
                            then checkPass xs Nothing (openMinusClose + 1)
                            else
                                if isEnd x
                                then
                                    case openMinusClose of
                                        0 -> False
                                        1 -> True
                                        _ ->
                                            checkPass
                                            xs
                                            Nothing
                                            (openMinusClose - 1)
                                else
                                    checkPass xs Nothing openMinusClose
                    Just _ -> checkPass xs Nothing openMinusClose
            checkPass [] _ _ = False

            checkPassBeg [] = False
            checkPassBeg xxs@(x:_)
                | isBegin x = checkPass xxs Nothing (0 :: Int)
                | otherwise = False

            escapeFrame begin end escape l =
                let
                    helper (x : xs) maybePrevEsc openMinusClose =
                        case maybePrevEsc of
                            Nothing ->
                                if escape x
                                then helper xs (Just x) openMinusClose
                                else
                                    if begin x
                                    then helper xs Nothing (openMinusClose + 1)
                                    else
                                        if end x
                                        then
                                            if openMinusClose - 1 == 0
                                            then []
                                            else
                                                helper
                                                xs
                                                Nothing
                                                (openMinusClose - 1)
                                        else
                                            x : helper xs Nothing openMinusClose
                            Just prevEsc ->
                                if escape x || begin x || end x
                                then x : helper xs Nothing openMinusClose
                                else
                                    prevEsc : x : helper xs Nothing openMinusClose
                    helper [] _ _ = error "Cannot Reach Here"
                in
                    helper l Nothing (0 :: Int)
        in
            case runIdentity $ consumer prsr (producer ls) of
                Right parsed_list ->
                    if checkPassBeg ls
                    then checkListEqual parsed_list $
                        escapeFrame isBegin isEnd isEsc ls
                    else property False
                Left _ ->
                    if checkPassBeg ls
                    then property False
                    else property True

takeFramedByEsc_Pass :: ParserTestCase_Temp Int Identity [Int] Property
takeFramedByEsc_Pass producer consumer =
    forAll (listOf (chooseInt (min_value, max_value))) $ \list ->
        let
            ls = (0 : list) ++ (Prelude.replicate (Prelude.length list + 1) 1)

            isBegin = (== 0)

            isEnd = (== 1)

            isEsc = (== 2)

            prsr = P.takeFramedByEsc_ isEsc isBegin isEnd FL.toList

            escapeFrame begin end escape l =
                let
                    helper (x : xs) maybePrevEsc openMinusClose =
                        case maybePrevEsc of
                            Nothing ->
                                if escape x
                                then helper xs (Just x) openMinusClose
                                else
                                    if begin x
                                    then
                                        if openMinusClose == 0
                                        then helper xs Nothing (openMinusClose + 1)
                                        else x : helper xs Nothing (openMinusClose + 1)
                                    else
                                        if end x
                                        then
                                            if openMinusClose - 1 == 0
                                            then []
                                            else
                                                x :
                                                helper
                                                xs
                                                Nothing
                                                (openMinusClose - 1)
                                        else
                                            x : helper xs Nothing openMinusClose
                            Just _ ->
                                x : helper xs Nothing openMinusClose
                    helper [] _ _ = error "Cannot Reach Here"
                in
                    helper l Nothing (0 :: Int)
        in
            case runIdentity $ consumer prsr (producer ls) of
                Right parsed_list -> checkListEqual parsed_list $ escapeFrame isBegin isEnd isEsc ls
                _ -> property False

takeFramedByEsc_Fail1 :: ParserTestCase_Temp Int Identity [Int] Property
takeFramedByEsc_Fail1 producer consumer =
    let
        msg = "takeFramedByEsc_: missing frame end"

        isBegin = (== 0)

        isEnd = (== 0)

        isEsc = (== 2)

        prsr = P.takeFramedByEsc_ isEsc isBegin isEnd FL.toList

        ls = [0 :: Int]
    in
        case runIdentity $ consumer prsr (producer ls) of
            Right _ -> property False
            Left err -> property (msg `isSuffixOf` displayException err)

takeFramedByEsc_Fail2 :: ParserTestCase_Temp Int Identity [Int] Property
takeFramedByEsc_Fail2 producer consumer =
    let
        msg = "takeFramedByEsc_: missing frame start"

        isBegin = (== 0)

        isEnd = (== 1)

        isEsc = (== 1)

        prsr = P.takeFramedByEsc_ isEsc isBegin isEnd FL.toList

        ls = [1 :: Int]
    in
        case runIdentity $ consumer prsr (producer ls) of
            Right _ -> property False
            Left err -> property (msg `isSuffixOf` displayException err)

takeFramedByEsc_Fail3 :: ParserTestCase_Temp Int Identity [Int] Property
takeFramedByEsc_Fail3 producer consumer =
    let
        msg = "takeFramedByEsc_: missing frame end"

        isBegin = (== 2)

        isEnd = (== 1)

        isEsc = (== 2)

        prsr = P.takeFramedByEsc_ isEsc isBegin isEnd FL.toList

        ls = [2 :: Int]
    in
        case runIdentity $ consumer prsr (producer ls) of
            Right _ -> property False
            Left err -> property (msg `isSuffixOf` displayException err)

takeStartBy_ :: ParserTestCase_Temp Int Identity [Int] Property
takeStartBy_ producer consumer =
     forAll (listOf (chooseInt (min_value, max_value))) $ \ls ->
        let ls1 = 1:ls
            msg = "takeFramedByGeneric: empty token"
        in
            case runIdentity $ consumer parser (producer ls1) of
                Right parsed_list ->
                  if not $ Prelude.null ls1
                  then
                    let tls = Prelude.takeWhile (not . predicate) (tail ls1)
                    in checkListEqual parsed_list $
                      if predicate (head ls1)
                      then tls
                      else Prelude.takeWhile (not . predicate) ls1
                  else property $ Prelude.null parsed_list
                Left err -> property (msg `isSuffixOf` displayException err)
            where
                predicate = odd
                parser = P.takeBeginBy_ predicate FL.toList

-------------------------------------------------------------------------------
-- Main
-------------------------------------------------------------------------------

data TestMode
    = TMParserStream
    | TMParserKStreamK
    | TMParserKStreamKChunks
    | TMParserKStreamKChunksGeneric
    deriving (Show)

runParserTC :: (Unbox a, Monad m) => TestMode -> ParserTestCase a m b c -> c
runParserTC tm runner =
    case tm of
        TMParserStream ->
            runner $ \p -> mapMTup S.toList . S.parseBreakPos p . S.fromList
        TMParserKStreamK ->
            runner $ \p ->
                mapMTup K.toList . K.parseBreakPos (PK.toParserK p) . K.fromList
        TMParserKStreamKChunks ->
            runner $ \p ->
                mapMTup
                    (fmap (concatMap A.toList) . K.toList)
                        . A.parseBreakPos (A.toParserK p)
                        . producerChunks A.fromList
        TMParserKStreamKChunksGeneric ->
            runner $ \p ->
                mapMTup
                    (fmap (concatMap GA.toList) . K.toList)
                        . GA.parseBreakPos (GA.toParserK p)
                        . producerChunks GA.fromList

    where
    mapMTup f tupM = do
        (t, a) <- tupM
        (t,) <$> f a

    cSize = 50
    -- Not using A.createOf here because of the MonadIO constraint
    producerChunks fl =
        K.fromStream
             . S.groupsOf cSize (fl <$> FL.toList)
             . S.fromList

runParserTC_temp :: (Unbox a, Monad m) => TestMode -> ParserTestCase_Temp a m b c -> c
runParserTC_temp tm runner =
    case tm of
        TMParserStream -> runner S.fromList S.parsePos
        TMParserKStreamK -> runner K.fromList (K.parsePos . PK.toParserK)
        TMParserKStreamKChunks ->
            runner (producerChunks A.fromList) (A.parsePos . A.toParserK)
        TMParserKStreamKChunksGeneric ->
            runner
                (producerChunks GA.fromList)
                (GA.parsePos . GA.toParserK)

    where
    cSize = 50
    -- Not using A.createOf here because of the MonadIO constraint
    producerChunks fl =
        K.fromStream
             . S.groupsOf cSize (fl <$> FL.toList)
             . S.fromList

{-# NOINLINE mainCommon #-}
mainCommon :: TestMode -> Spec
mainCommon ptt = do
  describe (show ptt) $ do
    describe "Instances" $ do
        prop "applicative" $ runParserTC_temp ptt applicative
        prop "Alternative: end of input 1" $ runParserTC_temp ptt altEOF1
        prop "Alternative: end of input 2" $ runParserTC_temp ptt altEOF2
        prop "monad" $ runParserTC_temp ptt monad
        prop "sequence" $ runParserTC_temp ptt sequence

    describe "test for accumulator" $ do
        prop "P.fromFold FL.sum = FL.sum" $ runParserTC ptt fromFold
        prop "fromPure value provided" $ runParserTC ptt fromPure
        prop "fromPure monadic value provided" $ runParserTC ptt fromEffect
        prop "fail err = Left (SomeException (ParseError err))" $ runParserTC ptt parserFail
        prop "always fail" $ runParserTC ptt die
        prop "always fail but monadic" $ runParserTC ptt dieM

    describe "test for element parser" $ do
        prop "peek = head with list length > 0" $ runParserTC ptt peekPass
        prop "peek fail on []" $ runParserTC ptt peekFail
        prop "eof pass on []" $ runParserTC_temp ptt eofPass
        prop "eof fail on non-empty list" $ runParserTC_temp ptt eofFail
        prop "first element exists and >= mid_value" $ runParserTC_temp ptt satisfyPass
        prop "one pass on [Int]" $ runParserTC_temp ptt onePass
        prop "one fail on []" $ runParserTC_temp ptt one
        prop "check first element exists and satisfies predicate" $ runParserTC_temp ptt satisfy
    describe "test for sequence parser" $ do
        prop "P.takeBetween = Prelude.take when len >= m and len <= n"
            $ runParserTC_temp ptt takeBetweenPass
        prop ("P.takeBetween = Prelude.take when len >= m and len <= n and fail"
              ++ "otherwise fail") $ runParserTC_temp ptt takeBetween
        prop "P.take = Prelude.take" $ runParserTC_temp ptt Streamly.Test.Data.Parser.Common.take
        prop "P.takeEQ = Prelude.take when len >= n" $ runParserTC_temp ptt takeEQPass
        prop "P.takeEQ = Prelude.take when len >= n and fail otherwise"
            $ runParserTC_temp ptt Streamly.Test.Data.Parser.Common.takeEQ
        prop "P.takeGE n ls = ls when len >= n" $ runParserTC_temp ptt takeGEPass
        prop "P.takeGE n ls = ls when len >= n and fail otherwise" $ runParserTC_temp ptt Streamly.Test.Data.Parser.Common.takeGE
        prop "lookAhead . take n >> lookAhead . take n = lookAhead . take n" $ runParserTC_temp ptt lookAheadPass
        -- prop "Fail when stream length exceeded" lookAheadFail
        prop "lookAhead . take n >> lookAhead . take n = lookAhead . take n, else fail" $ runParserTC_temp ptt lookAhead
        prop ("P.takeStartBy pred = head : Prelude.takeWhile (not . pred)"
                ++ " tail") $ runParserTC ptt takeStartBy
        prop "P.takeWhile = Prelude.takeWhile" $ runParserTC ptt Streamly.Test.Data.Parser.Common.takeWhile
        prop ("P.takeWhile1 = Prelude.takeWhile if taken something,"
                ++ " else check why failed") $ runParserTC ptt takeWhile1
        prop "takeWhileP prd P.take = takeWhileMaxLen prd" $ runParserTC ptt takeWhileP
        prop ("P.takeP = Prelude.take") $ runParserTC ptt takeP
        prop "P.groupBy = Prelude.head . Prelude.groupBy" $ runParserTC_temp ptt groupBy
        prop "groupByRolling" $ runParserTC_temp ptt groupByRolling
        prop "many (P.wordBy ' ') = words'" $ runParserTC_temp ptt wordBy
        -- prop "choice" choice
        prop "parse 0, then 1, else fail" $ runParserTC_temp ptt splitWith
        prop "fail due to die as left parser" $ runParserTC_temp ptt splitWithFailLeft
        prop "fail due to die as right parser" $ runParserTC_temp ptt splitWithFailRight
        prop "fail due to die as both parsers" $ runParserTC_temp ptt splitWithFailBoth
        -- prop "" teeWithPass
        -- prop "" teeWithFailLeft
        -- prop "" teeWithFailRight
        -- prop "" teeWithFailBoth
        -- prop "deintercalate" deintercalate
        -- prop "" shortestPass
        -- prop "" shortestFailLeft
        -- prop "" shortestFailRight
        -- prop "" shortestFailBoth
        prop ("P.many concatFold $ P.takeEndBy_ (== 1) FL.toList ="
                ++ "Prelude.filter (== 0)") $ runParserTC_temp ptt many
        prop "[] due to parser being die" $ runParserTC_temp ptt many_empty
        prop ("P.some concatFold $ P.takeEndBy_ (== 1) FL.toList ="
                ++ "Prelude.filter (== 0)") $ runParserTC_temp ptt some
        prop "fail due to parser being die" $ runParserTC_temp ptt someFail
        prop "takeEndBy_" $ runParserTC ptt takeEndBy_
        prop "takeEndByOrMax_" $ runParserTC ptt takeEndByOrMax_
        prop "takeEndBy1" $ runParserTC_temp ptt takeEndBy1
        prop "takeEndByEsc" $ runParserTC_temp ptt takeEndByEsc
        prop "takeFramedByEsc_" $ runParserTC_temp ptt takeFramedByEsc_
        prop "takeFramedByEsc_Pass" $ runParserTC_temp ptt takeFramedByEsc_Pass
        prop "takeFramedByEsc_Fail1" $ runParserTC_temp ptt takeFramedByEsc_Fail1
        prop "takeFramedByEsc_Fail2" $ runParserTC_temp ptt takeFramedByEsc_Fail2
        prop "takeFramedByEsc_Fail3" $ runParserTC_temp ptt takeFramedByEsc_Fail3
        prop "takeStartBy_" $ runParserTC_temp ptt takeStartBy_

    runParserTC_temp ptt takeProperties

main :: Spec
main = do
        -- We keep Parser and ParserK tests in the same (Parser) executable for 2
        -- reasons:
        -- 1. We almost always write Parser tests hence we prioritize Parser over
        --    ParserK
        -- 2. This results in minimal compilation overhead compared to duplicating
        --    or keeping the common part in the library.
        --    2.1. Duplication will result in compilation of this code twice
        --    2.2. Keeping the common part in the library will compile the Parser
        --         code even when it's not necessary. For example, if we are running
        --         non-parser test suites.
        --
        -- One problem is that this module becomes very big for compilation. We can
        -- break this further and keep them as a part of "other-modules" in
        -- Test.Parser test-suite.
        mainCommon TMParserStream
        mainCommon TMParserKStreamKChunks
        mainCommon TMParserKStreamK
        mainCommon TMParserKStreamKChunksGeneric