How zimmski/go-mutesting works
1. Purpose and scope
- This repo is a Go mutation-testing framework and CLI, not an application service.
- Its core job is to take Go source targets, generate small source-level mutations, run tests against each mutant, and report which changes survive.
2. Top-level execution path
- The binary entrypoint is cmd/go-mutesting/main.go.
- Users pass files, directories, or package patterns; the tool resolves those targets, finds Go source files, generates mutations, runs an exec command for each mutation, and aggregates a mutation score.
3. Source discovery and parsing boundary
- parse.go and walk.go handle repository-wide source selection and AST traversal.
- The tool explicitly excludes _test.go files from mutation targets so the test harness itself is not mutated.
- This layer is the boundary between filesystem/package resolution and AST-level mutation generation.
4. AST utility layer
- astutil/ contains helpers for creating and querying AST nodes.
- These helpers support mutator implementation by making it easier to inspect and rewrite syntax trees without duplicating AST plumbing.
5. Mutation framework core
- mutator/ defines the mutation abstraction and registry used by the CLI.
- mutator/mutator.go provides the interface and registration mechanism for plugging in new mutators.
- mutator/mutation.go represents a specific mutation instance, including the original location and the changed source.
6. Concrete mutator families
- The mutators are organized by syntax category:
- mutator/branch/: empties if, else, and case blocks.
- mutator/expression/: changes comparison operators and removes boolean-expression terms.
- mutator/statement/: removes assignments, increments/decrements, and expression statements.
- This structure mirrors the syntax tree and makes it easy to reason about what kind of code is being attacked.
7. Mutation generation model
- Mutations are generated from AST nodes, not by string substitution.
- That means the framework aims to produce syntactically valid mutants tied to real language constructs, reducing invalid edits and making patches meaningful.
8. Test execution boundary
- The framework does not hardcode one testing strategy.
- A mutation is applied, then an exec command is invoked to determine whether that mutant is “killed,” “alive,” or skipped.
- The built-in behavior is to replace the file, run the package tests, and restore/clean up afterward.
9. External exec command contract
- scripts/exec/ contains sample shell scripts that implement the mutation-test lifecycle for Go projects.
- The README documents the environment variables passed to these commands, such as the original and changed file paths, package import path, timeout, and verbosity flags.
- This isolates the mutation engine from the actual test runner implementation.
10. Results, diffing, and scoring
- For surviving mutants, the tool prints the patch so engineers can inspect what was not covered by tests.
- It also computes a mutation score from killed vs total mutants.
- A checksum-based blacklist can suppress known false positives, though the README notes this mechanism is brittle if source changes.
11. Example and golden test assets
- example/ is a small package used to demonstrate the CLI and verify end-to-end behavior.
- testdata/ contains many golden mutated outputs for branch, expression, and statement mutators.
- The large set of numbered *.go fixtures indicates the project uses snapshot-style tests to validate exact mutation output.
12. Automated verification and repo hygiene
- Each mutator has dedicated unit tests alongside its implementation.
- cmd/go-mutesting/main_test.go, parse_test.go, and mutator/*_test.go validate the framework pieces.
- travis config, Makefile, and shell scripts suggest standard CI/lint/test automation around the CLI and mutator suite.
13. Architecture summary for a diagram
- Draw this as a pipeline: target resolution → AST parsing/traversal → mutator registry and concrete mutators → mutation materialization to temp files → external test exec → result reporting/scoring.
- The main boundaries are: source discovery vs AST rewriting, mutation generation vs test execution, and core engine vs external exec scripts.
Main entry points: mutator.go Mutator API · mutateif.go Mutate if · testdata Golden outputs · main.go go-mutesting
Components 19
CLI entrypoint
Command-line interface and target resolution
- go-mutesting · Main command that drives mutation testing
cmd/go-mutesting/main.go
Mutation engine
Parsing, traversal, mutation orchestration, and reporting
- Parse targets · Resolves files, directories, and package patterns into Go sources
parse.go - AST walk · Traverses parsed source and finds mutation points
walk.go - Mutator API · Defines mutation interfaces and registration
mutator/mutator.go - Mutation model · Represents a specific mutant and its source replacement
mutator/mutation.go - Apply and run · Materializes a mutant, invokes tests, and restores state
- Score report · Aggregates killed, alive, skipped mutants and prints surviving patches
Mutator families
Concrete AST mutation strategies
- Mutate if · Empties if blocks
mutator/branch/mutateif.go - Mutate else · Empties else blocks
mutator/branch/mutateelse.go - Mutate case · Empties case blocks
mutator/branch/mutatecase.go - Compare ops · Changes comparison operators
mutator/expression/comparison.go - Bool remove · Removes boolean expression terms
mutator/expression/remove.go - Stmt remove · Removes assignments, increments, and expression statements
mutator/statement/remove.go
Support code
AST helpers and test harness utilities
- AST create · Builds AST nodes for mutation implementations
astutil/create.go - AST query · Inspects and matches AST nodes for mutators
astutil/query.go
Examples and fixtures
Demonstration package and golden mutation outputs
- Example app · Small package used for CLI demonstration and end-to-end checks
example/example.go - Golden outputs · Snapshot mutated files for branch, expression, and statement mutators
testdata
Scripts
External exec and CI helpers
- Exec scripts · Sample shell scripts that implement the mutation-test lifecycle
scripts/exec - Lint and CI · Project scripts and CI wiring for validation
scripts/lint.sh
Connections 21
- go-mutesting → Parse targets: resolve targets · CLI turns user input into mutation targets
- Parse targets → AST walk: parse source · Discovered files are parsed and traversed
- AST walk → Mutator API: emit candidates · Traversal identifies AST nodes that mutators can handle
- Mutator API → Mutate if: registers · Registry exposes concrete mutators
- Mutator API → Mutate else: registers · Registry exposes concrete mutators
- Mutator API → Mutate case: registers · Registry exposes concrete mutators
- Mutator API → Compare ops: registers · Registry exposes concrete mutators
- Mutator API → Bool remove: registers · Registry exposes concrete mutators
- Mutator API → Stmt remove: registers · Registry exposes concrete mutators
- AST create → Mutate if: supports · AST construction helpers used by mutators
- AST query → Mutate if: supports · AST query helpers used by mutators
- AST create → Compare ops: supports · AST construction helpers used by mutators
- AST query → Bool remove: supports · AST query helpers used by mutators
- Mutation model → Apply and run: materialized by · Mutation instances are applied to files for execution
- Apply and run → Exec scripts: invokes · External scripts execute package tests against the mutant
- Apply and run → Score report: feeds results · Execution outcome is aggregated into score and patches
- Example app → go-mutesting: exercise · Example package demonstrates the CLI path
- Golden outputs → Mutate if: verifies · Golden fixtures validate branch mutator output
- Golden outputs → Compare ops: verifies · Golden fixtures validate expression mutator output
- Golden outputs → Stmt remove: verifies · Golden fixtures validate statement mutator output
- Lint and CI → go-mutesting: checks · Automation runs tests and lint around the CLI