Documentation
¶
Index ¶
- func ForceColors() func(Options) Options
- func Gated() func(Options) Options
- func IgnoreSourceFiles(patterns ...string) func(Options) Options
- func Parallel() func(Options) Options
- func Release(t *testing.T, options ...Option)
- func Run(options ...Option) error
- func RunStaged(directory string, excludePrefixes []string, options ...Option) error
- func Verbose() func(Options) Options
- func WithChangedRanges(ranges map[string][]Range) func(Options) Options
- func WithMinimumThreshold(minimumThreshold float32) func(Options) Options
- func WithRepositoryRoot(repositoryRoot string) func(Options) Options
- func WithSandboxStrategy(strategy string) func(Options) Options
- func WithTestCommand(testCommand string) func(Options) Options
- func WithViruses(virus viruses.Virus, rest ...viruses.Virus) func(Options) Options
- type Option
- type Options
- type Range
- type ScoreBelowThresholdError
- type StagedPlan
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ForceColors ¶
ForceColors forces the use of colors in the output. This is useful when running the mutation tests in a CI environment, for example.
func Gated ¶ added in v0.3.0
Gated runs a file's mutants from one compilation instead of one each.
Ditto normally starts the test command once per mutant, and that start costs 750-950 ms whatever the suite does — the dominant cost of a run. With this, the mutants a file can express as one instrumented source are compiled together and selected at run time. Anything that cannot be expressed that way keeps the path it always had, so no mutant is lost by turning it on.
It builds with `go test -c`, so it applies to a Go package and it replaces WithTestCommand for the mutants it takes.
func IgnoreSourceFiles ¶
IgnoreSourceFiles configures regular expressions representing source files to be filtered out and not suffer any mutations.
func Parallel ¶
Parallel indicates whether to run the tests on the mutants in parallel. Given Ditto is executed via Go's testing framework, the level of parallelism can be configured when running the mutation tests. For example, with WithTestCommand(`go test -v -tags=mutation -parallel 3`).
func Release ¶
Release releases the ditto! It infects all source files with viruses that mutate the source code DNA and perform tests to determine whether the mutants survive.
This is the entry point to configure and run mutation tests. You may want to configure it with some options. Here is the available options and their defaults:
- WithRepositoryRoot: `.`
- WithTestCommand: `go test -count=1 ./...`
- WithMinimumThreshold: `1.0`
- Parallel: `false`
- IgnoreSourceFiles: `nil`
- WithViruses: all available (see viruses.Virus' implementations)
The results are then presented in the console. If the mutation score is equal to or above the configured threshold (WithMinimumThreshold), the execution is considered successful. Failed otherwise. Regardless of the execution result, any surviving mutant (no tests failed after applying the source code mutation) will also be presented in the console for analysis.
func Run ¶ added in v0.4.0
Run is the same release without a test binary around it.
Everything a release does — reading the repository, mutating, scoring, reporting — was already free of `testing`: internal/ditto takes a repository, a laboratory and a reporter, and none of them knows what is driving. Only four things in Release ever needed a *testing.T, and this is the same run with other answers for them: cleanup by defer instead of t.Cleanup, an error instead of t.Fail, no subtest per mutant, and verbosity asked for rather than read off `go test`.
It returns the refusal a red baseline panics with rather than letting it through, because a command that panics cannot be told apart from one that broke. Any other panic is still a defect and is re-raised untouched.
func RunStaged ¶ added in v0.4.0
RunStaged mutates exactly what a staged change justifies.
The release is pointed at a checkout of the index rather than at the worktree, and that is the part that must not be dropped. Measured on a fixture built for it: against the worktree, with one tracked file left dirty and unstaged, seven of eight verdicts moved. The staged-file check does not cover that case, because the file that moved them was never staged.
Options are applied after the scope and the root, so a caller can set a threshold or a test command but cannot quietly point the run somewhere else.
func Verbose ¶ added in v0.4.0
Verbose prints what a run is doing as it does it.
Release reads `go test`'s own verbosity as well, because inside a test binary that is where a reader has already said what they want. Run cannot: outside a test binary `testing.Verbose` panics rather than answering, so a caller that wants the same output asks for it here.
func WithChangedRanges ¶ added in v0.2.0
WithChangedRanges restricts the release to the given byte ranges of the given files, keyed by repository-relative path with forward slashes.
This is what makes ditto cheap enough to run while you are still writing the code. Every mutant costs a full run of the test command, so mutating a line the change never touched buys nothing and is charged at the same rate as one that matters.
A file with no entry is not mutated at all. A file with an empty range list is mutated whole.
The ranges are kept per file on purpose, and callers should keep them that way too. A byte offset only means something against the file it was measured in, because each file is parsed on its own and every file's positions start from the same base. Ranges from several files merged into one set make every file answer to all of them: mutants appear in code no diff touched, and the number of them grows as the square of the number of files rather than in proportion to it.
func WithMinimumThreshold ¶
WithMinimumThreshold represents the minimum mutation test score to consider the execution successful. A float between `0.0` and `1.0`.
func WithRepositoryRoot ¶
WithRepositoryRoot configures which directory is the repository root. This is usually required when your mutation test file lives some other place that is not root itself.
func WithSandboxStrategy ¶ added in v0.5.0
WithSandboxStrategy chooses how each file reaches a sandbox: "link", "copy" or "hardlink".
It exists to be measured rather than argued about. A symlink is a reference to a file and not a copy of one, and Go refuses to embed an irregular file, so a package with an embed directive cannot build in a linked sandbox. See docs/experiments/the-sandbox-is-a-reference.md.
func WithTestCommand ¶
WithTestCommand configures the test command to run, as string. You may configure it as you wish, as a `makefile` phony target, for example. Or simply run the standard `go test` command with extra flags, such as `timeout` and `tags`.
Types ¶
type Options ¶
type Options struct {
Repository ditto.Repository
TestRunner laboratory.TestRunner
TemporaryDir laboratory.TemporaryDirectory
MinimumThreshold float32
Parallel bool
IgnoreSourceFilesPatterns []*regexp.Regexp
Viruses []viruses.Virus
ChangedRanges map[string][]Range
Gated bool
Verbose bool
SandboxStrategy string
// RepositoryRoot is kept beside Repository so a later option can rebuild it.
RepositoryRoot string
}
type Range ¶ added in v0.2.0
Range is a half-open byte range within one file: Start is included, End is not. Offsets are counted from the first byte of that file.
type ScoreBelowThresholdError ¶ added in v0.4.0
type ScoreBelowThresholdError struct {
Minimum float32
}
ScoreBelowThresholdError reports a run that finished and did not reach its bar.
It is not the same answer as a refusal: the mutants ran, the number is real, and it is lower than the caller asked for.
func (ScoreBelowThresholdError) Error ¶ added in v0.4.0
func (e ScoreBelowThresholdError) Error() string
type StagedPlan ¶ added in v0.4.0
type StagedPlan struct {
// Root is the repository the plan was read from.
Root string
// Files are the staged sources worth mutating, repository-relative with
// forward slashes.
Files []string
// Ranges is the scope, keyed by file. A file mapped to no ranges is mutated
// whole, which is what failing open means.
Ranges map[string][]Range
// Derived is false when the diff could not be turned into byte ranges and
// the plan fell back to whole files. Reason then says why.
Derived bool
Reason string
}
StagedPlan is what a staged change justifies mutating, before anything runs.
func PlanStaged ¶ added in v0.4.0
func PlanStaged(directory string, excludePrefixes []string) (StagedPlan, error)
PlanStaged answers what a staged change justifies, and changes nothing.
It is the whole of `--dry`: the question "what would this cost" is worth asking on its own, and answering it must not write a sandbox or start a suite.
func (StagedPlan) Mutable ¶ added in v0.4.0
func (p StagedPlan) Mutable() bool
Mutable reports whether there is anything to do.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
ditto
command
Command ditto runs mutation testing from a shell instead of from a test.
|
Command ditto runs mutation testing from a shell instead of from a test. |
|
internal
|
|
|
gatedlaboratory
Package gatedlaboratory runs a file's mutants from one compilation.
|
Package gatedlaboratory runs a file's mutants from one compilation. |
|
gatedreporter
Package gatedreporter says how much of a run came from one compilation.
|
Package gatedreporter says how much of a run came from one compilation. |
|
gobuildrunner
Package gobuildrunner runs a package's tests from a binary it builds itself, once, instead of invoking `go test` for every mutant.
|
Package gobuildrunner runs a package's tests from a binary it builds itself, once, instead of invoking `go test` for every mutant. |
|
perfbench
Package perfbench holds ditto's performance contract.
|
Package perfbench holds ditto's performance contract. |
|
schemata
Package schemata turns per-mutant source files into one instrumented file that selects a mutant at run time, so a release compiles once instead of once per mutant.
|
Package schemata turns per-mutant source files into one instrumented file that selects a mutant at run time, so a release compiles once instead of once per mutant. |
|
staged
Package staged answers three questions about a change that is staged but not committed: which files it touches, which bytes of them, and which bytes the suite should be run against.
|
Package staged answers three questions about a change that is staged but not committed: which files it touches, which bytes of them, and which bytes the suite should be run against. |