diff --git a/godotenv.go b/godotenv.go index 61b0ebb..8e9fe3f 100644 --- a/godotenv.go +++ b/godotenv.go @@ -20,7 +20,6 @@ import ( "os" "os/exec" "sort" - "strconv" "strings" ) @@ -159,13 +158,33 @@ func Write(envMap map[string]string, filename string) error { return file.Sync() } +// isInt checks if the string may be serialized as a number value, leading +// "-" symbol is allowed for negative numbers, leading "+" sign is not. The +// length of the value is not limited. +func isInt(s string) bool { + s = strings.TrimPrefix(s, "-") + + if len(s) == 0 { + return false + } + + for _, r := range s { + if '0' <= r && r <= '9' { + continue + } + return false + } + + return true +} + // Marshal outputs the given environment as a dotenv-formatted environment file. // Each line is in the format: KEY="VALUE" where VALUE is backslash-escaped. func Marshal(envMap map[string]string) (string, error) { lines := make([]string, 0, len(envMap)) for k, v := range envMap { - if d, err := strconv.Atoi(v); err == nil { - lines = append(lines, fmt.Sprintf(`%s=%d`, k, d)) + if isInt(v) { + lines = append(lines, fmt.Sprintf(`%s=%s`, k, v)) } else { lines = append(lines, fmt.Sprintf(`%s="%s"`, k, doubleQuoteEscape(v))) } diff --git a/godotenv_test.go b/godotenv_test.go index c6d7e54..db9f7e0 100644 --- a/godotenv_test.go +++ b/godotenv_test.go @@ -479,6 +479,30 @@ func TestComments(t *testing.T) { loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets) } +func TestIsInt(t *testing.T) { + checkAndCompare := func(s string, expected bool) { + if isInt(s) != expected { + t.Fail() + } + } + + // invalid values + checkAndCompare("", false) + checkAndCompare("+123", false) + checkAndCompare("+12a3", false) + checkAndCompare("12a3", false) + checkAndCompare("abc", false) + checkAndCompare("12 3", false) + checkAndCompare("-", false) + checkAndCompare(" ", false) + + // valid values + checkAndCompare("-123", true) + checkAndCompare("123", true) + checkAndCompare("-922337203685477580868712", true) + checkAndCompare("922337203685477580837281", true) +} + func TestWrite(t *testing.T) { writeAndCompare := func(env string, expected string) { envMap, _ := Unmarshal(env) @@ -582,42 +606,42 @@ func TestWhitespace(t *testing.T) { }{ "Leading whitespace": { input: " A=a\n", - key: "A", + key: "A", value: "a", }, "Leading tab": { input: "\tA=a\n", - key: "A", + key: "A", value: "a", }, "Leading mixed whitespace": { input: " \t \t\n\t \t A=a\n", - key: "A", + key: "A", value: "a", }, "Leading whitespace before export": { input: " \t\t export A=a\n", - key: "A", + key: "A", value: "a", }, "Trailing whitespace": { input: "A=a \t \t\n", - key: "A", + key: "A", value: "a", }, "Trailing whitespace with export": { input: "export A=a\t \t \n", - key: "A", + key: "A", value: "a", }, "No EOL": { input: "A=a", - key: "A", + key: "A", value: "a", }, "Trailing whitespace with no EOL": { input: "A=a ", - key: "A", + key: "A", value: "a", }, }