From 63028f8b2c2ecd86f92f4d26048db0e223a66947 Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 12 Aug 2020 16:02:17 +0530 Subject: [PATCH 1/2] tester: Report missing lines in test coverage With the --threshold flag set, opa did not report the missing lines, making it difficult to understand where the problem is. This commit modifies opa test so that the pretty format reports text instead of JSON, and shows the lines not covered if the threshold is not met. Fixes #2562 Signed-off-by: Aditya --- cmd/test.go | 2 +- tester/reporter.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/cmd/test.go b/cmd/test.go index 389d6451b1..83231d0e7e 100644 --- a/cmd/test.go +++ b/cmd/test.go @@ -236,7 +236,7 @@ func opaTest(args []string) int { } } } else { - reporter = tester.JSONCoverageReporter{ + reporter = tester.PrettyCoverageReporter{ Cover: cov, Modules: modules, Output: os.Stdout, diff --git a/tester/reporter.go b/tester/reporter.go index 7c5a87c376..55d6abe2dc 100644 --- a/tester/reporter.go +++ b/tester/reporter.go @@ -199,6 +199,66 @@ func (r JSONCoverageReporter) Report(ch chan *Result) error { return encoder.Encode(report) } +// PrettyCoverageReporter reports coverage as text. +type PrettyCoverageReporter struct { + Cover *cover.Cover + Modules map[string]*ast.Module + Output io.Writer + Threshold float64 +} + +// Report prints the test report to the reporter's output. +func (r PrettyCoverageReporter) Report(ch chan *Result) error { + for tr := range ch { + if !tr.Pass() { + if tr.Error != nil { + return tr.Error + } + return errors.New(tr.String()) + } + } + report := r.Cover.Report(r.Modules) + if report.Coverage < r.Threshold { + fmt.Fprintln(r.Output, "Missing coverage:") + for name, coverageReport := range report.Files { + if coverageReport.Coverage != 100 { + r.printCoverage(name, coverageReport.NotCovered) + } + } + return &cover.CoverageThresholdError{ + Coverage: report.Coverage, + Threshold: r.Threshold, + } + } + for name, coverageReport := range report.Files { + fmt.Fprintf(r.Output, "%v %v%%\n", name, coverageReport.Coverage) + r.hl() + fmt.Fprintln(r.Output, "Covered:") + r.printCoverage(name, coverageReport.Covered) + if len(coverageReport.NotCovered) != 0 { + fmt.Fprintln(r.Output, "Not covered:") + r.printCoverage(name, coverageReport.NotCovered) + } + fmt.Println() + } + return errors.New("") +} + +// Prints the Coverage for a file as text +func (r PrettyCoverageReporter) printCoverage(name string, ar []cover.Range) { + for _, cov := range ar { + if cov.Start.Row == cov.End.Row { + fmt.Fprintf(r.Output, "%v: %v\n", name, cov.Start.Row) + } else { + fmt.Fprintf(r.Output, "%v: %v-%v\n", name, cov.Start.Row, cov.End.Row) + } + } +} + +func (r PrettyCoverageReporter) hl() { + fmt.Fprintln(r.Output, strings.Repeat("-", 80)) +} + type indentingWriter struct { w io.Writer } From e465450da00c441a82958b9eb2d0b7d55e95b839 Mon Sep 17 00:00:00 2001 From: Aditya Date: Thu, 13 Aug 2020 21:55:07 +0530 Subject: [PATCH 2/2] tester: report missing coverage Add support for --verbose flag in reporting test coverage in pretty mode Signed-off-by: Aditya --- cmd/test.go | 20 +++++++++++++++----- tester/reporter.go | 44 ++++++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/cmd/test.go b/cmd/test.go index 83231d0e7e..d6068b9bac 100644 --- a/cmd/test.go +++ b/cmd/test.go @@ -236,11 +236,21 @@ func opaTest(args []string) int { } } } else { - reporter = tester.PrettyCoverageReporter{ - Cover: cov, - Modules: modules, - Output: os.Stdout, - Threshold: testParams.threshold, + if testParams.outputFormat.String() == "json" { + reporter = tester.JSONCoverageReporter{ + Cover: cov, + Modules: modules, + Output: os.Stdout, + Threshold: testParams.threshold, + } + } else { + reporter = tester.PrettyCoverageReporter{ + Verbose: testParams.verbose, + Cover: cov, + Modules: modules, + Output: os.Stdout, + Threshold: testParams.threshold, + } } } diff --git a/tester/reporter.go b/tester/reporter.go index 55d6abe2dc..3e0532eaa8 100644 --- a/tester/reporter.go +++ b/tester/reporter.go @@ -201,6 +201,7 @@ func (r JSONCoverageReporter) Report(ch chan *Result) error { // PrettyCoverageReporter reports coverage as text. type PrettyCoverageReporter struct { + Verbose bool Cover *cover.Cover Modules map[string]*ast.Module Output io.Writer @@ -218,28 +219,39 @@ func (r PrettyCoverageReporter) Report(ch chan *Result) error { } } report := r.Cover.Report(r.Modules) - if report.Coverage < r.Threshold { - fmt.Fprintln(r.Output, "Missing coverage:") + if r.Verbose { + fmt.Fprintf(r.Output, "Got coverage %v%%\n\n", report.Coverage) for name, coverageReport := range report.Files { - if coverageReport.Coverage != 100 { + fmt.Fprintf(r.Output, "%v %v%%\n", name, coverageReport.Coverage) + r.hl() + fmt.Fprintln(r.Output, "Covered:") + r.printCoverage(name, coverageReport.Covered) + if len(coverageReport.NotCovered) > 0 { + fmt.Fprintln(r.Output, "Not covered:") r.printCoverage(name, coverageReport.NotCovered) } + fmt.Println() } - return &cover.CoverageThresholdError{ - Coverage: report.Coverage, - Threshold: r.Threshold, + } else { + if report.Coverage < r.Threshold { + fmt.Fprintln(r.Output, "Missing coverage:") + for name, coverageReport := range report.Files { + if coverageReport.Coverage != 100 { + r.printCoverage(name, coverageReport.NotCovered) + } + } + return &cover.CoverageThresholdError{ + Coverage: report.Coverage, + Threshold: r.Threshold, + } } - } - for name, coverageReport := range report.Files { - fmt.Fprintf(r.Output, "%v %v%%\n", name, coverageReport.Coverage) - r.hl() - fmt.Fprintln(r.Output, "Covered:") - r.printCoverage(name, coverageReport.Covered) - if len(coverageReport.NotCovered) != 0 { - fmt.Fprintln(r.Output, "Not covered:") - r.printCoverage(name, coverageReport.NotCovered) + fmt.Fprintf(r.Output, "Expected coverage %v%%, got %v%%\n", r.Threshold, report.Coverage) + fmt.Fprintln(r.Output, "Missing coverage:") + for name, coverageReport := range report.Files { + if coverageReport.Coverage != 100{ + r.printCoverage(name, coverageReport.NotCovered) + } } - fmt.Println() } return errors.New("") }