-- | Tests for the snippet environment (cwd, available files, env vars, etc.) module TestSuite.Tests.SnippetEnvironment (testGroupSnippetEnvironment) where import Data.Monoid import System.Exit import System.FilePath import System.Process import Test.Tasty import Test.HUnit import qualified Data.ByteString.Lazy.Char8 as L (unlines) import qualified Data.ByteString.Lazy.UTF8 as L import qualified Data.Text as T import IdeSession import TestSuite.Session import TestSuite.Assertions import TestSuite.State testGroupSnippetEnvironment :: TestSuiteEnv -> TestTree testGroupSnippetEnvironment env = testGroup "Snippet environment" $ [ stdTest env "Set environment variables" test_SetEnvVars , stdTest env "Test CWD by reading a data file" test_readDataFile , stdTest env "Test CWD in executable building" test_CwdInExeBuilding , stdTest env "Set command line arguments" test_SetCmdLineArgs , stdTest env "Check that command line arguments survive restartSession" test_CmdLineArgsAfterRestart ] ++ exeTests env [ stdTest env "Set environment variables in runExe" test_SetEnvVars_runExe ] test_SetEnvVars :: TestSuiteEnv -> Assertion test_SetEnvVars env = withAvailableSession env $ \session -> do updateSessionD session upd 1 assertNoErrors session -- At the start, both Foo and Bar are undefined do runActions <- runStmt session "M" "printFoo" (_, result) <- runWaitAll runActions case result of RunProgException ex -> assertEqual "" ex "IOException: Foo: getEnv: does not exist (no environment variable)" _ -> assertFailure $ "Unexpected result " ++ show result do runActions <- runStmt session "M" "printBar" (_, result) <- runWaitAll runActions case result of RunProgException ex -> assertEqual "" ex "IOException: Bar: getEnv: does not exist (no environment variable)" _ -> assertFailure $ "Unexpected result " ++ show result -- Update Foo, leave Bar undefined updateSession session (updateEnv [("Foo", Just "Value1")]) (\_ -> return ()) do runActions <- runStmt session "M" "printFoo" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "Value1" output do runActions <- runStmt session "M" "printBar" (_, result) <- runWaitAll runActions assertEqual "" result (RunProgException "IOException: Bar: getEnv: does not exist (no environment variable)") -- Update Bar, leave Foo defined updateSession session (updateEnv [("Foo", Just "Value1"), ("Bar", Just "Value2")]) (\_ -> return ()) do runActions <- runStmt session "M" "printFoo" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "Value1" output do runActions <- runStmt session "M" "printBar" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "Value2" output -- Unset Foo, leave Bar defined updateSession session (updateEnv [("Foo", Nothing), ("Bar", Just "Value2")]) (\_ -> return ()) do runActions <- runStmt session "M" "printFoo" (_, result) <- runWaitAll runActions assertEqual "" result (RunProgException "IOException: Foo: getEnv: does not exist (no environment variable)") do runActions <- runStmt session "M" "printBar" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "Value2" output -- Rely on statelessness of updateEnv to reset Bar updateSession session (updateEnv []) (\_ -> return ()) do runActions <- runStmt session "M" "printFoo" (_, result) <- runWaitAll runActions case result of RunProgException ex -> assertEqual "" ex "IOException: Foo: getEnv: does not exist (no environment variable)" _ -> assertFailure $ "Unexpected result " ++ show result do runActions <- runStmt session "M" "printBar" (_, result) <- runWaitAll runActions case result of RunProgException ex -> assertEqual "" ex "IOException: Bar: getEnv: does not exist (no environment variable)" _ -> assertFailure $ "Unexpected result " ++ show result where upd = (updateCodeGeneration True) <> (updateSourceFile "M.hs" . L.unlines $ [ "module M where" , "import System.Environment (getEnv)" , "printFoo :: IO ()" , "printFoo = getEnv \"Foo\" >>= putStr" , "printBar :: IO ()" , "printBar = getEnv \"Bar\" >>= putStr" ]) test_SetEnvVars_runExe :: TestSuiteEnv -> Assertion test_SetEnvVars_runExe env = withAvailableSession env $ \session -> do updateSessionD session upd 1 assertNoErrors session let m = "M" updExe = buildExe [] [(T.pack m, "M.hs")] updateSessionD session updExe 2 assertNoErrors session -- At the start, both Foo and Bar are undefined do updateSessionD session (updateArgs ["Foo"]) 1 runActions <- runExe session "M" (_, result) <- runWaitAll runActions assertEqual "" result (ExitFailure 1) do updateSessionD session (updateArgs ["Bar"]) 1 runActions <- runExe session "M" (_, result) <- runWaitAll runActions assertEqual "" result (ExitFailure 1) -- Update Foo, leave Bar undefined updateSession session (updateEnv [("Foo", Just "Value1")]) (\_ -> return ()) do updateSessionD session (updateArgs ["Foo"]) 1 runActions <- runExe session "M" (output, result) <- runWaitAll runActions assertEqual "" result ExitSuccess assertEqual "" "Value1" output do updateSessionD session (updateArgs ["Bar"]) 1 runActions <- runExe session "M" (_, result) <- runWaitAll runActions assertEqual "" result (ExitFailure 1) -- Update Bar, leave Foo defined updateSession session (updateEnv [("Foo", Just "Value1"), ("Bar", Just "Value2")]) (\_ -> return ()) do updateSessionD session (updateArgs ["Foo"]) 1 runActions <- runExe session "M" (output, result) <- runWaitAll runActions assertEqual "" result ExitSuccess assertEqual "" "Value1" output do updateSessionD session (updateArgs ["Bar"]) 1 runActions <- runExe session "M" (output, result) <- runWaitAll runActions assertEqual "" result ExitSuccess assertEqual "" "Value2" output -- Unset Foo, leave Bar defined updateSession session (updateEnv [("Foo", Nothing), ("Bar", Just "Value2")]) (\_ -> return ()) do updateSessionD session (updateArgs ["Foo"]) 1 runActions <- runExe session "M" (_, result) <- runWaitAll runActions assertEqual "" result (ExitFailure 1) do updateSessionD session (updateArgs ["Bar"]) 1 runActions <- runExe session "M" (output, result) <- runWaitAll runActions assertEqual "" result ExitSuccess assertEqual "" "Value2" output -- Rely on statelessness of updateEnv to reset Bar updateSession session (updateEnv []) (\_ -> return ()) do updateSessionD session (updateArgs ["Foo"]) 1 runActions <- runExe session "M" (_, result) <- runWaitAll runActions assertEqual "" result (ExitFailure 1) do updateSessionD session (updateArgs ["Bar"]) 1 runActions <- runExe session "M" (_, result) <- runWaitAll runActions assertEqual "" result (ExitFailure 1) where upd = (updateCodeGeneration True) <> (updateSourceFile "M.hs" . L.unlines $ [ "module M where" , "import System.Environment" , "main :: IO ()" , "main = do" , " args <- getArgs" , " case args of" , " [\"Foo\"] -> getEnv \"Foo\" >>= putStr" , " [\"Bar\"] -> getEnv \"Bar\" >>= putStr" , " _ -> fail \"wrong args\"" ]) test_readDataFile :: TestSuiteEnv -> Assertion test_readDataFile env = withAvailableSession env $ \session -> do let update = updateDataFile "datafile.dat" "test data content" updateSessionD session update 0 let update2 = loadModule "Main.hs" "main = readFile \"datafile.dat\" >>= putStrLn" updateSessionD session update2 1 assertNoErrors session let update3 = updateCodeGeneration True updateSessionD session update3 1 do runActions <- runStmt session "Main" "main" (output, _) <- runWaitAll runActions assertEqual "compare test data content" "test data content\n" output let m = "Main" ifTestingExe env $ do let updExe = buildExe [] [(T.pack m, "Main.hs")] updateSessionD session updExe 2 runActionsExe <- runExe session m (outExe, statusExe) <- runWaitAll runActionsExe assertEqual "Output from runExe" "test data content\n" outExe assertEqual "after runExe" ExitSuccess statusExe let update4 = updateDataFile "datafile.dat" "new content" <> update2 updateSessionD session update4 1 do runActions2 <- runStmt session "Main" "main" (output2, _) <- runWaitAll runActions2 assertEqual "compare new content" "new content\n" output2 ifTestingExe env $ do let updExe2 = buildExe [] [(T.pack m, "Main.hs")] updateSessionD session updExe2 2 runActionsExe2 <- runExe session m (outExe2, statusExe2) <- runWaitAll runActionsExe2 assertEqual "Output from runExe" "new content\n" outExe2 assertEqual "after runExe" ExitSuccess statusExe2 test_CwdInExeBuilding :: TestSuiteEnv -> Assertion test_CwdInExeBuilding env = withAvailableSession env $ \session -> do let update = updateCodeGeneration True <> updateDataFile "test.txt" "test data" let update2 = updateSourceFile "Main.hs" $ L.unlines [ "{-# LANGUAGE TemplateHaskell #-}" , "module Main where" , "import Language.Haskell.TH.Syntax" , "main = putStrLn $(qRunIO (readFile \"test.txt\") >>= lift)" ] updateSessionD session (update <> update2) 1 assertNoErrors session output <- do runActions <- runStmt session "Main" "main" (output, _) <- runWaitAll runActions assertEqual "compare test data" "test data\n" output return output let m = "Main" ifTestingExe env $ do let upd = buildExe [] [(T.pack m, "Main.hs")] updateSessionD session upd 2 distDir <- getDistDir session out <- readProcess (distDir "build" m m) [] [] assertEqual "CWD exe output" (L.toString output) out runActionsExe <- runExe session m (outExe, statusExe) <- runWaitAll runActionsExe assertEqual "Output from runExe" output outExe assertEqual "after runExe" ExitSuccess statusExe test_SetCmdLineArgs :: TestSuiteEnv -> Assertion test_SetCmdLineArgs env = withAvailableSession env $ \session -> do updateSessionD session upd 1 assertNoErrors session -- Check that default is [] do runActions <- runStmt session "M" "printArgs" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "[]\n" output let m = "M" ifTestingExe env $ do let updExe = buildExe [] [(T.pack m, "M.hs")] updateSessionD session updExe 2 runActionsExe <- runExe session m (outExe, statusExe) <- runWaitAll runActionsExe assertEqual "after runExe" ExitSuccess statusExe assertEqual "Output from runExe" "[]\n" outExe -- Check that we can set command line arguments updateSession session (updateArgs ["A", "B", "C"]) (\_ -> return ()) do runActions <- runStmt session "M" "printArgs" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "[\"A\",\"B\",\"C\"]\n" output ifTestingExe env $ do runActionsExe <- runExe session m (outExe, statusExe) <- runWaitAll runActionsExe assertEqual "after runExe" ExitSuccess statusExe assertEqual "Output from runExe" "[\"A\",\"B\",\"C\"]\n" outExe -- Check that we can change command line arguments updateSession session (updateArgs ["D", "E"]) (\_ -> return ()) do runActions <- runStmt session "M" "printArgs" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "[\"D\",\"E\"]\n" output ifTestingExe env $ do runActionsExe <- runExe session m (outExe, statusExe) <- runWaitAll runActionsExe assertEqual "after runExe" ExitSuccess statusExe assertEqual "Output from runExe" "[\"D\",\"E\"]\n" outExe -- Check that we can clear command line arguments updateSession session (updateArgs []) (\_ -> return ()) do runActions <- runStmt session "M" "printArgs" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "[]\n" output ifTestingExe env $ do runActionsExe <- runExe session m (outExe, statusExe) <- runWaitAll runActionsExe assertEqual "after runExe" ExitSuccess statusExe assertEqual "Output from runExe" "[]\n" outExe where upd = (updateCodeGeneration True) <> (updateSourceFile "M.hs" $ L.unlines [ "module M where" , "import System.Environment (getArgs)" , "printArgs :: IO ()" , "printArgs = getArgs >>= print" , "main :: IO ()" , "main = printArgs" ]) test_CmdLineArgsAfterRestart :: TestSuiteEnv -> Assertion test_CmdLineArgsAfterRestart env = withAvailableSession env $ \session -> do updateSessionD session upd 1 assertNoErrors session -- Sanity check: check before restart session updateSession session (updateArgs ["A", "B", "C"]) (\_ -> return ()) do runActions <- runStmt session "M" "printArgs" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "[\"A\",\"B\",\"C\"]\n" output let m = "M" ifTestingExe env $ do let updExe = buildExe [] [(T.pack m, "M.hs")] updateSessionD session updExe 3 -- TODO: Some modules may be compiled twice (#189) runActionsExe <- runExe session m (outExe, statusExe) <- runWaitAll runActionsExe assertEqual "after runExe" ExitSuccess statusExe assertEqual "Output from runExe" "[\"A\",\"B\",\"C\"]\n" outExe -- Restart and update the session restartSession session updateSessionD session upd 1 assertNoErrors session -- Check that arguments are still here do runActions <- runStmt session "M" "printArgs" (output, result) <- runWaitAll runActions assertEqual "" RunOk result assertEqual "" "[\"A\",\"B\",\"C\"]\n" output ifTestingExe env $ do runActionsExe <- runExe session m (outExe, statusExe) <- runWaitAll runActionsExe assertEqual "after runExe" ExitSuccess statusExe assertEqual "Output from runExe" "[\"A\",\"B\",\"C\"]\n" outExe where upd = (updateCodeGeneration True) <> (updateSourceFile "M.hs" $ L.unlines [ "module M where" , "import System.Environment (getArgs)" , "printArgs :: IO ()" , "printArgs = getArgs >>= print" , "main :: IO ()" , "main = printArgs" ])