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 as Text
13import qualified Data.Text.IO as Text
14import Data.Text (Text)
16import System.Directory (createDirectoryIfMissing)
17import System.Environment (lookupEnv)
18import System.FilePath ((</>), (<.>), dropFileName, joinPath, splitDirectories)
19import System.FilePath.Find (find, (==?), extension)
22import Test.Framework.Providers.HUnit (testCase)
23import Test.HUnit (Assertion, assertFailure, assertBool, assertEqual)
25import qualified Elm.Compiler as Compiler
26import qualified Elm.Package as Package
27import qualified AST.Module as Module
28import qualified AST.Module.Name as ModuleName
29import qualified AST.Variable as Variable
30import qualified AST.Type as Type
33writeExpectedJsEnvVarName :: String
34writeExpectedJsEnvVarName =
35 "ELM_WRITE_NEW_EXPECTED"
41 do goods <- testIf isSuccess =<< getElms "good"
42 bads <- testIf isFailure =<< getElms "bad"
43 expectedJsTests <- testMatchesExpected "good" "good-expected-js"
45 testGroup "Compile Tests"
46 [ testGroup "Good Tests" goods
47 , testGroup "Bad Tests" bads
48 , testGroup "Expected JS Tests" expectedJsTests
56getElms :: FilePath -> IO [FilePath]
60 (extension ==? ".elm")
61 (testsDir </> filePath)
66 "tests" </> "test-files"
68convertToExpectedJsFilePath :: String -> FilePath -> FilePath
69convertToExpectedJsFilePath expectedJsDir filePath =
72 </> joinPath (drop 3 (splitDirectories filePath))
80essentialInterfaces :: Module.Interfaces
84 (ModuleName.inCore "Debug",
87 ("crash", Type.Lambda (Type.Var "String") (Type.Var "a"))
93buildCoreInterface :: [(Text, Type.Canonical)] -> Module.Interface
94buildCoreInterface members =
96 exports = map (Variable.Value . fst) members
98 types = Map.fromList members
103 Module.Interface Compiler.version Package.core exports imports types adts aliases fixities
106compile :: FilePath -> Text -> Either String Compiler.Result
107compile filePath source =
108 let dependentModuleNames =
109 Map.keys essentialInterfaces
111 Compiler.Context Package.core False dependentModuleNames
112 (dealiaser, _warnings, result) =
113 Compiler.compile context source essentialInterfaces
114 formatErrors errors =
115 concatMap (Compiler.errorToString dealiaser filePath (Text.unpack source)) errors
117 either (Left . formatErrors) Right result
120readFileOrErrorStr :: FilePath -> IO String
121readFileOrErrorStr filePath =
122 do strOrExc <- try $ readFile filePath
127 Left (e :: IOException) ->
136 :: (Either String Compiler.Result -> Assertion)
139testIf handleResult filePaths =
140 let doTest filePath =
141 do source <- Text.readFile filePath
142 let formattedResult = compile filePath source
143 return $ testCase filePath (handleResult formattedResult)
145 traverse doTest filePaths
148doMatchesExpectedTest :: String -> FilePath -> IO Test
149doMatchesExpectedTest expectedJsDir filePath =
150 do source <- Text.readFile filePath
151 expectedJs <- readFileOrErrorStr (convertToExpectedJsFilePath expectedJsDir filePath)
153 let formattedResult = compile filePath source
154 let assertion = matchesExpected expectedJs formattedResult
156 return $ testCase filePath assertion
159doWriteNewExpectedTest :: String -> FilePath -> IO Test
160doWriteNewExpectedTest expectedJsDir filePath =
161 do source <- Text.readFile filePath
162 let formattedResult = compile filePath source
163 let expectedFilePath = convertToExpectedJsFilePath expectedJsDir filePath
165 case formattedResult of
166 Right (Compiler.Result _ _ js) ->
167 do createDirectoryIfMissing True (dropFileName expectedFilePath)
168 -- Force the evaluation of `js` before `writeFile`
169 -- so that if an error is raised we do not unintentionally write an empty file.
170 -- NB: `js` can be an empty string in the case of NoExpressions.elm
171 assertBool "" (LText.length js >= 0)
172 LText.writeFile expectedFilePath js
173 assertFailure ("Wrote new expected js: " ++ expectedFilePath)
176 assertFailure "Compile failed. Could not write new expected js."
177 return $ testCase filePath assertion
180testMatchesExpected :: String -> String -> IO [Test]
181testMatchesExpected elmDir expectedJsDir =
182 do elmFiles <- getElms elmDir
183 envVar <- lookupEnv writeExpectedJsEnvVarName
186 traverse (doWriteNewExpectedTest expectedJsDir) elmFiles
188 traverse (doMatchesExpectedTest expectedJsDir) elmFiles
195isSuccess :: Either String a -> Assertion
201 Left errorMessages ->
202 assertFailure errorMessages
205isFailure :: Either a b -> Assertion
209 assertFailure "Compilation succeeded but should have failed"
215matchesExpected :: String -> Either String Compiler.Result -> Assertion
216matchesExpected expectedJs result =
218 Right (Compiler.Result _ _ js) ->
219 assertEqual matchFailureMessage (LText.pack expectedJs) js
221 Left errorMessages ->
222 assertFailure $ "Compile failed:\n" ++ errorMessages
225matchFailureMessage :: String
227 "Compiled JS did not match expected JS." ++
228 "\n If the change is intentional, rerun " ++
229 "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