@@ -1,32 +1,45 @@
1{-# OPTIONS_GHC -W #-}
1{-# OPTIONS_GHC -W #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
2module Test.Compiler (compilerTests) where
3module Test.Compiler (compilerTests) where
5+import Control.Exception (try, IOException)
4import qualified Data.Map as Map
7import qualified Data.Map as Map
8+import Data.Maybe (isJust)
5import Data.Traversable (traverse)
9import Data.Traversable (traverse)
7−import System.FilePath ((</>))
11+import System.Directory (createDirectoryIfMissing)
12+import System.Environment (lookupEnv)
13+import System.FilePath ((</>), (<.>), dropFileName, joinPath, splitDirectories)
8import System.FilePath.Find (find, (==?), extension)
14import System.FilePath.Find (find, (==?), extension)
10import Test.Framework
16import Test.Framework
11import Test.Framework.Providers.HUnit (testCase)
17import Test.Framework.Providers.HUnit (testCase)
12−import Test.HUnit (Assertion, assertFailure, assertBool)
18+import Test.HUnit (Assertion, assertFailure, assertBool, assertEqual)
14import qualified Elm.Compiler as Compiler
20import qualified Elm.Compiler as Compiler
15import qualified Elm.Package as Package
21import qualified Elm.Package as Package
23+writeExpectedJsEnvVarName :: String
24+writeExpectedJsEnvVarName =
25+ "ELM_WRITE_NEW_EXPECTED"
17compilerTests :: Test
28compilerTests :: Test
18compilerTests =
29compilerTests =
19− buildTest $ do
30+ buildTest $
20− goods <- testIf isSuccess =<< getElms "good"
31+ do goods <- testIf isSuccess =<< getElms "good"
21− bads <- testIf isFailure =<< getElms "bad"
32+ bads <- testIf isFailure =<< getElms "bad"
33+ expectedJsTests <- testMatchesExpected "good" "good-expected-js"
23− testGroup "Compile Tests"
35+ testGroup "Compile Tests"
24− [ testGroup "Good Tests" goods
36+ [ testGroup "Good Tests" goods
25− , testGroup "Bad Tests" bads
37+ , testGroup "Bad Tests" bads
38+ , testGroup "Expected JS Tests" expectedJsTests
29−-- GATHER ELM FILES
42+-- GATHER FILES
31getElms :: FilePath -> IO [FilePath]
44getElms :: FilePath -> IO [FilePath]
32getElms filePath =
45getElms filePath =
@@ -40,29 +53,91 @@ testsDir :: FilePath
41 "tests" </> "test-files"
54 "tests" </> "test-files"
56+convertToExpectedJsFilePath :: String -> FilePath -> FilePath
57+convertToExpectedJsFilePath expectedJsDir filePath =
60+ </> joinPath (drop 3 (splitDirectories filePath))
66+compileString :: FilePath -> String -> Either String Compiler.Result
67+compileString filePath source =
69+ Compiler.Context Package.coreName True False []
70+ (dealiaser, _warnings, result) =
71+ Compiler.compile context source Map.empty
72+ formatErrors errors =
73+ concatMap (Compiler.errorToString dealiaser filePath source) errors
75+ either (Left . formatErrors) Right result
78+readFileOrErrorStr :: FilePath -> IO String
79+readFileOrErrorStr filePath =
80+ do strOrExc <- try $ readFile filePath
85+ Left (e :: IOException) ->
47 :: (Either String Compiler.Result -> Assertion)
92 :: (Either String Compiler.Result -> Assertion)
48 -> [FilePath]
93 -> [FilePath]
49 -> IO [Test]
94 -> IO [Test]
50testIf handleResult filePaths =
95testIf handleResult filePaths =
96+ let doTest filePath =
97+ do source <- readFile filePath
98+ let formattedResult = compileString filePath source
99+ return $ testCase filePath (handleResult formattedResult)
51− traverse setupTest filePaths
101+ traverse doTest filePaths
53− setupTest filePath = do
103+
54− source <- readFile filePath
104+doMatchesExpectedTest :: String -> FilePath -> IO Test
105+doMatchesExpectedTest expectedJsDir filePath =
106+ do source <- readFile filePath
107+ expectedJs <- readFileOrErrorStr (convertToExpectedJsFilePath expectedJsDir filePath)
56− let context =
109+ let formattedResult = compileString filePath source
57− Compiler.Context Package.coreName True False []
110+ let assertion = matchesExpected expectedJs formattedResult
58− let (dealiaser, _warnings, result) =
59− Compiler.compile context source Map.empty
60− let formatErrors errors =
61− concatMap (Compiler.errorToString dealiaser filePath source) errors
62− let formattedResult =
63− either (Left . formatErrors) Right result
65− return $ testCase filePath (handleResult formattedResult)
112+ return $ testCase filePath assertion
115+doWriteNewExpectedTest :: String -> FilePath -> IO Test
116+doWriteNewExpectedTest expectedJsDir filePath =
117+ do source <- readFile filePath
118+ let formattedResult = compileString filePath source
119+ let expectedFilePath = convertToExpectedJsFilePath expectedJsDir filePath
121+ case formattedResult of
122+ Right (Compiler.Result _ _ js) ->
123+ do createDirectoryIfMissing True (dropFileName expectedFilePath)
124+ writeFile expectedFilePath js
125+ assertFailure ("Wrote new expected js: " ++ expectedFilePath)
128+ assertFailure "Compile failed. Could not write new expected js."
129+ return $ testCase filePath assertion
132+testMatchesExpected :: String -> String -> IO [Test]
133+testMatchesExpected elmDir expectedJsDir =
134+ do elmFiles <- getElms elmDir
135+ envVar <- lookupEnv writeExpectedJsEnvVarName
138+ traverse (doWriteNewExpectedTest expectedJsDir) elmFiles
140+ traverse (doMatchesExpectedTest expectedJsDir) elmFiles
68-- CHECK RESULTS
143-- CHECK RESULTS
@@ -86,3 +161,19 @@ isFailure result =
86 Left _ ->
161 Left _ ->
87 assertBool "" True
162 assertBool "" True
165+matchesExpected :: String -> Either String Compiler.Result -> Assertion
166+matchesExpected expectedJs result =
168+ Right (Compiler.Result _ _ js) ->
169+ assertEqual matchFailureMessage expectedJs js
171+ Left errorMessages ->
172+ assertFailure $ "Compile failed:\n" ++ errorMessages
175+matchFailureMessage :: String
176+matchFailureMessage =
177+ "Compiled JS did not match expected JS." ++
178+ "\n If the change is intentional, rerun " ++
179+ "the tests with environment variable: " ++ writeExpectedJsEnvVarName ++ "=1"