Skip to content

Commit

Permalink
Merge pull request #257 from ikedam/feature/9431_CaseInsensitiveEnv
Browse files Browse the repository at this point in the history
Resolve environments case-insensitively on Windows
  • Loading branch information
glours authored May 5, 2022
2 parents bdac2d1 + eeab8f0 commit 0e9b532
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 1 deletion.
23 changes: 22 additions & 1 deletion types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,17 @@ package types

import (
"encoding/json"
"runtime"
"strings"

"github.com/mitchellh/mapstructure"
)

var (
// isCaseInsensitiveEnvVars is true on platforms where environment variable names are treated case-insensitively.
isCaseInsensitiveEnvVars = (runtime.GOOS == "windows")
)

// ConfigDetails are the details about a group of ConfigFiles
type ConfigDetails struct {
Version string
Expand All @@ -33,7 +40,21 @@ type ConfigDetails struct {
// LookupEnv provides a lookup function for environment variables
func (cd ConfigDetails) LookupEnv(key string) (string, bool) {
v, ok := cd.Environment[key]
return v, ok
if !isCaseInsensitiveEnvVars || ok {
return v, ok
}
// variable names must be treated case-insensitively on some platforms (that is, Windows).
// Resolves in this way:
// * Return the value if its name matches with the passed name case-sensitively.
// * Otherwise, return the value if its lower-cased name matches lower-cased passed name.
// * The value is indefinite if multiple variables match.
lowerKey := strings.ToLower(key)
for k, v := range cd.Environment {
if strings.ToLower(k) == lowerKey {
return v, true
}
}
return "", false
}

// ConfigFile is a filename and the contents of the file as a Dict
Expand Down
99 changes: 99 additions & 0 deletions types/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,102 @@ func Test_WithServices(t *testing.T) {
assert.NilError(t, err)
assert.DeepEqual(t, order, []string{"service_2", "service_3", "service_1"})
}

func Test_LookupEnv(t *testing.T) {
tests := []struct {
name string
environment map[string]string
caseInsensitive bool
search string
expectedValue string
expectedOk bool
}{
{
name: "case sensitive/case match",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: false,
search: "Env1",
expectedValue: "Value1",
expectedOk: true,
},
{
name: "case sensitive/case unmatch",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: false,
search: "ENV1",
expectedValue: "",
expectedOk: false,
},
{
name: "case sensitive/nil environment",
environment: nil,
caseInsensitive: false,
search: "Env1",
expectedValue: "",
expectedOk: false,
},
{
name: "case insensitive/case match",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: true,
search: "Env1",
expectedValue: "Value1",
expectedOk: true,
},
{
name: "case insensitive/case unmatch",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: true,
search: "ENV1",
expectedValue: "Value1",
expectedOk: true,
},
{
name: "case insensitive/unmatch",
environment: map[string]string{
"Env1": "Value1",
"Env2": "Value2",
},
caseInsensitive: true,
search: "Env3",
expectedValue: "",
expectedOk: false,
},
{
name: "case insensitive/nil environment",
environment: nil,
caseInsensitive: true,
search: "Env1",
expectedValue: "",
expectedOk: false,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
origIsCaseInsensitiveEnvVars := isCaseInsensitiveEnvVars
defer func() {
isCaseInsensitiveEnvVars = origIsCaseInsensitiveEnvVars
}()
isCaseInsensitiveEnvVars = test.caseInsensitive
cd := ConfigDetails{
Environment: test.environment,
}
v, ok := cd.LookupEnv(test.search)
assert.Equal(t, v, test.expectedValue)
assert.Equal(t, ok, test.expectedOk)
})
}
}

0 comments on commit 0e9b532

Please sign in to comment.