1*9bb1b549SSpandan Das// Copyright 2020, 2021, 2022 Google LLC 2*9bb1b549SSpandan Das// 3*9bb1b549SSpandan Das// Licensed under the Apache License, Version 2.0 (the "License"); 4*9bb1b549SSpandan Das// you may not use this file except in compliance with the License. 5*9bb1b549SSpandan Das// You may obtain a copy of the License at 6*9bb1b549SSpandan Das// 7*9bb1b549SSpandan Das// https://www.apache.org/licenses/LICENSE-2.0 8*9bb1b549SSpandan Das// 9*9bb1b549SSpandan Das// Unless required by applicable law or agreed to in writing, software 10*9bb1b549SSpandan Das// distributed under the License is distributed on an "AS IS" BASIS, 11*9bb1b549SSpandan Das// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9bb1b549SSpandan Das// See the License for the specific language governing permissions and 13*9bb1b549SSpandan Das// limitations under the License. 14*9bb1b549SSpandan Das 15*9bb1b549SSpandan Daspackage runfiles_test 16*9bb1b549SSpandan Das 17*9bb1b549SSpandan Dasimport ( 18*9bb1b549SSpandan Das "errors" 19*9bb1b549SSpandan Das "os" 20*9bb1b549SSpandan Das "os/exec" 21*9bb1b549SSpandan Das "path/filepath" 22*9bb1b549SSpandan Das "runtime" 23*9bb1b549SSpandan Das "strings" 24*9bb1b549SSpandan Das "testing" 25*9bb1b549SSpandan Das 26*9bb1b549SSpandan Das "github.com/bazelbuild/rules_go/go/runfiles" 27*9bb1b549SSpandan Das) 28*9bb1b549SSpandan Das 29*9bb1b549SSpandan Dasfunc TestPath_FileLookup(t *testing.T) { 30*9bb1b549SSpandan Das path, err := runfiles.Rlocation("io_bazel_rules_go/tests/runfiles/test.txt") 31*9bb1b549SSpandan Das if err != nil { 32*9bb1b549SSpandan Das t.Fatal(err) 33*9bb1b549SSpandan Das } 34*9bb1b549SSpandan Das b, err := os.ReadFile(path) 35*9bb1b549SSpandan Das if err != nil { 36*9bb1b549SSpandan Das t.Fatal(err) 37*9bb1b549SSpandan Das } 38*9bb1b549SSpandan Das got := strings.TrimSpace(string(b)) 39*9bb1b549SSpandan Das want := "hi!" 40*9bb1b549SSpandan Das if got != want { 41*9bb1b549SSpandan Das t.Errorf("got %q, want %q", got, want) 42*9bb1b549SSpandan Das } 43*9bb1b549SSpandan Das} 44*9bb1b549SSpandan Das 45*9bb1b549SSpandan Dasfunc TestPath_SubprocessRunfilesLookup(t *testing.T) { 46*9bb1b549SSpandan Das r, err := runfiles.New() 47*9bb1b549SSpandan Das if err != nil { 48*9bb1b549SSpandan Das panic(err) 49*9bb1b549SSpandan Das } 50*9bb1b549SSpandan Das // The binary “testprog” is itself built with Bazel, and needs 51*9bb1b549SSpandan Das // runfiles. 52*9bb1b549SSpandan Das testprogRpath := "io_bazel_rules_go/tests/runfiles/testprog/testprog_/testprog" 53*9bb1b549SSpandan Das if runtime.GOOS == "windows" { 54*9bb1b549SSpandan Das testprogRpath += ".exe" 55*9bb1b549SSpandan Das } 56*9bb1b549SSpandan Das prog, err := r.Rlocation(testprogRpath) 57*9bb1b549SSpandan Das if err != nil { 58*9bb1b549SSpandan Das panic(err) 59*9bb1b549SSpandan Das } 60*9bb1b549SSpandan Das cmd := exec.Command(prog) 61*9bb1b549SSpandan Das // We add r.Env() after os.Environ() so that runfile environment 62*9bb1b549SSpandan Das // variables override anything set in the process environment. 63*9bb1b549SSpandan Das cmd.Env = append(os.Environ(), r.Env()...) 64*9bb1b549SSpandan Das out, err := cmd.Output() 65*9bb1b549SSpandan Das if err != nil { 66*9bb1b549SSpandan Das t.Fatal(err) 67*9bb1b549SSpandan Das } 68*9bb1b549SSpandan Das got := strings.TrimSpace(string(out)) 69*9bb1b549SSpandan Das want := "hi!" 70*9bb1b549SSpandan Das if got != want { 71*9bb1b549SSpandan Das t.Errorf("got %q, want %q", got, want) 72*9bb1b549SSpandan Das } 73*9bb1b549SSpandan Das} 74*9bb1b549SSpandan Das 75*9bb1b549SSpandan Dasfunc TestPath_errors(t *testing.T) { 76*9bb1b549SSpandan Das r, err := runfiles.New() 77*9bb1b549SSpandan Das if err != nil { 78*9bb1b549SSpandan Das t.Fatal(err) 79*9bb1b549SSpandan Das } 80*9bb1b549SSpandan Das for _, s := range []string{"", "/..", "../", "a/../b", "a//b", "a/./b", `\a`} { 81*9bb1b549SSpandan Das t.Run(s, func(t *testing.T) { 82*9bb1b549SSpandan Das if got, err := r.Rlocation(s); err == nil { 83*9bb1b549SSpandan Das t.Errorf("got %q, want error", got) 84*9bb1b549SSpandan Das } 85*9bb1b549SSpandan Das }) 86*9bb1b549SSpandan Das } 87*9bb1b549SSpandan Das for _, s := range []string{"foo/..bar", "foo/.bar"} { 88*9bb1b549SSpandan Das t.Run(s, func(t *testing.T) { 89*9bb1b549SSpandan Das if _, err := r.Rlocation(s); err != nil && !os.IsNotExist(err.(runfiles.Error).Err) { 90*9bb1b549SSpandan Das t.Errorf("got %q, want none or 'file not found' error", err) 91*9bb1b549SSpandan Das } 92*9bb1b549SSpandan Das }) 93*9bb1b549SSpandan Das } 94*9bb1b549SSpandan Das} 95*9bb1b549SSpandan Das 96*9bb1b549SSpandan Dasfunc TestRunfiles_zero(t *testing.T) { 97*9bb1b549SSpandan Das var r runfiles.Runfiles 98*9bb1b549SSpandan Das if got, err := r.Rlocation("a"); err == nil { 99*9bb1b549SSpandan Das t.Errorf("Rlocation: got %q, want error", got) 100*9bb1b549SSpandan Das } 101*9bb1b549SSpandan Das if got := r.Env(); got != nil { 102*9bb1b549SSpandan Das t.Errorf("Env: got %v, want nil", got) 103*9bb1b549SSpandan Das } 104*9bb1b549SSpandan Das} 105*9bb1b549SSpandan Das 106*9bb1b549SSpandan Dasfunc TestRunfiles_empty(t *testing.T) { 107*9bb1b549SSpandan Das dir := t.TempDir() 108*9bb1b549SSpandan Das manifest := filepath.Join(dir, "manifest") 109*9bb1b549SSpandan Das if err := os.WriteFile(manifest, []byte("__init__.py \n"), 0o600); err != nil { 110*9bb1b549SSpandan Das t.Fatal(err) 111*9bb1b549SSpandan Das } 112*9bb1b549SSpandan Das r, err := runfiles.New(runfiles.ManifestFile(manifest)) 113*9bb1b549SSpandan Das if err != nil { 114*9bb1b549SSpandan Das t.Fatal(err) 115*9bb1b549SSpandan Das } 116*9bb1b549SSpandan Das _, got := r.Rlocation("__init__.py") 117*9bb1b549SSpandan Das want := runfiles.ErrEmpty 118*9bb1b549SSpandan Das if !errors.Is(got, want) { 119*9bb1b549SSpandan Das t.Errorf("Rlocation for empty file: got error %q, want something that wraps %q", got, want) 120*9bb1b549SSpandan Das } 121*9bb1b549SSpandan Das} 122*9bb1b549SSpandan Das 123*9bb1b549SSpandan Dasfunc TestRunfiles_manifestWithDir(t *testing.T) { 124*9bb1b549SSpandan Das dir := t.TempDir() 125*9bb1b549SSpandan Das manifest := filepath.Join(dir, "manifest") 126*9bb1b549SSpandan Das if err := os.WriteFile(manifest, []byte("foo/dir path/to/foo/dir\n"), 0o600); err != nil { 127*9bb1b549SSpandan Das t.Fatal(err) 128*9bb1b549SSpandan Das } 129*9bb1b549SSpandan Das r, err := runfiles.New(runfiles.ManifestFile(manifest)) 130*9bb1b549SSpandan Das if err != nil { 131*9bb1b549SSpandan Das t.Fatal(err) 132*9bb1b549SSpandan Das } 133*9bb1b549SSpandan Das 134*9bb1b549SSpandan Das for rlocation, want := range map[string]string{ 135*9bb1b549SSpandan Das "foo/dir": filepath.FromSlash("path/to/foo/dir"), 136*9bb1b549SSpandan Das "foo/dir/file": filepath.FromSlash("path/to/foo/dir/file"), 137*9bb1b549SSpandan Das "foo/dir/deeply/nested/file": filepath.FromSlash("path/to/foo/dir/deeply/nested/file"), 138*9bb1b549SSpandan Das } { 139*9bb1b549SSpandan Das t.Run(rlocation, func(t *testing.T) { 140*9bb1b549SSpandan Das got, err := r.Rlocation(rlocation) 141*9bb1b549SSpandan Das if err != nil { 142*9bb1b549SSpandan Das t.Fatalf("Rlocation failed: got unexpected error %q", err) 143*9bb1b549SSpandan Das } 144*9bb1b549SSpandan Das if got != want { 145*9bb1b549SSpandan Das t.Errorf("Rlocation failed: got %q, want %q", got, want) 146*9bb1b549SSpandan Das } 147*9bb1b549SSpandan Das }) 148*9bb1b549SSpandan Das } 149*9bb1b549SSpandan Das} 150