packages feed

fnotation-0.1.1.0: test/Main.hs

module Main (main) where

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

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 = fileReporter h
    tokens <- lex lexConfig (contramap LexerCode r) f
    ns <- parse parseConfig (contramap 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"
      ]