// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os_test
import (
. "os"
"reflect"
"strings"
"testing"
)
// testGetenv gives us a controlled set of variables for testing Expand.
func testGetenv(s string) string {
switch s {
case "*":
return "all the args"
case "#":
return "NARGS"
case "$":
return "PID"
case "1":
return "ARGUMENT1"
case "HOME":
return "/usr/gopher"
case "H":
return "(Value of H)"
case "home_1":
return "/usr/foo"
case "_":
return "underscore"
}
return ""
}
var expandTests = []struct {
in, out string
}{
{"", ""},
{"$*", "all the args"},
{"$$", "PID"},
{"${*}", "all the args"},
{"$1", "ARGUMENT1"},
{"${1}", "ARGUMENT1"},
{"now is the time", "now is the time"},
{"$HOME", "/usr/gopher"},
{"$home_1", "/usr/foo"},
{"${HOME}", "/usr/gopher"},
{"${H}OME", "(Value of H)OME"},
{"A$$$#$1$H$home_1*B", "APIDNARGSARGUMENT1(Value of H)/usr/foo*B"},
{"start$+middle$^end$", "start$+middle$^end$"},
{"mixed$|bag$$$", "mixed$|bagPID$"},
{"$", "$"},
{"$}", "$}"},
{"${", ""}, // invalid syntax; eat up the characters
{"${}", ""}, // invalid syntax; eat up the characters
}
func TestExpand(t *testing.T) {
for _, test := range expandTests {
result := Expand(test.in, testGetenv)
if result != test.out {
t.Errorf("Expand(%q)=%q; expected %q", test.in, result, test.out)
}
}
}
var global interface{}
func BenchmarkExpand(b *testing.B) {
b.Run("noop", func(b *testing.B) {
var s string
b.ReportAllocs()
for i := 0; i < b.N; i++ {
s = Expand("tick tick tick tick", func(string) string { return "" })
}
global = s
})
b.Run("multiple", func(b *testing.B) {
var s string
b.ReportAllocs()
for i := 0; i < b.N; i++ {
s = Expand("$a $a $a $a", func(string) string { return "boom" })
}
global = s
})
}
func TestConsistentEnviron(t *testing.T) {
e0 := Environ()
for i := 0; i < 10; i++ {
e1 := Environ()
if !reflect.DeepEqual(e0, e1) {
t.Fatalf("environment changed")
}
}
}
func TestUnsetenv(t *testing.T) {
const testKey = "GO_TEST_UNSETENV"
set := func() bool {
prefix := testKey + "="
for _, key := range Environ() {
if strings.HasPrefix(key, prefix) {
return true
}
}
return false
}
if err := Setenv(testKey, "1"); err != nil {
t.Fatalf("Setenv: %v", err)
}
if !set() {
t.Error("Setenv didn't set TestUnsetenv")
}
if err := Unsetenv(testKey); err != nil {
t.Fatalf("Unsetenv: %v", err)
}
if set() {
t.Fatal("Unsetenv didn't clear TestUnsetenv")
}
}
func TestClearenv(t *testing.T) {
const testKey = "GO_TEST_CLEARENV"
const testValue = "1"
// reset env
defer func(origEnv []string) {
for _, pair := range origEnv {
// Environment variables on Windows can begin with =
// https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
i := strings.Index(pair[1:], "=") + 1
if err := Setenv(pair[:i], pair[i+1:]); err != nil {
t.Errorf("Setenv(%q, %q) failed during reset: %v", pair[:i], pair[i+1:], err)
}
}
}(Environ())
if err := Setenv(testKey, testValue); err != nil {
t.Fatalf("Setenv(%q, %q) failed: %v", testKey, testValue, err)
}
if _, ok := LookupEnv(testKey); !ok {
t.Errorf("Setenv(%q, %q) didn't set $%s", testKey, testValue, testKey)
}
Clearenv()
if val, ok := LookupEnv(testKey); ok {
t.Errorf("Clearenv() didn't clear $%s, remained with value %q", testKey, val)
}
}
func TestLookupEnv(t *testing.T) {
const smallpox = "SMALLPOX" // No one has smallpox.
value, ok := LookupEnv(smallpox) // Should not exist.
if ok || value != "" {
t.Fatalf("%s=%q", smallpox, value)
}
defer Unsetenv(smallpox)
err := Setenv(smallpox, "virus")
if err != nil {
t.Fatalf("failed to release smallpox virus")
}
_, ok = LookupEnv(smallpox)
if !ok {
t.Errorf("smallpox release failed; world remains safe but LookupEnv is broken")
}
}