{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeSynonymInstances #-} import Prelude import qualified Control.Exception as E import Control.Monad import Data.Aeson import Data.Aeson.Types (Parser) import qualified Data.ByteString.Lazy as BL import Data.Char (isSpace, toLower) import Data.List (isInfixOf, sort) import qualified Data.Map as M import System.Directory import System.Environment (getArgs) import System.Exit import System.FilePath import System.IO.Temp (withSystemTempDirectory) import System.Process import Text.CSL import Text.CSL.Compat.Pandoc (writeHtmlString) import Text.CSL.Reference import Text.CSL.Style hiding (Number) import Text.Pandoc (Block (..), Format (..), Inline (..), Pandoc (..), bottomUp, nullMeta) import qualified Text.Pandoc.UTF8 as UTF8 import Text.Printf data TestCase = TestCase{ testMode :: Mode -- mode , testBibopts :: BibOpts -- bibsection , testCitations :: [CiteObject] -- citations , testCitationItems :: Citations -- citation-items , testCsl :: Style -- csl , testAbbreviations :: Abbreviations -- abbreviations , testReferences :: [Reference] -- input , testResult :: String -- result } deriving (Show) data Mode = CitationMode | CitationRTFMode | BibliographyMode | BibliographyHeaderMode | BibliographyNoSortMode deriving Show instance FromJSON Mode where parseJSON (String "citation") = return CitationMode parseJSON (String "citation-rtf") = return CitationRTFMode parseJSON (String "bibliography") = return BibliographyMode parseJSON (String "bibliography-header") = return BibliographyHeaderMode parseJSON (String "bibliography-nosort") = return BibliographyNoSortMode parseJSON _ = fail "Unknown mode" instance FromJSON TestCase where parseJSON (Object v) = TestCase <$> v .: "mode" <*> v .:? "bibsection" .!= Select [] [] <*> ((v .: "citations") >>= parseCitations) <*> v .:? "citation_items" .!= [] <*> (parseCSL <$> (v .: "csl")) <*> v .:? "abbreviations" .!= (Abbreviations M.empty) <*> v .: "input" <*> v .: "result" where parseCitations :: Data.Aeson.Value -> Parser [CiteObject] parseCitations x@Array{} = parseJSON x parseCitations _ = return [] parseJSON _ = fail "Could not parse test case" newtype CiteObject = CiteObject { unCiteObject :: [Cite] } deriving Show instance FromJSON CiteObject where parseJSON (Array v) = case fromJSON (Array v) of Success [Object x, Array _, Array _] -> CiteObject <$> x .: "citationItems" Error e -> fail $ "Could not parse CiteObject: " ++ e x -> fail $ "Could not parse CiteObject" ++ show x parseJSON x = fail $ "Could not parse CiteObject " ++ show x #if MIN_VERSION_aeson(0,10,0) #else instance FromJSON [CiteObject] where parseJSON (Array v) = mapM parseJSON $ V.toList v parseJSON _ = return [] #endif data TestResult = Passed | Skipped | Failed | Errored deriving (Show, Eq) testDir :: FilePath testDir = "citeproc-test" > "processor-tests" > "machines" handler :: FilePath -> E.SomeException -> IO TestResult handler path e = do putStrLn $ "[ERROR] " ++ path ++ "\n" ++ show e return Errored runTest :: FilePath -> IO TestResult runTest path = E.handle (handler path) $ do raw <- BL.readFile path let testCase = either error id $ eitherDecode raw let procOpts' = ProcOpts (testBibopts testCase) False style <- localizeCSL Nothing $ (testCsl testCase) { styleAbbrevs = testAbbreviations testCase } let refs = testReferences testCase let cites = map unCiteObject (testCitations testCase) ++ testCitationItems testCase let cites' = if null cites then [map (\ref -> emptyCite{ citeId = unLiteral $ refId ref}) refs] else cites let expected = adjustEntities $ fixBegins $ trimEnd $ testResult testCase let mode = testMode testCase let assemble BibliographyMode xs = "