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
36writeExpectedJsEnvVarName :: String
37writeExpectedJsEnvVarName =
38 "ELM_WRITE_NEW_EXPECTED"
44 do goods <- testIf isSuccess =<< getElms "good"
45 bads <- testIf isFailure =<< getElms "bad"
46 expectedJsTests <- testMatchesExpected "good" "good-expected-js"
48 testGroup "Compile Tests"
49 [ testGroup "Good Tests" goods
50 , testGroup "Bad Tests" bads
51 , testGroup "Expected JS Tests" expectedJsTests
59getElms :: FilePath -> IO [FilePath]
63 (extension ==? ".elm")
64 (testsDir </> filePath)
69 "tests" </> "test-files"
72convertToExpectedJsFilePath :: String -> FilePath -> FilePath
73convertToExpectedJsFilePath expectedJsDir filePath =
76 </> joinPath (drop 3 (splitDirectories filePath))
84compile :: FilePath -> Text -> Either String Compiler.Result
85compile filePath source =
88 Compiler.Context Package.core False importDict interfaces
90 (dealiaser, _warnings, result) =
91 Compiler.compile context source
94 concatMap (Compiler.errorToString dealiaser filePath source) errors
96 either (Left . formatErrors) Right result
99importDict :: Map.Map ModuleName.Raw ModuleName.Canonical
103 ( ModuleName._module name, name )
105 Map.fromList $ map toPair $ Map.keys interfaces
108interfaces :: Module.Interfaces
112 (ModuleName.inCore "Debug",
115 ("crash", Type.Lambda (Type.Var "String") (Type.Var "a"))
121buildCoreInterface :: [(Text, Type.Canonical)] -> Module.Interface
122buildCoreInterface members =
124 exports = map (Variable.Value . fst) members
126 types = Map.fromList members
131 Module.Interface Compiler.version Package.core exports imports types adts aliases fixities
138readFileOrErrorStr :: FilePath -> IO String
139readFileOrErrorStr filePath =
140 do strOrExc <- try $ readFile filePath
145 Left (e :: IOException) ->
154 :: (Either String Compiler.Result -> Assertion)
157testIf handleResult filePaths =
158 let doTest filePath =
159 do source <- Text.readFile filePath
160 let formattedResult = compile filePath source
161 return $ testCase filePath (handleResult formattedResult)
163 traverse doTest filePaths
166doMatchesExpectedTest :: String -> FilePath -> IO Test
167doMatchesExpectedTest expectedJsDir filePath =
168 do source <- Text.readFile filePath
169 expectedJs <- readFileOrErrorStr (convertToExpectedJsFilePath expectedJsDir filePath)
171 let formattedResult = compile filePath source
172 let assertion = matchesExpected expectedJs formattedResult
174 return $ testCase filePath assertion
177doWriteNewExpectedTest :: String -> FilePath -> IO Test
178doWriteNewExpectedTest expectedJsDir filePath =
179 do source <- Text.readFile filePath
180 let formattedResult = compile filePath source
181 let expectedFilePath = convertToExpectedJsFilePath expectedJsDir filePath
183 case formattedResult of
184 Right (Compiler.Result _ _ js) ->
185 do createDirectoryIfMissing True (dropFileName expectedFilePath)
186 -- Force the evaluation of `js` before `writeFile`
187 -- so that if an error is raised we do not unintentionally write an empty file.
188 -- NB: `js` can be an empty string in the case of NoExpressions.elm
189 assertBool "" (LText.length js >= 0)
190 LText.writeFile expectedFilePath js
191 assertFailure ("Wrote new expected js: " ++ expectedFilePath)
194 assertFailure "Compile failed. Could not write new expected js."
195 return $ testCase filePath assertion
198testMatchesExpected :: String -> String -> IO [Test]
199testMatchesExpected elmDir expectedJsDir =
200 do elmFiles <- getElms elmDir
201 envVar <- lookupEnv writeExpectedJsEnvVarName
204 traverse (doWriteNewExpectedTest expectedJsDir) elmFiles
206 traverse (doMatchesExpectedTest expectedJsDir) elmFiles
213isSuccess :: Either String a -> Assertion
219 Left errorMessages ->
220 assertFailure errorMessages
223isFailure :: Either a b -> Assertion
227 assertFailure "Compilation succeeded but should have failed"
233matchesExpected :: String -> Either String Compiler.Result -> Assertion
234matchesExpected expectedJs result =
236 Right (Compiler.Result _ _ js) ->
237 assertEqual matchFailureMessage (LText.pack expectedJs) js
239 Left errorMessages ->
240 assertFailure $ "Compile failed:\n" ++ errorMessages
243matchFailureMessage :: String
245 "Compiled JS did not match expected JS." ++
246 "\n If the change is intentional, rerun " ++
247 "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