content: {-# LANGUAGE CPP               #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  module Configuration.DotenvSpec (main, spec) where
  
  import           Configuration.Dotenv             (Config (..), load, loadFile,
                                                     onMissingFile, parseFile)
  import           Configuration.Dotenv.Environment (getEnvironment, lookupEnv,
                                                     setEnv, unsetEnv)
  
  
  import           Test.Hspec
  
  import           Control.Monad                    (liftM)
  import           Data.Maybe                       (fromMaybe)
  import           System.Process                   (readCreateProcess, shell)
  
  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"
  
      it "loads the last set value in config list with duplicates" $ do
        lookupEnv "foo" `shouldReturn` Nothing
        lookupEnv "bar" `shouldReturn` Nothing
  
        load False [("foo", "first"), ("bar", "second"), ("foo", "third")]
  
        lookupEnv "foo" `shouldReturn` Just "third"
        lookupEnv "bar" `shouldReturn` Just "second"
  
    describe "loadFile" $ before_ setupEnv $ after_ clearEnvs $  do
      it "loads the configuration options to the environment from a file" $ do
        lookupEnv "DOTENV" `shouldReturn` Nothing
  
        loadFile sampleConfig
  
        lookupEnv "DOTENV" `shouldReturn` Just "true"
  
      it "respects predefined settings when overload is false" $ do
        setEnv "DOTENV" "preset"
  
        loadFile sampleConfig
  
        lookupEnv "DOTENV" `shouldReturn` Just "preset"
  
      it "overrides predefined settings when overload is true" $ do
        setEnv "DOTENV" "preset"
  
        loadFile sampleConfig { configOverride = True }
  
        lookupEnv "DOTENV" `shouldReturn` Just "true"
  
      it "loads the last set value in dotenv file with duplicates" $ do
        lookupEnv "FOO" `shouldReturn` Nothing
        lookupEnv "BAR" `shouldReturn` Nothing
  
        loadFile (Config ["spec/fixtures/.dotenv.dup"] [] False False False True)
  
        lookupEnv "FOO" `shouldReturn` Just "last"
        lookupEnv "BAR" `shouldReturn` Just "tender"
  
      context "when the .env.example is present" $ do
        let config = sampleConfig { configExamplePath = ["spec/fixtures/.dotenv.example"]}
        context "when the needed env vars are missing" $
          it "should fail with an error call" $ do
            unsetEnv "ANOTHER_ENV"
            loadFile config `shouldThrow` anyErrorCall
  
        context "when the needed env vars are not missing" $ do
          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
            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"
  
          it "succeeds when variable is preset" $ do
            setEnv "DOTENV" "preset"
  
            loadFile config
  
            lookupEnv "DOTENV" `shouldReturn` Just "preset"
  
    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)
  
  #if MIN_VERSION_base(4,11,0)
      it "recognizes blank variable" $
        liftM (!! 5) (parseFile "spec/fixtures/.dotenv") `shouldReturn`
          ("BLANK", "")
  #endif
  
    describe "onMissingFile" $ after_ clearEnvs $ do
      context "when target file is present" $
        it "loading works as usual" $ do
          onMissingFile (loadFile sampleConfig {configOverride = True}) (return ())
          lookupEnv "DOTENV" `shouldReturn` Just "true"
  
      context "when target file is missing" $
        it "executes supplied handler instead" $
          onMissingFile (True <$ loadFile sampleConfig {configPath= ["spec/fixtures/.foo"], configOverride = True}) (return False)
            `shouldReturn` False
  
    describe "onDuplicatedKeys" $ after_ clearEnvs $ do
      context "when duplicates are forbidden" $ do
        it "throws an error on duplicated keys" $
          loadFile sampleConfig { configPath = ["spec/fixtures/.dotenv", "spec/fixtures/.dotenv"], allowDuplicates = False }
            `shouldThrow` anyIOException
        it "works as usual when there is no duplicated keys" $ do
          loadFile sampleConfig { allowDuplicates = False }
          lookupEnv "DOTENV" `shouldReturn` Just "true"
  
    describe "onConfigDryRun" $ after_ clearEnvs $
      context "when dry-run is enabled " $
        it "loads the variables" $ do
          loadFile sampleConfig { configPath = ["spec/fixtures/.dotenv"], configDryRun = True }
          lookupEnv "DOTENV" `shouldReturn` Just "true"
  
  sampleConfig :: Config
  sampleConfig = Config ["spec/fixtures/.dotenv"] [] False False False True
  
  clearEnvs :: IO ()
  clearEnvs =
    getEnvironment >>= mapM_ unsetEnv . fmap fst
  
  setupEnv :: IO ()
  setupEnv = do
    setEnv "ANOTHER_ENV" "hello"
    setEnv "HOME" "/home/me"
  