package pkgpath

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"
)

func TestPkgpathMain(t *testing.T) {
	pkg, ok := Main()
	if have, want := pkg, "code.justin.tv/common/golibs/pkgpath/_test"; have != want {
		t.Errorf("Main(); %q != %q", have, want)
	}
	if have, want := ok, true; have != want {
		t.Errorf("Main(); %t != %t", have, want)
	}
}

func TestByRunning(t *testing.T) {
	pkg, err := exec.Command("go", "list", "-e", ".").CombinedOutput()
	if err != nil {
		t.Fatalf("go list: %v", err)
	}

	dir, err := os.Getwd()
	if err != nil {
		t.Fatalf("pwd: %v", err)
	}

	dir = strings.TrimSuffix(dir, strings.TrimSpace(strings.SplitN(string(pkg), "\n", 2)[0]))
	dir = strings.TrimRight(filepath.Clean(dir), "/")

	_ = fmt.Sprint
	for _, flags := range [][]string{
		{"-a"},
		{"-a", "-gcflags", fmt.Sprintf("-trimpath %q", dir)},
	} {
		var args []string
		args = append(args, "go", "run")
		args = append(args, flags...)
		args = append(args, "--", "./maintest/main.go")
		cmd := exec.Command(args[0], args[1:]...)

		// Create environment for go run.
		for _, env := range os.Environ() {
			if strings.HasPrefix(env, "GO15VENDOREXPERIMENT=") {
				continue
			}
			if strings.HasPrefix(env, "GOPATH=") {
				continue
			}
			cmd.Env = append(cmd.Env, env)
		}
		cmd.Env = append(cmd.Env, "GO15VENDOREXPERIMENT=1")
		// Set GOPATH to contain the _vendor directory after the usual value.
		gopath := []string{os.Getenv("GOPATH")}
		if gopath[0] == "" {
			gopath = gopath[:0]
		}
		wd, _ := os.Getwd()
		gopath = append(gopath, filepath.Join(wd, "maintest/_vendor"))
		cmd.Env = append(cmd.Env, "GOPATH="+strings.Join(gopath, string(os.PathListSeparator)))

		out, err := cmd.CombinedOutput()
		if err != nil {
			t.Fatalf("go run maintest/main.go; err = %q, output = %q", err, out)
		}

		// We're looking for four separate behaviors here, represented by the four
		// lines of output below. The first is that a program should be able to
		// determine its own name, definited as the import path of its package
		// main. The second is that a package should be able to determine its own
		// import path, even when it is a main package. The third is that a non-
		// main pacakge should be able to determine its import path. Finally, a
		// package that appears under a "vendor" path (per the Go 1.5 vendor
		// experiment https://golang.org/s/go15vendor) should observe its import
		// path without the .../vendor/ prefix.
		if have, want := string(out), `
code.justin.tv/common/golibs/pkgpath/maintest
code.justin.tv/common/golibs/pkgpath/maintest
code.justin.tv/common/golibs/pkgpath/maintest/imported
imported2
`[1:]; have != want {
			t.Errorf("pkgpath.Main();\n%q\n!=\n%q\n", have, want)
		}
	}
}

func TestPkgpathCaller(t *testing.T) {
	pkg, ok := Caller(0)
	if have, want := pkg, "code.justin.tv/common/golibs/pkgpath"; have != want {
		t.Errorf("Main(); %q != %q", have, want)
	}
	if have, want := ok, true; have != want {
		t.Errorf("Main(); %t != %t", have, want)
	}
}

func TestPkgpathCallerClosure(t *testing.T) {
	var pkg string
	var ok bool
	func() {
		pkg, ok = Caller(0)
	}()
	if have, want := pkg, "code.justin.tv/common/golibs/pkgpath"; have != want {
		t.Errorf("Main(); %q != %q", have, want)
	}
	if have, want := ok, true; have != want {
		t.Errorf("Main(); %t != %t", have, want)
	}
}

func TestFileImportPath(t *testing.T) {
	tests := []struct {
		file string
		path string
	}{
		{file: "/go/src/code.justin.tv/web/tmi/irc/irc.go",
			path: "code.justin.tv/web/tmi/irc"},
		{file: "/go/src/code.justin.tv/web/owl/Godeps/_workspace/src/github.com/kisielk/errcheck/main.go",
			path: "github.com/kisielk/errcheck"},
		{file: "code.justin.tv/common/chitin/_test/generated.go",
			path: "code.justin.tv/common/chitin/_test"},
		{file: "/tmp/runme.go",
			path: "main"},
	}

	for _, tt := range tests {
		if have, want := fileImportPath(tt.file), tt.path; have != want {
			t.Errorf("fileImportPath(%q); %q != %q", tt.file, have, want)
		}
	}
}
