Go: cmd/go: -coverprofile with relative path uses wrong file name

Created on 25 Oct 2017  Β·  7Comments  Β·  Source: golang/go

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version go1.9.1 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

macOS Sierra 10.12.6

What did you do?

If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.

I am trying to generate coverage reports for a simple application but am unable to due to the wrong path being generated in the -coverprofile output

I am having the issue outlined here: https://github.com/Masterminds/glide/issues/43 . I've recreated the problem with a simple example modeled after the skeleton of my application. I am on macOS Sierra, go1.9 is installed via goenv.

Directory structure

$ tree src/
src/
β”œβ”€β”€ cover.out
β”œβ”€β”€ lib
β”‚Β Β  └── foo
β”‚Β Β      β”œβ”€β”€ Dummy.go
β”‚Β Β      β”œβ”€β”€ SuperDummy.go
β”‚Β Β      └── TestSuperDummy_test.go
β”œβ”€β”€ main.go

Dummy.go

package foo

func HelloWorld() string {
    return  "hello world"
}

SuperDummy.go

package foo

import "fmt"

type SuperDummy struct {
    Forename string
}

func (dummy SuperDummy) SayHello() {
    fmt.Printf("Hello my name is %s!", dummy.Forename)
}

TestSuperDummy_test.go

package foo

import "testing"

func TestSuperDummy_SayHello(t *testing.T) {
    var d = SuperDummy{"Paul"}
    d.SayHello()
}

main.go

package main

import (
    "./lib/foo"
    "fmt"
)

func main() {
    var d foo.SuperDummy = foo.SuperDummy{"Patrick"}
    d.SayHello()
    fmt.Println(foo.HelloWorld())
}

From the src/ directory I ran go test ./lib/foo -coverprofile=cover.out which yielded:

src$ go test ./lib/foo -coverprofile=cover.out
ok      _/Users/patrickburton/IdeaProjects/gotestcoverage/src/lib/foo   0.007s  coverage: 50.0% of statements
src$ cat cover.out 
mode: set
_/Users/patrickburton/IdeaProjects/gotestcoverage/src/lib/foo/Dummy.go:3.26,5.2 1 0
_/Users/patrickburton/IdeaProjects/gotestcoverage/src/lib/foo/SuperDummy.go:9.36,11.2 1 1

Running go tool cover -html=cover.out yields the error :

src$ go tool cover -html=cover.out
cover: can't find "Dummy.go": cannot find package "_/Users/patrickburton/IdeaProjects/gotestcoverage/src/lib/foo/" in any of:
        /Users/patrickburton/.goenv/versions/1.9.0/src/_/Users/patrickburton/IdeaProjects/gotestcoverage/src/lib/foo (from $GOROOT)
        /Users/patrickburton/.go/src/_/Users/patrickburton/IdeaProjects/gotestcoverage/src/lib/foo (from $GOPATH)
        /Users/patrickburton/IdeaProjects/src/_/Users/patrickburton/IdeaProjects/gotestcoverage/src/lib/foo
NeedsInvestigation

Most helpful comment

I see this too, here's my workaround (running inside my repo directory):

go test -coverprofile=c.out
sed -i "s/_$(pwd|sed 's/\//\\\//g')/./g" c.out
go tool cover -html=c.out -o=c.html
  1. Outputs test coverage to c.out
  2. Uses two seds:

    • The inside sed escapes the slashes from the pwd command (\/dirs\/now\/like\/so)

    • With the escaped pwd, we use the outer sed to find/replace the absolute path, with just a relative path of ./

  3. go tool cover can now successfully process c.out into c.html

All 7 comments

My guess is that this is a bug related to using something other than an import path with -coverprofile.

@ianlancetaylor What do you mean? Do you know of any workarounds?

I think I meant that in the command line go test ./lib/foo -coverprofile=cover.out the argument to go test, ./lib/foo, is not an import path. The workaround would be to use an import path. It's worth trying, anyhow.

I tried this, however the cover tool seems to prefix the coverage data with things like the CWD or command-line-arguments. For example I run the following commands from the foo/ directory and get these results:

foo$ go test *.go -coverprofile=cover.out
ok      command-line-arguments  0.006s  coverage: 50.0% of statements
foo$ go tool cover -html=cover.out
cover: can't find "Dummy.go": cannot find package "command-line-arguments/" in any of:
        /Users/patrickburton/.goenv/versions/1.9.1/src/command-line-arguments (from $GOROOT)
        /Users/patrickburton/.go/src/command-line-arguments (from $GOPATH)
        /Users/patrickburton/IdeaProjects/gotest-issue/src/command-line-arguments

If you look at the last line /Users/patrickburton/IdeaProjects/gotest-issue/src/command-line-arguments, command-line-arguments isn't even in my GOPATH:

elimstats$ echo $GOPATH
/Users/patrickburton/.go:/Users/patrickburton/IdeaProjects:/Users/patrickburton/IdeaProjects/elimstats/src/lib/elimstats:/Users/patrickburton/IdeaProjects/elimstats/src/lib

@thed0ctor did you ever find a workaround for this? Still seeing this in 1.9.5

I see this too, here's my workaround (running inside my repo directory):

go test -coverprofile=c.out
sed -i "s/_$(pwd|sed 's/\//\\\//g')/./g" c.out
go tool cover -html=c.out -o=c.html
  1. Outputs test coverage to c.out
  2. Uses two seds:

    • The inside sed escapes the slashes from the pwd command (\/dirs\/now\/like\/so)

    • With the escaped pwd, we use the outer sed to find/replace the absolute path, with just a relative path of ./

  3. go tool cover can now successfully process c.out into c.html

FWIW this is still in this state as of go1.11

$ go test -v -coverprofile=coverage.out -covermode=count ./...
...
coverage: 70.0% of statements
$ more coverage.out
mode: count
/home/me/scripts/git/parsembox/parsembox.go:31.38,36.2 1 10
/home/me/scripts/git/parsembox/parsembox.go:38.34,42.2 3 15

For some projects I've had this in a githook:
go test -coverprofile=coverage.out sed -i "s/_$(pwd|sed 's/\//\\\//g')/./g" coverage.out
which kinda stinks, but works :(

note: the sed recipe acopy/paste problem... fixed, I hope :)

Was this page helpful?
0 / 5 - 0 ratings