@@ -15,6 +15,13 @@ import (
15
15
"testing"
16
16
)
17
17
18
+ var pathVar string = func () string {
19
+ if runtime .GOOS == "plan9" {
20
+ return "path"
21
+ }
22
+ return "PATH"
23
+ }()
24
+
18
25
func TestLookPath (t * testing.T ) {
19
26
testenv .MustHaveExec (t )
20
27
@@ -42,22 +49,24 @@ func TestLookPath(t *testing.T) {
42
49
if err = os .Chdir (tmpDir ); err != nil {
43
50
t .Fatal (err )
44
51
}
45
- origPath := os .Getenv ("PATH" )
46
- defer os .Setenv ("PATH" , origPath )
52
+ t .Setenv ("PWD" , tmpDir )
53
+ t .Logf (". is %#q" , tmpDir )
54
+
55
+ origPath := os .Getenv (pathVar )
47
56
48
57
// Add "." to PATH so that exec.LookPath looks in the current directory on all systems.
49
58
// And try to trick it with "../testdir" too.
50
59
for _ , dir := range []string {"." , "../testdir" } {
51
- os . Setenv ( "PATH" , dir + string ( filepath . ListSeparator ) + origPath )
52
- t . Run ( "PATH=" + dir , func ( t * testing. T ) {
60
+ t . Run ( pathVar + "=" + dir , func ( t * testing. T ) {
61
+ t . Setenv ( pathVar , dir + string ( filepath . ListSeparator ) + origPath )
53
62
good := dir + "/execabs-test"
54
63
if found , err := LookPath (good ); err != nil || ! strings .HasPrefix (found , good ) {
55
- t .Fatalf (" LookPath(%q) = %q, %v, want \ " %s...\ " , nil" , good , found , err , good )
64
+ t .Fatalf (` LookPath(%# q) = %# q, %v, want "%s...", nil` , good , found , err , good )
56
65
}
57
66
if runtime .GOOS == "windows" {
58
67
good = dir + `\execabs-test`
59
68
if found , err := LookPath (good ); err != nil || ! strings .HasPrefix (found , good ) {
60
- t .Fatalf (" LookPath(%q) = %q, %v, want \ " %s...\ " , nil" , good , found , err , good )
69
+ t .Fatalf (` LookPath(%# q) = %# q, %v, want "%s...", nil` , good , found , err , good )
61
70
}
62
71
}
63
72
@@ -84,4 +93,81 @@ func TestLookPath(t *testing.T) {
84
93
}
85
94
})
86
95
}
96
+
97
+ // Test the behavior when the first entry in PATH is an absolute name for the
98
+ // current directory.
99
+ //
100
+ // On Windows, "." may or may not be implicitly included before the explicit
101
+ // %PATH%, depending on the process environment;
102
+ // see https://go.dev/issue/4394.
103
+ //
104
+ // If the relative entry from "." resolves to the same executable as what
105
+ // would be resolved from an absolute entry in %PATH% alone, LookPath should
106
+ // return the absolute version of the path instead of ErrDot.
107
+ // (See https://go.dev/issue/53536.)
108
+ //
109
+ // If PATH does not implicitly include "." (such as on Unix platforms, or on
110
+ // Windows configured with NoDefaultCurrentDirectoryInExePath), then this
111
+ // lookup should succeed regardless of the behavior for ".", so it may be
112
+ // useful to run as a control case even on those platforms.
113
+ t .Run (pathVar + "=$PWD" , func (t * testing.T ) {
114
+ t .Setenv (pathVar , tmpDir + string (filepath .ListSeparator )+ origPath )
115
+ good := filepath .Join (tmpDir , "execabs-test" )
116
+ if found , err := LookPath (good ); err != nil || ! strings .HasPrefix (found , good ) {
117
+ t .Fatalf (`LookPath(%#q) = %#q, %v, want \"%s...\", nil` , good , found , err , good )
118
+ }
119
+
120
+ if found , err := LookPath ("execabs-test" ); err != nil || ! strings .HasPrefix (found , good ) {
121
+ t .Fatalf (`LookPath(%#q) = %#q, %v, want \"%s...\", nil` , "execabs-test" , found , err , good )
122
+ }
123
+
124
+ cmd := Command ("execabs-test" )
125
+ if cmd .Err != nil {
126
+ t .Fatalf ("Command(%#q).Err = %v; want nil" , "execabs-test" , cmd .Err )
127
+ }
128
+ })
129
+
130
+ t .Run (pathVar + "=$OTHER" , func (t * testing.T ) {
131
+ // Control case: if the lookup returns ErrDot when PATH is empty, then we
132
+ // know that PATH implicitly includes ".". If it does not, then we don't
133
+ // expect to see ErrDot at all in this test (because the path will be
134
+ // unambiguously absolute).
135
+ wantErrDot := false
136
+ t .Setenv (pathVar , "" )
137
+ if found , err := LookPath ("execabs-test" ); errors .Is (err , ErrDot ) {
138
+ wantErrDot = true
139
+ } else if err == nil {
140
+ t .Fatalf (`with PATH='', LookPath(%#q) = %#q; want non-nil error` , "execabs-test" , found )
141
+ }
142
+
143
+ // Set PATH to include an explicit directory that contains a completely
144
+ // independent executable that happens to have the same name as an
145
+ // executable in ".". If "." is included implicitly, looking up the
146
+ // (unqualified) executable name will return ErrDot; otherwise, the
147
+ // executable in "." should have no effect and the lookup should
148
+ // unambiguously resolve to the directory in PATH.
149
+
150
+ dir := t .TempDir ()
151
+ executable := "execabs-test"
152
+ if runtime .GOOS == "windows" {
153
+ executable += ".exe"
154
+ }
155
+ if err := os .WriteFile (filepath .Join (dir , executable ), []byte {1 , 2 , 3 }, 0777 ); err != nil {
156
+ t .Fatal (err )
157
+ }
158
+ t .Setenv (pathVar , dir + string (filepath .ListSeparator )+ origPath )
159
+
160
+ found , err := LookPath ("execabs-test" )
161
+ if wantErrDot {
162
+ wantFound := filepath .Join ("." , executable )
163
+ if found != wantFound || ! errors .Is (err , ErrDot ) {
164
+ t .Fatalf (`LookPath(%#q) = %#q, %v, want %#q, Is ErrDot` , "execabs-test" , found , err , wantFound )
165
+ }
166
+ } else {
167
+ wantFound := filepath .Join (dir , executable )
168
+ if found != wantFound || err != nil {
169
+ t .Fatalf (`LookPath(%#q) = %#q, %v, want %#q, nil` , "execabs-test" , found , err , wantFound )
170
+ }
171
+ }
172
+ })
87
173
}
0 commit comments