]> Cypherpunks repositories - gostls13.git/commitdiff
internal/coverage/cformat: add aggregation option to EmitPercent
authorThan McIntosh <thanm@google.com>
Tue, 16 May 2023 17:06:22 +0000 (13:06 -0400)
committerThan McIntosh <thanm@google.com>
Tue, 23 May 2023 11:36:57 +0000 (11:36 +0000)
Add a flag to EmitPercent indicating to emit a single line percent
summary across all packages as opposed to a line per package. We need
to set this flag when reporting as part of a "go test -cover" run, but
false when reporting as part of a "go tool covdata percent" run.

Change-Id: Iba6a81b9ae27e3a5aaf9d0e46c0023c0e7ceae16
Reviewed-on: https://go-review.googlesource.com/c/go/+/495448
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Than McIntosh <thanm@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
src/cmd/covdata/dump.go
src/internal/coverage/cformat/fmt_test.go
src/internal/coverage/cformat/format.go
src/runtime/coverage/testsupport.go
src/runtime/coverage/ts_test.go

index 4b4671e9712a7ae782919aefcaf24fdbb3a60e91..a51762f0d10e2c8b4296e16dd3cb7cb9df8150ee 100644 (file)
@@ -325,7 +325,7 @@ func (d *dstate) Finish() {
        // d.format maybe nil here if the specified input dir was empty.
        if d.format != nil {
                if d.cmd == percentMode {
-                       d.format.EmitPercent(os.Stdout, "", false)
+                       d.format.EmitPercent(os.Stdout, "", false, false)
                }
                if d.cmd == funcMode {
                        d.format.EmitFuncs(os.Stdout)
index 576ed2c18c244e498fef8885bac0a095e9a0cb59..f5ed01b3b0f5355926025addad2c28a322b1847b 100644 (file)
@@ -7,13 +7,13 @@ package cformat_test
 import (
        "internal/coverage"
        "internal/coverage/cformat"
+       "slices"
        "strings"
        "testing"
 )
 
 func TestBasics(t *testing.T) {
        fm := cformat.NewFormatter(coverage.CtrModeAtomic)
-       fm.SetPackage("my/pack")
 
        mku := func(stl, enl, nx uint32) coverage.CoverableUnit {
                return coverage.CoverableUnit{
@@ -34,6 +34,7 @@ func TestBasics(t *testing.T) {
        fn3units := []coverage.CoverableUnit{
                mku(99, 100, 1),
        }
+       fm.SetPackage("my/pack1")
        for k, u := range fn1units {
                fm.AddUnit("p.go", "f1", false, u, uint32(k))
        }
@@ -41,52 +42,114 @@ func TestBasics(t *testing.T) {
                fm.AddUnit("q.go", "f2", false, u, 0)
                fm.AddUnit("q.go", "f2", false, u, uint32(k))
        }
+       fm.SetPackage("my/pack2")
        for _, u := range fn3units {
                fm.AddUnit("lit.go", "f3", true, u, 0)
        }
 
-       var b1, b2, b3 strings.Builder
+       var b1, b2, b3, b4 strings.Builder
        if err := fm.EmitTextual(&b1); err != nil {
                t.Fatalf("EmitTextual returned %v", err)
        }
        wantText := strings.TrimSpace(`
 mode: atomic
-lit.go:99.0,100.0 1 0
 p.go:10.0,11.0 2 0
 p.go:15.0,11.0 1 1
 q.go:20.0,25.0 3 0
 q.go:30.0,31.0 2 1
-q.go:33.0,40.0 7 2`)
+q.go:33.0,40.0 7 2
+lit.go:99.0,100.0 1 0`)
        gotText := strings.TrimSpace(b1.String())
        if wantText != gotText {
                t.Errorf("emit text: got:\n%s\nwant:\n%s\n", gotText, wantText)
        }
 
-       if err := fm.EmitPercent(&b2, "", false); err != nil {
+       // Percent output with no aggregation.
+       noCoverPkg := ""
+       if err := fm.EmitPercent(&b2, noCoverPkg, false, false); err != nil {
                t.Fatalf("EmitPercent returned %v", err)
        }
-       wantPercent := strings.TrimSpace(`
-my/pack                coverage: 62.5% of statements
+       wantPercent := strings.Fields(`
+               my/pack1                coverage: 66.7% of statements
+        my/pack2               coverage: 0.0% of statements
 `)
-       gotPercent := strings.TrimSpace(b2.String())
-       if wantPercent != gotPercent {
-               t.Errorf("emit percent: got:\n%s\nwant:\n%s\n", gotPercent, wantPercent)
+       gotPercent := strings.Fields(b2.String())
+       if !slices.Equal(wantPercent, gotPercent) {
+               t.Errorf("emit percent: got:\n%+v\nwant:\n%+v\n",
+                       gotPercent, wantPercent)
        }
 
-       if err := fm.EmitFuncs(&b3); err != nil {
+       // Percent mode with aggregation.
+       withCoverPkg := " in ./..."
+       if err := fm.EmitPercent(&b3, withCoverPkg, false, true); err != nil {
+               t.Fatalf("EmitPercent returned %v", err)
+       }
+       wantPercent = strings.Fields(`
+               coverage: 62.5% of statements in ./...
+`)
+       gotPercent = strings.Fields(b3.String())
+       if !slices.Equal(wantPercent, gotPercent) {
+               t.Errorf("emit percent: got:\n%+v\nwant:\n%+v\n",
+                       gotPercent, wantPercent)
+       }
+
+       if err := fm.EmitFuncs(&b4); err != nil {
                t.Fatalf("EmitFuncs returned %v", err)
        }
        wantFuncs := strings.TrimSpace(`
 p.go:10:       f1              33.3%
 q.go:20:       f2              75.0%
 total          (statements)    62.5%`)
-       gotFuncs := strings.TrimSpace(b3.String())
+       gotFuncs := strings.TrimSpace(b4.String())
        if wantFuncs != gotFuncs {
                t.Errorf("emit funcs: got:\n%s\nwant:\n%s\n", gotFuncs, wantFuncs)
        }
        if false {
                t.Logf("text is %s\n", b1.String())
                t.Logf("perc is %s\n", b2.String())
-               t.Logf("funcs is %s\n", b3.String())
+               t.Logf("perc2 is %s\n", b3.String())
+               t.Logf("funcs is %s\n", b4.String())
+       }
+}
+
+func TestEmptyPackages(t *testing.T) {
+
+       fm := cformat.NewFormatter(coverage.CtrModeAtomic)
+       fm.SetPackage("my/pack1")
+       fm.SetPackage("my/pack2")
+
+       // No aggregation.
+       {
+               var b strings.Builder
+               noCoverPkg := ""
+               if err := fm.EmitPercent(&b, noCoverPkg, true, false); err != nil {
+                       t.Fatalf("EmitPercent returned %v", err)
+               }
+               wantPercent := strings.Fields(`
+               my/pack1 coverage:      [no statements]
+        my/pack2 coverage:     [no statements]
+`)
+               gotPercent := strings.Fields(b.String())
+               if !slices.Equal(wantPercent, gotPercent) {
+                       t.Errorf("emit percent: got:\n%+v\nwant:\n%+v\n",
+                               gotPercent, wantPercent)
+               }
+       }
+
+       // With aggregation.
+       {
+               var b strings.Builder
+               noCoverPkg := ""
+               if err := fm.EmitPercent(&b, noCoverPkg, true, true); err != nil {
+                       t.Fatalf("EmitPercent returned %v", err)
+               }
+               wantPercent := strings.Fields(`
+               coverage:       [no statements]
+`)
+               gotPercent := strings.Fields(b.String())
+               if !slices.Equal(wantPercent, gotPercent) {
+                       t.Errorf("emit percent: got:\n%+v\nwant:\n%+v\n",
+                               gotPercent, wantPercent)
+               }
        }
 }
index 0e1d8caf99f7644fd3c87785cf462eed77ba6c18..7e7a2778c725f15faec197d57794726897cddf63 100644 (file)
@@ -23,7 +23,7 @@ package cformat
 //                             }
 //                     }
 //             }
-//             myformatter.EmitPercent(os.Stdout, "")
+//             myformatter.EmitPercent(os.Stdout, "", true, true)
 //             myformatter.EmitTextual(somefile)
 //
 // These apis are linked into tests that are built with "-cover", and
@@ -200,17 +200,33 @@ func (fm *Formatter) EmitTextual(w io.Writer) error {
 }
 
 // EmitPercent writes out a "percentage covered" string to the writer 'w'.
-func (fm *Formatter) EmitPercent(w io.Writer, covpkgs string, noteEmpty bool) error {
+func (fm *Formatter) EmitPercent(w io.Writer, covpkgs string, noteEmpty bool, aggregate bool) error {
        pkgs := make([]string, 0, len(fm.pm))
        for importpath := range fm.pm {
                pkgs = append(pkgs, importpath)
        }
+
+       rep := func(cov, tot uint64) error {
+               if tot != 0 {
+                       if _, err := fmt.Fprintf(w, "coverage: %.1f%% of statements%s\n",
+                               100.0*float64(cov)/float64(tot), covpkgs); err != nil {
+                               return err
+                       }
+               } else if noteEmpty {
+                       if _, err := fmt.Fprintf(w, "coverage: [no statements]\n"); err != nil {
+                               return err
+                       }
+               }
+               return nil
+       }
+
        sort.Strings(pkgs)
-       seenPkg := false
+       var totalStmts, coveredStmts uint64
        for _, importpath := range pkgs {
-               seenPkg = true
                p := fm.pm[importpath]
-               var totalStmts, coveredStmts uint64
+               if !aggregate {
+                       totalStmts, coveredStmts = 0, 0
+               }
                for unit, count := range p.unitTable {
                        nx := uint64(unit.NxStmts)
                        totalStmts += nx
@@ -218,21 +234,17 @@ func (fm *Formatter) EmitPercent(w io.Writer, covpkgs string, noteEmpty bool) er
                                coveredStmts += nx
                        }
                }
-               if _, err := fmt.Fprintf(w, "\t%s\t\t", importpath); err != nil {
-                       return err
-               }
-               if totalStmts == 0 {
-                       if _, err := fmt.Fprintf(w, "coverage: [no statements]\n"); err != nil {
+               if !aggregate {
+                       if _, err := fmt.Fprintf(w, "\t%s\t\t", importpath); err != nil {
                                return err
                        }
-               } else {
-                       if _, err := fmt.Fprintf(w, "coverage: %.1f%% of statements%s\n", 100*float64(coveredStmts)/float64(totalStmts), covpkgs); err != nil {
+                       if err := rep(coveredStmts, totalStmts); err != nil {
                                return err
                        }
                }
        }
-       if noteEmpty && !seenPkg {
-               if _, err := fmt.Fprintf(w, "coverage: [no statements]\n"); err != nil {
+       if aggregate {
+               if err := rep(coveredStmts, totalStmts); err != nil {
                        return err
                }
        }
index a481bbbd9ddaa3065af8d88bd7d1bc3b5228f3c2..2b9e58b5f63bfeae124b00e432f56fb652bb0976 100644 (file)
@@ -96,7 +96,7 @@ func processCoverTestDirInternal(dir string, cfile string, cm string, cpkg strin
        }
 
        // Emit percent.
-       if err := ts.cf.EmitPercent(w, cpkg, true); err != nil {
+       if err := ts.cf.EmitPercent(w, cpkg, true, true); err != nil {
                return err
        }
 
index b826058a5419b3648d1668526e2a32d87d26e307..a95d405a3e2d1cff718fa6323055a07e1884e4a8 100644 (file)
@@ -47,12 +47,9 @@ func TestTestSupport(t *testing.T) {
 
        // Check for percent output with expected tokens.
        strout := sb.String()
-       want1 := "runtime/coverage"
-       want2 := "of statements"
-       if !strings.Contains(strout, want1) ||
-               !strings.Contains(strout, want2) {
+       want := "of statements"
+       if !strings.Contains(strout, want) {
                t.Logf("output from run: %s\n", strout)
-               t.Fatalf("percent output missing key tokens: %q and %q",
-                       want1, want2)
+               t.Fatalf("percent output missing token: %q", want)
        }
 }