packages feed

pandoc-pyplot-1.1.0.0: test/Main.hs

module Main where

import Control.Monad     (unless)
import Data.List         (isInfixOf)

import Test.Tasty
import Test.Tasty.HUnit

import qualified Text.Pandoc.Filter.Pyplot as Filter
import qualified Text.Pandoc.Filter.Scripting as Filter
import Text.Pandoc.JSON

import System.Directory (doesFileExist)
import System.FilePath  ((</>))
import System.IO.Temp   (getCanonicalTemporaryDirectory)

main :: IO ()
main = defaultMain $ 
    testGroup "Text.Pandoc.Filter.Pyplot" 
        [ testFileCreation
        , testFileInclusion
        , testBlockingCallError
        ]

-- | Create a code block with the right attributes to trigger pandoc-pyplot
mkPlotCodeBlock :: FilePath            -- ^ Plot target
                -> String              -- ^ Plot alt description
                -> String              -- ^ Plot caption
                -> Maybe FilePath      -- ^ Possible inclusion
                -> Filter.PythonScript -- ^ Script
                -> Block
mkPlotCodeBlock target alt caption include script = CodeBlock attrs script
    where
        attrs = case include of
            Nothing -> ( mempty , mempty
                       , [ ("plot_target", target)
                         , ("plot_alt", alt)
                         , ("plot_caption", caption)
                         ]
                       )
            Just includePath -> ( mempty , mempty
                                , [ ("plot_target", target)
                                , ("plot_alt", alt)
                                , ("plot_caption", caption)
                                , ("plot_include", includePath)
                                  ]
                                )

-- | Assert that a file exists
assertFileExists :: HasCallStack 
                 => FilePath
                 -> Assertion
assertFileExists filepath = do
    fileExists <- doesFileExist filepath 
    unless fileExists (assertFailure msg)
    where
        msg = mconcat ["File ", filepath, " does not exist."]

-- | Assert that a list first list is contained, 
-- wholly and intact, anywhere within the second.
assertIsInfix :: (Eq a, Show a, HasCallStack)
              => [a]
              -> [a]
              -> Assertion
assertIsInfix xs ys = 
    unless (xs `isInfixOf` ys) (assertFailure msg)
    where
        msg = mconcat ["Expected ", show xs, " to be an infix of ", show ys]

-------------------------------------------------------------------------------
-- Test that plot files and source files are created when the filter is run
testFileCreation :: TestTree
testFileCreation = testCase "writes output and source files" $ do
    tempDir <- getCanonicalTemporaryDirectory
    let codeBlock = mkPlotCodeBlock 
            (tempDir </> "test.png") 
            mempty 
            mempty 
            Nothing
            "import matplotlib.pyplot as plt\n"    
    _ <- Filter.makePlot' codeBlock
    assertFileExists (tempDir </> "test.png")
    assertFileExists (tempDir </> "test.txt")

-------------------------------------------------------------------------------
-- Test that included files are found within the source
testFileInclusion :: TestTree
testFileInclusion = testCase "includes plot inclusions" $ do
    tempDir <- getCanonicalTemporaryDirectory
    
    let codeBlock = mkPlotCodeBlock 
            (tempDir </> "test.png") 
            mempty 
            mempty 
            (Just "test/fixtures/include.py") 
            "import matplotlib.pyplot as plt\n"
    _ <- Filter.makePlot' codeBlock

    inclusion <- readFile "test/fixtures/include.py"
    src <- readFile (tempDir </> "test.txt")
    assertIsInfix inclusion src

-------------------------------------------------------------------------------
-- Test that a script containing a blockign call to matplotlib.pyplot.show
-- returns the appropriate error
testBlockingCallError :: TestTree
testBlockingCallError = testCase "raises an exception for blocking calls" $ do
    tempDir <- getCanonicalTemporaryDirectory

    let codeBlock = mkPlotCodeBlock 
            (tempDir </> "test.png") 
            mempty 
            mempty 
            Nothing
            "import matplotlib.pyplot as plt\nplt.show()"
    
    result <- Filter.makePlot' codeBlock
    case result of
        Right block -> assertFailure "did not catch the expected blocking call"
        Left  error -> 
            if error == Filter.BlockingCallError 
            then pure () 
            else assertFailure "did not catch the expected blocking call"

-------------------------------------------------------------------------------