packages feed

gigaparsec-0.2.0.0: test/Text/Gigaparsec/PrimitiveTests.hs

{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Alternative law, right identity" #-}
{-# HLINT ignore "Alternative law, left identity" #-}
{-# HLINT ignore "Use <$>" #-}
module Text.Gigaparsec.PrimitiveTests where

import Test.Tasty
import Test.Tasty.HUnit
--import Test.Tasty.ExpectedFailure

import Text.Gigaparsec
import Text.Gigaparsec.Internal.Test

import Data.Void

emptyAndPure, emptyPureAndAp :: String
emptyAndPure = "/primitives.pure/ || /primitives.empty/"
emptyPureAndAp = emptyAndPure ++ " || /primitives.(<*>)/"

tests :: TestTree
tests = testGroup "primitives"
  [ eofTests
  , pureTests
  , emptyTests
  , apTests
  , orTests
  , atomicTests
  , lookAheadTests
  , notFollowedByTests
  -- TODO: _branch, monad, semigroup?
  ]

eofTests :: TestTree
eofTests = testGroup "eof should"
  [ testCase "fail if input available" do ensureFails eof "a"
  , testCase "succeed if input ended" do testParse eof "" @?= Success ()
  , testCase "be pure" do pureParse eof
  ]

pureTests :: TestTree
pureTests = testGroup "pure should"
  [ testCase "be pure" do pureParse unit
  , testCase "produce the given result" do testParse unit "" @?= Success ()
  ]

emptyTests :: TestTree
emptyTests = testGroup "empty should"
  [ testCase "be pure" do pureParse empty
  , testCase "fail unconditionally" do
      ensureFails @Void empty ""
      ensureFails @Void empty "a"
  ]

apTests :: TestTree
apTests = after AllSucceed emptyAndPure $
  testGroup "(<*>) should"
    [ testCase "be pure if the sub-parsers are" do pureParse (pure id <*> pure 7)
    , testCase "be impure if either sub-parser is" do
        impureParse (consume id <*> pure 7)
        impureParse (pure id <*> consume 7)
        impureParse (consume id <*> consume 7)
    , testCase "sequence the left before the right" do pureParse (empty <*> consume 7)
    , testCase "be impure if the left is even when right fails" do impureParse (consume id <*> empty)
    ]

orTests :: TestTree
orTests = after AllSucceed emptyPureAndAp $
  testGroup "(<|>) should"
    [ testCase "be pure if the left-hand side is pure and succeeds" do
        pureParse (unit <|> consume ())
    , testCase "be impure if the left-hand side is impure and succeeds" do
        impureParse (consume () <|> empty)
    , testCase "succeed if the left-hand side succeeds" do
        testParse (unit <|> empty) "" @?= Success ()
        testParse (consume () <|> empty) "" @?= Success ()
    , testCase "be pure if the right-hand side succeeds purely" do
        pureParse (empty <|> unit)
    , testCase "be impure if the right-hand side succeeds impurely" do
        impureParse (empty <|> consume ())
    , testCase "fail if both sides fail" do ensureFails @Void (empty <|> empty) ""
    , testCase "be impure if the left-hand side is impure and fails" do
        impureParse (consume () <~> empty <|> empty)
    , testCase "fail if the left-hand side fails impurely" do
        ensureFails (consume () <**> empty <|> unit) ""
    ]

atomicTests :: TestTree
atomicTests = after AllSucceed emptyPureAndAp $
  testGroup "atomic should"
    [ testCase "be pure if the argument is pure" do
        pureParse (atomic unit)
        pureParse (atomic empty)
    , testCase "be impure if the argument is impure and succeeds" do
        impureParse (atomic (consume ()))
    , testCase "be pure if the argument fails, even if impure" do
        pureParse (atomic (consume () <**> empty))
    , testCase "not alter failure characteristics of argument" do
        testParse (atomic (consume ())) "" @?= Success ()
        testParse (atomic unit) "" @?= Success ()
        ensureFails @Void (atomic empty) ""
        ensureFails (atomic (consume () <* empty)) ""
    ]

lookAheadTests :: TestTree
lookAheadTests = after AllSucceed emptyPureAndAp $
  testGroup "lookAhead should"
    [ testCase "be pure if the argument is pure" do
        pureParse (lookAhead unit)
        pureParse (lookAhead empty)
    , testCase "be pure if the argument is impure and succeeds" do
        pureParse (lookAhead (consume ()))
    , testCase "be impure if the argument is impure and fails" do
        impureParse (lookAhead (consume () <* empty))
    , testCase "not alter failure characteristics of argument" do
        testParse (lookAhead (pure 7)) "" @?= Success 7
        testParse (lookAhead (consume 14)) "" @?= Success 14
        ensureFails @Void (lookAhead empty) ""
        ensureFails (lookAhead (consume () <* empty)) ""
    ]

notFollowedByTests :: TestTree
notFollowedByTests = after AllSucceed emptyPureAndAp $
  testGroup "notFollowedBy should"
    [ testCase "should always be pure" do
        pureParse (notFollowedBy unit)
        pureParse (notFollowedBy empty)
        pureParse (notFollowedBy (consume ()))
        pureParse (notFollowedBy (consume () *> empty))
    , testCase "should succeed if the argument fails" do
        testParse (notFollowedBy empty) "" @?= Success ()
        testParse (notFollowedBy (consume () *> empty)) "" @?= Success ()
    , testCase "should fail if the argument succeeds" do
        ensureFails (notFollowedBy unit) ""
        ensureFails (notFollowedBy (consume ())) ""
    ]