This commit is contained in:
Luma 2022-11-12 12:35:18 +09:00 committed by GitHub
commit b3c9e9107d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 93 additions and 4 deletions

View File

@ -26,6 +26,23 @@ import (
"strings"
)
type ParseError struct {
Line uint
Err error
}
func (e *ParseError) Error() string {
if e.Line == 0 {
return fmt.Sprintf("parse error before reading: %s", e.Err.Error())
}
return fmt.Sprintf("parse error on line %d: %s", e.Line, e.Err.Error())
}
func IsParseError(err error) bool {
_, ok := err.(*ParseError)
return ok
}
const doubleQuoteSpecialChars = "\\\n\r\"!$`"
// Load will read your env file(s) and load them into ENV for this process.
@ -99,6 +116,7 @@ func Read(filenames ...string) (envMap map[string]string, err error) {
// Parse reads an env file from io.Reader, returning a map of keys and values.
func Parse(r io.Reader) (envMap map[string]string, err error) {
envMap = make(map[string]string)
err = nil
var lines []string
scanner := bufio.NewScanner(r)
@ -106,16 +124,24 @@ func Parse(r io.Reader) (envMap map[string]string, err error) {
lines = append(lines, scanner.Text())
}
if err = scanner.Err(); err != nil {
if e := scanner.Err(); e != nil {
err = &ParseError{
Err: e,
}
return
}
for _, fullLine := range lines {
for line, fullLine := range lines {
if !isIgnoredLine(fullLine) {
var key, value string
key, value, err = parseLine(fullLine, envMap)
var e error
key, value, e = parseLine(fullLine, envMap)
if err != nil {
if e != nil {
err = &ParseError{
Line: uint(line) + 1,
Err: e,
}
return
}
envMap[key] = value

View File

@ -2,6 +2,7 @@ package godotenv
import (
"bytes"
"errors"
"fmt"
"os"
"reflect"
@ -115,6 +116,68 @@ func TestParse(t *testing.T) {
}
}
func TestIsParseError(t *testing.T) {
err := errors.New("test error")
if IsParseError(err) {
t.Errorf("Expected IsParseError(\"%s\") to be false, got true", err)
}
err = &ParseError{
Line: 1,
Err: errors.New("test error inside"),
}
if !IsParseError(err) {
t.Errorf("Expected IsParseError(\"%s\") to be true, got false", err)
}
}
func TestErrorParse(t *testing.T) {
envMap, err := Parse(bytes.NewReader([]byte("ONE=1\nTWO\nTHREE = \"3\"")))
if err == nil {
t.Errorf("Expected error, got %v", envMap)
}
pErr, ok := err.(*ParseError)
if !ok {
t.Fatalf("expected to be ParseError, got %d", err)
}
if pErr.Line != 2 {
t.Fatalf("expected parse error line to be %d, got \"%s\"", 2, pErr)
}
if !strings.Contains(err.Error(), pErr.Err.Error()) {
t.Fatalf("expected parse error contain underlying error \"%s\", got \"%s\"", pErr.Err, err)
}
}
type testBrokenReader struct{}
func (testBrokenReader) Read([]byte) (int, error) {
return 0, errors.New("reader error")
}
func TestErrorParseNoLine(t *testing.T) {
envMap, err := Parse(testBrokenReader{})
if err == nil {
t.Errorf("Expected error, got %v", envMap)
}
pErr, ok := err.(*ParseError)
if !ok {
t.Fatalf("expected to be ParseError, got %d", err)
}
if pErr.Line != 0 {
t.Fatalf("expected parse error line to be %d, got \"%s\"", 0, pErr)
}
if strings.Contains(strings.ToLower(err.Error()), "line") {
t.Fatalf("expected parse error not contain \"line\", got \"%s\"", pErr)
}
}
func TestLoadDoesNotOverride(t *testing.T) {
envFileName := "fixtures/plain.env"