tobari

package module
v0.9.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 5, 2026 License: BSD-3-Clause, MIT Imports: 12 Imported by: 0

README

Tobari

DeepWiki PkgGoDev Go

Tobari is a scoped coverage measurement tool for Go.

"Tobari" (帷) is a Japanese word meaning "curtain" or "veil," similar to the English word "cover".

Tobari provides coverage measurement capabilities that introduce a new concept called Scoped Coverage in addition to the coverage features provided by runtime/coverage. This feature enables clear mapping between test code and its impact area, allowing for high-precision test code generation using AI and other tools.

Background

To understand what Tobari enables, we first need to understand the current coverage mechanisms provided by Go.

The most common coverage measurement method we use is specifying coverage options with go test, such as go test -cover. We can control coverage target packages with -coverpkg and output coverage results with -coverprofile. However, using coverage through go test means we can only measure coverage when writing test code in Go. This means coverage can only be measured for tests starting from functions like func TestFoo(t *testing.T). For example, it was not possible to measure coverage for a binary created with go build after the fact.

To improve this, Go version 1.20 and later allows the -cover option with go build and supports the runtime/coverage package. With go build -cover, applications can be built with coverage instrumentation points. The runtime/coverage API allows coverage counter initialization and result output at any timing.

This made it possible to measure coverage of servers implemented in Go using E2E testing tools not written in Go when implementing HTTP or gRPC servers. Coverage functionality that was only available during go test execution became available at any timing during application runtime.

However, when actually trying to use runtime/coverage, you'll notice that some operational considerations are needed. Coverage measurement with runtime/coverage increases coverage counters when processing passes through embedded coverage measurement points, but it doesn't care what caused the passage. This is similar to traffic surveys for automobiles, where the number of cars passing a certain location is measured, but the type of cars is not considered. This mechanism becomes problematic in situations like measuring coverage for server applications:

  • To measure E2E test effectiveness, you want to measure coverage only when E2E testing tools access the server
    • Accesses other than from E2E tests should not be measured
  • For test acceleration, you want to access the server concurrently from E2E testing tools, but manage access contexts separately
    • For example, when E2E test scenarios A and B exist, you want to measure accesses from A and B separately even when accessing the server concurrently
  • Asynchronous processing by Goroutines created through methods not originating from E2E test requests should be excluded from coverage measurement

To meet these requirements, the server application must serialize and handle requests, ensuring that accesses from A and B are not processed simultaneously. Additionally, you need to implement mechanisms to determine E2E test accesses by referencing headers and reject other requests. Furthermore, what if you want to use this running server application for purposes other than E2E testing? For example, when performing manual verification in parallel with E2E test verification. In this case, other requests may reach the server while E2E tests are running, and these requests should not be rejected. Also, serializing processing defeats the purpose of concurrent access for test acceleration. Moreover, there's no way to ignore asynchronous processing not originating from E2E tests.

Therefore, I conceived the Scoped Coverage approach and decided to develop Tobari.

What is Scoped Coverage ?

What Scoped Coverage provides over runtime/coverage coverage measurement is measuring "what passed through". Using the E2E testing example, when measuring coverage from scenario A and B accesses, it distinguishes between "access from A" and "access from B". Additionally, it measures only asynchronous processing originating from E2E tests. This enables coverage measurement limited to the scope you want to measure. Concurrent access is also possible.

Coverage also needs to record "places that should be passed" in addition to recording "places that were passed". Coverage is calculated using a formula like this:

Coverage (%) = (Places passed / Places that should be passed) * 100

In normal coverage measurement, all files in packages specified by coverpkg could be considered "places that should be passed", requiring no special processing. However, Scoped Coverage is different. How should we define "places that should be passed" ? For example, when calculating coverage for scenario A, if places that scenario A will never pass are included in "places that should be passed", coverage will never reach 100% no matter how hard you try.

Tobari determines "places that should be passed" by reverse calculation from the results of what was passed. It extracts inter-function dependencies through static analysis in advance and calculates functions that could potentially be passed based on the dependency relationships of actually passed functions. Considering this, the formula becomes:

Coverage (%) = (Places passed / All places in functions that could potentially be called from passed functions) * 100

How to Use

Using tobari is very simple with 3 steps:

1. Installation

First, install the tobari tool with the following command:

go install github.com/goccy/tobari/cmd/tobari@latest

Important: The version of the tobari CLI tool and the tobari library used in your application must match. For example, if you install tobari@v0.2.1, your go.mod should also require github.com/goccy/tobari v0.2.1. Version mismatch will cause fingerprint errors during linking.

2. Use the API (like using the runtime/coverage package)

Using a gRPC server as an example:

tobari.CoverWithName serves as the entry point for coverage measurement. Specify a name in the first argument to distinguish coverage units. The behavior with runtime/coverage is the same as specifying an empty name. For gRPC, the name is obtained from metadata. If there's no metadata, it's treated as a normal request and the function exits without measuring coverage.

tobariInterceptor := func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
  md, ok := metadata.FromIncomingContext(ctx)
  if !ok { return handler(ctx, req) }
  scenarioNames, exists := md["E2E-Tool-Scenario-Name"]
  if !exists { return handler(ctx, req) }
  if len(scenarioNames) == 0 { return handler(ctx, req) }

  scenarioName := scenarioNames[0]

  var (
    res any
    err error
  )
  tobari.CoverWithName(scenarioName, func() {
    res, err = handler(ctx, req)
  })
  return res, err
}

grpcServer := grpc.NewServer(grpc.UnaryInterceptor(tobariInterceptor))

When outputting coverage data, you can use WriteCoverprofileByName or CoverprofileMap:

  • WriteCoverprofileByName: Get coverprofile results for a specified name
  • CoverprofileMap: Return the relationship between names and coverprofiles in map format

These APIs can be executed by creating a separate gRPC server and calling specific endpoints when E2E tests finish.

3. Build the Application

Then, when building the application you want to measure coverage for, simply specify GOFLAGS as follows:

GOFLAGS="$(tobari flags)" go build .

This example shows distinguishing coverage results by name, but you can also use it the same way as runtime/coverage. For specific APIs, please refer here.

Embedding Source Code

Tobari supports embedding the original source code into instrumented binaries with the --embed-code (-E) option. This is useful for archiving the exact source that was compiled, enabling offline coverage analysis without access to the original source tree.

# Using tobari flags
GOFLAGS="$(tobari flags -E)" go build .

# Using tobari directly as toolexec
go build -cover -toolexec='tobari --embed-code' ./...

To retrieve the embedded sources at runtime, use ReadCoverArchivedFile():

reader := tobari.ReadCoverArchivedFile()
if reader == nil {
    // No sources were embedded
    return
}
// reader provides a tar.gz archive of the original source files
Extracting Embedded Sources from a Binary

You can also extract embedded sources directly from a built binary using the tobari extract command, without writing any code:

tobari extract -o sources.tar.gz ./my-binary

This runs the instrumented binary internally, extracts all embedded source files, and writes them as a tar.gz archive to the specified path. The -o flag is required.

The extraction hook is injected at compile time into the main package, so it works regardless of -coverpkg settings. When the TOBARI_EXTRACT_SOURCES environment variable is set (which tobari extract does internally), the binary writes the archive and exits immediately without running the application's main function.

Generating HTML Coverage Reports

The tobari html command generates an HTML coverage report from a coverprofile or tobari.json file. It wraps go tool cover -html and adds support for tobari's JSON format and source resolution from embedded binaries or tar.gz archives.

# Generate HTML from a coverprofile
tobari html -o coverage.html profile.cover

# Generate HTML from tobari.json (merges all test entries with summed counts)
tobari html -o coverage.html tobari.json

When the source code is not available locally (e.g., on a CI server or a different machine), you can use the -b or -s flags to provide the source files needed for HTML generation:

# Use embedded sources from a tobari-built binary
tobari html -o coverage.html -b ./my-binary profile.cover

# Use sources from a previously extracted tar.gz archive
tobari html -o coverage.html -s sources.tar.gz tobari.json
Flag Description
-o <file> Output HTML file path (default: coverage.html)
-b <binary> Path to a tobari-built binary with embedded sources (requires --embed-code build)
-s <tar.gz> Path to a tar.gz archive of extracted sources (from tobari extract)

The -b and -s flags are mutually exclusive. When -b is specified, the command runs the binary with TOBARI_EXTRACT_SOURCES to obtain the source archive, then uses it to resolve file paths in the coverage data.

Example

We will use a more practical example to give you a better idea of how to use tobari. The example code is located in examples/http, so you can run it on your own environment as well.

First, install the tobari CLI using the following command.

go install github.com/goccy/tobari/cmd/tobari@latest

Next, to run the example, clone the repository and move to the repository root.

git clone https://github.com/goccy/tobari.git
cd tobari

The examples/http directory contains code structured as follows.

package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"os"

	"github.com/goccy/tobari"
)

func coverageMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if v := r.Header.Get("X-GO-COVERAGE"); v != "" {
			// When measuring coverage, wrap the function with tobari.Cover.
			tobari.Cover(func() { next.ServeHTTP(w, r) })
		} else {
			next.ServeHTTP(w, r)
		}
	})
}

var ch = make(chan struct{})

func run(ctx context.Context) error {
	mux := http.NewServeMux()

	// This is the endpoint used to start measuring coverage.
	mux.HandleFunc("/coverstart", func(w http.ResponseWriter, req *http.Request) {
		// Similar to ClearCounters in runtime/coverage, this resets the currently active counters.
		// It is intended to be called at the start of coverage measurement.
		tobari.ClearCounters()

		// This process is used to ensure that goroutines not subject to measurement are correctly ignored.
		// Normally, when coverage measurement begins, all goroutines are included in the measurement.
		// However, in Tobari, it is possible to count only specific processes, so the coverage of this goroutine will be ignored.
		go func() {
			<-ch
		}()

		fmt.Fprintf(w, "started")
	})

	// This is the endpoint used to stop coverage measurement and retrieve the results.
	mux.HandleFunc("/coverend", func(w http.ResponseWriter, req *http.Request) {
		// Writes data in coverprofile format.
		// The resulting output can be directly used with `go tool cover`.
		tobari.WriteCoverprofile(tobari.SetMode, w)
	})

	mux.HandleFunc("/foo", func(w http.ResponseWriter, req *http.Request) {
		if v := req.Header.Get("xxxx"); v != "" {
			uncoveredFunc()
		}
		fmt.Fprintf(w, "foo")
	})
	mux.HandleFunc("/bar", func(w http.ResponseWriter, req *http.Request) {
		fmt.Fprintf(w, "bar")
	})

	// A middleware is added to switch behavior based on the presence of the coverage flag.
	srv := httptest.NewServer(coverageMiddleware(mux))
	defer srv.Close()

	cli := new(http.Client)

	// start coverage.
	if err := func() error {
		req, err := http.NewRequest("GET", srv.URL+"/coverstart", nil)
		if err != nil {
			return err
		}
		resp, err := cli.Do(req)
		if err != nil {
			return err
		}
		defer resp.Body.Close()
		b, err := io.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		fmt.Println(string(b))
		return nil
	}(); err != nil {
		return err
	}

	// access foo endpoint with X-GO-COVERAGE header.
	if err := func() error {
		req, err := http.NewRequest("GET", srv.URL+"/foo", nil)
		if err != nil {
			return err
		}
		req.Header.Add("X-GO-COVERAGE", "true")
		resp, err := cli.Do(req)
		if err != nil {
			return err
		}
		defer resp.Body.Close()
		b, err := io.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		fmt.Println(string(b))
		return nil
	}(); err != nil {
		return err
	}

	// access bar endpoint without coverage header.
	if err := func() error {
		req, err := http.NewRequest("GET", srv.URL+"/bar", nil)
		if err != nil {
			return err
		}
		resp, err := cli.Do(req)
		if err != nil {
			return err
		}
		defer resp.Body.Close()
		b, err := io.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		fmt.Println(string(b))
		return nil
	}(); err != nil {
		return err
	}

	// end coverage.
	if err := func() error {
		req, err := http.NewRequest("GET", srv.URL+"/coverend", nil)
		if err != nil {
			return err
		}
		resp, err := cli.Do(req)
		if err != nil {
			return err
		}
		defer resp.Body.Close()
		b, err := io.ReadAll(resp.Body)
		if err != nil {
			return err
		}
		return os.WriteFile("test.cover", b, 0o600)
	}(); err != nil {
		return err
	}
	return nil
}

func uncoveredFunc() {
	uncoveredFunc2()
}

func uncoveredFunc2() {
	uncoveredFunc3()
}

func uncoveredFunc3() {
	fmt.Println("uncovered func3")
}

func main() {
	if err := run(context.Background()); err != nil {
		log.Fatal(err)
	}
}

Run this code using the following command.

GOFLAGS="$(tobari flags)" go run ./examples/http/main.go

Then, a test.cover file should be created in the current directory. Let’s view it using go tool cover -html.

go tool cover -html test.cover

This will produce an output like the following. Only the coverage related to foo is displayed.

Image Image Image

Using with go test

Tobari can also be used with go test to collect coverage data. When running tests with tobari, coverage data is written to tobari/tobari.json and tobari/tobari.toon files.

Basic Usage
GOFLAGS="$(tobari flags)" go test ./...

This will create tobari/tobari.json and tobari/tobari.toon files in the current directory.

Specifying Output Directory

You can use the TOBARI_COVERDIR environment variable to specify where the coverage data should be written:

TOBARI_COVERDIR=/path/to/output GOFLAGS="$(tobari flags)" go test ./...

This will create /path/to/output/tobari/tobari.json and /path/to/output/tobari/tobari.toon.

Using with go test -c

When building a test binary with go test -c, you can specify TOBARI_COVERDIR at runtime:

# Build the test binary
GOFLAGS="$(tobari flags)" go test -c .

# Run with default output (current directory)
./pkg.test

# Run with custom output directory
TOBARI_COVERDIR=/path/to/output ./pkg.test
Scenario Output Location
go test ./... ./tobari/tobari.json, ./tobari/tobari.toon
TOBARI_COVERDIR=dir go test ./... dir/tobari/tobari.json, dir/tobari/tobari.toon
go test -c && ./pkg.test ./tobari/tobari.json, ./tobari/tobari.toon
go test -c && TOBARI_COVERDIR=dir ./pkg.test dir/tobari/tobari.json, dir/tobari/tobari.toon
Output Formats

Tobari generates coverage data in two formats:

JSON Format (tobari.json)

A structured JSON format where each test name maps to an array of coverage entries:

{
  "TestAdd": [
    {
      "FileName": "/path/to/file.go",
      "Start": {"Line": 7, "Column": 24},
      "End": {"Line": 9, "Column": 2},
      "StatementCount": 1,
      "Count": 4
    }
  ]
}
TOON Format (tobari.toon)

A compact Token-Oriented Object Notation format optimized for LLM consumption. TOON uses approximately 40% fewer tokens than JSON while maintaining the same information:

TestAdd[1]{FileName,StartLine,StartCol,EndLine,EndCol,StatementCount,Count}:
	/path/to/file.go,7,24,9,2,1,4
TestMultiply[3]{FileName,StartLine,StartCol,EndLine,EndCol,StatementCount,Count}:
	/path/to/file.go,11,29,12,22,1,5
	/path/to/file.go,15,2,15,14,1,3
	/path/to/file.go,12,22,14,3,1,2

The TOON format is particularly useful when feeding coverage data to AI coding agents, as it reduces token usage while preserving all necessary information for coverage analysis.

Using Coverage Data with AI

The coverage data generated by tobari can be used to improve your test suite with AI assistance. By analyzing which code paths are covered (Count > 0) and which are not (Count = 0), AI coding agents can:

  • Identify duplicate test cases that cover nearly identical code paths
  • Suggest new test cases to improve coverage
  • Find dead code that is never executed

Agent Skills

Tobari provides Agent Skills to help automate test coverage improvement workflows. Agent Skills is an open standard for giving AI coding agents new capabilities and expertise. Skills are supported by many coding agents including Claude Code, Cursor, GitHub Copilot, OpenAI Codex, Gemini CLI, and more.

Available Skills

The following skills are available in the skills/ directory:

Skill Description
tobari-installer Install and set up the tobari CLI tool
tobari-duplicated-tests-remover Find and remove duplicate test cases that cover >95% identical code paths
tobari-coverage-improver Incrementally improve test coverage by 5% steps with user confirmation
How to Use
  1. Run tests with tobari to generate coverage data:

    GOFLAGS="$(tobari flags)" go test ./...
    
  2. Use the agent skills with your preferred coding agent (Claude Code, Cursor, Codex, etc.) to analyze and improve your test coverage.

The skills will automatically read the tobari.toon file and guide you through:

  • Detecting and removing redundant tests
  • Identifying uncovered code blocks
  • Adding new test cases to improve coverage

How It Works

Tobari records which Goroutine increased the counter by obtaining the Goroutine ID (GID) and Parent Goroutine ID (PGID) when increasing coverage counters. At the same time, when calling the coverage measurement entry function passed to tobari.Cover or tobari.CoverWithName, it creates a Goroutine and records its ID. By tracing Goroutines that have the GID from when coverage measurement started as their parent, it can target only Goroutines related to coverage. To implement this functionality, Tobari passes two options during go build: -cover and -toolexec.

  • -cover: Added to have the Go compiler determine coverage instrumentation targets
  • -toolexec: Hooks execution of Go build tools to dynamically add APIs to the runtime package for obtaining GID and PGID (which are not public APIs), and to embed measurement points that include GID and PGID

These options are output by the tobari flags command, so they can be added to go build options by simply specifying GOFLAGS=$(tobari flags).

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ClearCounters

func ClearCounters()

ClearCounters similar to ClearCounters in runtime/coverage, this resets the currently active counters. It is intended to be called at the start of coverage measurement.

func Cover

func Cover(fn func())

Cover this feature is used to scoped coverage measurement. While `runtime/coverage` measures coverage across entire specified packages, using this feature allows coverage to be measured for specific functions. For example, by implementing this feature in an HTTP server middleware or a gRPC server interceptor, you can measure coverage on a per-method basis for each request.

func CoverWithName

func CoverWithName(name string, fn func())

CoverWithName when measuring coverage, you can assign a name to the measurement scope. By using the WriteCoverprofileByName method when writing out the results, you can filter and output only the coverage data associated with the named measurement target.

func CoverprofileMap added in v0.7.0

func CoverprofileMap(mode Mode) map[string]*Coverprofile

CoverprofileMap if coverage was measured using CoverWithName, it outputs the correspondence between the names and the coverprofile data for each name.

func DisableCoverageCounting added in v0.2.0

func DisableCoverageCounting()

DisableCoverageCounting disables the counting functionality required for calculating coverage. Since it is enabled by default, this is used in scenarios such as production environments where you want to disable the counting logic to avoid performance impact.

func EnableCoverageCounting added in v0.2.0

func EnableCoverageCounting()

EnableCoverageCounting enables the counting functionality necessary for calculating coverage. Since it is enabled by default, it is assumed that this function is called after DisableCoverageCounting has been invoked.

func MergeCoverArchivedFiles added in v0.8.0

func MergeCoverArchivedFiles(inputs []io.Reader, w io.Writer) error

MergeCoverArchivedFiles merges multiple tar.gz source archives into a single archive. Duplicate archives (identical SHA-256 hash) are automatically skipped. If the same file path appears in multiple archives with different content, an error is returned. The output is deterministic: entries are sorted by path and gzip metadata is fixed, so identical inputs always produce identical output.

func ReadCoverArchivedFile added in v0.6.0

func ReadCoverArchivedFile() io.Reader

ReadCoverArchivedFile extracts the original source files embedded during coverage instrumentation and returns them as a tar.gz archive. Returns nil if no sources were embedded. Each embedded source is stored as a gzip-compressed const string in rodata. Decompression and tar construction are streamed via io.Pipe so that only one file's content is in memory at a time. Errors during streaming are reported through the returned io.Reader.

func WriteAllCoverprofile added in v0.7.0

func WriteAllCoverprofile(mode Mode, w io.Writer)

WriteAllCoverprofile uses the coverage counts at the time this method is called to write coverage data for all locations subject to coverage measurement to the provided io.Writer value. Since the data is written in the coverprofile format, you can directly use with `go tool cover`. The resulting data is the same as the data obtained by decoding the output from executing WriteMeta and WriteCounters using runtime/coverage.

func WriteCoverprofile added in v0.7.0

func WriteCoverprofile(mode Mode, w io.Writer)

WriteCoverprofile writes coverprofile data based on the coverage range measured by Cover or CoverWithName. Parts that are not invoked via the Cover or CoverWithName methods are not counted. Also, unreachable ranges are calculated based on the paths that were actually called.

func WriteCoverprofileByName added in v0.7.0

func WriteCoverprofileByName(name string, mode Mode, w io.Writer)

WriteCoverprofileByName it basically works the same as WriteCoverprofile, but additionally allows you to target only the ranges with the specified name.

Types

type CoverReport added in v0.7.0

type CoverReport struct {
	Metadata  CoverReportMetadata `json:"metadata"`
	Counts    []*CoverReportCount `json:"counts"`
	AllCounts []int               `json:"allcounts,omitempty"`
}

CoverReport holds per-test coverage data in a compact format. The struct mirrors the tobari.json schema directly, so json.Marshal produces the compact format without custom marshaling.

func CollectCoverReport added in v0.7.0

func CollectCoverReport() *CoverReport

CollectCoverReport collects the current coverage data measured by CoverWithName and returns it as a CoverReport.

func MergeCoverReports added in v0.8.0

func MergeCoverReports(reports []*CoverReport) (*CoverReport, error)

MergeCoverReports merges multiple CoverReport values into a single unified report. File lists and block definitions are unified with deduplication, block indices in Counts are remapped accordingly, and AllCounts are summed per block.

func (*CoverReport) MarshalTOON added in v0.7.0

func (r *CoverReport) MarshalTOON() ([]byte, error)

MarshalTOON produces human-readable TOON format from the CoverReport.

func (*CoverReport) WriteCoverprofile added in v0.7.0

func (r *CoverReport) WriteCoverprofile(w io.Writer) error

WriteCoverprofile writes the merged coverage data in coverprofile format. All blocks from Metadata.All are included; blocks not covered by any test appear with count=0. If AllCounts is present, it is used directly; otherwise counts from all tests are summed per block.

type CoverReportCount added in v0.7.0

type CoverReportCount struct {
	Name         string  `json:"name"`
	Coverprofile [][]int `json:"coverprofile"`
}

CoverReportCount holds a test name and its coverage entries.

type CoverReportMetadata added in v0.7.0

type CoverReportMetadata struct {
	Files []string `json:"files"`
	Entry []string `json:"entry"`
	All   [][]int  `json:"all"`
}

CoverReportMetadata contains file names, entry column definitions, and all instrumented block definitions.

type Coverprofile added in v0.7.0

type Coverprofile struct {
	// Mode indicates the coverage mode used.
	Mode Mode
	// Entries contains the list of coverage entries.
	Entries []*Entry
}

Coverprofile represents coverage data in coverprofile format.

func CoverprofileByName added in v0.7.0

func CoverprofileByName(name string, mode Mode) *Coverprofile

CoverprofileByName retrieve coverage data for the specified name.

type Entry added in v0.4.0

type Entry struct {
	// FileName is the name of the source file.
	FileName string
	// Start is the starting position of the covered entry.
	Start EntryPos
	// End is the ending position of the covered entry.
	End EntryPos
	// StatementCount is the number of statements in the covered entry.
	StatementCount int
	// Count is the number of times the entry was covered.
	Count int
}

Entry represents a coverage entry for a source file.

type EntryPos added in v0.4.0

type EntryPos struct {
	// Line number in the source file.
	Line int
	// Column number in the source file.
	Column int
}

EntryPos represents a position in a source file.

type Mode

type Mode string

Mode corresponds to the mode in the coverprofile format.

const (
	// SetMode represents `set` mode.
	SetMode Mode = "set"
	// CountMode represents `count` mode.
	CountMode Mode = "count"
	// AtomicMode represents `atomic` mode.
	AtomicMode Mode = "atomic"
)

Directories

Path Synopsis
cmd
tobari command
internal
cli
cover
Package cover implements coverage instrumentation functionality.
Package cover implements coverage instrumentation functionality.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL