Skip to content

CI: run the portable unit tests on Windows and Android#36

Merged
odrobnik merged 4 commits into
mainfrom
claude/cross-platform-portable-tests
Jun 18, 2026
Merged

CI: run the portable unit tests on Windows and Android#36
odrobnik merged 4 commits into
mainfrom
claude/cross-platform-portable-tests

Conversation

@odrobnik

Copy link
Copy Markdown
Contributor

What

Promotes the Windows and Android CI jobs from build-only (swift build --target SwiftTextMarkdown) to running the portable unit tests — on Android, on an x86_64 emulator.

Why

swift test builds every test target, and several need native deps those toolchains don't readily provide:

  • SwiftTextHTMLTests / SwiftTextRenderTests → libxml2 (vcpkg on Windows, absent in the Android SDK)
  • SwiftTextDOCXTests / SwiftTextPagesTests → ZIPFoundation

So the pure-Swift surface — SwiftTextMarkdown, SwiftTextAttributedString, and the WeasyPrint-port foundations (SwiftTextPDFWriter, SwiftTextOpenType, SwiftTextCSS) plus SwiftTextCore — was never actually exercised off-Apple, only build-checked through the Markdown target.

How

A SWIFTTEXT_PORTABLE_ONLY=1 switch in Package.swift trims the manifest to those six Foundation-only targets and their tests (verified: every one imports only Foundation / Markdown / SwiftTextMarkdown, with all Darwin/PDFKit imports #if canImport-guarded). The Windows and Android jobs set that env var and run the suite.

  • Default manifest unchangedswift package dump-package still reports 26 targets / 14 products / 4 deps; the portable manifest reports exactly 12 targets / 6 products / 1 dep (swift-markdown).
  • Local proofSWIFTTEXT_PORTABLE_ONLY=1 swift test builds the subset and passes 140 tests in 13 suites on macOS (incl. the AttributedString, PDF-writer, OpenType, and CSS suites).
  • Package.resolved untouched; SwiftLint --strict clean on Package.swift.

What this proves

Turns the cross-platform AttributedString claim (and the rendering-engine foundations) from "same code path as Linux, asserted" into a continuously tested checkmark — or a clear red if swift-foundation's AttributedString isn't yet available on a given toolchain.

Risk / things to watch on the first run

  • Android + swift-testing: our portable tests use import Testing. skiptools/swift-android-action runs "the SwiftPM test targets on an emulator"; if swift-testing isn't executed there, the test bundle still compiles, which already answers the real question (does the portable code, incl. AttributedString, build for Android). We can fall back to build-only for Android if the emulator step is unhappy.
  • Job env propagation: SWIFTTEXT_PORTABLE_ONLY is set at job level so the host-side manifest evaluation sees it during cross-compile.

🤖 Generated with Claude Code

odrobnik and others added 4 commits June 18, 2026 19:14
The Windows and Android CI jobs were build-only, scoped to `--target
SwiftTextMarkdown`, because `swift test` builds every test target and some
(SwiftTextHTMLTests/SwiftTextRenderTests via libxml2, SwiftTextDOCXTests/
SwiftTextPagesTests via ZIPFoundation) need native deps those toolchains
don't readily provide. So the pure-Swift surface — Markdown, AttributedString,
and the WeasyPrint-port foundations (PDFWriter, OpenType, CSS) plus Core — was
never actually exercised off-Apple.

Add a SWIFTTEXT_PORTABLE_ONLY=1 manifest switch that trims the package to those
six Foundation-only targets and their tests, then point the Windows and Android
jobs at it with tests *running* (Android on an x86_64 emulator). A plain
`swift build` / `swift test` is unchanged; default manifest still resolves all
26 targets. Verified locally: the portable subset builds and its 140 tests pass
on macOS, and the default manifest dump is byte-for-byte unaffected.

This turns the cross-platform AttributedString claim (and the rendering-engine
foundations) from "same code path as Linux, asserted" into a continuously
tested checkmark — or a clear red if swift-foundation's AttributedString isn't
yet available on a given toolchain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ink gap)

First cross-platform run: Android passes the full portable suite (AttributedString
compiles, links, and runs on the x86_64 emulator). Windows fails at *link*, not
compile:

    lld-link: error: undefined symbol:
      $s22_FoundationCollections9BigStringV5IndexVMn

That's `_FoundationCollections.BigString.Index` — the rope storage backing
AttributedString. The Windows 6.3.1 toolchain ships the AttributedString API
(it compiles) but not the linkable _FoundationCollections symbols, so the
module can't link there yet. Linux and Android link it fine.

Add a SWIFTTEXT_PORTABLE_EXCLUDE comma-separated knob and use it to drop
SwiftTextAttributedString(+Tests) on the Windows job only. Windows now runs the
other five portable targets (Markdown, Core, PDFWriter, OpenType, CSS); Android
keeps the full set. Drop the exclude once a Windows toolchain ships the symbols.

Verified locally: default manifest still 26 targets; the Windows subset (10
targets) builds and passes 100 tests on macOS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ring exclude

The Windows link failure is a known compiler-side bug: Foundation vendors
_FoundationCollections as a static internal import, and Windows DLLs (unlike
ELF's libFoundationEssentials.so on Linux/Android) don't re-export those
symbols. Cite the tracking issue so the exclude has a precise removal trigger.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@odrobnik odrobnik merged commit d3b757e into main Jun 18, 2026
6 checks passed
@odrobnik odrobnik deleted the claude/cross-platform-portable-tests branch June 18, 2026 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant