--- /dev/null
+// Copyright 2013 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 main
+
+import (
+ "fmt"
+ "go/build"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+// Unit tests for internal guru functions
+
+func TestIssue17515(t *testing.T) {
+ // Tests handling of symlinks in function guessImportPath
+ // If we have Go code inside $HOME/go/src and create a symlink $HOME/src to it
+ // there are 4 possible cases that need to be tested:
+ // (1) absolute & absolute: GOPATH=$HOME/go/src file=$HOME/go/src/test/test.go
+ // (2) absolute & symlink: GOPATH=$HOME/go/src file=$HOME/src/test/test.go
+ // (3) symlink & symlink: GOPATH=$HOME/src file=$HOME/src/test/test.go
+ // (4) symlink & absolute: GOPATH=$HOME/src file= $HOME/go/src/test/test.go
+
+ // Create a temporary home directory under /tmp
+ home, err := ioutil.TempDir(os.TempDir(), "home")
+ if err != nil {
+ t.Errorf("Unable to create a temporary directory in %s", os.TempDir())
+ }
+
+ defer os.RemoveAll(home)
+
+ // create filepath /tmp/home/go/src/test/test.go
+ if err = os.MkdirAll(home+"/go/src/test", 0755); err != nil {
+ t.Fatal(err)
+ }
+
+ var buildContext = build.Default
+
+ // Success test cases
+ type SuccessTest struct {
+ gopath, filename, wantSrcdir string
+ }
+
+ successTests := []SuccessTest{
+ {home + "/go", home + "/go/src/test/test.go", filepath.FromSlash(home + "/go/src")},
+ }
+
+ // Add symlink cases if not on Windows, Plan 9
+ if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
+ // symlink between /tmp/home/go/src and /tmp/home/src
+ if err := os.Symlink(home+"/go/src", home+"/src"); err != nil {
+ t.Fatal(err)
+ }
+
+ successTests = append(successTests, []SuccessTest{
+ {home + "/go", home + "/src/test/test.go", filepath.FromSlash(home + "/go/src")},
+ {home, home + "/go/src/test/test.go", filepath.FromSlash(home + "/src")},
+ {home, home + "/src/test/test.go", filepath.FromSlash(home + "/src")},
+ }...)
+ }
+
+ for _, test := range successTests {
+ buildContext.GOPATH = test.gopath
+ srcdir, importPath, err := guessImportPath(test.filename, &buildContext)
+ if srcdir != test.wantSrcdir || importPath != "test" || err != nil {
+ t.Errorf("guessImportPath(%q, %q) = %q, %q, %q; want %q, %q, %q",
+ test.filename, test.gopath, srcdir, importPath, err, test.wantSrcdir, "test", "nil")
+ }
+ }
+ // Function to format expected error message
+ errFormat := func(fpath string) string {
+ return fmt.Sprintf("can't evaluate symlinks of %s", fpath)
+ }
+
+ // Failure test cases
+ type FailTest struct {
+ gopath, filename, wantErr string
+ }
+
+ failTests := []FailTest{
+ {home + "/go", home + "/go/src/fake/test.go", errFormat(filepath.FromSlash(home + "/go/src/fake"))},
+ }
+
+ if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
+ failTests = append(failTests, []FailTest{
+ {home + "/go", home + "/src/fake/test.go", errFormat(filepath.FromSlash(home + "/src/fake"))},
+ {home, home + "/src/fake/test.go", errFormat(filepath.FromSlash(home + "/src/fake"))},
+ {home, home + "/go/src/fake/test.go", errFormat(filepath.FromSlash(home + "/go/src/fake"))},
+ }...)
+ }
+
+ for _, test := range failTests {
+ buildContext.GOPATH = test.gopath
+ srcdir, importPath, err := guessImportPath(test.filename, &buildContext)
+ if !strings.HasPrefix(fmt.Sprint(err), test.wantErr) {
+ t.Errorf("guessImportPath(%q, %q) = %q, %q, %q; want %q, %q, %q",
+ test.filename, test.gopath, srcdir, importPath, err, "", "", test.wantErr)
+ }
+ }
+}