From 999efc12fa21e1936be5da805128540a968e1c46 Mon Sep 17 00:00:00 2001
From: Jin <chinjinhong@hotmail.com>
Date: Thu, 29 Apr 2021 18:22:18 +0800
Subject: [PATCH 1/4] Refactors to support package importing

---
 .idea/.gitignore                  |  8 +++
 .idea/gcov2lcov.iml               |  9 +++
 .idea/modules.xml                 |  8 +++
 .idea/vcs.xml                     |  6 ++
 Makefile                          |  6 +-
 cmd/main.go                       | 68 ++++++++++++++++++++++
 cmd/main_test.go                  |  4 ++
 main.go => gcov2kov.go            | 93 +++++++------------------------
 main_test.go => gcov2lcov_test.go | 35 ++++++------
 9 files changed, 143 insertions(+), 94 deletions(-)
 create mode 100644 .idea/.gitignore
 create mode 100644 .idea/gcov2lcov.iml
 create mode 100644 .idea/modules.xml
 create mode 100644 .idea/vcs.xml
 create mode 100644 cmd/main.go
 create mode 100644 cmd/main_test.go
 rename main.go => gcov2kov.go (80%)
 rename main_test.go => gcov2lcov_test.go (72%)

diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..73f69e0
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/gcov2lcov.iml b/.idea/gcov2lcov.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/gcov2lcov.iml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="Go" enabled="true" />
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..e512733
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/gcov2lcov.iml" filepath="$PROJECT_DIR$/.idea/gcov2lcov.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 6be341a..78d3f40 100644
--- a/Makefile
+++ b/Makefile
@@ -2,9 +2,9 @@
 .PHONY: build test inttest clean
 
 build:
-	GOOS=linux GOARCH=amd64 go build -o bin/gcov2lcov-linux-amd64 .
-	GOOS=windows GOARCH=amd64 go build -o bin/gcov2lcov-win-amd64 .
-	GOOS=darwin GOARCH=amd64 go build -o bin/gcov2lcov-darwin-amd64 .
+	GOOS=linux GOARCH=amd64 go build -o bin/gcov2lcov-linux-amd64 ./cmd
+	GOOS=windows GOARCH=amd64 go build -o bin/gcov2lcov-win-amd64 ./cmd
+	GOOS=darwin GOARCH=amd64 go build -o bin/gcov2lcov-darwin-amd64 ./cmd
 
 test:
 	go test ./... -coverprofile coverage.out
diff --git a/cmd/main.go b/cmd/main.go
new file mode 100644
index 0000000..0eb7308
--- /dev/null
+++ b/cmd/main.go
@@ -0,0 +1,68 @@
+// gcov2lcov - convert golang coverage files to the lcov format.
+//
+// Copyright (c) 2019 Jan Delgado
+// Copyright (c) 2019 Richard S Allinson
+//
+// Credits:
+// This tool is based on covfmt (https://github.com/ricallinson/covfmt) and
+// uses some parts of goveralls (https://github.com/mattn/goveralls).
+//
+package main
+
+import (
+	"flag"
+	"github.com/jandelgado/gcov2lcov"
+	"log"
+	"os"
+)
+
+func main() {
+	os.Exit(gcovmain())
+}
+
+func gcovmain() int {
+	infileName := flag.String("infile", "", "go coverage file to read, default: <stdin>")
+	outfileName := flag.String("outfile", "", "lcov file to write, default: <stdout>")
+	useAbsoluteSourcePath := flag.Bool("use-absolute-source-path", false,
+		"use absolute paths for source file in lcov output, default: false")
+	flag.Parse()
+	if len(flag.Args()) > 0 {
+		flag.Usage()
+		return 1
+	}
+
+	infile := os.Stdin
+	outfile := os.Stdout
+	var err error
+	if *infileName != "" {
+		infile, err = os.Open(*infileName)
+		if err != nil {
+			log.Printf("error opening input file: %v\n", err)
+			return 2
+		}
+		defer infile.Close()
+	}
+	if *outfileName != "" {
+		outfile, err = os.Create(*outfileName)
+		if err != nil {
+			log.Printf("error opening output file: %v\n", err)
+			return 3
+		}
+		defer outfile.Close()
+	}
+
+	var pathResolverFunc func(string) string
+	if *useAbsoluteSourcePath {
+		pathResolverFunc = gcov2lcov.AbsolutePathResolver
+	} else {
+		pathResolverFunc = gcov2lcov.RelativePathResolver
+	}
+
+	err = gcov2lcov.ConvertCoverage(infile, outfile, pathResolverFunc)
+	if err != nil {
+		log.Printf("error: convert: %v", err)
+		return 4
+	}
+	return 0
+}
+
diff --git a/cmd/main_test.go b/cmd/main_test.go
new file mode 100644
index 0000000..5675657
--- /dev/null
+++ b/cmd/main_test.go
@@ -0,0 +1,4 @@
+// gcov2lcov - convert golang coverage files to the lcov format.
+// (c) 2019 Jan Delgado
+package main
+
diff --git a/main.go b/gcov2kov.go
similarity index 80%
rename from main.go
rename to gcov2kov.go
index e9d6496..388c1ef 100644
--- a/main.go
+++ b/gcov2kov.go
@@ -7,12 +7,11 @@
 // This tool is based on covfmt (https://github.com/ricallinson/covfmt) and
 // uses some parts of goveralls (https://github.com/mattn/goveralls).
 //
-package main
+package gcov2lcov
 
 import (
 	"bufio"
 	"errors"
-	"flag"
 	"go/build"
 	"io"
 	"log"
@@ -41,6 +40,26 @@ type cacheEntry struct {
 
 var pkgCache = map[string]cacheEntry{}
 
+func ConvertCoverage(in io.Reader, out io.Writer, pathResolverFunc func(string) string) error {
+	blocks, err := parseCoverage(in, pathResolverFunc)
+	if err != nil {
+		return err
+	}
+	return writeLcov(blocks, out)
+}
+
+func AbsolutePathResolver(name string) string {
+	return name
+}
+
+func RelativePathResolver(name string) string {
+	if dir, ok := findRepositoryRoot(name); ok {
+		filename := strings.TrimPrefix(name, dir+string(os.PathSeparator))
+		return filename
+	}
+	return name
+}
+
 // given a module+file spec (e.g. github.com/jandelgado/gcov2lcov/main.go),
 // strip of the module name and return the file name (e.g. main.go).
 func findFile(filePath string) (string, error) {
@@ -73,18 +92,6 @@ func findRepositoryRoot(dir string) (string, bool) {
 	return findRepositoryRoot(nextdir)
 }
 
-func getSourceFileName(name string) string {
-	return name
-}
-
-func getCoverallsSourceFileName(name string) string {
-	if dir, ok := findRepositoryRoot(name); ok {
-		filename := strings.TrimPrefix(name, dir+string(os.PathSeparator))
-		return filename
-	}
-	return name
-}
-
 func keysOfMap(m map[int]int) []int {
 	keys := make([]int, len(m))
 	i := 0
@@ -235,61 +242,3 @@ func parseCoverage(coverage io.Reader, pathResolverFunc func(string) string) (ma
 	}
 	return blocks, nil
 }
-
-func convertCoverage(in io.Reader, out io.Writer, pathResolverFunc func(string) string) error {
-	blocks, err := parseCoverage(in, pathResolverFunc)
-	if err != nil {
-		return err
-	}
-	return writeLcov(blocks, out)
-}
-
-func main() {
-	os.Exit(gcovmain())
-}
-
-func gcovmain() int {
-	infileName := flag.String("infile", "", "go coverage file to read, default: <stdin>")
-	outfileName := flag.String("outfile", "", "lcov file to write, default: <stdout>")
-	useAbsoluteSourcePath := flag.Bool("use-absolute-source-path", false,
-		"use absolute paths for source file in lcov output, default: false")
-	flag.Parse()
-	if len(flag.Args()) > 0 {
-		flag.Usage()
-		return 1
-	}
-
-	infile := os.Stdin
-	outfile := os.Stdout
-	var err error
-	if *infileName != "" {
-		infile, err = os.Open(*infileName)
-		if err != nil {
-			log.Printf("error opening input file: %v\n", err)
-			return 2
-		}
-		defer infile.Close()
-	}
-	if *outfileName != "" {
-		outfile, err = os.Create(*outfileName)
-		if err != nil {
-			log.Printf("error opening output file: %v\n", err)
-			return 3
-		}
-		defer outfile.Close()
-	}
-
-	var pathResolverFunc func(string) string
-	if *useAbsoluteSourcePath {
-		pathResolverFunc = getSourceFileName
-	} else {
-		pathResolverFunc = getCoverallsSourceFileName
-	}
-
-	err = convertCoverage(infile, outfile, pathResolverFunc)
-	if err != nil {
-		log.Printf("error: convert: %v", err)
-		return 4
-	}
-	return 0
-}
diff --git a/main_test.go b/gcov2lcov_test.go
similarity index 72%
rename from main_test.go
rename to gcov2lcov_test.go
index 8d3817d..1605e1d 100644
--- a/main_test.go
+++ b/gcov2lcov_test.go
@@ -1,14 +1,11 @@
-// gcov2lcov - convert golang coverage files to the lcov format.
-// (c) 2019 Jan Delgado
-package main
+package gcov2lcov
 
 import (
 	"bytes"
+	"github.com/stretchr/testify/assert"
 	"os"
 	"strings"
 	"testing"
-
-	"github.com/stretchr/testify/assert"
 )
 
 func TestKeysOfMapReturnsAllKeysOfMap(t *testing.T) {
@@ -35,11 +32,11 @@ func TestParseCoverageLineFailsOnInvalidLines(t *testing.T) {
 }
 
 func TestParseCoverageLineOfParsesValidLineCorrectly(t *testing.T) {
-	line := "github.com/jandelgado/gcov2lcov/main.go:6.14,8.3 2 1"
+	line := "github.com/jandelgado/gcov2lcov/cmd/main.go:6.14,8.3 2 1"
 	file, b, err := parseCoverageLine(line)
 
 	assert.Nil(t, err)
-	assert.Equal(t, "github.com/jandelgado/gcov2lcov/main.go", file)
+	assert.Equal(t, "github.com/jandelgado/gcov2lcov/cmd/main.go", file)
 	assert.Equal(t, 6, b.startLine)
 	assert.Equal(t, 14, b.startChar)
 	assert.Equal(t, 8, b.endLine)
@@ -53,17 +50,17 @@ func TestParseCoverage(t *testing.T) {
 	// note: in this integrative test, the package path must match the actual
 	// repository name of this project.
 	cov := `mode: set
-github.com/jandelgado/gcov2lcov/main.go:6.14,8.3 2 1`
+github.com/jandelgado/gcov2lcov/cmd/main.go:6.14,8.3 2 1`
 
 	reader := strings.NewReader(cov)
-	res, err := parseCoverage(reader, getCoverallsSourceFileName)
+	res, err := parseCoverage(reader, RelativePathResolver)
 
 	assert.NoError(t, err)
 	assert.Equal(t, 1, len(res))
 	for k, blks := range res {
 		assert.Equal(t, 1, len(blks))
 		b := blks[0]
-		assert.Equal(t, "main.go", k)
+		assert.Equal(t, "cmd/main.go", k)
 		assert.Equal(t, 6, b.startLine)
 		assert.Equal(t, 14, b.startChar)
 		assert.Equal(t, 8, b.endLine)
@@ -78,16 +75,16 @@ func TestConvertCoverage(t *testing.T) {
 	// repository name of this project. Format:
 	//   name.go:line.column,line.column numberOfStatements count
 	cov := `mode: set
-github.com/jandelgado/gcov2lcov/main.go:6.14,8.3 2 1
-github.com/jandelgado/gcov2lcov/main.go:7.14,9.3 2 0
-github.com/jandelgado/gcov2lcov/main.go:10.1,11.10 2 2`
+github.com/jandelgado/gcov2lcov/cmd/main.go:6.14,8.3 2 1
+github.com/jandelgado/gcov2lcov/cmd/main.go:7.14,9.3 2 0
+github.com/jandelgado/gcov2lcov/cmd/main.go:10.1,11.10 2 2`
 
 	in := strings.NewReader(cov)
 	out := bytes.NewBufferString("")
-	err := convertCoverage(in, out, getCoverallsSourceFileName)
+	err := ConvertCoverage(in, out, RelativePathResolver)
 
 	expected := `TN:
-SF:main.go
+SF:cmd/main.go
 DA:6,1
 DA:7,1
 DA:8,1
@@ -106,9 +103,9 @@ func TestPathResolverFunc(t *testing.T) {
 	pwd, err := os.Getwd()
 	assert.NoError(t, err)
 
-	name := getCoverallsSourceFileName(pwd + "/main.go")
-	assert.Equal(t, "main.go", name)
+	name := RelativePathResolver(pwd + "/cmd/main.go")
+	assert.Equal(t, "cmd/main.go", name)
 
-	name = getSourceFileName(pwd + "/main.go")
-	assert.Equal(t, pwd+"/main.go", name)
+	name = AbsolutePathResolver(pwd + "/cmd/main.go")
+	assert.Equal(t, pwd+"/cmd/main.go", name)
 }

From 6544f4249b597b56046690b2d89167cc13205739 Mon Sep 17 00:00:00 2001
From: Jin <chinjinhong@hotmail.com>
Date: Thu, 29 Apr 2021 18:24:05 +0800
Subject: [PATCH 2/4] remove .idea files

---
 .idea/.gitignore    | 8 --------
 .idea/gcov2lcov.iml | 9 ---------
 .idea/modules.xml   | 8 --------
 .idea/vcs.xml       | 6 ------
 4 files changed, 31 deletions(-)
 delete mode 100644 .idea/.gitignore
 delete mode 100644 .idea/gcov2lcov.iml
 delete mode 100644 .idea/modules.xml
 delete mode 100644 .idea/vcs.xml

diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 73f69e0..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
-# Editor-based HTTP Client requests
-/httpRequests/
diff --git a/.idea/gcov2lcov.iml b/.idea/gcov2lcov.iml
deleted file mode 100644
index 5e764c4..0000000
--- a/.idea/gcov2lcov.iml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="WEB_MODULE" version="4">
-  <component name="Go" enabled="true" />
-  <component name="NewModuleRootManager">
-    <content url="file://$MODULE_DIR$" />
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index e512733..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectModuleManager">
-    <modules>
-      <module fileurl="file://$PROJECT_DIR$/.idea/gcov2lcov.iml" filepath="$PROJECT_DIR$/.idea/gcov2lcov.iml" />
-    </modules>
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$" vcs="Git" />
-  </component>
-</project>
\ No newline at end of file

From 91ee25c07918abd23eb4ec0222d63f601b67a4b6 Mon Sep 17 00:00:00 2001
From: Jin <chinjinhong@hotmail.com>
Date: Thu, 29 Apr 2021 18:24:42 +0800
Subject: [PATCH 3/4] remove empty test file

---
 cmd/main_test.go | 4 ----
 1 file changed, 4 deletions(-)
 delete mode 100644 cmd/main_test.go

diff --git a/cmd/main_test.go b/cmd/main_test.go
deleted file mode 100644
index 5675657..0000000
--- a/cmd/main_test.go
+++ /dev/null
@@ -1,4 +0,0 @@
-// gcov2lcov - convert golang coverage files to the lcov format.
-// (c) 2019 Jan Delgado
-package main
-

From 2c41a9e28e2d7b99614d3a215a63f9260f4a9c4c Mon Sep 17 00:00:00 2001
From: Jin <chinjinhong@hotmail.com>
Date: Thu, 29 Apr 2021 20:13:59 +0800
Subject: [PATCH 4/4] refactors

---
 cmd/main.go                 |  2 +-
 gcov2kov.go => gcov2lcov.go | 25 +++++++++++++++----------
 gcov2lcov_test.go           | 10 ++++------
 3 files changed, 20 insertions(+), 17 deletions(-)
 rename gcov2kov.go => gcov2lcov.go (92%)

diff --git a/cmd/main.go b/cmd/main.go
index 0eb7308..d6f7acf 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -51,7 +51,7 @@ func gcovmain() int {
 		defer outfile.Close()
 	}
 
-	var pathResolverFunc func(string) string
+	var pathResolverFunc gcov2lcov.PathResolver
 	if *useAbsoluteSourcePath {
 		pathResolverFunc = gcov2lcov.AbsolutePathResolver
 	} else {
diff --git a/gcov2kov.go b/gcov2lcov.go
similarity index 92%
rename from gcov2kov.go
rename to gcov2lcov.go
index 388c1ef..5a5f7ee 100644
--- a/gcov2kov.go
+++ b/gcov2lcov.go
@@ -40,7 +40,9 @@ type cacheEntry struct {
 
 var pkgCache = map[string]cacheEntry{}
 
-func ConvertCoverage(in io.Reader, out io.Writer, pathResolverFunc func(string) string) error {
+type PathResolver func(name string) (string, error)
+
+func ConvertCoverage(in io.Reader, out io.Writer, pathResolverFunc PathResolver) error {
 	blocks, err := parseCoverage(in, pathResolverFunc)
 	if err != nil {
 		return err
@@ -48,16 +50,21 @@ func ConvertCoverage(in io.Reader, out io.Writer, pathResolverFunc func(string)
 	return writeLcov(blocks, out)
 }
 
-func AbsolutePathResolver(name string) string {
-	return name
+func AbsolutePathResolver(name string) (string, error) {
+	return name, nil
 }
 
-func RelativePathResolver(name string) string {
+func RelativePathResolver(name string) (string, error) {
+	name, err := findFile(name)
+	if err != nil {
+		return "", err
+	}
+
 	if dir, ok := findRepositoryRoot(name); ok {
 		filename := strings.TrimPrefix(name, dir+string(os.PathSeparator))
-		return filename
+		return filename, nil
 	}
-	return name
+	return name, nil
 }
 
 // given a module+file spec (e.g. github.com/jandelgado/gcov2lcov/main.go),
@@ -210,7 +217,7 @@ func parseCoverageLine(line string) (string, *block, error) {
 	return path[0], b, err
 }
 
-func parseCoverage(coverage io.Reader, pathResolverFunc func(string) string) (map[string][]*block, error) {
+func parseCoverage(coverage io.Reader, pathResolverFunc PathResolver) (map[string][]*block, error) {
 	scanner := bufio.NewScanner(coverage)
 	blocks := map[string][]*block{}
 	for scanner.Scan() {
@@ -219,14 +226,12 @@ func parseCoverage(coverage io.Reader, pathResolverFunc func(string) string) (ma
 			continue
 		}
 		if f, b, err := parseCoverageLine(line); err == nil {
-			f, err := findFile(f)
+			f, err = pathResolverFunc(f)
 			if err != nil {
 				log.Printf("warn: %v", err)
 				continue
 			}
 
-			f = pathResolverFunc(f)
-
 			// Make sure the filePath is a key in the map.
 			if _, found := blocks[f]; !found {
 				blocks[f] = []*block{}
diff --git a/gcov2lcov_test.go b/gcov2lcov_test.go
index 1605e1d..d7610b3 100644
--- a/gcov2lcov_test.go
+++ b/gcov2lcov_test.go
@@ -3,7 +3,6 @@ package gcov2lcov
 import (
 	"bytes"
 	"github.com/stretchr/testify/assert"
-	"os"
 	"strings"
 	"testing"
 )
@@ -100,12 +99,11 @@ end_of_record
 }
 
 func TestPathResolverFunc(t *testing.T) {
-	pwd, err := os.Getwd()
+	name, err := RelativePathResolver("github.com/jandelgado/gcov2lcov/cmd/main.go")
 	assert.NoError(t, err)
-
-	name := RelativePathResolver(pwd + "/cmd/main.go")
 	assert.Equal(t, "cmd/main.go", name)
 
-	name = AbsolutePathResolver(pwd + "/cmd/main.go")
-	assert.Equal(t, pwd+"/cmd/main.go", name)
+	name, err = AbsolutePathResolver("github.com/jandelgado/gcov2lcov/cmd/main.go")
+	assert.NoError(t, err)
+	assert.Equal(t, "github.com/jandelgado/gcov2lcov/cmd/main.go", name)
 }