{-# LANGUAGE CPP #-} module Configuration.DotenvSpec (main, spec) where import Configuration.Dotenv.Types (Config(..)) import Configuration.Dotenv (load, loadFile, parseFile, onMissingFile) import Test.Hspec import System.Process (readCreateProcess, shell) import System.Environment (lookupEnv) import Control.Monad (liftM, void) import Data.Maybe (fromMaybe) #if !MIN_VERSION_base(4,8,0) import Data.Functor ((<$>)) #endif #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$)) #endif #if MIN_VERSION_base(4,7,0) import System.Environment (getEnvironment, setEnv, unsetEnv) #else import System.Environment.Compat (getEnvironment, setEnv, unsetEnv) #endif {-# ANN module "HLint: ignore Reduce duplication" #-} main :: IO () main = hspec spec spec :: Spec spec = do describe "load" $ after_ clearEnvs $ do it "loads the given list of configuration options to the environment" $ do lookupEnv "foo" `shouldReturn` Nothing load False [("foo", "bar")] lookupEnv "foo" `shouldReturn` Just "bar" it "preserves existing settings when overload is false" $ do setEnv "foo" "preset" load False [("foo", "new setting")] lookupEnv "foo" `shouldReturn` Just "preset" it "overrides existing settings when overload is true" $ do setEnv "foo" "preset" load True [("foo", "new setting")] lookupEnv "foo" `shouldReturn` Just "new setting" describe "loadFile" $ before_ setupEnv $ after_ clearEnvs $ do it "loads the configuration options to the environment from a file" $ do lookupEnv "DOTENV" `shouldReturn` Nothing void $ loadFile $ Config ["spec/fixtures/.dotenv"] [] False lookupEnv "DOTENV" `shouldReturn` Just "true" it "respects predefined settings when overload is false" $ do setEnv "DOTENV" "preset" void $ loadFile $ Config ["spec/fixtures/.dotenv"] [] False lookupEnv "DOTENV" `shouldReturn` Just "preset" it "overrides predefined settings when overload is true" $ do setEnv "DOTENV" "preset" void $ loadFile $ Config ["spec/fixtures/.dotenv"] [] True lookupEnv "DOTENV" `shouldReturn` Just "true" context "when the .env.example is present" $ do let config = Config ["spec/fixtures/.dotenv"] ["spec/fixtures/.dotenv.example"] False context "when the needed env vars are missing" $ it "should fail with an error call" $ do unsetEnv "ANOTHER_ENV" void $ loadFile config `shouldThrow` anyErrorCall context "when the needed env vars are not missing" $ it "should succeed when loading all of the needed env vars" $ do -- Load extra information me <- init <$> readCreateProcess (shell "whoami") "" home <- fromMaybe "" <$> lookupEnv "HOME" -- Load envs void $ loadFile config -- Check existing envs lookupEnv "ENVIRONMENT" `shouldReturn` Just home lookupEnv "ME" `shouldReturn` Just me lookupEnv "DOTENV" `shouldReturn` Just "true" lookupEnv "UNICODE_TEST" `shouldReturn` Just "ManabĂ­" lookupEnv "ANOTHER_ENV" `shouldReturn` Just "hello" describe "parseFile" $ after_ clearEnvs $ do it "returns variables from a file without changing the environment" $ do lookupEnv "DOTENV" `shouldReturn` Nothing liftM head (parseFile "spec/fixtures/.dotenv") `shouldReturn` ("DOTENV", "true") lookupEnv "DOTENV" `shouldReturn` Nothing it "recognizes unicode characters" $ liftM (!! 1) (parseFile "spec/fixtures/.dotenv") `shouldReturn` ("UNICODE_TEST", "ManabĂ­") it "recognises environment variables" $ do home <- fromMaybe "" <$> lookupEnv "HOME" liftM (!! 2) (parseFile "spec/fixtures/.dotenv") `shouldReturn` ("ENVIRONMENT", home) it "recognises previous variables" $ liftM (!! 3) (parseFile "spec/fixtures/.dotenv") `shouldReturn` ("PREVIOUS", "true") it "recognises commands" $ do me <- init <$> readCreateProcess (shell "whoami") "" liftM (!! 4) (parseFile "spec/fixtures/.dotenv") `shouldReturn` ("ME", me) describe "onMissingFile" $ after_ clearEnvs $ do context "when target file is present" $ it "loading works as usual" $ do void $ onMissingFile (loadFile $ Config ["spec/fixtures/.dotenv"] [] True) (return []) lookupEnv "DOTENV" `shouldReturn` Just "true" context "when target file is missing" $ it "executes supplied handler instead" $ onMissingFile (True <$ loadFile (Config ["spec/fixtures/foo"] [] True)) (return False) `shouldReturn` False clearEnvs :: IO () clearEnvs = fmap (fmap fst) getEnvironment >>= mapM_ unsetEnv setupEnv :: IO () setupEnv = do setEnv "ANOTHER_ENV" "hello" setEnv "HOME" "/home/me"