2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE ScopedTypeVariables #-}
4module Test.Compiler (compilerTests) where
6import Control.Exception (try, IOException)
8import qualified Data.Text.Lazy as LText
9import qualified Data.Text.Lazy.IO as LText
10import qualified Data.Map as Map
11import Data.Maybe (isJust)
12import qualified Data.Text.IO as Text
13import Data.Text (Text)
15import System.Directory (createDirectoryIfMissing)
16import System.Environment (lookupEnv)
17import System.FilePath ((</>), (<.>), dropFileName, joinPath, splitDirectories)
18import System.FilePath.Find (find, (==?), extension)
21import Test.Framework.Providers.HUnit (testCase)
22import Test.HUnit (Assertion, assertFailure, assertBool, assertEqual)
24import qualified Elm.Compiler as Compiler
25import qualified Elm.Package as Package
26import qualified AST.Module as Module
27import qualified AST.Module.Name as ModuleName
28import qualified AST.Variable as Variable
29import qualified AST.Type as Type
32writeExpectedJsEnvVarName :: String
33writeExpectedJsEnvVarName =
34 "ELM_WRITE_NEW_EXPECTED"
40 do goods <- testIf isSuccess =<< getElms "good"
41 bads <- testIf isFailure =<< getElms "bad"
42 expectedJsTests <- testMatchesExpected "good" "good-expected-js"
44 testGroup "Compile Tests"
45 [ testGroup "Good Tests" goods
46 , testGroup "Bad Tests" bads
47 , testGroup "Expected JS Tests" expectedJsTests
55getElms :: FilePath -> IO [FilePath]
59 (extension ==? ".elm")
60 (testsDir </> filePath)
65 "tests" </> "test-files"
67convertToExpectedJsFilePath :: String -> FilePath -> FilePath
68convertToExpectedJsFilePath expectedJsDir filePath =
71 </> joinPath (drop 3 (splitDirectories filePath))
79essentialInterfaces :: Module.Interfaces
83 (ModuleName.inCore "Debug",
86 ("crash", Type.Lambda (Type.Var "String") (Type.Var "a"))
92buildCoreInterface :: [(Text, Type.Canonical)] -> Module.Interface
93buildCoreInterface members =
95 exports = map (Variable.Value . fst) members
97 types = Map.fromList members
102 Module.Interface Compiler.version Package.core exports imports types adts aliases fixities
105compile :: FilePath -> Text -> Either String Compiler.Result
106compile filePath source =
107 let dependentModuleNames =
108 Map.keys essentialInterfaces
110 Compiler.Context Package.core False dependentModuleNames
111 (dealiaser, _warnings, result) =
112 Compiler.compile context source essentialInterfaces
113 formatErrors errors =
114 concatMap (Compiler.errorToString dealiaser filePath source) errors
116 either (Left . formatErrors) Right result
119readFileOrErrorStr :: FilePath -> IO String
120readFileOrErrorStr filePath =
121 do strOrExc <- try $ readFile filePath
126 Left (e :: IOException) ->
135 :: (Either String Compiler.Result -> Assertion)
138testIf handleResult filePaths =
139 let doTest filePath =
140 do source <- Text.readFile filePath
141 let formattedResult = compile filePath source
142 return $ testCase filePath (handleResult formattedResult)
144 traverse doTest filePaths
147doMatchesExpectedTest :: String -> FilePath -> IO Test
148doMatchesExpectedTest expectedJsDir filePath =
149 do source <- Text.readFile filePath
150 expectedJs <- readFileOrErrorStr (convertToExpectedJsFilePath expectedJsDir filePath)
152 let formattedResult = compile filePath source
153 let assertion = matchesExpected expectedJs formattedResult
155 return $ testCase filePath assertion
158doWriteNewExpectedTest :: String -> FilePath -> IO Test
159doWriteNewExpectedTest expectedJsDir filePath =
160 do source <- Text.readFile filePath
161 let formattedResult = compile filePath source
162 let expectedFilePath = convertToExpectedJsFilePath expectedJsDir filePath
164 case formattedResult of
165 Right (Compiler.Result _ _ js) ->
166 do createDirectoryIfMissing True (dropFileName expectedFilePath)
167 -- Force the evaluation of `js` before `writeFile`
168 -- so that if an error is raised we do not unintentionally write an empty file.
169 -- NB: `js` can be an empty string in the case of NoExpressions.elm
170 assertBool "" (LText.length js >= 0)
171 LText.writeFile expectedFilePath js
172 assertFailure ("Wrote new expected js: " ++ expectedFilePath)
175 assertFailure "Compile failed. Could not write new expected js."
176 return $ testCase filePath assertion
179testMatchesExpected :: String -> String -> IO [Test]
180testMatchesExpected elmDir expectedJsDir =
181 do elmFiles <- getElms elmDir
182 envVar <- lookupEnv writeExpectedJsEnvVarName
185 traverse (doWriteNewExpectedTest expectedJsDir) elmFiles
187 traverse (doMatchesExpectedTest expectedJsDir) elmFiles
194isSuccess :: Either String a -> Assertion
200 Left errorMessages ->
201 assertFailure errorMessages
204isFailure :: Either a b -> Assertion
208 assertFailure "Compilation succeeded but should have failed"
214matchesExpected :: String -> Either String Compiler.Result -> Assertion
215matchesExpected expectedJs result =
217 Right (Compiler.Result _ _ js) ->
218 assertEqual matchFailureMessage (LText.pack expectedJs) js
220 Left errorMessages ->
221 assertFailure $ "Compile failed:\n" ++ errorMessages
224matchFailureMessage :: String
226 "Compiled JS did not match expected JS." ++
227 "\n If the change is intentional, rerun " ++
228 "the tests with environment variable: " ++ writeExpectedJsEnvVarName ++ "=1"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list