forked from coop-cloud-mirrors/godotenv
Multiline string support (#156)
* refactor dotenv parser in order to support multi-line variable values declaration Signed-off-by: x1unix <denis0051@gmail.com> * Add multi-line var values test case and update comment test Signed-off-by: x1unix <denis0051@gmail.com> * Expand fixture tests to include multiline strings * Update go versions to test against * Switch to GOINSECURE for power8 CI task * When tests fail, show source version of string (inc special chars) * Update parser.go Co-authored-by: Austin Sasko <austintyler0239@yahoo.com> * Fix up bad merge * Add a full fixture for comments for extra piece of mind * Fix up some lint/staticcheck recommendations * Test against go 1.19 too Signed-off-by: x1unix <denis0051@gmail.com> Co-authored-by: x1unix <denis0051@gmail.com> Co-authored-by: Austin Sasko <austintyler0239@yahoo.com>
This commit is contained in:
100
godotenv_test.go
100
godotenv_test.go
@ -35,7 +35,7 @@ func loadEnvAndCompareValues(t *testing.T, loader func(files ...string) error, e
|
||||
envValue := os.Getenv(k)
|
||||
v := expectedValues[k]
|
||||
if envValue != v {
|
||||
t.Errorf("Mismatch for key '%v': expected '%v' got '%v'", k, v, envValue)
|
||||
t.Errorf("Mismatch for key '%v': expected '%#v' got '%#v'", k, v, envValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -189,6 +189,10 @@ func TestLoadQuotedEnv(t *testing.T) {
|
||||
"OPTION_G": "",
|
||||
"OPTION_H": "\n",
|
||||
"OPTION_I": "echo 'asd'",
|
||||
"OPTION_J": "line 1\nline 2",
|
||||
"OPTION_K": "line one\nthis is \\'quoted\\'\none more line",
|
||||
"OPTION_L": "line 1\nline 2",
|
||||
"OPTION_M": "line one\nthis is \"quoted\"\none more line",
|
||||
}
|
||||
|
||||
loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
|
||||
@ -271,6 +275,34 @@ func TestExpanding(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestVariableStringValueSeparator(t *testing.T) {
|
||||
input := "TEST_URLS=\"stratum+tcp://stratum.antpool.com:3333\nstratum+tcp://stratum.antpool.com:443\""
|
||||
want := map[string]string{
|
||||
"TEST_URLS": "stratum+tcp://stratum.antpool.com:3333\nstratum+tcp://stratum.antpool.com:443",
|
||||
}
|
||||
got, err := Parse(strings.NewReader(input))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf(
|
||||
"unexpected value:\nwant:\n\t%#v\n\ngot:\n\t%#v", want, got)
|
||||
}
|
||||
|
||||
for k, wantVal := range want {
|
||||
gotVal, ok := got[k]
|
||||
if !ok {
|
||||
t.Fatalf("key %q doesn't present in result", k)
|
||||
}
|
||||
if wantVal != gotVal {
|
||||
t.Fatalf(
|
||||
"mismatch in %q value:\nwant:\n\t%s\n\ngot:\n\t%s", k,
|
||||
wantVal, gotVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestActualEnvVarsAreLeftAlone(t *testing.T) {
|
||||
os.Clearenv()
|
||||
os.Setenv("OPTION_A", "actualenv")
|
||||
@ -377,33 +409,38 @@ func TestParsing(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLinesToIgnore(t *testing.T) {
|
||||
// it 'ignores empty lines' do
|
||||
// expect(env("\n \t \nfoo=bar\n \nfizz=buzz")).to eql('foo' => 'bar', 'fizz' => 'buzz')
|
||||
if !isIgnoredLine("\n") {
|
||||
t.Error("Line with nothing but line break wasn't ignored")
|
||||
cases := map[string]struct {
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
"Line with nothing but line break": {
|
||||
input: "\n",
|
||||
},
|
||||
"Line with nothing but windows-style line break": {
|
||||
input: "\r\n",
|
||||
},
|
||||
"Line full of whitespace": {
|
||||
input: "\t\t ",
|
||||
},
|
||||
"Comment": {
|
||||
input: "# Comment",
|
||||
},
|
||||
"Indented comment": {
|
||||
input: "\t # comment",
|
||||
},
|
||||
"non-ignored value": {
|
||||
input: `export OPTION_B='\n'`,
|
||||
want: `export OPTION_B='\n'`,
|
||||
},
|
||||
}
|
||||
|
||||
if !isIgnoredLine("\r\n") {
|
||||
t.Error("Line with nothing but windows-style line break wasn't ignored")
|
||||
}
|
||||
|
||||
if !isIgnoredLine("\t\t ") {
|
||||
t.Error("Line full of whitespace wasn't ignored")
|
||||
}
|
||||
|
||||
// it 'ignores comment lines' do
|
||||
// expect(env("\n\n\n # HERE GOES FOO \nfoo=bar")).to eql('foo' => 'bar')
|
||||
if !isIgnoredLine("# comment") {
|
||||
t.Error("Comment wasn't ignored")
|
||||
}
|
||||
|
||||
if !isIgnoredLine("\t#comment") {
|
||||
t.Error("Indented comment wasn't ignored")
|
||||
}
|
||||
|
||||
// make sure we're not getting false positives
|
||||
if isIgnoredLine(`export OPTION_B='\n'`) {
|
||||
t.Error("ignoring a perfectly valid line to parse")
|
||||
for n, c := range cases {
|
||||
t.Run(n, func(t *testing.T) {
|
||||
got := string(getStatementStart([]byte(c.input)))
|
||||
if got != c.want {
|
||||
t.Errorf("Expected:\t %q\nGot:\t %q", c.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -424,6 +461,17 @@ func TestErrorParsing(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestComments(t *testing.T) {
|
||||
envFileName := "fixtures/comments.env"
|
||||
expectedValues := map[string]string{
|
||||
"foo": "bar",
|
||||
"bar": "foo#baz",
|
||||
"baz": "foo",
|
||||
}
|
||||
|
||||
loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
|
||||
}
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
writeAndCompare := func(env string, expected string) {
|
||||
envMap, _ := Unmarshal(env)
|
||||
|
Reference in New Issue
Block a user