package kvfile import ( "bufio" "os" "path/filepath" "strings" "testing" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) // Test Parse for a non existent file. func TestParseNonExistentFile(t *testing.T) { _, err := Parse("no_such_file", nil) assert.Check(t, is.ErrorType(err, os.IsNotExist)) } // Test Parse from a file with a lookup function. func TestParseWithLookup(t *testing.T) { content := `# comment= VAR=VAR_VALUE EMPTY_VAR= UNDEFINED_VAR DEFINED_VAR ` vars := map[string]string{ "DEFINED_VAR": "defined-value", } lookupFn := func(name string) (string, bool) { v, ok := vars[name] return v, ok } fileName := filepath.Join(t.TempDir(), "envfile") err := os.WriteFile(fileName, []byte(content), 0o644) assert.NilError(t, err) variables, err := Parse(fileName, lookupFn) assert.NilError(t, err) expectedLines := []string{"VAR=VAR_VALUE", "EMPTY_VAR=", "DEFINED_VAR=defined-value"} assert.Check(t, is.DeepEqual(variables, expectedLines)) } // Test ParseEnvFile for a file with a few well formatted lines func TestParseFromReaderGoodFile(t *testing.T) { content := `foo=bar baz=quux # comment _foobar=foobaz with.dots=working and_underscore=working too ` // Adding a newline + a line with pure whitespace. // This is being done like this instead of the block above // because it's common for editors to trim trailing whitespace // from lines, which becomes annoying since that's the // exact thing we need to test. content += "\n \t " lines, err := ParseFromReader(strings.NewReader(content), nil) assert.NilError(t, err) expectedLines := []string{ "foo=bar", "baz=quux", "_foobar=foobaz", "with.dots=working", "and_underscore=working too", } assert.Check(t, is.DeepEqual(lines, expectedLines)) } // Test ParseFromReader for an empty file func TestParseFromReaderEmptyFile(t *testing.T) { lines, err := ParseFromReader(strings.NewReader(""), nil) assert.NilError(t, err) assert.Check(t, is.Len(lines, 0)) } // Test ParseFromReader for a badly formatted file func TestParseFromReaderBadlyFormattedFile(t *testing.T) { content := `foo=bar f =quux ` _, err := ParseFromReader(strings.NewReader(content), nil) const expectedMessage = "variable 'f ' contains whitespaces" assert.Check(t, is.ErrorContains(err, expectedMessage)) } // Test ParseFromReader for a file with a line exceeding bufio.MaxScanTokenSize func TestParseFromReaderLineTooLongFile(t *testing.T) { content := "foo=" + strings.Repeat("a", bufio.MaxScanTokenSize+42) _, err := ParseFromReader(strings.NewReader(content), nil) const expectedMessage = "bufio.Scanner: token too long" assert.Check(t, is.ErrorContains(err, expectedMessage)) } // ParseEnvFile with a random file, pass through func TestParseFromReaderRandomFile(t *testing.T) { content := `first line another invalid line` _, err := ParseFromReader(strings.NewReader(content), nil) const expectedMessage = "variable 'first line' contains whitespaces" assert.Check(t, is.ErrorContains(err, expectedMessage)) } // Test ParseFromReader with a lookup function. func TestParseFromReaderWithLookup(t *testing.T) { content := `# comment= VAR=VAR_VALUE EMPTY_VAR= UNDEFINED_VAR DEFINED_VAR ` vars := map[string]string{ "DEFINED_VAR": "defined-value", } lookupFn := func(name string) (string, bool) { v, ok := vars[name] return v, ok } variables, err := ParseFromReader(strings.NewReader(content), lookupFn) assert.NilError(t, err) expectedLines := []string{"VAR=VAR_VALUE", "EMPTY_VAR=", "DEFINED_VAR=defined-value"} assert.Check(t, is.DeepEqual(variables, expectedLines)) } // Test ParseFromReader with empty variable name func TestParseFromReaderWithNoName(t *testing.T) { content := `# comment= =blank variable names are an error case ` _, err := ParseFromReader(strings.NewReader(content), nil) const expectedMessage = "no variable name on line '=blank variable names are an error case'" assert.Check(t, is.ErrorContains(err, expectedMessage)) }