pandoc-plot-0.1.0.0: tests/Common.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module Common where
import Control.Monad (unless)
import Control.Monad.Reader
import Data.Default.Class (def)
import Data.List (isInfixOf, isSuffixOf)
import Data.Monoid ((<>))
import Data.Text (Text, pack, unpack)
import Test.Tasty
import Test.Tasty.HUnit
import Text.Pandoc.Filter.Plot
import Text.Pandoc.Filter.Plot.Internal
import qualified Text.Pandoc.Builder as B
import qualified Text.Pandoc.Definition as B
import Text.Pandoc.JSON
import System.Directory (createDirectory,
createDirectoryIfMissing,
doesDirectoryExist,
doesFileExist, listDirectory,
removeDirectoryRecursive,
removePathForcibly)
import System.FilePath (takeExtensions, (</>))
import System.IO.Temp (getCanonicalTemporaryDirectory)
-------------------------------------------------------------------------------
-- Test that plot files and source files are created when the filter is run
testFileCreation :: Toolkit -> TestTree
testFileCreation tk =
testCase "writes output files in appropriate directory" $ do
tempDir <- (</> "test-file-creation") <$> getCanonicalTemporaryDirectory
ensureDirectoryExistsAndEmpty tempDir
let cb = (addDirectory tempDir $ codeBlock tk (trivialContent tk))
_ <- (make tk) def cb
filesCreated <- length <$> listDirectory tempDir
assertEqual "" 2 filesCreated
-------------------------------------------------------------------------------
-- Test that included files are found within the source
testFileInclusion :: Toolkit -> TestTree
testFileInclusion tk =
testCase "includes plot inclusions" $ do
tempDir <- (</> "test-file-inclusion") <$> getCanonicalTemporaryDirectory
ensureDirectoryExistsAndEmpty tempDir
let cb = (addInclusion (include tk) $
addDirectory tempDir $ codeBlock tk (trivialContent tk))
_ <- (make tk) def cb
inclusion <- readFile (include tk)
sourcePath <- head . filter (isExtensionOf "txt") <$> listDirectory tempDir
src <- readFile (tempDir </> sourcePath)
assertIsInfix inclusion src
where
include Matplotlib = "tests/includes/matplotlib.py"
include PlotlyPython = "tests/includes/plotly-python.py"
include Matlab = "tests/includes/matlabplot.m"
include Mathematica = "tests/includes/mathplot.m"
include Octave = "tests/includes/octave.m"
include GGPlot2 = "tests/includes/ggplot2.r"
-------------------------------------------------------------------------------
-- Test that the files are saved in the appropriate format
testSaveFormat :: Toolkit -> TestTree
testSaveFormat tk =
testCase "saves in the appropriate format" $ do
tempDir <- (</> "test-safe-format") <$> getCanonicalTemporaryDirectory
ensureDirectoryExistsAndEmpty tempDir
let fmt = head (supportedSaveFormats tk)
cb = (addSaveFormat fmt $
addDirectory tempDir $ codeBlock tk (trivialContent tk))
_ <- (make tk) def cb
numberjpgFiles <-
length <$> filter (isExtensionOf (extension fmt)) <$>
listDirectory tempDir
assertEqual "" numberjpgFiles 1
codeBlock :: Toolkit -> Script -> Block
codeBlock tk script = CodeBlock (mempty, [cls tk], mempty) script
trivialContent :: Toolkit -> Script
trivialContent Matplotlib = "import matplotlib.pyplot as plt\n"
trivialContent PlotlyPython = "import plotly.graph_objects as go; fit = go.Figure()\n"
trivialContent Matlab = "figure('visible', 'off')\n"
trivialContent Mathematica = "\n"
trivialContent Octave = "figure('visible', 'off')\nplot (-10:0.1:10);"
trivialContent GGPlot2 = "library(ggplot2)\nggplot()\n"
addCaption :: String -> Block -> Block
addCaption caption (CodeBlock (id', cls, attrs) script) =
CodeBlock (id', cls, attrs ++ [(tshow CaptionK, pack caption)]) script
addDirectory :: FilePath -> Block -> Block
addDirectory dir (CodeBlock (id', cls, attrs) script) =
CodeBlock (id', cls, attrs ++ [(tshow DirectoryK, pack dir)]) script
addInclusion :: FilePath -> Block -> Block
addInclusion inclusionPath (CodeBlock (id', cls, attrs) script) =
CodeBlock (id', cls, attrs ++ [(tshow PreambleK, pack inclusionPath)]) script
addSaveFormat :: SaveFormat -> Block -> Block
addSaveFormat saveFormat (CodeBlock (id', cls, attrs) script) =
CodeBlock (id', cls, attrs ++ [(tshow SaveFormatK, pack . extension $ saveFormat)]) script
addDPI :: Int -> Block -> Block
addDPI dpi (CodeBlock (id', cls, attrs) script) =
CodeBlock (id', cls, attrs ++ [(tshow DpiK, pack . show $ dpi)]) script
addWithSource :: Bool -> Block -> Block
addWithSource yn (CodeBlock (id', cls, attrs) script) =
CodeBlock (id', cls, attrs ++ [(tshow WithSourceK, pack . show $ yn)]) script
-- | 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."]
-- | Not available with GHC < 8.4
-- since this function was added in filepath-1.4.2
-- but GHC 8.2.2 comes with filepath-1.4.1.2
isExtensionOf :: String -> FilePath -> Bool
isExtensionOf ext@('.':_) = isSuffixOf ext . takeExtensions
isExtensionOf ext = isSuffixOf ('.':ext) . takeExtensions
-- | Assert that the 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]
-- Ensure a directory is empty but exists.
ensureDirectoryExistsAndEmpty :: FilePath -> IO ()
ensureDirectoryExistsAndEmpty dir = do
exists <- doesDirectoryExist dir
if exists
then removePathForcibly dir
else return ()
createDirectory dir
tshow :: Show a => a -> Text
tshow = pack . show