packages feed

dotenv-0.3.3.0: spec/Configuration/Dotenv/ParseSpec.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}

module Configuration.Dotenv.ParseSpec (main, spec) where

import Configuration.Dotenv.Parse (configParser)
import Configuration.Dotenv.ParsedVariable (ParsedVariable(..),
                                            VarValue(..),
                                            VarFragment(..))
import Test.Hspec (it, describe, Spec, hspec)
import Test.Hspec.Megaparsec (shouldParse, shouldFailOn)
import Text.Megaparsec (ParseError, Dec, parse)

main :: IO ()
main = hspec spec

spec :: Spec
spec = describe "parse" $ do
  it "parses unquoted values" $
    parseConfig "FOO=bar"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarLiteral "bar"])]

  it "parses values with spaces around equal signs" $ do
    parseConfig "FOO =bar"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarLiteral "bar"])]
    parseConfig "FOO= bar"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarLiteral "bar"])]
    parseConfig "FOO =\t bar"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarLiteral "bar"])]

  it "parses double-quoted values" $
    parseConfig "FOO=\"bar\""
      `shouldParse` [ParsedVariable "FOO" (DoubleQuoted [VarLiteral "bar"])]

  it "parses single-quoted values" $
    parseConfig "FOO='bar'"
      `shouldParse` [ParsedVariable "FOO" (SingleQuoted [VarLiteral "bar"])]

  it "parses escaped double quotes" $
    parseConfig "FOO=\"escaped\\\"bar\""
      `shouldParse` [ParsedVariable "FOO" (DoubleQuoted [VarLiteral "escaped\"bar"])]

  it "supports CRLF line breaks" $
    parseConfig "FOO=bar\r\nbaz=fbb"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarLiteral "bar"]),
                     ParsedVariable "baz" (Unquoted [VarLiteral "fbb"])]

  it "parses empty values" $
    parseConfig "FOO="
      `shouldParse` [ParsedVariable "FOO" (Unquoted [])]

  it "parses unquoted interpolated values" $ do
    parseConfig "FOO=$HOME"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarInterpolation "HOME"])]
    parseConfig "FOO=abc_$HOME"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarLiteral "abc_",
                                                     VarInterpolation "HOME"])
                    ]
    parseConfig "FOO=${HOME}"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarInterpolation "HOME"])]
    parseConfig "FOO=abc_${HOME}"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarLiteral "abc_",
                                                     VarInterpolation "HOME"])
                    ]

  it "parses double-quoted interpolated values" $ do
    parseConfig "FOO=\"$HOME\""
      `shouldParse` [ParsedVariable "FOO" (DoubleQuoted [VarInterpolation "HOME"])]
    parseConfig "FOO=\"abc_$HOME\""
      `shouldParse` [ParsedVariable "FOO" (DoubleQuoted [VarLiteral "abc_",
                                                         VarInterpolation "HOME"])
                    ]
    parseConfig "FOO=\"${HOME}\""
      `shouldParse` [ParsedVariable "FOO" (DoubleQuoted [VarInterpolation "HOME"])]
    parseConfig "FOO=\"abc_${HOME}\""
      `shouldParse` [ParsedVariable "FOO" (DoubleQuoted [VarLiteral "abc_",
                                                         VarInterpolation "HOME"])
                    ]

  it "parses single-quoted interpolated values as literals" $ do
    parseConfig "FOO='$HOME'"
      `shouldParse` [ParsedVariable "FOO" (SingleQuoted [VarLiteral "$HOME"])]
    parseConfig "FOO='abc_$HOME'"
      `shouldParse` [ParsedVariable "FOO" (SingleQuoted [VarLiteral "abc_$HOME"])]
    parseConfig "FOO='${HOME}'"
      `shouldParse` [ParsedVariable "FOO" (SingleQuoted [VarLiteral "${HOME}"])]
    parseConfig "FOO='abc_${HOME}'"
      `shouldParse` [ParsedVariable "FOO" (SingleQuoted [VarLiteral "abc_${HOME}"])]

  it "does not parse if line format is incorrect" $ do
    parseConfig `shouldFailOn` "lol$wut"
    parseConfig `shouldFailOn` "KEY=\nVALUE"
    parseConfig `shouldFailOn` "KEY\n=VALUE"

  it "expands newlines in quoted strings" $
    parseConfig "FOO=\"bar\nbaz\""
      `shouldParse` [ParsedVariable "FOO" (DoubleQuoted [VarLiteral "bar\nbaz"])]

  it "does not parse variables with hyphens in the name" $
    parseConfig `shouldFailOn` "FOO-BAR=foobar"

  it "parses variables with \"_\" in the name" $
    parseConfig "FOO_BAR=foobar"
      `shouldParse` [ParsedVariable "FOO_BAR" (Unquoted [VarLiteral "foobar"])]

  it "parses variables with digits after the first character" $
    parseConfig "FOO_BAR_12=foobar"
      `shouldParse` [ParsedVariable "FOO_BAR_12" (Unquoted [VarLiteral "foobar"])]

  it "allows vertical spaces after a quoted variable" $
    parseConfig "foo='bar' "
      `shouldParse` [ParsedVariable "foo" (SingleQuoted [VarLiteral "bar"])]

  it "does not parse variable names beginning with a digit" $
    parseConfig `shouldFailOn` "45FOO_BAR=foobar"

  it "strips unquoted values" $
    parseConfig "foo=bar "
      `shouldParse` [ParsedVariable "foo" (Unquoted [VarLiteral "bar"])]

  it "ignores empty lines" $
    parseConfig "\n \t  \nfoo=bar\n \nfizz=buzz"
      `shouldParse` [ParsedVariable "foo" (Unquoted [VarLiteral "bar"]),
                     ParsedVariable "fizz" (Unquoted [VarLiteral "buzz"])]

  it "ignores inline comments after unquoted arguments" $
    parseConfig "FOO=bar # this is foo"
      `shouldParse` [ParsedVariable "FOO" (Unquoted [VarLiteral "bar"])]

  it "ignores inline comments after quoted arguments" $
    parseConfig "FOO=\"bar\" # this is foo"
      `shouldParse` [ParsedVariable "FOO" (DoubleQuoted [VarLiteral "bar"])]

  it "allows \"#\" in quoted values" $
    parseConfig "foo=\"bar#baz\" # comment"
      `shouldParse` [ParsedVariable "foo" (DoubleQuoted [VarLiteral "bar#baz"])]

  it "ignores comment lines" $
    parseConfig "\n\t \n\n # HERE GOES FOO \nfoo=bar"
      `shouldParse` [ParsedVariable "foo" (Unquoted [VarLiteral "bar"])]

  it "doesn't allow more configuration options after a quoted value" $
    parseConfig `shouldFailOn` "foo='bar'baz='buz'"

parseConfig :: String -> Either (ParseError Char Dec) [ParsedVariable]
parseConfig = parse configParser ""