{-# LANGUAGE OverloadedStrings #-} module Main (main) where import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BL import qualified Data.Text as T import qualified Data.Text.Encoding as TE import Data.Text.IO as TIO import System.FilePath (replaceExtension) import Test.Tasty (TestTree, Timeout (..), defaultMain, localOption, testGroup) import Test.Tasty.Golden (findByExtension, goldenVsStringDiff) import Text.Show.Pretty (ppShow) import Typst.Evaluate (evaluateTypst) import Typst.Parse (parseTypst) import Typst.Types (Val (VContent), repr) main :: IO () main = defaultMain =<< goldenTests goldenTests :: IO TestTree goldenTests = do inputs <- findByExtension [".typ"] "test/typ" pure $ localOption (Timeout 100000 "100ms") $ testGroup "golden tests" (map runTest inputs) runTest :: FilePath -> TestTree runTest input = goldenVsStringDiff input (\ref new -> ["diff", "-u", ref, new]) ("test/out" <> drop 8 (replaceExtension input ".out")) (writeTest input) writeTest :: FilePath -> IO BL.ByteString writeTest input = do let fromText = BL.fromStrict . TE.encodeUtf8 . (<> "\n") let testCommand = "#let test = (x,y) => { if x == y [✅] else [❌(#repr(x) /= #repr(y))] }\n" contents <- TIO.readFile input if "// Error" `T.isInfixOf` contents || "cycle1.typ" `T.isInfixOf` contents || "cycle2.typ" `T.isInfixOf` contents then pure $ fromText "--- skipped ---\n" else do let parseResult = parseTypst input (testCommand <> contents) case parseResult of Left e -> pure $ fromText $ T.pack $ show e Right parsed -> do evalResult <- evaluateTypst BS.readFile input parsed let parseOutput = "--- parse tree ---\n" <> T.pack (ppShow parsed) <> "\n" case evalResult of Left e -> pure $ fromText $ parseOutput <> T.pack (show e) Right cs -> do let evalOutput = "--- evaluated ---\n" <> repr (VContent cs) pure $ fromText $ parseOutput <> evalOutput