redact-0.4.0.0: test/Redact/Markdown/Mock.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
module Redact.Markdown.Mock (tests) where
-- https://hackage.haskell.org/package/base
import System.IO (IOMode(ReadMode), stdin)
-- https://hackage.haskell.org/package/explainable-predicates
import Test.Predicates (anything, eq)
-- https://hackage.haskell.org/package/HMock
import Test.HMock ((|->), (|=>), expect, inSequence, runMockT)
-- https://hackage.haskell.org/package/tasty
import Test.Tasty (TestTree, testGroup)
-- https://hackage.haskell.org/package/tasty-hunit
import Test.Tasty.HUnit ((@=?), testCase)
-- (redact)
import qualified Redact.Markdown as Redact
import Redact.Monad.Handle (MonadHandle)
import Redact.Monad.Terminal (resetSGRs)
-- (redact:test)
import TestLib
------------------------------------------------------------------------------
testTextToTerminalStrictEmpty :: TestTree
testTextToTerminalStrictEmpty = testCase "empty" . runMockT $
assertSuccess =<< Redact.textToTerminal redactSGRs ""
------------------------------------------------------------------------------
testTextToTerminalStrictOK :: TestTree
testTextToTerminalStrictOK = testCase "OK" . runMockT $ do
inSequence
[ expect $ PutStr "one`" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStr "two" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "`" |-> ()
, expect $ PutStr "```" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ PutStr "three" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ PutStrLn "```" |-> ()
]
assertSuccess =<< Redact.textToTerminal redactSGRs
"one`two`\n```\nthree\n```\n"
------------------------------------------------------------------------------
testTextToTerminalStrictErrorInline :: TestTree
testTextToTerminalStrictErrorInline = testCase "error_inline" $ do
Left err <- runMockT $
Redact.textToTerminal redactSGRs "one\ntwo`three\nfour`five`six\n"
err @=? Redact.RedactError "inline code not terminated (line 2)"
------------------------------------------------------------------------------
testTextToTerminalStrictErrorFenced :: TestTree
testTextToTerminalStrictErrorFenced = testCase "error_fenced" $ do
Left err <- runMockT $
Redact.textToTerminal redactSGRs "one\n```\ntwo\n"
err @=? Redact.RedactError "fenced code not terminated (line 4)"
------------------------------------------------------------------------------
testTextToTerminalLenientEmpty :: TestTree
testTextToTerminalLenientEmpty = testCase "empty" . runMockT $
Redact.textToTerminal' redactSGRs ""
------------------------------------------------------------------------------
testTextToTerminalLenientOK :: TestTree
testTextToTerminalLenientOK = testCase "OK" . runMockT $ do
inSequence
[ expect $ PutStr "one`" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStr "two" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "`" |-> ()
, expect $ PutStr "```" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ PutStr "three" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ PutStrLn "```" |-> ()
]
Redact.textToTerminal' redactSGRs "one`two`\n```\nthree\n```\n"
------------------------------------------------------------------------------
testTextToTerminalLenientErrorInline :: TestTree
testTextToTerminalLenientErrorInline = testCase "error_inline" . runMockT $ do
inSequence
[ expect $ PutStrLn "one" |-> ()
, expect $ PutStr "two`" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStr "three" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ PutStr "four`" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStr "five" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "`six" |-> ()
]
Redact.textToTerminal' redactSGRs "one\ntwo`three\nfour`five`six\n"
------------------------------------------------------------------------------
testTextToTerminalLenientErrorFenced :: TestTree
testTextToTerminalLenientErrorFenced = testCase "error_fenced" . runMockT $ do
inSequence
[ expect $ PutStrLn "one" |-> ()
, expect $ PutStr "```" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ PutStr "two" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "" |-> ()
]
Redact.textToTerminal' redactSGRs "one\n```\ntwo\n"
------------------------------------------------------------------------------
testHandleToTerminalStrictNone :: TestTree
testHandleToTerminalStrictNone = testCase "none" . runMockT $ do
expect $ HIsEOF stdin |-> True
assertSuccess =<< Redact.handleToTerminal redactSGRs stdin
------------------------------------------------------------------------------
testHandleToTerminalStrictOK :: TestTree
testHandleToTerminalStrictOK = testCase "OK" . runMockT $ do
inSequence
[ expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "one`two`"
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "```"
, expect $ PutStr "one`" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStr "two" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "`" |-> ()
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "three"
, expect $ PutStr "```" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "```"
, expect $ PutStr "three" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ HIsEOF stdin |-> True
, expect $ PutStrLn "```" |-> ()
]
assertSuccess =<< Redact.handleToTerminal redactSGRs stdin
------------------------------------------------------------------------------
testHandleToTerminalStrictErrorInline :: TestTree
testHandleToTerminalStrictErrorInline = testCase "error_inline" $ do
Left err <- runMockT $ do
inSequence
[ expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "one"
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "two`three"
, expect $ PutStrLn "one"
]
Redact.handleToTerminal redactSGRs stdin
err @=? Redact.RedactError "inline code not terminated (line 2)"
------------------------------------------------------------------------------
testHandleToTerminalStrictErrorFenced :: TestTree
testHandleToTerminalStrictErrorFenced = testCase "error_fenced" $ do
Left err <- runMockT $ do
inSequence
[ expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "one"
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "```"
, expect $ PutStrLn "one" |-> ()
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "two"
, expect $ PutStr "```" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ HIsEOF stdin |-> True
, expect $ PutStr "two" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "" |-> ()
]
Redact.handleToTerminal redactSGRs stdin
err @=? Redact.RedactError "fenced code not terminated (line 4)"
------------------------------------------------------------------------------
testHandleToTerminalLenientNone :: TestTree
testHandleToTerminalLenientNone = testCase "none" . runMockT $ do
expect $ HIsEOF stdin |-> True
Redact.handleToTerminal' redactSGRs stdin
------------------------------------------------------------------------------
testHandleToTerminalLenientOK :: TestTree
testHandleToTerminalLenientOK = testCase "OK" . runMockT $ do
inSequence
[ expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "one`two`"
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "```"
, expect $ PutStr "one`" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStr "two" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "`" |-> ()
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "three"
, expect $ PutStr "```" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "```"
, expect $ PutStr "three" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ HIsEOF stdin |-> True
, expect $ PutStrLn "```" |-> ()
]
Redact.handleToTerminal' redactSGRs stdin
------------------------------------------------------------------------------
testHandleToTerminalLenientErrorInline :: TestTree
testHandleToTerminalLenientErrorInline =
testCase "error_inline" . runMockT $ do
inSequence
[ expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "one"
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "two`three"
, expect $ PutStrLn "one"
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "four`five`six"
, expect $ PutStr "two`" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStr "three" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ HIsEOF stdin |-> True
, expect $ PutStr "four`" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStr "five" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "`six" |-> ()
]
Redact.handleToTerminal' redactSGRs stdin
------------------------------------------------------------------------------
testHandleToTerminalLenientErrorFenced :: TestTree
testHandleToTerminalLenientErrorFenced =
testCase "error_fenced" . runMockT $ do
inSequence
[ expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "one"
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "```"
, expect $ PutStrLn "one" |-> ()
, expect $ HIsEOF stdin |-> False
, expect $ HGetLine stdin |-> "two"
, expect $ PutStr "```" |-> ()
, expect $ SetSGR redactSGRs |-> ()
, expect $ PutStrLn "" |-> ()
, expect $ HIsEOF stdin |-> True
, expect $ PutStr "two" |-> ()
, expect $ SetSGR resetSGRs |-> ()
, expect $ PutStrLn "" |-> ()
]
Redact.handleToTerminal' redactSGRs stdin
------------------------------------------------------------------------------
testFileToTerminalStrictOK :: TestTree
testFileToTerminalStrictOK = testCase "OK" . runMockT $ do
expect $
( WithFile_ (eq "test.md") (eq ReadMode) anything
:: Matcher MonadHandle "withFile" IO
(Either IOError (Either Redact.Error ()))
)
|=> \(WithFile _path _mode _action) -> pure . Right $ Right ()
assertSuccess =<< Redact.fileToTerminal redactSGRs "test.md"
------------------------------------------------------------------------------
testFileToTerminalStrictRedactError :: TestTree
testFileToTerminalStrictRedactError = testCase "error_redact" $ do
let err = Redact.RedactError "inline code not terminated (line 42)"
Left err' <- runMockT $ do
expect $
( WithFile_ (eq "test.md") (eq ReadMode) anything
:: Matcher MonadHandle "withFile" IO
(Either IOError (Either Redact.Error ()))
)
|=> \(WithFile _path _mode _action) -> pure . Right $ Left err
Redact.fileToTerminal redactSGRs "test.md"
err' @=? err
------------------------------------------------------------------------------
testFileToTerminalStrictIOError :: TestTree
testFileToTerminalStrictIOError = testCase "error_io" $ do
let err = userError "nope"
Left err' <- runMockT $ do
expect $
( WithFile_ (eq "test.md") (eq ReadMode) anything
:: Matcher MonadHandle "withFile" IO
(Either IOError (Either Redact.Error ()))
)
|=> \(WithFile _path _mode _action) -> pure $ Left err
Redact.fileToTerminal redactSGRs "test.md"
err' @=? Redact.IOError err
------------------------------------------------------------------------------
testFileToTerminalLenientOK :: TestTree
testFileToTerminalLenientOK = testCase "OK" . runMockT $ do
expect $
( WithFile_ (eq "test.md") (eq ReadMode) anything
:: Matcher MonadHandle "withFile" IO (Either IOError ())
)
|=> \(WithFile _path _mode _action) -> pure $ Right ()
assertSuccess =<< Redact.fileToTerminal' redactSGRs "test.md"
------------------------------------------------------------------------------
testFileToTerminalLenientIOError :: TestTree
testFileToTerminalLenientIOError = testCase "error_io" $ do
let err = userError "nope"
Left err' <- runMockT $ do
expect $
( WithFile_ (eq "test.md") (eq ReadMode) anything
:: Matcher MonadHandle "withFile" IO (Either IOError ())
)
|=> \(WithFile _path _mode _action) -> pure $ Left err
Redact.fileToTerminal' redactSGRs "test.md"
err' @=? Redact.IOError err
------------------------------------------------------------------------------
tests :: TestTree
tests = testGroup "Redact.Markdown:Mock"
[ testGroup "textToTerminal"
[ testTextToTerminalStrictEmpty
, testTextToTerminalStrictOK
, testTextToTerminalStrictErrorInline
, testTextToTerminalStrictErrorFenced
]
, testGroup "textToTerminal'"
[ testTextToTerminalLenientEmpty
, testTextToTerminalLenientOK
, testTextToTerminalLenientErrorInline
, testTextToTerminalLenientErrorFenced
]
, testGroup "handleToTerminal"
[ testHandleToTerminalStrictNone
, testHandleToTerminalStrictOK
, testHandleToTerminalStrictErrorInline
, testHandleToTerminalStrictErrorFenced
]
, testGroup "handleToTerminal'"
[ testHandleToTerminalLenientNone
, testHandleToTerminalLenientOK
, testHandleToTerminalLenientErrorInline
, testHandleToTerminalLenientErrorFenced
]
, testGroup "fileToTerminal"
[ testFileToTerminalStrictOK
, testFileToTerminalStrictRedactError
, testFileToTerminalStrictIOError
]
, testGroup "fileToTerminal'"
[ testFileToTerminalLenientOK
, testFileToTerminalLenientIOError
]
]