blob: 3ad93a1644238cc078f3a139f9fc03a413f8744e [file] [log] [blame]
// Copyright 2016 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package environ
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func newImpl(caseInsensitive bool, entries []string) Env {
e := Env{CaseInsensitive: caseInsensitive}
e.LoadSlice(entries)
return e
}
func TestEnvironmentConversion(t *testing.T) {
t.Parallel()
Convey(`Source environment slice translates correctly to/from an Env.`, t, func() {
Convey(`Case insensitive (e.g., Windows)`, func() {
env := newImpl(true, []string{
"",
"FOO",
"BAR=BAZ",
"bar=baz",
"qux=quux=quuuuuuux",
})
So(env, ShouldResemble, Env{
CaseInsensitive: true,
env: map[string]string{
"FOO": "FOO=",
"BAR": "bar=baz",
"QUX": "qux=quux=quuuuuuux",
},
})
So(env.Sorted(), ShouldResemble, []string{
"FOO=",
"bar=baz",
"qux=quux=quuuuuuux",
})
So(env.GetEmpty(""), ShouldEqual, "")
So(env.GetEmpty("FOO"), ShouldEqual, "")
So(env.GetEmpty("BAR"), ShouldEqual, "baz")
So(env.GetEmpty("bar"), ShouldEqual, "baz")
So(env.GetEmpty("qux"), ShouldEqual, "quux=quuuuuuux")
So(env.GetEmpty("QuX"), ShouldEqual, "quux=quuuuuuux")
})
Convey(`Case sensitive (e.g., POSIX)`, func() {
env := newImpl(false, []string{
"",
"FOO",
"BAR=BAZ",
"bar=baz",
"qux=quux=quuuuuuux",
})
So(env, ShouldResemble, Env{
env: map[string]string{
"FOO": "FOO=",
"BAR": "BAR=BAZ",
"bar": "bar=baz",
"qux": "qux=quux=quuuuuuux",
},
})
So(env.Sorted(), ShouldResemble, []string{
"BAR=BAZ",
"FOO=",
"bar=baz",
"qux=quux=quuuuuuux",
})
So(env.GetEmpty(""), ShouldEqual, "")
So(env.GetEmpty("FOO"), ShouldEqual, "")
So(env.GetEmpty("BAR"), ShouldEqual, "BAZ")
So(env.GetEmpty("bar"), ShouldEqual, "baz")
So(env.GetEmpty("qux"), ShouldEqual, "quux=quuuuuuux")
So(env.GetEmpty("QuX"), ShouldEqual, "")
})
})
}
func TestEnvironmentManipulation(t *testing.T) {
t.Parallel()
Convey(`A zero-valued Env`, t, func() {
var env Env
So(env.Len(), ShouldEqual, 0)
Convey(`Can be sorted.`, func() {
So(env.Sorted(), ShouldEqual, nil)
})
Convey(`Can call Get`, func() {
v, ok := env.Get("foo")
So(ok, ShouldBeFalse)
So(v, ShouldEqual, "")
})
Convey(`Can call Set`, func() {
env.Set("foo", "bar")
So(env.Len(), ShouldEqual, 1)
So(env.Sorted(), ShouldResemble, []string{"foo=bar"})
})
Convey(`Can be cloned, and propagates case insensitivity.`, func() {
env.CaseInsensitive = true
So(env.Clone(), ShouldResemble, env)
})
})
Convey(`A testing Env`, t, func() {
env := newImpl(true, []string{
"PYTHONPATH=/foo:/bar:/baz",
"http_proxy=wiped-out-by-next",
"http_proxy=http://example.com",
"novalue",
})
So(env.Len(), ShouldEqual, 3)
Convey(`Can Get values.`, func() {
v, ok := env.Get("PYTHONPATH")
So(ok, ShouldBeTrue)
So(v, ShouldEqual, "/foo:/bar:/baz")
v, ok = env.Get("http_proxy")
So(ok, ShouldBeTrue)
So(v, ShouldEqual, "http://example.com")
v, ok = env.Get("novalue")
So(ok, ShouldBeTrue)
So(v, ShouldEqual, "")
})
Convey(`Will note missing values.`, func() {
_, ok := env.Get("missing")
So(ok, ShouldBeFalse)
_, ok = env.Get("")
So(ok, ShouldBeFalse)
})
Convey(`Can be converted into a map and enumerated`, func() {
So(env.Map(), ShouldResemble, map[string]string{
"PYTHONPATH": "/foo:/bar:/baz",
"http_proxy": "http://example.com",
"novalue": "",
})
Convey(`Can perform iteration`, func() {
buildMap := make(map[string]string)
So(env.Iter(func(k, v string) error {
buildMap[k] = v
return nil
}), ShouldBeNil)
So(env.Map(), ShouldResemble, buildMap)
})
Convey(`Can have elements removed through iteration`, func() {
env.RemoveMatch(func(k, v string) bool {
switch k {
case "PYTHONPATH", "novalue":
return true
default:
return false
}
})
So(env.Map(), ShouldResemble, map[string]string{
"http_proxy": "http://example.com",
})
})
})
Convey(`Can update its values.`, func() {
orig := env.Clone()
// Update PYTHONPATH, confirm that it updated correctly.
v, _ := env.Get("PYTHONPATH")
env.Set("PYTHONPATH", "/override:"+v)
So(env.Sorted(), ShouldResemble, []string{
"PYTHONPATH=/override:/foo:/bar:/baz",
"http_proxy=http://example.com",
"novalue=",
})
// Use a different-case key, and confirm that it still updated correctly.
Convey(`When case insensitive, will update common keys.`, func() {
env.CaseInsensitive = true
env.Set("pYtHoNpAtH", "/override:"+v)
So(env.Sorted(), ShouldResemble, []string{
"http_proxy=http://example.com",
"novalue=",
"pYtHoNpAtH=/override:/foo:/bar:/baz",
})
So(env.GetEmpty("PYTHONPATH"), ShouldEqual, "/override:/foo:/bar:/baz")
So(env.Remove("HTTP_PROXY"), ShouldBeTrue)
So(env.Remove("nonexistent"), ShouldBeFalse)
So(env.Sorted(), ShouldResemble, []string{
"novalue=",
"pYtHoNpAtH=/override:/foo:/bar:/baz",
})
// Test that the clone didn't change.
So(orig.Sorted(), ShouldResemble, []string{
"PYTHONPATH=/foo:/bar:/baz",
"http_proxy=http://example.com",
"novalue=",
})
var mergeMe Env
mergeMe.LoadSlice([]string{
"http_PROXY=foo",
"HTTP_PROXY=FOO",
"newkey=value",
})
orig.Update(mergeMe)
So(orig.Sorted(), ShouldResemble, []string{
"PYTHONPATH=/foo:/bar:/baz",
"http_PROXY=foo",
"newkey=value",
"novalue=",
})
})
})
})
}
func TestEnvironmentConstruction(t *testing.T) {
t.Parallel()
Convey(`Testing Load* with an empty environment`, t, func() {
var env Env
Convey(`Can load an initial set of values from a map`, func() {
env.Load(map[string]string{
"FOO": "BAR",
"foo": "bar",
})
So(env, ShouldResemble, Env{
env: map[string]string{
"FOO": "FOO=BAR",
"foo": "foo=bar",
},
})
})
Convey(`Load with an nil/empty enviornment returns a zero value.`, func() {
env.Load(nil)
So(env.env, ShouldBeNil)
env.Load(map[string]string{})
So(env.env, ShouldBeNil)
})
})
Convey(`New with a nil/empty slice returns a zero value.`, t, func() {
So(New(nil).env, ShouldBeNil)
So(New([]string{}).env, ShouldBeNil)
})
}