github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/os/env_test.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package os_test 6 7 import ( 8 . "os" 9 "reflect" 10 "strings" 11 "testing" 12 ) 13 14 // testGetenv gives us a controlled set of variables for testing Expand. 15 func testGetenv(s string) string { 16 switch s { 17 case "*": 18 return "all the args" 19 case "#": 20 return "NARGS" 21 case "$": 22 return "PID" 23 case "1": 24 return "ARGUMENT1" 25 case "HOME": 26 return "/usr/gopher" 27 case "H": 28 return "(Value of H)" 29 case "home_1": 30 return "/usr/foo" 31 case "_": 32 return "underscore" 33 } 34 return "" 35 } 36 37 var expandTests = []struct { 38 in, out string 39 }{ 40 {"", ""}, 41 {"$*", "all the args"}, 42 {"$$", "PID"}, 43 {"${*}", "all the args"}, 44 {"$1", "ARGUMENT1"}, 45 {"${1}", "ARGUMENT1"}, 46 {"now is the time", "now is the time"}, 47 {"$HOME", "/usr/gopher"}, 48 {"$home_1", "/usr/foo"}, 49 {"${HOME}", "/usr/gopher"}, 50 {"${H}OME", "(Value of H)OME"}, 51 {"A$$$#$1$H$home_1*B", "APIDNARGSARGUMENT1(Value of H)/usr/foo*B"}, 52 {"start$+middle$^end$", "start$+middle$^end$"}, 53 {"mixed$|bag$$$", "mixed$|bagPID$"}, 54 {"$", "$"}, 55 {"$}", "$}"}, 56 {"${", ""}, // invalid syntax; eat up the characters 57 {"${}", ""}, // invalid syntax; eat up the characters 58 } 59 60 func TestExpand(t *testing.T) { 61 for _, test := range expandTests { 62 result := Expand(test.in, testGetenv) 63 if result != test.out { 64 t.Errorf("Expand(%q)=%q; expected %q", test.in, result, test.out) 65 } 66 } 67 } 68 69 var global any 70 71 func BenchmarkExpand(b *testing.B) { 72 b.Run("noop", func(b *testing.B) { 73 var s string 74 b.ReportAllocs() 75 for i := 0; i < b.N; i++ { 76 s = Expand("tick tick tick tick", func(string) string { return "" }) 77 } 78 global = s 79 }) 80 b.Run("multiple", func(b *testing.B) { 81 var s string 82 b.ReportAllocs() 83 for i := 0; i < b.N; i++ { 84 s = Expand("$a $a $a $a", func(string) string { return "boom" }) 85 } 86 global = s 87 }) 88 } 89 90 func TestConsistentEnviron(t *testing.T) { 91 e0 := Environ() 92 for i := 0; i < 10; i++ { 93 e1 := Environ() 94 if !reflect.DeepEqual(e0, e1) { 95 t.Fatalf("environment changed") 96 } 97 } 98 } 99 100 func TestUnsetenv(t *testing.T) { 101 const testKey = "GO_TEST_UNSETENV" 102 set := func() bool { 103 prefix := testKey + "=" 104 for _, key := range Environ() { 105 if strings.HasPrefix(key, prefix) { 106 return true 107 } 108 } 109 return false 110 } 111 if err := Setenv(testKey, "1"); err != nil { 112 t.Fatalf("Setenv: %v", err) 113 } 114 if !set() { 115 t.Error("Setenv didn't set TestUnsetenv") 116 } 117 if err := Unsetenv(testKey); err != nil { 118 t.Fatalf("Unsetenv: %v", err) 119 } 120 if set() { 121 t.Fatal("Unsetenv didn't clear TestUnsetenv") 122 } 123 } 124 125 func TestClearenv(t *testing.T) { 126 const testKey = "GO_TEST_CLEARENV" 127 const testValue = "1" 128 129 // reset env 130 defer func(origEnv []string) { 131 for _, pair := range origEnv { 132 // Environment variables on Windows can begin with = 133 // https://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx 134 i := strings.Index(pair[1:], "=") + 1 135 if err := Setenv(pair[:i], pair[i+1:]); err != nil { 136 t.Errorf("Setenv(%q, %q) failed during reset: %v", pair[:i], pair[i+1:], err) 137 } 138 } 139 }(Environ()) 140 141 if err := Setenv(testKey, testValue); err != nil { 142 t.Fatalf("Setenv(%q, %q) failed: %v", testKey, testValue, err) 143 } 144 if _, ok := LookupEnv(testKey); !ok { 145 t.Errorf("Setenv(%q, %q) didn't set $%s", testKey, testValue, testKey) 146 } 147 Clearenv() 148 if val, ok := LookupEnv(testKey); ok { 149 t.Errorf("Clearenv() didn't clear $%s, remained with value %q", testKey, val) 150 } 151 } 152 153 func TestLookupEnv(t *testing.T) { 154 const smallpox = "SMALLPOX" // No one has smallpox. 155 value, ok := LookupEnv(smallpox) // Should not exist. 156 if ok || value != "" { 157 t.Fatalf("%s=%q", smallpox, value) 158 } 159 defer Unsetenv(smallpox) 160 err := Setenv(smallpox, "virus") 161 if err != nil { 162 t.Fatalf("failed to release smallpox virus") 163 } 164 _, ok = LookupEnv(smallpox) 165 if !ok { 166 t.Errorf("smallpox release failed; world remains safe but LookupEnv is broken") 167 } 168 } 169 170 // On Windows, Environ was observed to report keys with a single leading "=". 171 // Check that they are properly reported by LookupEnv and can be set by SetEnv. 172 // See https://golang.org/issue/49886. 173 func TestEnvironConsistency(t *testing.T) { 174 t.Parallel() 175 176 for _, kv := range Environ() { 177 i := strings.Index(kv, "=") 178 if i == 0 { 179 // We observe in practice keys with a single leading "=" on Windows. 180 // TODO(#49886): Should we consume only the first leading "=" as part 181 // of the key, or parse through arbitrarily many of them until a non-=, 182 // or try each possible key/value boundary until LookupEnv succeeds? 183 i = strings.Index(kv[1:], "=") + 1 184 } 185 if i < 0 { 186 t.Errorf("Environ entry missing '=': %q", kv) 187 } 188 189 k := kv[:i] 190 v := kv[i+1:] 191 v2, ok := LookupEnv(k) 192 if ok && v == v2 { 193 t.Logf("LookupEnv(%q) = %q, %t", k, v2, ok) 194 } else { 195 t.Errorf("Environ contains %q, but LookupEnv(%q) = %q, %t", kv, k, v2, ok) 196 } 197 198 // Since k=v is already present in the environment, 199 // setting it should be a no-op. 200 if err := Setenv(k, v); err == nil { 201 t.Logf("Setenv(%q, %q)", k, v) 202 } else { 203 t.Errorf("Environ contains %q, but SetEnv(%q, %q) = %q", kv, k, v, err) 204 } 205 } 206 }