Repository navigation
Conversation
Swift Testing runs a process's tests in parallel, which the process-wide
counters can't tell apart: overlapping tests were left without evidence.
Code built with -sanitize-coverage=func,trace-pc-guard,pc-table now calls
back on every function entry, and the observer attributes the function to
the test whose task runs it, read from the trait's TaskLocal: child tasks,
Task {} and awaited actors keep it. What no test's task runs goes to a
floor. Each test case gets a function record in functions.bin, apart from
records.bin so older readers never meet one.
The callbacks live in the Swift module, which every test target links
directly however the package is linked, and forward to one recording copy
per process through a sized owner table (TEST_COVERAGE_ATTRIBUTION_OWNER_2);
copies that predate it are still forwarded to.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Traits listed before it on a test, and tests without it, run outside any test's context, so their work counts for every test of the process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The static analyzer flags using getenv's result after a setenv, which process_owner() may call when it publishes the owner table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Swift Testing tests that run in parallel in one process now get per-test evidence. Code built with
-sanitize-coverage=func,trace-pc-guard,pc-table(plus-sanitize=undefined, which the Swift driver requires for-sanitize-coverageand which adds no checks to Swift) calls into the package on every function entry. The observer credits the function to the test whose task is running it, read from aTaskLocalthe.coverageAttributiontrait binds. Child tasks,async let,Task {}and awaited actors inherit the context. What no test's task runs (GCD queues, threads,Task.detached, suite setup) goes to a per-process floor.functions.bin(indexed byfunctions.tsv). It is kept apart fromrecords.bin, so readers that predate it never see one.TEST_COVERAGE_ATTRIBUTION_OWNER_2). Copies of the package that predate the table are still forwarded to.Why
Swift Testing runs a process's tests in parallel by default. The process-wide counters can't tell overlapping tests apart, so those tests were marked overlapped and got no evidence. Tuist could only fall back to serial runs, which took the TuistUnitTests scheme from about 650 s to about 1,420 s of test execution.
Alternatives considered
Test.currenton each function entry: building aTestvalue on every function entry is far too costly. ATaskLocalof aUInt32is one lookup.Impact
Validation
swift testpasses. The newFixtures/Parallelruns 10 Swift Testing tests that wait at a barrier, so all 10 run at once.attributesParallelSwiftTestingTestsThroughTheirTaskschecks, under SwiftPM, xcodebuild on macOS and the iOS simulator, that each test's function record holds exactly the functions its task ran, and none of another test's:Task {};It also checks that
Task.detachedand GCD work land in the floor and in no test, and that an unused function appears nowhere. The existing tests (counters, skip list, UI-test launches) pass unchanged.End to end, with the tuist CLI branch, on the whole TuistUnitTests scheme (3,700 Swift Testing tests, parallel), against a serial run whose counter records are exact:
Extra files beyond the serial run come from the shared floor, which only adds files, so selection runs more tests, never fewer.
🤖 Generated with Claude Code