packages feed

fnotation-0.1.0.0: test/Main.hs

module Main (main) where

import Prelude hiding (lex)
import Data.ByteString.Lazy qualified as LBS
import Data.Map (Map)
import Data.Map qualified as Map
import Data.Vector qualified as V
import Data.Text.IO.Utf8 qualified as T
import Data.Text.Lazy.Encoding qualified as TLE
import Diagnostician
import FNotation
import FNotation.Tokens qualified as K
import Prettyprinter
import Prettyprinter.Render.Text
import Test.Tasty (defaultMain, TestTree, testGroup)
import Test.Tasty.Golden (goldenVsString, findByExtension)
import System.FilePath (takeBaseName, replaceExtension)
import System.IO
import System.IO.Temp (withSystemTempFile)

main :: IO ()
main = defaultMain =<< goldenTests

render :: DDoc -> LBS.ByteString
render = TLE.encodeUtf8 . renderLazy . layoutPretty defaultLayoutOptions

lexConfig :: ConfTable Kind
lexConfig = confTableFromList
  [ ("sig", K.Block),
    ("struct", K.Block),
    ("sum", K.Block),
    ("match", K.Block),
    ("theory", K.Decl),
    ("def", K.Decl),
    ("type", K.Decl),
    ("let", K.Decl),
    ("open", K.Decl),
    ("import", K.Decl),
    ("end", K.End),
    ("Type", K.AKeyword),
    ("Int", K.AKeyword),
    ("String", K.AKeyword),
    (":=", K.SKeyword),
    ("=", K.SKeyword),
    (":", K.SKeyword),
    ("->", K.SKeyword),
    ("=>", K.SKeyword)
  ]

parseConfig :: ConfTable Prec
parseConfig = confTableFromList
  [ (":=", Prec 10 AssocNon),
    (":", Prec 20 AssocNon),
    ("->", Prec 30 AssocR),
    ("=>", Prec 30 AssocR),
    ("=", Prec 40 AssocNon),
    ("+", Prec 50 AssocL),
    ("-", Prec 50 AssocL),
    ("*", Prec 60 AssocL),
    ("/", Prec 60 AssocL)
  ]

data TestCode = LexerCode LexerCode | ParserCode ParserCode
  deriving (Eq, Ord)

codeTable :: Map TestCode CodeMeta
codeTable = mconcat
  [ promoteCodeTable lexerCodeTable LexerCode 0,
    promoteCodeTable parserCodeTable ParserCode 100
  ]

instance Code TestCode where
  codeMeta c = case Map.lookup c codeTable of
    Just m -> m
    Nothing -> error "unregistered code"

parseToPretty :: FilePath -> IO LBS.ByteString
parseToPretty fp = do
  src <- T.readFile fp
  let f = newFile fp src
  withSystemTempFile "reporter-output" $ \path h -> do
    let r = Reporter h False
    tokens <- lex lexConfig (ReporterFor LexerCode r) f
    ns <- parse parseConfig (ReporterFor ParserCode r) f tokens
    hFlush h
    hClose h
    msgs <- T.readFile path
    pure $ render $ vsep [
      "-- tokens",
      vsep $ dpretty <$> V.toList tokens,
      "",
      "-- notation",
      vsep $ dpretty <$> ns,
      "",
      "-- pretty",
      vsep $ dprettyWithPrecs parseConfig <$> ns,
      "",
      "-- messages",
      pretty $ msgs]

goldenTests :: IO TestTree
goldenTests = do
  ntnFiles <- findByExtension [".ntn"] "."
  return $ testGroup "FNotation golden tests"
    [ goldenVsString (takeBaseName ntnFile) outputFile (parseToPretty ntnFile)
    | ntnFile <- ntnFiles
    , let outputFile = replaceExtension ntnFile ".output"
    ]