Skip to content

CI: require swift-testing-extensions 0.3.1 for WASM (groundwork for running tests) - #89

Open
mansbernhardt wants to merge 1 commit into
orchetect:mainfrom
mansbernhardt:ci/wasm-run-tests
Open

CI: require swift-testing-extensions 0.3.1 for WASM (groundwork for running tests)#89
mansbernhardt wants to merge 1 commit into
orchetect:mainfrom
mansbernhardt:ci/wasm-run-tests

Conversation

@mansbernhardt

@mansbernhardt mansbernhardt commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Groundwork for running swift test on the WASM jobs rather than only swift build. Not green yet — but the remaining blocker is no longer tooling, and is described below.

(Rewritten: this PR originally removed TestingExtensions from SwiftTimecodeCoreTests. With 0.3.1 that is unnecessary, so the removal is gone and this is now a one-line version bump.)

The two tooling blockers, both solved

1. SWCompression — fixed by 0.3.1. In 0.3.0, Algorithm+DEFLATE.swift imports it from the #if canImport(Darwin) / #else branch, so it fires on every non-Darwin platform including WASI. 0.3.1 narrows it to #if os(Linux), which is correct: on wasm32-unknown-wasip1, os(WASI) is true and os(Linux) is false (probed directly). This PR requires 0.3.1 so resolution is explicit rather than depending on what a consumer's Package.resolved happens to hold.

2. The macro errors — your prebuilds hunch was exactly right. The SwiftPM CLI equivalent of -IDEPackageEnablePrebuilts=NO is --disable-experimental-prebuilts:

swift build --swift-sdk swift-6.3-RELEASE_wasm --build-tests --disable-experimental-prebuilts

With it, both @Test"global variable must be a compile-time constant to use @section attribute" and @Suite"'@const' value should be initialized with a compile-time value" disappear.

What is left: 8 sites, one file, and it is an API question

With 0.3.1 + that flag, the entire suite compiles for wasm32 except 8 errors, all in Tests/SwiftTimecodeCoreTests/Timecode/Source/Timecode Samples Tests.swift — 4 integer literals and 4 DoubleInt conversions that overflow.

These are not test bugs. The API is:

public func samplesValue(sampleRate: Int) -> Int

and the tests use values like 4_147_200_000 — 24 hours at 48 kHz. On a 32-bit platform that is simply unrepresentable, so audio sample counts are a fourth total-count domain in the same family as frames, subframes and Fraction — and the one with the least headroom, since it overflows at ordinary limits rather than at a hypothetical future frame rate.

So this PR is gated on the consistency work discussed in #88, not on CI configuration. Once totals are Int64, adding the WASM test job here should be mechanical.

Notes for whoever wires the job up

Four things that cost me time on my own WASM test lane:

  1. swift build --build-tests has no per-target form, so it builds every test target including Apple-only ones. I narrow the manifest from an env var to the targets I want plus their transitive first-party deps.
  2. SwiftPM's generated runner defaults to XCTest, whose wasi entry point reads Bundle.main and traps before running anything. Pass --testing-library swift-testing.
  3. Run --no-parallel — a trap kills the process, and only serial execution makes "last test to start" the actual culprit.
  4. Give the module a real stack. wasi-libc links a 64 KiB stack and wasm32 has no guard page, so overflow silently corrupts the heap and surfaces later, differently each run. It must go in the manifest, not the CLI: a CLI -Xlinker -z -Xlinker stack-size=… also reaches the host link of the macro plugins, and macOS ld rejects it.

@orchetect orchetect self-assigned this Aug 11, 2026
@orchetect orchetect added the testing Related to automated unit testing label Aug 11, 2026
@orchetect

orchetect commented Aug 11, 2026

Copy link
Copy Markdown
Owner

While not implicitly necessary, this surfaces the need to get the TestingExtensions package building cross-platform on WASM. Otherwise this situation will repeat itself over other repositories I use it in as a dependency. I use the dependency to test logic in various packages so I will eventually need it to be functional on WASM. However, it's a bit of chicken or the egg because I was waiting for a solution to get not just builds happening on CI but also unit testing for WASM. So maybe I can use this a template to add WASM testing for TestingExtensions itself.

I'm adding a build job in orchetect/swift-testing-extensions#3, and once that goes green a unit test run can be added after.

@orchetect

Copy link
Copy Markdown
Owner

if you know offhand why this package resolves swift-testing differently

I'm not sure if this sheds any light, but in TestingExtension's CI pipeline I have to disable prebuilds otherwise there are compilation errors. I also recall that if you somehow intermix prebuilds and non-prebuilds in the derived data folder, it can really jam things up. Deleting DerivedData may be necessary to rule that part out. I'm not sure what would be different about WASM here but this may be a clue.

https://github.com/orchetect/swift-testing-extensions/blob/966023b48c4d74142f0233b304c3e4935f9a49b0/.github/workflows/build.yml#L71-L80

@orchetect

orchetect commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Why is the commit from #88 duplicated here? It's not necessary for building WASM CI tests to run (but not pass), which was why I suggested branching from main so it would be a totally separate concern.

@mansbernhardt

Copy link
Copy Markdown
Contributor Author

Apologies on the duplicated commit — that was my error, I branched from the #88 work rather than from main. Rebased; this is now a single commit touching only Package.swift.

Your prebuilds hunch was exactly right, and it is the whole blocker. The SwiftPM CLI equivalent of your -IDEPackageEnablePrebuilts=NO is --disable-experimental-prebuilts:

swift build --swift-sdk swift-6.3-RELEASE_wasm --build-tests --disable-experimental-prebuilts

With that flag the @Test / @section error disappears completely. So WASM unit testing is not blocked on anything structural — just on that flag.

Two real errors were hiding underneath it:

  1. Timecode Samples Tests.swift — integer literals like 4_147_200_000 stored into Int, plus several DoubleInt conversions that overflow. That is 48 kHz × 24 hours, so audio sample counts are a third total-count domain with the same 32-bit problem as frames and subframes — and the one with the least headroom, since it overflows at the library's ordinary limits rather than at some hypothetical future frame rate. Relevant to the consistency question you raised on Fix Int overflow on 32-bit platforms (wasm32, watchOS) #88; I have noted it there.
  2. @Suite expansion'@const' value should be initialized with a compile-time value. Still swift-testing on WASM rather than anything in your packages.

To be clear about where this leaves things: I have moved it from one compile error to two different ones, not to a passing suite. But the diagnosis is solid and the prebuilts part is verified.

On TestingExtensions — I think you have already fixed it. In 0.3.0 (what this package resolves), Algorithm+DEFLATE.swift imports SWCompression inside the #if canImport(Darwin) / #else branch, so it fires on every non-Darwin platform including WASI — line 11, exactly where the build here failed. On current main you have narrowed it to #if os(Linux), which is correct: I probed wasm32-unknown-wasip1 directly and os(WASI) is true while os(Linux) is false.

So that may need only a release and a version bump rather than new work. Happy to test it here if you cut one — I can point this branch at it and report back.

@orchetect

Copy link
Copy Markdown
Owner

I pushed TestingExtensions 0.3.1 earlier today with a passing build on WASM. You're probably building off your local resolved file which would be behind. SwiftTimecode's manifest can be updated to that version so it forces it.

Groundwork for running `swift test` on the WASM jobs rather than only
`swift build`. Not green yet — see the PR description.

0.3.0 imports `SWCompression` from the `#if canImport(Darwin)` / `#else`
branch, so it fires on every non-Darwin platform including WASI, and
`SWCompression` has no WebAssembly support. 0.3.1 narrows it to `#if os(Linux)`,
which is correct — on wasm32-unknown-wasip1, `os(WASI)` is true and `os(Linux)`
is false.

Requiring 0.3.1 makes the resolution explicit rather than leaving it to whatever
a consumer's Package.resolved happens to hold.
@mansbernhardt mansbernhardt changed the title CI: groundwork for running the test suite on WASM (not green yet) CI: require swift-testing-extensions 0.3.1 for WASM (groundwork for running tests) Aug 12, 2026
@mansbernhardt

Copy link
Copy Markdown
Contributor Author

That was it — thank you. Retested with 0.3.1 and the dependency kept, and the tooling side is fully clear:

  • SWCompression — gone (0.3.1)
  • @Test / @section — gone (--disable-experimental-prebuilts)
  • @Suite / @const — gone (same flag)

So I have dropped the dependency removal entirely; this PR is now a one-line bump to from: "0.3.1", and the description is rewritten around what actually blocks it.

What remains is 8 errors, all in one fileTimecode Samples Tests.swift, 4 integer literals and 4 DoubleInt conversions. They are not test bugs:

public func samplesValue(sampleRate: Int) -> Int

with tests using 4_147_200_000 — 24 hours at 48 kHz, unrepresentable in a 32-bit Int. So audio sample counts are a fourth total-count domain alongside frames, subframes and Fraction, and the one with the least headroom: it overflows at the library's ordinary limits rather than at a hypothetical future frame rate.

Which means this PR is gated on the consistency work in #88 rather than on anything CI-side. Once totals are Int64, wiring up the actual job should be mechanical — I have put the four gotchas from my own WASM test lane in the PR description so they are not rediscovered.

Happy to do the samples part along with the rest whenever you have decided how you would like #88 staged.

@orchetect

orchetect commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Apologies on the duplicated commit

No worries, just wanted to point that out before more commits were added downstream here.

What remains is 8 errors, all in one file — Timecode Samples Tests.swift
this PR is gated on the consistency work in #88

Ok, that's great. If the refactors for audio sample rate are addressed in #88 then we can either 1) merge this PR now and open a new PR later to add the actual WASM CI test run job, or 2) keep this PR open and after merging #88 to main you can pull-up main into this PR and add the WASM CI test job here.

@orchetect
orchetect self-requested a review August 12, 2026 18:48
@mansbernhardt

Copy link
Copy Markdown
Contributor Author

Correction, and apologies — I got this wrong.

--disable-experimental-prebuilts does not fix the macro errors. I re-tested properly: same branch, clean scratch directory each time, only the flag differing.

--disable-experimental-prebuilts  →  2816 @section/@const errors
(no flag)                         →  2816 @section/@const errors

My earlier claim was an artifact of my own output filtering. Macro-expansion diagnostics carry no file:line: prefix, so the grep I was using to summarise errors never displayed them, and a sort -u | head truncated what was left. I read their absence from my terminal as their being fixed. They were there the whole time — which, given what you just said about chasing false positives, is exactly the kind of thing I did not want to hand you. Sorry.

So the remaining blocker for compiling tests on WASM is still @Test / @Suite expansion emitting @section globals and @const values that wasm32 rejects, and I do not know why. What I can say is that a working configuration exists — my own project compiles and runs 551 swift-testing tests on wasm32 under wasmtime — but I have not isolated what differs between the two, and I am not going to guess at it a second time.

The other half of the diagnosis stands, and that one I did verify directly: 0.3.0 imports SWCompression from the #if canImport(Darwin) / #else branch so it fires on WASI, 0.3.1 narrows it to #if os(Linux), and os(WASI) is true while os(Linux) is false on wasm32-unknown-wasip1. This PR's one-line bump to 0.3.1 is unaffected by the correction above.

@orchetect

orchetect commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Ok we can circle back to this after there is a chance to do more triage on the issue.

Just for clarification - Swift Testing itself does actually work in a WASM unit test run? As in, a brand new empty Swift package with a test target and one @Test method will compile and run? I think I inferred that from your local test run succeeding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

testing Related to automated unit testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants