|  | // 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") | 
|  | } | 
|  | } |