123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- package godotenv
- import (
- "os"
- "testing"
- )
- var noopPresets = make(map[string]string)
- func parseAndCompare(t *testing.T, rawEnvLine string, expectedKey string, expectedValue string) {
- key, value, _ := parseLine(rawEnvLine)
- if key != expectedKey || value != expectedValue {
- t.Errorf("Expected '%v' to parse as '%v' => '%v', got '%v' => '%v' instead", rawEnvLine, expectedKey, expectedValue, key, value)
- }
- }
- func loadEnvAndCompareValues(t *testing.T, loader func(files ...string) error, envFileName string, expectedValues map[string]string, presets map[string]string) {
- // first up, clear the env
- os.Clearenv()
- for k, v := range presets {
- os.Setenv(k, v)
- }
- err := loader(envFileName)
- if err != nil {
- t.Fatalf("Error loading %v", envFileName)
- }
- for k := range expectedValues {
- envValue := os.Getenv(k)
- v := expectedValues[k]
- if envValue != v {
- t.Errorf("Mismatch for key '%v': expected '%v' got '%v'", k, v, envValue)
- }
- }
- }
- func TestLoadWithNoArgsLoadsDotEnv(t *testing.T) {
- err := Load()
- pathError := err.(*os.PathError)
- if pathError == nil || pathError.Op != "open" || pathError.Path != ".env" {
- t.Errorf("Didn't try and open .env by default")
- }
- }
- func TestOverloadWithNoArgsOverloadsDotEnv(t *testing.T) {
- err := Overload()
- pathError := err.(*os.PathError)
- if pathError == nil || pathError.Op != "open" || pathError.Path != ".env" {
- t.Errorf("Didn't try and open .env by default")
- }
- }
- func TestLoadFileNotFound(t *testing.T) {
- err := Load("somefilethatwillneverexistever.env")
- if err == nil {
- t.Error("File wasn't found but Load didn't return an error")
- }
- }
- func TestOverloadFileNotFound(t *testing.T) {
- err := Overload("somefilethatwillneverexistever.env")
- if err == nil {
- t.Error("File wasn't found but Overload didn't return an error")
- }
- }
- func TestReadPlainEnv(t *testing.T) {
- envFileName := "fixtures/plain.env"
- expectedValues := map[string]string{
- "OPTION_A": "1",
- "OPTION_B": "2",
- "OPTION_C": "3",
- "OPTION_D": "4",
- "OPTION_E": "5",
- }
- envMap, err := Read(envFileName)
- if err != nil {
- t.Error("Error reading file")
- }
- if len(envMap) != len(expectedValues) {
- t.Error("Didn't get the right size map back")
- }
- for key, value := range expectedValues {
- if envMap[key] != value {
- t.Error("Read got one of the keys wrong")
- }
- }
- }
- func TestLoadDoesNotOverride(t *testing.T) {
- envFileName := "fixtures/plain.env"
- // ensure NO overload
- presets := map[string]string{
- "OPTION_A": "do_not_override",
- }
- expectedValues := map[string]string{
- "OPTION_A": "do_not_override",
- }
- loadEnvAndCompareValues(t, Load, envFileName, expectedValues, presets)
- }
- func TestOveroadDoesOverride(t *testing.T) {
- envFileName := "fixtures/plain.env"
- // ensure NO overload
- presets := map[string]string{
- "OPTION_A": "do_not_override",
- }
- expectedValues := map[string]string{
- "OPTION_A": "1",
- }
- loadEnvAndCompareValues(t, Overload, envFileName, expectedValues, presets)
- }
- func TestLoadPlainEnv(t *testing.T) {
- envFileName := "fixtures/plain.env"
- expectedValues := map[string]string{
- "OPTION_A": "1",
- "OPTION_B": "2",
- "OPTION_C": "3",
- "OPTION_D": "4",
- "OPTION_E": "5",
- }
- loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
- }
- func TestLoadExportedEnv(t *testing.T) {
- envFileName := "fixtures/exported.env"
- expectedValues := map[string]string{
- "OPTION_A": "2",
- "OPTION_B": "\n",
- }
- loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
- }
- func TestLoadEqualsEnv(t *testing.T) {
- envFileName := "fixtures/equals.env"
- expectedValues := map[string]string{
- "OPTION_A": "postgres://localhost:5432/database?sslmode=disable",
- }
- loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
- }
- func TestLoadQuotedEnv(t *testing.T) {
- envFileName := "fixtures/quoted.env"
- expectedValues := map[string]string{
- "OPTION_A": "1",
- "OPTION_B": "2",
- "OPTION_C": "",
- "OPTION_D": "\n",
- "OPTION_E": "1",
- "OPTION_F": "2",
- "OPTION_G": "",
- "OPTION_H": "\n",
- }
- loadEnvAndCompareValues(t, Load, envFileName, expectedValues, noopPresets)
- }
- func TestActualEnvVarsAreLeftAlone(t *testing.T) {
- os.Clearenv()
- os.Setenv("OPTION_A", "actualenv")
- _ = Load("fixtures/plain.env")
- if os.Getenv("OPTION_A") != "actualenv" {
- t.Error("An ENV var set earlier was overwritten")
- }
- }
- func TestParsing(t *testing.T) {
- // unquoted values
- parseAndCompare(t, "FOO=bar", "FOO", "bar")
- // parses values with spaces around equal sign
- parseAndCompare(t, "FOO =bar", "FOO", "bar")
- parseAndCompare(t, "FOO= bar", "FOO", "bar")
- // parses double quoted values
- parseAndCompare(t, "FOO=\"bar\"", "FOO", "bar")
- // parses single quoted values
- parseAndCompare(t, "FOO='bar'", "FOO", "bar")
- // parses escaped double quotes
- parseAndCompare(t, "FOO=escaped\\\"bar\"", "FOO", "escaped\"bar")
- // parses yaml style options
- parseAndCompare(t, "OPTION_A: 1", "OPTION_A", "1")
- // parses export keyword
- parseAndCompare(t, "export OPTION_A=2", "OPTION_A", "2")
- parseAndCompare(t, "export OPTION_B='\\n'", "OPTION_B", "\n")
- // it 'expands newlines in quoted strings' do
- // expect(env('FOO="bar\nbaz"')).to eql('FOO' => "bar\nbaz")
- parseAndCompare(t, "FOO=\"bar\\nbaz\"", "FOO", "bar\nbaz")
- // it 'parses varibales with "." in the name' do
- // expect(env('FOO.BAR=foobar')).to eql('FOO.BAR' => 'foobar')
- parseAndCompare(t, "FOO.BAR=foobar", "FOO.BAR", "foobar")
- // it 'parses varibales with several "=" in the value' do
- // expect(env('FOO=foobar=')).to eql('FOO' => 'foobar=')
- parseAndCompare(t, "FOO=foobar=", "FOO", "foobar=")
- // it 'strips unquoted values' do
- // expect(env('foo=bar ')).to eql('foo' => 'bar') # not 'bar '
- parseAndCompare(t, "FOO=bar ", "FOO", "bar")
- // it 'ignores inline comments' do
- // expect(env("foo=bar # this is foo")).to eql('foo' => 'bar')
- parseAndCompare(t, "FOO=bar # this is foo", "FOO", "bar")
- // it 'allows # in quoted value' do
- // expect(env('foo="bar#baz" # comment')).to eql('foo' => 'bar#baz')
- parseAndCompare(t, "FOO=\"bar#baz\" # comment", "FOO", "bar#baz")
- parseAndCompare(t, "FOO='bar#baz' # comment", "FOO", "bar#baz")
- parseAndCompare(t, "FOO=\"bar#baz#bang\" # comment", "FOO", "bar#baz#bang")
- // it 'parses # in quoted values' do
- // expect(env('foo="ba#r"')).to eql('foo' => 'ba#r')
- // expect(env("foo='ba#r'")).to eql('foo' => 'ba#r')
- parseAndCompare(t, "FOO=\"ba#r\"", "FOO", "ba#r")
- parseAndCompare(t, "FOO='ba#r'", "FOO", "ba#r")
- // it 'throws an error if line format is incorrect' do
- // expect{env('lol$wut')}.to raise_error(Dotenv::FormatError)
- badlyFormattedLine := "lol$wut"
- _, _, err := parseLine(badlyFormattedLine)
- if err == nil {
- t.Errorf("Expected \"%v\" to return error, but it didn't", badlyFormattedLine)
- }
- }
- func TestLinesToIgnore(t *testing.T) {
- // it 'ignores empty lines' do
- // expect(env("\n \t \nfoo=bar\n \nfizz=buzz")).to eql('foo' => 'bar', 'fizz' => 'buzz')
- if !isIgnoredLine("\n") {
- t.Error("Line with nothing but line break wasn't ignored")
- }
- if !isIgnoredLine("\t\t ") {
- t.Error("Line full of whitespace wasn't ignored")
- }
- // it 'ignores comment lines' do
- // expect(env("\n\n\n # HERE GOES FOO \nfoo=bar")).to eql('foo' => 'bar')
- if !isIgnoredLine("# comment") {
- t.Error("Comment wasn't ignored")
- }
- if !isIgnoredLine("\t#comment") {
- t.Error("Indented comment wasn't ignored")
- }
- // make sure we're not getting false positives
- if isIgnoredLine("export OPTION_B='\\n'") {
- t.Error("ignoring a perfectly valid line to parse")
- }
- }
- func TestErrorReadDirectory(t *testing.T) {
- envFileName := "fixtures/"
- envMap, err := Read(envFileName)
- if err == nil {
- t.Errorf("Expected error, got %v", envMap)
- }
- }
- func TestErrorParsing(t *testing.T) {
- envFileName := "fixtures/invalid1.env"
- envMap, err := Read(envFileName)
- if err == nil {
- t.Errorf("Expected error, got %v", envMap)
- }
- }
|