1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! Internal implementation library for [`cargo-gamma`](https://crates.io/crates/cargo-gamma).
//!
//! This crate is an implementation detail. Do not depend on it: it may change in incompatible
//! ways without warning, and it carries no semver commitment to anything it exposes.
//
// Everything cargo-gamma does, apart from talking to the real terminal.
//
// The `cargo-gamma` binary is a few dozen lines that implement `Host` and call `run`. Code in a
// `[[bin]]` target cannot be linked by an integration test, so putting anything here that could
// live in a library would be putting it somewhere no test can reach — an unusually bad trade for a
// tool whose subject is test quality.
//
// # What the tool does
//
// Conventional mutation testing rebuilds the crate under test once per mutant. A workspace with ten
// thousand mutants and a ninety-second build spends ten days building and a few minutes testing.
//
// cargo-gamma builds **once**. Every selected mutant is compiled into the same set of test binaries
// as a *guard* — a branch, taken only when that mutant's ordinal matches the one named by the
// `GAMMA_ACTIVE` environment variable:
//
// original: a < b
// instrumented: (if ::gamma_rt::a(7u32) { (a) <= (b) } else { a < b })
//
// This is the *mutant schema*: one artifact encoding the whole population, with the choice deferred
// from compile time to process start. Testing a mutant then costs one process launch instead of one
// build, and the guard itself costs a cached atomic load and a branch the CPU learns immediately.
//
// # The pipeline
//
// A run moves through these stages, in order. Each module names one of them.
//
// | Stage | Module | What it produces |
// |---|---|---|
// | Command line | `commands` | The parsed request, folded together with the config file |
// | Configuration | `config` | `gamma.toml`, with precedence against the command line decided in one place |
// | Enumeration | `discover` | Workspace packages, source files, the shard slice, and which package can reach which |
// | Parsing | `parse` | An AST with byte-accurate spans, plus the comment trivia suppression needs |
// | Definition | `ops` | Source-level mutant definitions from the mutator registry — the catalog of what can be changed |
// | Suppression | `suppress` | The mutants withdrawn by an attribute, a comment directive, or a config rule |
// | Identity | `model` | Content-addressed mutant IDs, outcomes, and the score they roll up into |
// | Instrumentation | `schema` | The rewritten sources, the guard for each mutant, and the rollback loop that withdraws whatever will not compile |
// | Execution | `exec` | The scratch tree with the guard runtime vendored into it, one build, a measured baseline, then every mutant run in parallel under a timeout and a stall detector |
// | Projection | `report`, `elements`, `html`, `ci` | Console output, the `mutation-testing-elements` document, a self-contained page, and SARIF plus CI annotations |
//
// The `vendor` directory beside these modules is not one: it holds the report viewer and the report
// schema, embedded so that an HTML report opens on a machine with no network at all.
//
// The rest stand beside the pipeline rather than inside it:
//
// - `estimate`: stops a run at the point it would stop measuring and start waiting, and projects
// the rest — so a four-hour job is discovered in the first minute rather than the last.
// - `advise`: turns a finished run into findings, each with a measured symptom, a remedy, and what
// the remedy costs in signal. This is what the advice artifact and CI job summary carry.
// - `fix`: plans and applies the source edits behind the `suppress` command.
// - `merge`: combines per-shard reports into one score, so a nightly job covering a slice at a time
// still adds up to an answer about the whole workspace.
// - `bounds`: the timeout arithmetic — baseline, multiplier, floor — kept in one place so that
// every command sizes a budget the same way.
// - `diag`: the hidden `--diag` dump, which reports where a run's wall clock actually went. It
// exists for developing this tool, not for using it.
// - `error`: the error type, its cause chain, and the usage-versus-failure distinction that picks
// the exit code.
//
// # Conventions
//
// - Every fallible path returns [`Result`], whose error carries a cause chain and knows whether it
// is a usage error, because that distinction is what picks the process exit code.
// - Nothing writes to `stdout` or `stderr` directly; everything goes through [`Host`], which is
// what makes the console UI, the color decisions and the exit codes ordinary assertions in a
// test rather than things verified by eye.
// - Hash maps are `rustc_hash`, not the standard library's. The keys are mutant IDs, paths and
// package names this run produced, and the cost of a DoS-resistant hash on several hundred
// thousand of them is not worth paying for keys nobody outside the run chooses. The one exception
// is `merge`, which decodes a document it did not write into a map keyed by the file names that
// document states — a crafted report can make those collide, and the worst it buys is a slow
// `merge` on a local CLI the user pointed at the file themselves. That is a trade the read path
// makes knowingly rather than an invariant it upholds.
/// The result type used throughout the crate.
///
/// The error carries a cause chain and knows whether it is a usage error, which is what decides
/// the process exit code.
pub type Result<T, E = Error> = Result;
use ;
pub type HashMap<K, V> = ;
pub type HashSet<V> = ;
// Every module below is declared twice, under opposite halves of the `internals` feature. Private
// is the shape that matters: this library has exactly one consumer, the `cargo-gamma` binary, so an
// item nothing here uses is genuinely dead, and only a private module tree lets rustc see that. The
// `internals` facade cannot name a private module — a `pub use` of one is a hard error rather than
// a lint — so the feature that opens the facade is also what widens these declarations, and the
// facade then re-exports them by name instead of by glob.
//
// Written out rather than generated, because rustfmt and every `syn`-based tool (cargo-gamma
// included) find sources by resolving file-bearing `mod` declarations, and a `mod` produced by a
// macro is invisible to them.
/// Runs the deterministic concurrency models selected by the dedicated Loom test target.
/// Re-exports the crate internals for the crate's own integration tests.
///
/// The modules above are declared privately whenever this feature is off, which is what keeps the
/// dead-code analysis honest. This library has exactly one consumer, the `cargo-gamma` binary, so
/// an item nothing here uses is genuinely dead — but a `pub` module makes it look like a deliberate
/// part of a public API some external crate might call, and the analysis goes quiet. Only a private
/// module tree lets rustc see the truth.
///
/// Integration tests reach directly into the internals and test them at the level they are designed
/// at, with no `pub(crate)` escape hatches and no `#[cfg(test)]` re-exports widening the API
/// surface. They compile as separate crates and so cannot see a private module; this facade opens
/// exactly the same paths for them, under `internals::`, and nothing else. The `internals` feature
/// is a required feature of those test targets, so Cargo skips them unless the test command
/// explicitly enables it.
///
/// Each module is named individually rather than glob-re-exported. A glob would take on whatever
/// the module gains next, silently and without review; naming the module itself re-exports the same
/// set of paths while keeping the list of what the facade offers readable in one place.
///
/// The facade declares no file-bearing modules, which is what lets it stay a macro. rustfmt and
/// every `syn`-based tool — cargo-gamma among them — find sources by resolving file-bearing `mod`
/// declarations to a path on disk, and a `mod` produced by a macro is invisible to them. There are
/// no such declarations here, so hiding this behind a macro costs those tools nothing.
///
/// It is gated on a feature rather than on `debug_assertions` because `cargo test --release` turns
/// `debug_assertions` off while still building the integration tests, which then fail to compile.
expose_internals!;
/// Shared test fixtures, reachable from the integration tests as well as the unit tests.
///
/// Gated the same way as the modules above rather than on `cfg(test)` alone, because `tests/`
/// compiles as a separate crate and cannot see anything a `cfg(test)` gate creates. Without this
/// the integration tests would need their own copy of every fixture.
pub use crate;