summaryrefslogtreecommitdiff
path: root/lambda-calcul/haskell/test/Minilang/REPLSpec.hs
blob: f6279c183453a53d5345c0c8eb9dac8071c7e09c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
module Minilang.REPLSpec where

import Control.Exception (bracket)
import Data.Text.IO
import Minilang.REPL
import System.Directory (getTemporaryDirectory, removeFile)
import System.FilePath ((<.>), (</>))
import System.IO (IOMode (..), hClose, withFile)
import System.Posix.Temp (mkstemp)
import Test.Hspec
import Prelude hiding (lines, readFile, writeFile)

spec :: Spec
spec = parallel $
  describe "MiniLang REPL" $ do
    it "evaluates MiniLang terms read from pure Monad" $ do
      let out =
            withInput
              ["((lam (x) x) y)"]

      out
        `shouldBe` [ "Bye!",
                     "y : b"
                   ]

    it "defaults to try to typecheck terms" $ do
      let out =
            withInput
              [ "(let ((Succ (lam (n z s) (s n))) \
                \ (Zero (lam (z s) z))) \
                \ (Succ (Succ Zero)))"
              ]

      out
        `shouldBe` [ "Bye!",
                     "Cannot unify type variable f with type (e -> f -> e) -> e due to circularity: The variable already occurs in the type."
                   ]

    it "shows error when trying to load a non-existent file" $ do
      withInput [":load foo"]
        `shouldBe` [ "Bye!",
                     "REPLError \"cannot load file foo in Pure interpreter\""
                   ]

    around withTempFile $
      it "evaluates single MiniLang term read from IO" $ \fileName -> do
        let outputFileName = fileName <> ".out"

        writeFile
          fileName
          "(let ((Succ (lam (n z s) (s n))) \
          \ (Zero (lam (z s) z))) \
          \ Zero)"

        _ <- withFile fileName ReadMode $ \hin ->
          withFile outputFileName AppendMode $ \hout ->
            withHandles hin hout

        out <- readFile outputFileName

        out
          `shouldBe` "\955\928> (lam (z s) z) : c -> d -> c\n\955\928> Bye!\n"

withTempFile :: (String -> IO ()) -> IO ()
withTempFile =
  bracket mkTempFile rmTempFile
  where
    mkTempFile = getTemporaryDirectory >>= \dir -> mkstemp (dir </> "test-repl") >>= \(fp, h) -> hClose h >> pure fp
    rmTempFile fn = removeFile fn >> removeFile (fn <.> "out")