packages feed

foundation-0.0.2: tests/Test/Foundation/Parser.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Test.Foundation.Parser
  ( testParsers
  ) where

import Foundation
import Foundation.Parser

import Test.Tasty
import Test.Tasty.HUnit

data TestCaseRes a
    = TestCaseOk String a
    | TestCaseMore (Maybe String) (TestCaseRes a)
    | TestCaseFail
  deriving (Show)

parseTestCase :: (Show a, Eq a)
              => String
              -> Parser String a
              -> TestCaseRes a
              -> Assertion
parseTestCase buff parser = check (parse parser buff)
check :: (Show a, Eq a) => Result String a -> TestCaseRes a -> Assertion
check r e = case (r, e) of
    (ParseOK remain a, TestCaseOk eRemain ea) -> do
        assertEqual "remaining buffer" eRemain remain
        assertEqual "returned value" ea a
    (ParseMore fr, TestCaseMore mb res') -> check (fr mb) res'
    (ParseFail _, TestCaseFail) -> return ()
    _ -> assertFailure $ toList $
            "parseTestCase failed: "
                <> "expected: " <> show e <> " "
                <> "buf received: " <> show r

-- Some custom test cases
parseTestCases :: TestTree
parseTestCases = testGroup "units"
    [ testGroup "element"
        [ testCase "Ok" $ parseTestCase "a" (element 'a') (TestCaseOk "" ())
        , testCase "Fail" $ parseTestCase "b" (element 'a') TestCaseFail
        , testCase "MoreOk" $ parseTestCase "" (element 'a') (TestCaseMore (Just "a") (TestCaseOk "" ()))
        , testCase "MoreFail" $ parseTestCase "" (element 'a') (TestCaseMore Nothing TestCaseFail)
        ]
    , testGroup "elements"
        [ testCase "Ok" $ parseTestCase "abc" (elements "ab") (TestCaseOk "c" ())
        , testCase "Fail" $ parseTestCase "ac" (elements "ab") TestCaseFail
        , testCase "MoreOk" $ parseTestCase "a" (elements "abc") (TestCaseMore (Just "bc") (TestCaseOk "" ()))
        , testCase "MoreMoreOk" $ parseTestCase "a" (elements "abc") (TestCaseMore (Just "b") $ TestCaseMore (Just "c") (TestCaseOk "" ()))
        , testCase "MoreMoreFail" $ parseTestCase "a" (elements "abc") (TestCaseMore (Just "b") $ TestCaseMore Nothing TestCaseFail)
        ]
    , testGroup "anyElement"
        [ testCase "OK" $ parseTestCase "a"   anyElement (TestCaseOk "" 'a')
        , testCase "OkRemains" $ parseTestCase "abc" anyElement (TestCaseOk "bc" 'a')
        , testCase "MoreOk" $ parseTestCase ""    anyElement $ TestCaseMore (Just "abc")(TestCaseOk "bc" 'a')
        , testCase "MoreFail" $ parseTestCase ""    anyElement $ TestCaseMore Nothing TestCaseFail
        ]
    , testGroup "take"
        [ testCase "OK" $ parseTestCase "a" (take 1) (TestCaseOk "" "a")
        , testCase "OkRemains" $ parseTestCase "abc" (take 2) (TestCaseOk "c" "ab")
        , testCase "MoreOk" $ parseTestCase "" (take 2) $ TestCaseMore (Just "abc")(TestCaseOk "c" "ab")
        , testCase "MoreFail" $ parseTestCase "a" (take 2) $ TestCaseMore Nothing TestCaseFail
        ]
    , testGroup "takeWhile"
        [ testCase "OK" $ parseTestCase "a " (takeWhile (' ' /=)) (TestCaseOk " " "a")
        , testCase "OkRemains" $ parseTestCase "ab bc" (takeWhile (' ' /=)) (TestCaseOk " bc" "ab")
        , testCase "MoreOk" $ parseTestCase "ab" (takeWhile (' ' /=)) $ TestCaseMore (Just "cd ")(TestCaseOk " " "abcd")
        , testCase "MoreFail" $ parseTestCase "aa" (takeWhile (' ' /=)) $ TestCaseMore Nothing TestCaseFail
        ]
    , testGroup "takeAll"
        [ testCase "OK" $ parseTestCase "abc" takeAll (TestCaseMore Nothing $ TestCaseOk "" "abc")
        ]
    , testGroup "skip"
        [ testCase "OK" $ parseTestCase "a" (skip 1) (TestCaseOk "" ())
        , testCase "OkRemains" $ parseTestCase "abc" (skip 2) (TestCaseOk "c" ())
        , testCase "MoreOk" $ parseTestCase "" (skip 2) $ TestCaseMore (Just "abc")(TestCaseOk "c" ())
        , testCase "MoreFail" $ parseTestCase "a" (skip 2) $ TestCaseMore Nothing TestCaseFail
        ]
    , testGroup "skipWhile"
        [ testCase "OK" $ parseTestCase "a " (skipWhile (' ' /=)) (TestCaseOk " " ())
        , testCase "OkRemains" $ parseTestCase "ab bc" (skipWhile (' ' /=)) (TestCaseOk " bc" ())
        , testCase "MoreOk" $ parseTestCase "ab" (skipWhile (' ' /=)) $ TestCaseMore (Just "cd ")(TestCaseOk " " ())
        , testCase "MoreFail" $ parseTestCase "aa" (skipWhile (' ' /=)) $ TestCaseMore Nothing TestCaseFail
        ]
    , testGroup "skipAll"
        [ testCase "OK" $ parseTestCase "abc" skipAll (TestCaseMore Nothing $ TestCaseOk "abc" ())
        ]
    , testGroup "optional"
        [ testCase "Nothing" $ parseTestCase "aaa" (optional $ elements "bbb") (TestCaseOk "aaa" Nothing)
        , testCase "Just"    $ parseTestCase "aaa" (optional $ elements "a") (TestCaseOk "aa" (Just ()))
        ]
    , testGroup "many"
        [ testCase "many elements" $ parseTestCase "101010\0"
            (many ((element '1' >> pure True) <|> (element '0' >> pure False) ) )
            (TestCaseOk "\0" [True, False, True, False, True, False])
        ]
    ]

testParsers :: TestTree
testParsers = testGroup "Parsers"
    [ parseTestCases
    ]