Repository: qiniu/goc (go)

Issue:
wrong output binary name
The binary name should be generate from import path, not the directory path for gomodule project.

Pull request description:
fix wrong output binary name
1. fix #43 
2. add unittest: TestBuildBinaryName for #43 
3. add unittest for internal project
4. add Makefile for local dev

Patch:
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b2ded91
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,13 @@
+DEFAULT_EXCEPT_PKGS := e2e
+
+all:
+	go install ./...
+
+test:
+	go test -cover -p 1 `go list ./... | grep -v -E ${DEFAULT_EXCEPT_PKGS}`
+
+fmt:
+	go fmt ./...
+
+govet-check:
+	go vet ./...
\ No newline at end of file
diff --git a/pkg/build/build.go b/pkg/build/build.go
index 53b8ce4..b326253 100644
--- a/pkg/build/build.go
+++ b/pkg/build/build.go
@@ -115,21 +115,18 @@ func (b *Build) determineOutputDir(outputDir string) (string, error) {
 		return "", fmt.Errorf("can only be called after Build.MvProjectsToTmp(): %w", ErrWrongCallSequence)
 	}
 
-	if outputDir == "" {
-		_, last := filepath.Split(b.WorkingDir)
-		if b.IsMod {
-			// in mod, special rule
-			// replace "_" with "-" in the import path
-			last = strings.ReplaceAll(last, "_", "-")
+	// fix #43
+	// use target name from `go list -json ./...` of the main module
+	targetName := ""
+	for _, pkg := range b.Pkgs {
+		if pkg.Name == "main" {
+			_, file := filepath.Split(pkg.Target)
+			targetName = file
+			break
 		}
-		return filepath.Join(b.WorkingDir, last), nil
 	}
-	abs, err := filepath.Abs(outputDir)
-	if err != nil {
-		log.Errorf("Fail to transform the path: %v to absolute path: %v", outputDir, err)
-		return "", err
-	}
-	return abs, nil
+
+	return filepath.Join(b.WorkingDir, targetName), nil
 }
 
 // validatePackageForBuild only allow . as package name


Test patch:
diff --git a/cmd/build_test.go b/cmd/build_test.go
index 9d46dee..6e86287 100644
--- a/cmd/build_test.go
+++ b/cmd/build_test.go
@@ -60,3 +60,60 @@ func TestGeneratedBinary(t *testing.T) {
 	cnt = strings.Count(string(out), "GoCover")
 	assert.Equal(t, cnt > 0, true, "GoCover varibale should be in the binary")
 }
+
+func TestBuildBinaryName(t *testing.T) {
+	startTime := time.Now()
+
+	workingDir := filepath.Join(baseDir, "../tests/samples/simple_project2")
+	gopath := ""
+
+	os.Setenv("GOPATH", gopath)
+	os.Setenv("GO111MODULE", "on")
+
+	buildFlags, buildOutput = "", ""
+	args := []string{"."}
+	runBuild(args, workingDir)
+
+	obj := filepath.Join(workingDir, "simple-project")
+	fInfo, err := os.Lstat(obj)
+	assert.Equal(t, err, nil, "the binary should be generated.")
+	assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one")
+
+	cmd := exec.Command("go", "tool", "objdump", "simple-project")
+	cmd.Dir = workingDir
+	out, _ := cmd.CombinedOutput()
+	cnt := strings.Count(string(out), "main.registerSelf")
+	assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary")
+
+	cnt = strings.Count(string(out), "GoCover")
+	assert.Equal(t, cnt > 0, true, "GoCover varibale should be in the binary")
+}
+
+// test if goc can get variables in internal package
+func TestBuildBinaryForInternalPackage(t *testing.T) {
+	startTime := time.Now()
+
+	workingDir := filepath.Join(baseDir, "../tests/samples/simple_project_with_internal")
+	gopath := ""
+
+	os.Setenv("GOPATH", gopath)
+	os.Setenv("GO111MODULE", "on")
+
+	buildFlags, buildOutput = "", ""
+	args := []string{"."}
+	runBuild(args, workingDir)
+
+	obj := filepath.Join(workingDir, "simple-project")
+	fInfo, err := os.Lstat(obj)
+	assert.Equal(t, err, nil, "the binary should be generated.")
+	assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one")
+
+	cmd := exec.Command("go", "tool", "objdump", "simple-project")
+	cmd.Dir = workingDir
+	out, _ := cmd.CombinedOutput()
+	cnt := strings.Count(string(out), "GoCacheCover")
+	assert.Equal(t, cnt > 0, true, "GoCacheCover variable for internal package should be in the binary")
+
+	cnt = strings.Count(string(out), "internal.GoCover")
+	assert.Equal(t, cnt > 0, true, "internal.GoCover varibale should be in the binary")
+}
diff --git a/pkg/cover/cover_test.go b/pkg/cover/cover_test.go
index 7bf1549..f1a0de4 100644
--- a/pkg/cover/cover_test.go
+++ b/pkg/cover/cover_test.go
@@ -18,6 +18,7 @@ package cover
 
 import (
 	"fmt"
+	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -342,3 +343,30 @@ func TestListPackagesForSimpleModProject(t *testing.T) {
 	}
 
 }
+
+// test if goc can get variables in internal package
+func TestCoverResultForInternalPackage(t *testing.T) {
+
+	workingDir := "../../tests/samples/simple_project_with_internal"
+	gopath := ""
+
+	os.Setenv("GOPATH", gopath)
+	os.Setenv("GO111MODULE", "on")
+
+	testDir := filepath.Join(os.TempDir(), "goc-build-test")
+	copy.Copy(workingDir, testDir)
+
+	Execute("", gopath, testDir, "count", "", "http://127.0.0.1:7777")
+
+	_, err := os.Lstat(filepath.Join(testDir, "http_cover_apis_auto_generated.go"))
+	if !assert.Equal(t, err, nil) {
+		assert.FailNow(t, "should generate http_cover_apis_auto_generated.go")
+	}
+
+	out, err := ioutil.ReadFile(filepath.Join(testDir, "http_cover_apis_auto_generated.go"))
+	cnt := strings.Count(string(out), "GoCacheCover")
+	assert.Equal(t, cnt > 0, true, "GoCacheCover variable should be in http_cover_apis_auto_generated.go")
+
+	cnt = strings.Count(string(out), "example.com/simple-project/internal/foo.go")
+	assert.Equal(t, cnt > 0, true, "`example.com/simple-project/internal/foo.go` should be in http_cover_apis_auto_generated.go")
+}
diff --git a/tests/samples/simple_project2/go.mod b/tests/samples/simple_project2/go.mod
new file mode 100644
index 0000000..610643a
--- /dev/null
+++ b/tests/samples/simple_project2/go.mod
@@ -0,0 +1,3 @@
+module example.com/simple-project
+
+go 1.11
diff --git a/tests/samples/simple_project2/main.go b/tests/samples/simple_project2/main.go
new file mode 100644
index 0000000..01a2bca
--- /dev/null
+++ b/tests/samples/simple_project2/main.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+	"fmt"
+)
+
+func main() {
+	fmt.Println("hello, world.")
+}
diff --git a/tests/samples/simple_project_with_internal/go.mod b/tests/samples/simple_project_with_internal/go.mod
new file mode 100644
index 0000000..610643a
--- /dev/null
+++ b/tests/samples/simple_project_with_internal/go.mod
@@ -0,0 +1,3 @@
+module example.com/simple-project
+
+go 1.11
diff --git a/tests/samples/simple_project_with_internal/internal/foo.go b/tests/samples/simple_project_with_internal/internal/foo.go
new file mode 100644
index 0000000..90912fc
--- /dev/null
+++ b/tests/samples/simple_project_with_internal/internal/foo.go
@@ -0,0 +1,7 @@
+package internal
+
+import "fmt"
+
+func Hello() {
+	fmt.Println("hello, world.")
+}
diff --git a/tests/samples/simple_project_with_internal/main.go b/tests/samples/simple_project_with_internal/main.go
new file mode 100644
index 0000000..5bd41fa
--- /dev/null
+++ b/tests/samples/simple_project_with_internal/main.go
@@ -0,0 +1,7 @@
+package main
+
+import "example.com/simple-project/internal"
+
+func main() {
+	internal.Hello()
+}