package opts import ( "bufio" "os" "reflect" "strings" "testing" ) func tmpFileWithContent(t *testing.T, content string) string { t.Helper() tmpFile, err := os.CreateTemp("", "envfile-test") if err != nil { t.Fatal(err) } defer tmpFile.Close() _, err = tmpFile.WriteString(content) if err != nil { t.Fatal(err) } t.Cleanup(func() { _ = os.Remove(tmpFile.Name()) }) return tmpFile.Name() } // Test ParseEnvFile for a file with a few well formatted lines func TestParseEnvFileGoodFile(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 " tmpFile := tmpFileWithContent(t, content) lines, err := ParseEnvFile(tmpFile) if err != nil { t.Fatal(err) } expectedLines := []string{ "foo=bar", "baz=quux", "_foobar=foobaz", "with.dots=working", "and_underscore=working too", } if !reflect.DeepEqual(lines, expectedLines) { t.Fatal("lines not equal to expectedLines") } } // Test ParseEnvFile for an empty file func TestParseEnvFileEmptyFile(t *testing.T) { tmpFile := tmpFileWithContent(t, "") lines, err := ParseEnvFile(tmpFile) if err != nil { t.Fatal(err) } if len(lines) != 0 { t.Fatal("lines not empty; expected empty") } } // Test ParseEnvFile for a non existent file func TestParseEnvFileNonExistentFile(t *testing.T) { _, err := ParseEnvFile("foo_bar_baz") if err == nil { t.Fatal("ParseEnvFile succeeded; expected failure") } if _, ok := err.(*os.PathError); !ok { t.Fatalf("Expected a PathError, got [%v]", err) } } // Test ParseEnvFile for a badly formatted file func TestParseEnvFileBadlyFormattedFile(t *testing.T) { content := `foo=bar f =quux ` tmpFile := tmpFileWithContent(t, content) _, err := ParseEnvFile(tmpFile) if err == nil { t.Fatalf("Expected an ErrBadKey, got nothing") } if _, ok := err.(ErrBadKey); !ok { t.Fatalf("Expected an ErrBadKey, got [%v]", err) } expectedMessage := "poorly formatted environment: variable 'f ' contains whitespaces" if err.Error() != expectedMessage { t.Fatalf("Expected [%v], got [%v]", expectedMessage, err.Error()) } } // Test ParseEnvFile for a file with a line exceeding bufio.MaxScanTokenSize func TestParseEnvFileLineTooLongFile(t *testing.T) { content := "foo=" + strings.Repeat("a", bufio.MaxScanTokenSize+42) tmpFile := tmpFileWithContent(t, content) _, err := ParseEnvFile(tmpFile) if err == nil { t.Fatal("ParseEnvFile succeeded; expected failure") } } // ParseEnvFile with a random file, pass through func TestParseEnvFileRandomFile(t *testing.T) { content := `first line another invalid line` tmpFile := tmpFileWithContent(t, content) _, err := ParseEnvFile(tmpFile) if err == nil { t.Fatalf("Expected an ErrBadKey, got nothing") } if _, ok := err.(ErrBadKey); !ok { t.Fatalf("Expected an ErrBadKey, got [%v]", err) } expectedMessage := "poorly formatted environment: variable 'first line' contains whitespaces" if err.Error() != expectedMessage { t.Fatalf("Expected [%v], got [%v]", expectedMessage, err.Error()) } } // ParseEnvFile with environment variable import definitions func TestParseEnvVariableDefinitionsFile(t *testing.T) { content := `# comment= UNDEFINED_VAR HOME ` tmpFile := tmpFileWithContent(t, content) variables, err := ParseEnvFile(tmpFile) if nil != err { t.Fatal("There must not be any error") } if "HOME="+os.Getenv("HOME") != variables[0] { t.Fatal("the HOME variable is not properly imported as the first variable (but it is the only one to import)") } if 1 != len(variables) { t.Fatal("exactly one variable is imported (as the other one is not set at all)") } } // ParseEnvFile with empty variable name func TestParseEnvVariableWithNoNameFile(t *testing.T) { content := `# comment= =blank variable names are an error case ` tmpFile := tmpFileWithContent(t, content) _, err := ParseEnvFile(tmpFile) if nil == err { t.Fatal("if a variable has no name parsing an environment file must fail") } }