supercov 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -22
- package/docs/agent-loop.md +8 -13
- package/docs/assertions.md +161 -75
- package/docs/cli.md +111 -59
- package/docs/coverage-model.md +5 -6
- package/docs/evidence.md +0 -11
- package/docs/getting-started.md +1 -1
- package/docs/performance.md +6 -14
- package/docs/quality.md +1 -1
- package/docs/security.md +43 -12
- package/docs/supported-suites.md +44 -48
- package/docs/troubleshooting.md +12 -5
- package/docs/workspace-isolation.md +23 -2
- package/package.json +36 -21
- package/runtime/javascript/atomic.mjs +46 -2
- package/runtime/javascript/ava.mjs +82 -0
- package/runtime/javascript/bootstrap.cjs +43 -0
- package/runtime/javascript/jest.cjs +52 -15
- package/runtime/javascript/jest.config.mjs +9 -1
- package/runtime/javascript/jestReporter.mjs +5 -6
- package/runtime/javascript/launchSupervisor.mjs +127 -15
- package/runtime/javascript/mocha.mjs +180 -0
- package/runtime/javascript/nodeTest.mjs +57 -3
- package/runtime/javascript/playwright.mjs +241 -32
- package/runtime/javascript/provenance.mjs +1 -1
- package/runtime/javascript/register.mjs +290 -2
- package/runtime/javascript/resolve-loader.mjs +40 -1
- package/runtime/javascript/runnerEvidence.mjs +3 -5
- package/runtime/javascript/runtime.mjs +551 -61
- package/runtime/javascript/tap.mjs +130 -0
- package/runtime/javascript/transport.mjs +7 -2
- package/runtime/javascript/vitest.mjs +5 -8
- package/runtime/javascript/vitestReporter.mjs +3 -10
- package/docs/assertion-agent.md +0 -150
- package/docs/assertion-evidence.md +0 -103
- package/docs/assertion-maps.md +0 -316
- package/schemas/assertions.schema.json +0 -276
package/docs/cli.md
CHANGED
|
@@ -17,8 +17,11 @@ npx supercov --help
|
|
|
17
17
|
| Read the newest run | `npx supercov runs latest` |
|
|
18
18
|
| Find useful gaps | `npx supercov runs latest gaps` |
|
|
19
19
|
| Inspect one file | `npx supercov runs latest file <path>` |
|
|
20
|
-
|
|
|
21
|
-
|
|
|
20
|
+
| See how much executed code the tests assert | `npx supercov runs latest assertions` |
|
|
21
|
+
| Assess it with Jev | `npx supercov runs latest assertions assess` |
|
|
22
|
+
| Find what is not asserted in one file | `npx supercov runs latest assertions <path>` |
|
|
23
|
+
| See each test's answer for one statement | `npx supercov runs latest assertions <path>:<line>` |
|
|
24
|
+
| See what one test is judged to catch | `npx supercov runs latest assertions --test <name>` |
|
|
22
25
|
| Read matching current source code | `npx supercov runs latest source <path>` |
|
|
23
26
|
| Compare two runs | `npx supercov diff <older> <newer>` |
|
|
24
27
|
| Open an interactive report | `npx supercov report` |
|
|
@@ -36,17 +39,17 @@ npx supercov --help
|
|
|
36
39
|
## Assess source quality
|
|
37
40
|
|
|
38
41
|
```sh supercov-example
|
|
39
|
-
supercov quality # this repository
|
|
40
|
-
supercov quality src/ # one directory
|
|
41
|
-
supercov quality gaps # only files something fired on
|
|
42
|
-
supercov quality file src/a.ts # one file, every check
|
|
43
|
-
supercov quality scope # which files are assessed, and why
|
|
44
|
-
supercov quality snapshots # saved assessments
|
|
45
|
-
supercov quality diff <older> <newer>
|
|
46
|
-
supercov security # twelve security checks, every file
|
|
47
|
-
supercov security gaps # only files something fired on
|
|
48
|
-
supercov security patch --base origin/main
|
|
49
|
-
supercov security --run latest # flagged files no test exercises
|
|
42
|
+
npx supercov quality # this repository
|
|
43
|
+
npx supercov quality src/ # one directory
|
|
44
|
+
npx supercov quality gaps # only files something fired on
|
|
45
|
+
npx supercov quality file src/a.ts # one file, every check
|
|
46
|
+
npx supercov quality scope # which files are assessed, and why
|
|
47
|
+
npx supercov quality snapshots # saved assessments
|
|
48
|
+
npx supercov quality diff <older> <newer>
|
|
49
|
+
npx supercov security # twelve security checks, every file
|
|
50
|
+
npx supercov security gaps # only files something fired on
|
|
51
|
+
npx supercov security patch --base origin/main
|
|
52
|
+
npx supercov security --run latest # flagged files no test exercises
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
With no argument the subject is the repository you are standing in. Every
|
|
@@ -74,9 +77,9 @@ number is worth and which files get assessed.
|
|
|
74
77
|
## Review what a change introduced
|
|
75
78
|
|
|
76
79
|
```sh supercov-example
|
|
77
|
-
supercov quality patch
|
|
78
|
-
supercov quality patch --base origin/main
|
|
79
|
-
supercov quality patch --base origin/main --annotate github --run latest
|
|
80
|
+
npx supercov quality patch
|
|
81
|
+
npx supercov quality patch --base origin/main
|
|
82
|
+
npx supercov quality patch --base origin/main --annotate github --run latest
|
|
80
83
|
```
|
|
81
84
|
|
|
82
85
|
The same twelve properties asked of a change, plus six risk checks that only
|
|
@@ -146,8 +149,7 @@ npx supercov runs <run-id> [query] [options]
|
|
|
146
149
|
| `kinds` | Group coverage by test level, such as unit or E2E |
|
|
147
150
|
| `runners` | Group coverage by test runner |
|
|
148
151
|
| `scope` | Review included, excluded, and ambiguous source files |
|
|
149
|
-
| `assertions` |
|
|
150
|
-
| `assertion <id>` | Inspect one assertion and its authored flows |
|
|
152
|
+
| `assertions` | Read the share of executed statements the tests assert, and the ones they do not; `assertions assess` works it out |
|
|
151
153
|
| `source <path>` | Read matching current project source with line numbers |
|
|
152
154
|
| `minimize` | Find a small test subset that preserves a coverage target |
|
|
153
155
|
|
|
@@ -169,46 +171,34 @@ npx supercov runs latest file --help
|
|
|
169
171
|
npx supercov runs latest assertions --help
|
|
170
172
|
```
|
|
171
173
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
source changes to inherit the map into a new run.
|
|
174
|
+
`source <path>` reads the matching current file directly. It prints source code
|
|
175
|
+
with line numbers, preserving indentation; add `--json` only when you want
|
|
176
|
+
structured `{line, text}` items. `--offset` is zero-based and `--limit` controls
|
|
177
|
+
the number of source lines. The file must still match the run; rerun the suite
|
|
178
|
+
after source changes.
|
|
178
179
|
|
|
179
180
|
### Assertion coverage
|
|
180
181
|
|
|
181
|
-
The regular run summary includes assertion coverage when a map has been
|
|
182
|
-
assessed. JSON reports expose it under `data.assertionCoverage`. Start with
|
|
183
|
-
[Understanding assertion coverage](assertions.md), or use these commands to
|
|
184
|
-
inspect and check a map:
|
|
185
|
-
|
|
186
182
|
```sh supercov-example
|
|
187
|
-
npx supercov runs <run-id> assertions --
|
|
188
|
-
npx supercov runs <run-id>
|
|
189
|
-
npx supercov runs <run-id> assertions
|
|
190
|
-
npx supercov runs <run-id> assertions
|
|
191
|
-
npx supercov runs <run-id> assertions validate --json
|
|
192
|
-
npx supercov runs <run-id> assertions check --require-mappings
|
|
183
|
+
npx supercov runs <run-id> assertions assess --dry-run
|
|
184
|
+
npx supercov runs <run-id> assertions assess
|
|
185
|
+
npx supercov runs <run-id> assertions
|
|
186
|
+
npx supercov runs <run-id> assertions --all --json
|
|
193
187
|
```
|
|
194
188
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
to the assertion detail command. `--compact` omits repeated source text from the
|
|
203
|
-
report. Follow the printed next-page command or JSON `pagination.nextOffset`.
|
|
204
|
-
Validation supports `--view flows`, `--view changes` and `--view errors` for large
|
|
205
|
-
maps. The [map reference](assertion-maps.md) describes all fields and gates.
|
|
189
|
+
`assertions assess` asks Jev, test by test, whether each statement the test ran
|
|
190
|
+
would make it fail if changed, and saves the result to the run; it needs
|
|
191
|
+
`TYPESAFE_API_KEY` for questions not answered before. `assertions` reads the
|
|
192
|
+
saved result without the network. The regular run summary shows the same share,
|
|
193
|
+
and JSON reports expose it under `data.assertionCoverage`. See
|
|
194
|
+
[Assertion coverage](assertions.md) for what counts as asserted and how answers
|
|
195
|
+
are reused across runs.
|
|
206
196
|
|
|
207
197
|
## Fail CI below a coverage floor
|
|
208
198
|
|
|
209
199
|
```sh supercov-example
|
|
210
|
-
supercov runs check --min-lines 90 --min-branches 80 --min-mcdc 80
|
|
211
|
-
supercov runs check --min-lines 100 --per-file --json
|
|
200
|
+
npx supercov runs check --min-lines 90 --min-branches 80 --min-mcdc 80
|
|
201
|
+
npx supercov runs check --min-lines 100 --per-file --json
|
|
212
202
|
```
|
|
213
203
|
|
|
214
204
|
`check` reads a recorded run; it never runs tests again. Give a floor per metric
|
|
@@ -231,16 +221,11 @@ rather than a pass or a failure:
|
|
|
231
221
|
- a requested metric left obligations unmeasured, so no exact judgement exists
|
|
232
222
|
- a requested metric is not recorded by the language adapter
|
|
233
223
|
|
|
234
|
-
Assertion coverage keeps its own check. Whether a test *examines* what it
|
|
235
|
-
executes is a different question from whether a line ran, and
|
|
236
|
-
`runs <id> assertions check` carries the freshness and acknowledgement rules
|
|
237
|
-
that answer needs.
|
|
238
|
-
|
|
239
224
|
## Check the lines a change touches
|
|
240
225
|
|
|
241
226
|
```sh supercov-example
|
|
242
|
-
supercov runs patch --base origin/main --min-lines 100
|
|
243
|
-
supercov runs patch --base origin/main --annotate github
|
|
227
|
+
npx supercov runs patch --base origin/main --min-lines 100
|
|
228
|
+
npx supercov runs patch --base origin/main --annotate github
|
|
244
229
|
```
|
|
245
230
|
|
|
246
231
|
`patch` answers whether the lines this change added or modified are tested. It
|
|
@@ -267,9 +252,9 @@ needs no token and posts no comment.
|
|
|
267
252
|
## Export for other tools
|
|
268
253
|
|
|
269
254
|
```sh supercov-example
|
|
270
|
-
supercov runs report --format lcov --output coverage/lcov.info
|
|
271
|
-
supercov runs report --format cobertura --output coverage/cobertura.xml
|
|
272
|
-
supercov runs report --format html --output coverage/report
|
|
255
|
+
npx supercov runs report --format lcov --output coverage/lcov.info
|
|
256
|
+
npx supercov runs report --format cobertura --output coverage/cobertura.xml
|
|
257
|
+
npx supercov runs report --format html --output coverage/report
|
|
273
258
|
```
|
|
274
259
|
|
|
275
260
|
Both are written from the same view `check` and `patch` read, so a viewer,
|
|
@@ -401,11 +386,72 @@ neither do comments, blank lines or trailing whitespace. A test that did not
|
|
|
401
386
|
pass in the run is listed regardless.
|
|
402
387
|
|
|
403
388
|
`--names` prints one affected test name per line and `--files` one test file
|
|
404
|
-
per line, for a runner's filter. A
|
|
389
|
+
per line, for a runner's filter. A Vitest, Playwright or node:test test inside
|
|
390
|
+
`describe` blocks is printed as the blocks and the test joined by spaces
|
|
391
|
+
(`small charges`), which is what `vitest -t`, `--grep` and
|
|
392
|
+
`--test-name-pattern` match. A dependency, lockfile, configuration or
|
|
405
393
|
toolchain change affects every test and is reported as such. A source file
|
|
406
394
|
added since the run is outside every test's record; the working-tree check
|
|
407
395
|
says so, and the suite should run in full.
|
|
408
396
|
|
|
397
|
+
### Which affected tests check the change
|
|
398
|
+
|
|
399
|
+
When the run has an [assertion assessment](assertions.md), `tests affected`
|
|
400
|
+
also says, for each affected test, whether it was judged to catch a change to
|
|
401
|
+
the statements that changed in code it ran, and lists those tests first. A run
|
|
402
|
+
without an assessment answers from coverage alone, as above.
|
|
403
|
+
|
|
404
|
+
```sh supercov
|
|
405
|
+
npx supercov runs latest assertions assess # once, on the run
|
|
406
|
+
# ... edit code ...
|
|
407
|
+
npx supercov runs latest assertions assess --changed # ask every test that ran the changed code
|
|
408
|
+
npx supercov runs latest tests affected --names --ran-changed
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
The assessment stops asking about a statement once one test catches it, so on
|
|
412
|
+
its own it knows only some tests' answers. `assess --changed` asks, for the
|
|
413
|
+
statements in code changed since the run, every test that ran them: typically
|
|
414
|
+
a few requests per commit. After it, `--ran-changed` leaves out the affected
|
|
415
|
+
tests that ran the changed declaration but none of the changed statements, and
|
|
416
|
+
`--asserting` also those judged to catch no change to them. Tests whose own
|
|
417
|
+
file changed or that did not pass stay, and so does any test never asked. With
|
|
418
|
+
an assessment or without, `--names` and `--files` list first the tests whose
|
|
419
|
+
own file or name shares words with a changed file (`test_receivebuffer.py` for
|
|
420
|
+
`_receivebuffer.py`), the verdicts breaking ties.
|
|
421
|
+
|
|
422
|
+
Measured by applying random changes and running the suite:
|
|
423
|
+
|
|
424
|
+
| Project | Breaking changes (failing tests) | Coverage's set | `--ran-changed` | `--asserting` | A failing test in the first three |
|
|
425
|
+
| --- | --- | --- | --- | --- | --- |
|
|
426
|
+
| h11 (Python, 78 tests) | 23 (153) | all 153 in 28 tests | all 153 in 23.5 | 141 in 19.9 | 18 of 23 |
|
|
427
|
+
| go-version (Go, 31 tests) | 36 (140) | all 140 in 10.1 | all 140 in 9.8 | 133 in 9.4 | 32 of 36 |
|
|
428
|
+
|
|
429
|
+
`--ran-changed` never dropped a failing test; `--asserting` dropped 5 to 8% of
|
|
430
|
+
them. `assess --changed` cost about a tenth of a cent per change.
|
|
431
|
+
|
|
432
|
+
Measured on real history: at each of a project's recent commits, the source
|
|
433
|
+
the commit replaced was put back -- someone reintroducing what it fixed -- and
|
|
434
|
+
the commit's own tests run against it:
|
|
435
|
+
|
|
436
|
+
| Project | Commits (breaking) | Failing tests | Kept by coverage's set | Kept by `--asserting` | Tests selected (coverage / `--asserting`) of all |
|
|
437
|
+
| --- | --- | --- | --- | --- | --- |
|
|
438
|
+
| h11 (Python) | 60 (13) | 27 | 27 | 27 | 25.2 / 24.9 of 75 |
|
|
439
|
+
| go-version (Go) | 24 (2) | 3 | 3 | 3 | 15.2 / 14.1 of 25 |
|
|
440
|
+
| dry-inflector (Ruby) | 12 (7) | 26 | 26 | 26 | 813 / 718 of 1,109 |
|
|
441
|
+
| uuid (TypeScript, node:test) | 4 (3) | 6 | 6 | 6 | 13.2 / 11.5 of 64 |
|
|
442
|
+
| dtolnay/semver (Rust) | 20 (0) | 0 | -- | -- | 27.9 / 25.9 of 38 |
|
|
443
|
+
| commons-cli (Java) | 15 (7) | 12 | 12 | 12 | 159 / 143 of 985 |
|
|
444
|
+
|
|
445
|
+
No failing test was left out of the set to run. On real commits the
|
|
446
|
+
assessment narrows little -- Jev judges most tests that ran a changed line to
|
|
447
|
+
catch the change -- and its verdicts alone ranked a failing test in the first
|
|
448
|
+
three for only 6 of 32 breaking commits. Ranking by name, with the verdicts
|
|
449
|
+
breaking ties, put one there for 10 of those 32, and for 15 of 25 breaking
|
|
450
|
+
commits in four projects it was not designed on (hashie, Masterminds/semver,
|
|
451
|
+
itsdangerous, java-classmate), where file order managed 11; without an
|
|
452
|
+
assessment, name alone managed 8 and 12. After a project's first
|
|
453
|
+
assessment, each commit cost under a cent.
|
|
454
|
+
|
|
409
455
|
## Combine shards
|
|
410
456
|
|
|
411
457
|
```sh supercov
|
|
@@ -461,6 +507,7 @@ terminal or offline environment after the package has been downloaded.
|
|
|
461
507
|
| --- | --- |
|
|
462
508
|
| `SUPERCOV_SOURCE_ROOTS` | Comma-separated directories or files that hold your own code, in any language; everything else is left out |
|
|
463
509
|
| `SUPERCOV_TEST_KIND` | Label the wrapped command as a test level such as `unit` or `e2e` |
|
|
510
|
+
| `SUPERCOV_BUILD_COMMAND` | The build a JavaScript project's tests need, as words or a JSON array, such as `yarn workspace web build` in a monorepo whose root `build` builds every package. Without it Supercov runs the project's `build` script, through the package manager that started the tests, when the tests need built output |
|
|
464
511
|
|
|
465
512
|
Examples:
|
|
466
513
|
|
|
@@ -477,3 +524,8 @@ SUPERCOV_TEST_KIND=e2e npx supercov -- npx playwright test
|
|
|
477
524
|
| Wrapped command's code | The test command failed and Supercov preserved its status |
|
|
478
525
|
| `1` | A valid measurement failed a policy you set, such as a coverage floor |
|
|
479
526
|
| `2` | Supercov could not complete the request, or the evidence cannot answer it |
|
|
527
|
+
|
|
528
|
+
`quality` and `security` exit `0` for a complete report in which some files
|
|
529
|
+
could not be assessed, such as a file larger than the model accepts; each is
|
|
530
|
+
listed in the report with its reason, and stderr says how many. They exit `2`
|
|
531
|
+
when no file could be assessed.
|
package/docs/coverage-model.md
CHANGED
|
@@ -150,9 +150,8 @@ or generated output merely to make a warning disappear.
|
|
|
150
150
|
|
|
151
151
|
## Assertion percentage
|
|
152
152
|
|
|
153
|
-
When a run has
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
independently of `--filter`, `--kind` and `--runner
|
|
157
|
-
structural metrics above. See [assertion
|
|
158
|
-
freshness and incomplete-map rules.
|
|
153
|
+
When a run has been assessed with `assertions assess`, its regular summary also
|
|
154
|
+
shows assertion coverage: executed statements a test is judged to catch
|
|
155
|
+
breaking, divided by all assessed statements. This row always describes the
|
|
156
|
+
whole run, independently of `--filter`, `--kind` and `--runner`, and is separate
|
|
157
|
+
from the structural metrics above. See [assertion coverage](assertions.md).
|
package/docs/evidence.md
CHANGED
|
@@ -134,14 +134,3 @@ SUPERCOV_TEST_KIND=integration npx supercov -- npm test
|
|
|
134
134
|
|
|
135
135
|
Supported values are `unit`, `component`, `integration` and `e2e`. Use separate
|
|
136
136
|
runs when different suites need different classifications.
|
|
137
|
-
|
|
138
|
-
## When assertion evidence is missing
|
|
139
|
-
|
|
140
|
-
A test can make assertions without executing measured application code. It
|
|
141
|
-
might check static data or a dependency, or use work performed in shared setup.
|
|
142
|
-
Missing attribution across an asynchronous boundary can also leave a gap.
|
|
143
|
-
|
|
144
|
-
The assertion detail explains why a mapped node did or did not receive credit.
|
|
145
|
-
Use [Investigating assertion evidence](assertion-evidence.md) to distinguish
|
|
146
|
-
these cases. The report's runtime action-phase counts are separate from the
|
|
147
|
-
assertion map; zero action-phase lines does not mean zero asserted statements.
|
package/docs/getting-started.md
CHANGED
|
@@ -139,7 +139,7 @@ if anything is missing.
|
|
|
139
139
|
- for Go, Go 1.22 or newer;
|
|
140
140
|
- for Java and Kotlin, JDK 17 or newer, with Maven or Gradle;
|
|
141
141
|
- for Python, CPython 3.9 or newer with pytest or unittest;
|
|
142
|
-
- for Ruby, Ruby 3.
|
|
142
|
+
- for Ruby, Ruby 3.3 or newer with RSpec, Minitest, test-unit or Cucumber.
|
|
143
143
|
|
|
144
144
|
The CLI is a native binary. `npx supercov` picks the build for your operating
|
|
145
145
|
system and architecture, and nothing is compiled on install; the same binary is
|
package/docs/performance.md
CHANGED
|
@@ -130,18 +130,10 @@ Use `--dry-run` to preview cleanup. Keep enough run history for active reviews
|
|
|
130
130
|
and automation; remove the cache only when reclaiming space matters more than a
|
|
131
131
|
faster next run.
|
|
132
132
|
|
|
133
|
-
## Keep assertion
|
|
133
|
+
## Keep assertion assessments fast and cheap
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
the
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
For large maps, ask for a short page instead of the whole graph. Within one
|
|
141
|
-
flow, `--view nodes` or `--view edges` pages the details; `--compact` omits repeated
|
|
142
|
-
source text while keeping locations and credit reasons. See
|
|
143
|
-
[Investigating assertion evidence](assertion-evidence.md#read-a-large-flow).
|
|
144
|
-
|
|
145
|
-
The disposable `assertions.report.cache.json` and `assertions.summary.cache.json`
|
|
146
|
-
files live beside the map. A missing or damaged cache is rebuilt. Removing it affects the next query's speed, not
|
|
147
|
-
your saved explanations.
|
|
135
|
+
`assertions assess` asks only questions it has not answered before; answers live
|
|
136
|
+
in `.supercov/assertions/` and are reused across runs whenever the question is
|
|
137
|
+
the same. `--workers N` raises the requests in flight (default 8) for a faster,
|
|
138
|
+
slightly costlier pass. `--dry-run` prints the estimate without sending
|
|
139
|
+
anything.
|
package/docs/quality.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Understanding quality
|
|
2
2
|
|
|
3
|
-
`supercov quality` tells you what is in your code: twelve named properties,
|
|
3
|
+
`npx supercov quality` tells you what is in your code: twelve named properties,
|
|
4
4
|
checked file by file, so a score is never a number you have to take on faith.
|
|
5
5
|
|
|
6
6
|
Judgments come from [Jev](https://typesafe.ai), which answers typed questions
|
package/docs/security.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Security surface
|
|
2
2
|
|
|
3
|
-
`supercov security` tells you what security-relevant surface each file shows:
|
|
3
|
+
`npx supercov security` tells you what security-relevant surface each file shows:
|
|
4
4
|
twelve named checks, asked file by file, each mapped to the weakness classes it
|
|
5
5
|
stands for. There is no score. A file is clean, or it names what fired.
|
|
6
6
|
|
|
7
|
-
Judgments come from [Jev](https://typesafe.ai), the same way `supercov quality`
|
|
7
|
+
Judgments come from [Jev](https://typesafe.ai), the same way `npx supercov quality`
|
|
8
8
|
gets them. Set `TYPESAFE_API_KEY`, and optionally another provider, as described
|
|
9
9
|
in [quality](quality.md); reading a saved assessment never needs a key.
|
|
10
10
|
|
|
@@ -50,16 +50,47 @@ attempt measured on the labelled corpus fired on unguarded handlers the
|
|
|
50
50
|
application leaves open by design as often as on the ones it should not.
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
Measured with
|
|
54
|
-
140-repository labelled corpus,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
Measured with 2.0.1 on the 72 held-out repositories of RealVuln, a
|
|
54
|
+
140-repository labelled corpus, scored by its own rule: F1 0.42 with 42%
|
|
55
|
+
precision and 43% recall, in a median of 10 seconds and about 5 cents a
|
|
56
|
+
repository. The strongest agent-based scanners score 0.69 to 0.71 but take
|
|
57
|
+
5 to 9 minutes and about $4 a repository; Semgrep's default rules score 0.11.
|
|
58
|
+
Redirects, injection, unsafe code execution and paths taken from a request
|
|
59
|
+
are found at 79 to 89% recall; authorisation (11%) and authentication (24%)
|
|
60
|
+
are the weakest, because the guard that decides them lives in another file.
|
|
61
|
+
Every scanner's results are at
|
|
62
|
+
[supercov.com/docs/security-benchmark](https://supercov.com/docs/security-benchmark).
|
|
63
|
+
A file too large for one request is read in windows at declaration
|
|
64
|
+
boundaries, or at line boundaries where Supercov has no parser for it, such as
|
|
65
|
+
a template.
|
|
66
|
+
|
|
67
|
+
## What is read
|
|
68
|
+
|
|
69
|
+
Security reads every source file, template and configuration file that the
|
|
70
|
+
conventions do not exclude, including files under no recognised source root,
|
|
71
|
+
because code a project did not declare is deployed as often as not.
|
|
72
|
+
`npx supercov security scope` lists exactly the files a run reads and why the
|
|
73
|
+
rest were left out. Three kinds are left out because they are not the code
|
|
74
|
+
under review:
|
|
75
|
+
|
|
76
|
+
- **Tests and generated output**, as for `quality`.
|
|
77
|
+
- **Vendored and minified JavaScript.** A minified file anywhere, and in a
|
|
78
|
+
served or vendor directory (`static/`, `public/`, `assets/`, `plugins/`,
|
|
79
|
+
`vendor/`, `lib/`) a file with a licence banner or a well-known library's
|
|
80
|
+
name, such as `jquery.flot.js` or `swagger-ui-bundle.js`.
|
|
81
|
+
- **JSON data.** A JSON file is read when its name or directory says it
|
|
82
|
+
configures something (`config.json`, `proxy.conf.json`, `appsettings.json`,
|
|
83
|
+
`secrets.json`, anything under `config/`), and not when it holds data such
|
|
84
|
+
as translations, schema snapshots or scanner output.
|
|
85
|
+
|
|
86
|
+
A directory called `target/` is build output only when a build that writes
|
|
87
|
+
there (Cargo, Maven, Gradle, sbt, Leiningen) is declared beside it; otherwise
|
|
88
|
+
it is read like any other. Name a file directly to read it whatever the scope
|
|
89
|
+
says: `npx supercov security static/js/app.min.js`.
|
|
90
|
+
|
|
91
|
+
A run that could not assess a few files still exits 0: each one is in the
|
|
92
|
+
report with its reason, and stderr says how many. It exits 2 only when no
|
|
93
|
+
file could be assessed.
|
|
63
94
|
## Across files
|
|
64
95
|
|
|
65
96
|
The second pass also labels every function of every file, on the same
|
package/docs/supported-suites.md
CHANGED
|
@@ -50,9 +50,11 @@ Supercov reports the level it actually observed. It does not guess.
|
|
|
50
50
|
| --- | --- |
|
|
51
51
|
| Playwright | Exact per test, worker, retry, outcome, action, and assertion phase |
|
|
52
52
|
| Vitest | Exact per test, with setup execution kept separate; Browser Mode included |
|
|
53
|
-
| Jest | Exact per test, including parameterized tests, with the user's own configuration, setup files and reporters kept
|
|
53
|
+
| Jest | Exact per test, including parameterized tests, with the user's own configuration, setup files and reporters kept |
|
|
54
54
|
| `node:test` | Exact per test |
|
|
55
|
-
|
|
|
55
|
+
| Mocha | Exact per test and retry, `--parallel` included, with setup execution kept separate |
|
|
56
|
+
| AVA | Exact per test, concurrent tests included, in worker threads or child processes |
|
|
57
|
+
| node-tap 15 and newer | Exact per subtest, nested and parallel (`t.jobs`) subtests included |
|
|
56
58
|
| Other Node-based runners | Aggregate when their processes remain visible to Supercov |
|
|
57
59
|
| Browser component runners without an adapter | Aggregate structural coverage |
|
|
58
60
|
|
|
@@ -81,9 +83,6 @@ obligations. `{value}` is reached exactly when the tree is, and
|
|
|
81
83
|
`onClick={() => save()}` is measured where the handler is called rather than
|
|
82
84
|
where it is created.
|
|
83
85
|
|
|
84
|
-
`expect.element(...)`, `expect.soft(...)` and `expect.poll(...)` are recognised
|
|
85
|
-
as assertions, so their passing occurrences are available to assertion maps.
|
|
86
|
-
|
|
87
86
|
### React and React Native
|
|
88
87
|
|
|
89
88
|
React components can use Testing Library with Vitest/jsdom, Vitest Browser Mode,
|
|
@@ -93,11 +92,10 @@ it does not measure Hermes, native modules, simulator/device execution, Detox or
|
|
|
93
92
|
Maestro. React SSR hydration is exercised in jsdom and Chromium; this does not
|
|
94
93
|
establish Next.js Server Components, streaming SSR or server actions.
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
checked. Keep your existing runner and matchers.
|
|
95
|
+
Assertion coverage treats a JSX expression as a statement: it asks whether a
|
|
96
|
+
test would notice the displayed value, accessible name, disabled state or error
|
|
97
|
+
message becoming undefined. A button being rendered does not establish that its
|
|
98
|
+
disabled state was checked. Keep your existing runner and matchers.
|
|
101
99
|
|
|
102
100
|
The [React verification example](https://github.com/supercorp-ai/supercov/tree/main/examples/react-verification)
|
|
103
101
|
shows a fully executed checkout whose weak tests accept four UI regressions,
|
|
@@ -118,11 +116,6 @@ Supercov runs the project's build inside the isolated copy before testing.
|
|
|
118
116
|
Keep using your normal test and build commands. Instrumentation does not
|
|
119
117
|
require changing the project's TypeScript settings.
|
|
120
118
|
|
|
121
|
-
For assertion maps, Node, Vitest, Jest and Playwright's Node-side assertions
|
|
122
|
-
supply supported passing-occurrence evidence. Custom assertion wrappers and
|
|
123
|
-
browser-side checks can have additional observation limits. See
|
|
124
|
-
[Assertion evidence](assertion-evidence.md) before interpreting a missing occurrence.
|
|
125
|
-
|
|
126
119
|
### Browsers, servers, and child processes
|
|
127
120
|
|
|
128
121
|
Playwright support includes Chromium, Firefox, and WebKit, along with pages,
|
|
@@ -169,6 +162,19 @@ modules. Statements, functions, branches, boolean decisions, loops and error
|
|
|
169
162
|
propagation are measured. Const contexts and macro expansions remain visible
|
|
170
163
|
with explicit measurement limitations.
|
|
171
164
|
|
|
165
|
+
Test code is not measured, as cargo-llvm-cov and cargo-tarpaulin leave it out:
|
|
166
|
+
files under a `tests`, `examples` or `benches` directory, files named
|
|
167
|
+
`tests.rs`, `*_tests.rs` or `*-tests.rs`, everything a test target or a
|
|
168
|
+
`#[cfg(test)]` module declares, and items marked `#[cfg(test)]`, `#[test]` or
|
|
169
|
+
`#[bench]`. Its assertions still mark which evidence a passing assertion
|
|
170
|
+
witnessed.
|
|
171
|
+
|
|
172
|
+
Neither is code the compiler never builds for the target: a `#[cfg(windows)]`
|
|
173
|
+
function on Linux, or one behind `#[cfg(not(target_os = "macos"))]` on a Mac,
|
|
174
|
+
is not counted. Only predicates the target settles (`unix`, `windows`,
|
|
175
|
+
`target_*`) are decided; an item behind a feature or a custom cfg is counted
|
|
176
|
+
either way.
|
|
177
|
+
|
|
172
178
|
Use the repository's normal flags after the wrapped command:
|
|
173
179
|
|
|
174
180
|
```sh
|
|
@@ -200,7 +206,8 @@ comprehensions, short-circuit operators, `match` cases and exception paths.
|
|
|
200
206
|
Child interpreters, threads and thread pools can retain the calling test's
|
|
201
207
|
identity. The report also distinguishes execution before a passing assertion
|
|
202
208
|
from later execution. These phase records alone do not prove which values the
|
|
203
|
-
assertion checks.
|
|
209
|
+
assertion checks; [assertion coverage](assertions.md) measures which executed
|
|
210
|
+
statements the pytest and unittest tests would catch breaking.
|
|
204
211
|
|
|
205
212
|
Interpreters launched with `-I`, `-E` or `-S` ignore the required startup hook
|
|
206
213
|
and are not measured. Code compiled from strings at runtime has no source
|
|
@@ -222,23 +229,21 @@ npx supercov -- python -m unittest
|
|
|
222
229
|
| Runner | Attribution | Current requirement |
|
|
223
230
|
| --- | --- | --- |
|
|
224
231
|
| RSpec | Exact example and before/example/after phase identity | Ruby 3.4 or newer for full measurement; run with `npx supercov -- rspec` or `bundle exec rspec` |
|
|
225
|
-
| Minitest (including Minitest::Spec and ActiveSupport::TestCase) | Exact test and setup/test/teardown identity;
|
|
232
|
+
| Minitest (including Minitest::Spec and ActiveSupport::TestCase) | Exact test and setup/test/teardown identity; skips recorded | `ruby -Itest ...`, `rake test`, `rails test` |
|
|
226
233
|
| test-unit | Exact test and setup/test/teardown identity; omissions and pendings recorded | `ruby -Itest ...`, `rake test` |
|
|
227
234
|
| parallel_tests, Rails process workers | Exact per worker process | Workers inherit the run through `RUBYOPT`; verified on a Rails app with bootsnap, Zeitwerk and two forked workers |
|
|
228
235
|
| Thread-parallel Minitest (`parallelize_me!`, `parallelize(with: :threads)`) | Probe observations exact per test; line, method and simple-branch observations made while phases overlapped go to the run, declared | |
|
|
229
236
|
| Cucumber | Exact scenario identity (`features/x.feature:LINE`), hook steps as setup/teardown | `cucumber`, `bundle exec cucumber` |
|
|
230
237
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
cannot settle the question as **undetermined** rather than unaffected, so
|
|
241
|
-
`--names` includes it in the set to run.
|
|
238
|
+
Every test is credited with every line it runs: each statement of an
|
|
239
|
+
instrumented file carries a probe. Code Supercov cannot instrument -- a file
|
|
240
|
+
it could not compile with its probes, or a `Ractor.new` block, where no probe
|
|
241
|
+
can run -- falls back to Ruby's one-shot line coverage, which reports a line
|
|
242
|
+
the first time it executes and never again. There a test is credited with the
|
|
243
|
+
lines it was first to reach; what it is not credited with is not evidence it
|
|
244
|
+
did not run the code. The run says so, per-test numbers there read "at least",
|
|
245
|
+
and `tests affected` reports a test whose own record cannot settle the
|
|
246
|
+
question as **undetermined**, so `--names` includes it in the set to run.
|
|
242
247
|
|
|
243
248
|
Your project runs in place with its own interpreter and bundle. Supercov loads
|
|
244
249
|
through `RUBYOPT`; application files on disk and their backtrace line numbers
|
|
@@ -246,11 +251,9 @@ stay unchanged. RSpec, Minitest and test-unit assertions can identify execution
|
|
|
246
251
|
before a passing assertion. That timing evidence alone does not show which
|
|
247
252
|
values the assertion checks.
|
|
248
253
|
|
|
249
|
-
Ruby 3.
|
|
254
|
+
Ruby 3.3 and newer support statement, method, branch and MC/DC measurement,
|
|
250
255
|
including loops, iterator blocks, short-circuit operators, pattern matching,
|
|
251
|
-
optional calls and exception paths.
|
|
252
|
-
and branch coverage; obligations requiring additional instrumentation are
|
|
253
|
-
reported as measurement limits.
|
|
256
|
+
optional calls and exception paths.
|
|
254
257
|
|
|
255
258
|
Some constructs have narrower coverage. Code in a non-main Ractor keeps line
|
|
256
259
|
coverage but may lack other observations. Certain nested-return expressions
|
|
@@ -300,7 +303,7 @@ which costs whatever its parallelism was worth — on sixteen I/O-bound JUnit
|
|
|
300
303
|
tests across fifteen cores, 3.6x. Either way the coverage totals are the same;
|
|
301
304
|
what changes is whether a line can be traced to the test that ran it.
|
|
302
305
|
|
|
303
|
-
`supercov runs latest` reports which you got, under `Attribution`.
|
|
306
|
+
`npx supercov runs latest` reports which you got, under `Attribution`.
|
|
304
307
|
|
|
305
308
|
## Go
|
|
306
309
|
|
|
@@ -332,7 +335,7 @@ measured the same way: `go test` runs both, and what they reach is real
|
|
|
332
335
|
coverage no test can claim.
|
|
333
336
|
|
|
334
337
|
Such a test is still recorded as having run, with its outcome, and credited
|
|
335
|
-
with no coverage. `supercov runs <id> test <name>` says that rather than
|
|
338
|
+
with no coverage. `npx supercov runs <id> test <name>` says that rather than
|
|
336
339
|
reporting zeroes, coverage percentages leave it out, and `tests affected` lists
|
|
337
340
|
it as **undetermined**: nothing can say a change missed it, so `--names`
|
|
338
341
|
includes it in the set to run. A package where every test calls `t.Parallel()`
|
|
@@ -347,10 +350,6 @@ no way to run code on `os.Exit`, and a `TestMain` need not reach the `m.Run()`
|
|
|
347
350
|
call Supercov wraps — `goleak.VerifyTestMain(m)` runs the suite and exits
|
|
348
351
|
itself. Without periodic writes such a run recorded nothing at all.
|
|
349
352
|
|
|
350
|
-
For assertion maps, `t.Error`, `t.Errorf`, `t.Fatal`, `t.Fatalf` and testify's
|
|
351
|
-
`assert` and `require` are inventoried. A Go test states its claim with an `if`
|
|
352
|
-
and reports the violation, so the report is the site.
|
|
353
|
-
|
|
354
353
|
A repository with several modules works either way it is laid out. A directory
|
|
355
354
|
with a `go.mod` of its own that no `go.work` names is a different module, and
|
|
356
355
|
`go test ./...` walks past it, so Supercov leaves it alone. A `go.work`
|
|
@@ -372,7 +371,7 @@ npx supercov -- go test ./core/... ./app/...
|
|
|
372
371
|
| Kotest | Exact per test, under the names Kotest itself reports | — |
|
|
373
372
|
| Spock | Exact per feature, under the names Spock itself reports | — |
|
|
374
373
|
| TestNG | Exact per test, each data-provider invocation its own | — |
|
|
375
|
-
| JUnit 4 alone | Exact per test, through Vintage — see below | Maven |
|
|
374
|
+
| JUnit 4 alone | Exact per test, through Vintage — see below | Maven or Gradle |
|
|
376
375
|
|
|
377
376
|
Multi-module builds are measured module by module: each compiles its own source
|
|
378
377
|
set and forks its own JVM, so each gets a runtime and records evidence of its
|
|
@@ -391,10 +390,11 @@ report name the same thing.
|
|
|
391
390
|
JUnit 4 on its own is not a platform engine and does not run on one. Maven and
|
|
392
391
|
Gradle choose a test provider from what is on the classpath, so putting the
|
|
393
392
|
platform there makes the build pick a provider that finds no engine and fail.
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
393
|
+
Supercov adds `junit-vintage-engine` to the copy — the platform's own way of
|
|
394
|
+
running exactly those JUnit 4 tests through the lifecycle it listens to — and
|
|
395
|
+
measures them; your own build still runs JUnit 4 as it did. In a Gradle build
|
|
396
|
+
the copy also switches each JUnit 4 module's test tasks to `useJUnitPlatform()`,
|
|
397
|
+
leaving any task the build already put on the platform or on TestNG as it was.
|
|
398
398
|
|
|
399
399
|
Supercov instruments an isolated copy and leaves your build file alone. In the
|
|
400
400
|
copy it adds a test-scoped `junit-platform-launcher`, because the listener is
|
|
@@ -423,15 +423,11 @@ same goes for a loop over a constant, `while (true)`, which can only go one
|
|
|
423
423
|
way. A Kotlin `contract { }` has to stay the first statement of its function,
|
|
424
424
|
so the probe that records the function being entered is written after it.
|
|
425
425
|
|
|
426
|
-
Every one of these is named in the run: ask for `supercov runs latest
|
|
426
|
+
Every one of these is named in the run: ask for `npx supercov runs latest
|
|
427
427
|
limitations` and each appears with its file, its line, and why it was left
|
|
428
428
|
alone. A source file the parser cannot read is declared there too, so a hole in
|
|
429
429
|
the denominator stays visible after the build log is gone.
|
|
430
430
|
|
|
431
|
-
For assertion maps, forms spelled `assertSomething`, `assertThat` or `fail` are
|
|
432
|
-
inventoried, which covers JUnit, TestNG, AssertJ, Hamcrest and kotlin.test.
|
|
433
|
-
Kotest's infix matchers are not.
|
|
434
|
-
|
|
435
431
|
```sh
|
|
436
432
|
npx supercov -- mvn test
|
|
437
433
|
npx supercov -- ./gradlew test
|
package/docs/troubleshooting.md
CHANGED
|
@@ -93,11 +93,18 @@ outside that loader. Supercov declares this boundary on the affected file,
|
|
|
93
93
|
including on Python 3.9–3.11. It does not silently rewrite the child command,
|
|
94
94
|
which could change imports, `sys.argv`, or process behavior.
|
|
95
95
|
|
|
96
|
-
A file
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
A file that tests also import stays measured: what the imports ran is
|
|
97
|
+
counted, and the file carries the limitation, because lines it shows as
|
|
98
|
+
uncovered may have run in the direct execution. Its numbers are a lower bound,
|
|
99
|
+
and the run reports its measurement as incomplete. A file that is only ever
|
|
100
|
+
run directly has nothing observed, and is left out of the measured denominator
|
|
101
|
+
and the uncovered-lines list; inspect its measurement limitations before
|
|
102
|
+
treating a zero denominator as complete coverage.
|
|
103
|
+
|
|
104
|
+
To have a script measured, run it through the import system:
|
|
105
|
+
`python -m package.module`, or, for a file whose name is not a module name
|
|
106
|
+
such as `bin/anti-drift-gate.py`, `runpy.run_path("bin/anti-drift-gate.py",
|
|
107
|
+
run_name="__main__")` from a test.
|
|
101
108
|
|
|
102
109
|
## Python subprocess output or timeout assertions fail
|
|
103
110
|
|