1package opts
2
3import (
4	"bufio"
5	"fmt"
6	"io/ioutil"
7	"os"
8	"reflect"
9	"strings"
10	"testing"
11)
12
13func tmpFileWithContent(content string, t *testing.T) string {
14	tmpFile, err := ioutil.TempFile("", "envfile-test")
15	if err != nil {
16		t.Fatal(err)
17	}
18	defer tmpFile.Close()
19
20	tmpFile.WriteString(content)
21	return tmpFile.Name()
22}
23
24// Test ParseEnvFile for a file with a few well formatted lines
25func TestParseEnvFileGoodFile(t *testing.T) {
26	content := `foo=bar
27    baz=quux
28# comment
29
30_foobar=foobaz
31with.dots=working
32and_underscore=working too
33`
34	// Adding a newline + a line with pure whitespace.
35	// This is being done like this instead of the block above
36	// because it's common for editors to trim trailing whitespace
37	// from lines, which becomes annoying since that's the
38	// exact thing we need to test.
39	content += "\n    \t  "
40	tmpFile := tmpFileWithContent(content, t)
41	defer os.Remove(tmpFile)
42
43	lines, err := ParseEnvFile(tmpFile)
44	if err != nil {
45		t.Fatal(err)
46	}
47
48	expectedLines := []string{
49		"foo=bar",
50		"baz=quux",
51		"_foobar=foobaz",
52		"with.dots=working",
53		"and_underscore=working too",
54	}
55
56	if !reflect.DeepEqual(lines, expectedLines) {
57		t.Fatal("lines not equal to expectedLines")
58	}
59}
60
61// Test ParseEnvFile for an empty file
62func TestParseEnvFileEmptyFile(t *testing.T) {
63	tmpFile := tmpFileWithContent("", t)
64	defer os.Remove(tmpFile)
65
66	lines, err := ParseEnvFile(tmpFile)
67	if err != nil {
68		t.Fatal(err)
69	}
70
71	if len(lines) != 0 {
72		t.Fatal("lines not empty; expected empty")
73	}
74}
75
76// Test ParseEnvFile for a non existent file
77func TestParseEnvFileNonExistentFile(t *testing.T) {
78	_, err := ParseEnvFile("foo_bar_baz")
79	if err == nil {
80		t.Fatal("ParseEnvFile succeeded; expected failure")
81	}
82	if _, ok := err.(*os.PathError); !ok {
83		t.Fatalf("Expected a PathError, got [%v]", err)
84	}
85}
86
87// Test ParseEnvFile for a badly formatted file
88func TestParseEnvFileBadlyFormattedFile(t *testing.T) {
89	content := `foo=bar
90    f   =quux
91`
92
93	tmpFile := tmpFileWithContent(content, t)
94	defer os.Remove(tmpFile)
95
96	_, err := ParseEnvFile(tmpFile)
97	if err == nil {
98		t.Fatalf("Expected an ErrBadKey, got nothing")
99	}
100	if _, ok := err.(ErrBadKey); !ok {
101		t.Fatalf("Expected an ErrBadKey, got [%v]", err)
102	}
103	expectedMessage := "poorly formatted environment: variable 'f   ' has white spaces"
104	if err.Error() != expectedMessage {
105		t.Fatalf("Expected [%v], got [%v]", expectedMessage, err.Error())
106	}
107}
108
109// Test ParseEnvFile for a file with a line exceeding bufio.MaxScanTokenSize
110func TestParseEnvFileLineTooLongFile(t *testing.T) {
111	content := strings.Repeat("a", bufio.MaxScanTokenSize+42)
112	content = fmt.Sprint("foo=", content)
113
114	tmpFile := tmpFileWithContent(content, t)
115	defer os.Remove(tmpFile)
116
117	_, err := ParseEnvFile(tmpFile)
118	if err == nil {
119		t.Fatal("ParseEnvFile succeeded; expected failure")
120	}
121}
122
123// ParseEnvFile with a random file, pass through
124func TestParseEnvFileRandomFile(t *testing.T) {
125	content := `first line
126another invalid line`
127	tmpFile := tmpFileWithContent(content, t)
128	defer os.Remove(tmpFile)
129
130	_, err := ParseEnvFile(tmpFile)
131	if err == nil {
132		t.Fatalf("Expected an ErrBadKey, got nothing")
133	}
134	if _, ok := err.(ErrBadKey); !ok {
135		t.Fatalf("Expected an ErrBadKey, got [%v]", err)
136	}
137	expectedMessage := "poorly formatted environment: variable 'first line' has white spaces"
138	if err.Error() != expectedMessage {
139		t.Fatalf("Expected [%v], got [%v]", expectedMessage, err.Error())
140	}
141}
142
143// ParseEnvFile with environment variable import definitions
144func TestParseEnvVariableDefinitionsFile(t *testing.T) {
145	content := `# comment=
146UNDEFINED_VAR
147HOME
148`
149	tmpFile := tmpFileWithContent(content, t)
150	defer os.Remove(tmpFile)
151
152	variables, err := ParseEnvFile(tmpFile)
153	if nil != err {
154		t.Fatal("There must not be any error")
155	}
156
157	if "HOME="+os.Getenv("HOME") != variables[0] {
158		t.Fatal("the HOME variable is not properly imported as the first variable (but it is the only one to import)")
159	}
160
161	if 1 != len(variables) {
162		t.Fatal("exactly one variable is imported (as the other one is not set at all)")
163	}
164}
165
166// ParseEnvFile with empty variable name
167func TestParseEnvVariableWithNoNameFile(t *testing.T) {
168	content := `# comment=
169=blank variable names are an error case
170`
171	tmpFile := tmpFileWithContent(content, t)
172	defer os.Remove(tmpFile)
173
174	_, err := ParseEnvFile(tmpFile)
175	if nil == err {
176		t.Fatal("if a variable has no name parsing an environment file must fail")
177	}
178}
179