Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Normalize line endings to LF in every working tree, Windows included. Without this,
# `actions/checkout` honours Windows' default `core.autocrlf=true` and checks out CRLF, so tests
# that compare formatter output (LF) against a `stripMargin` source literal (CRLF) fail — e.g.
# JSONTest and YAMLFormatterTest on the Scala Native (Windows) CI job.
* text=auto eol=lf
16 changes: 4 additions & 12 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,18 +205,10 @@ jobs:
echo "LIB=$libDir;$env:LIB" >> $env:GITHUB_ENV
echo "$root\bin" >> $env:GITHUB_PATH
shell: pwsh
# `testOnly` still links the whole native test binary, so both of uni's C shims get compiled and
# linked for Windows here; running the http suite then exercises uni_socket_shim.c (WSAStartup /
# WSAPoll / closesocket) and uni_curl_shim.c (GetProcAddress over EnumProcessModules) for real.
#
# Deliberately not the full `projectNative/test` yet. Six tests outside http fail on Windows, all
# of them predating this job and none socket-related: IOSymlinkTest (3 — uni itself raises
# `createSymlink is not supported on Scala Native + Windows`, so they want skipping there),
# IOPathTest's `resolve child path` (a Windows-naive expectation), and JSONTest /
# YAMLFormatterTest (their `stripMargin` literals arrive CRLF, as the repo has no .gitattributes,
# while the formatters emit LF). Fix those, then widen this step to projectNative/test.
- name: Scala Native test (http)
run: JVM_OPTS=-Xmx4g ./sbt "uniNative/testOnly wvlet.uni.http.*"
# Exercises uni_socket_shim.c (WSAStartup / WSAPoll / closesocket) and uni_curl_shim.c
# (GetProcAddress over EnumProcessModules) at runtime, not merely at compile time.
- name: Scala Native test
run: JVM_OPTS=-Xmx4g ./sbt "projectNative/test"
shell: bash
- name: Publish Test Report
uses: mikepenz/action-junit-report@v6
Expand Down
26 changes: 14 additions & 12 deletions adr/2026-07-08-native-socket-shim.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,18 +128,20 @@ same on both platforms. `winsock2.h` also supplies `POLLERR`, `POLLHUP` and
now what would have caught v2026.1.17's `<dlfcn.h>` regression, and it exercises
both shims at runtime. `NativeServerTest` passes 21/21 there, keep-alive and
read timeouts (the `WSAPoll` timeout paths) and WebSocket upgrade included.
- That job runs `uniNative/testOnly wvlet.uni.http.*`, not the full
`projectNative/test`. `testOnly` still links the entire test binary, so both
shims are compiled and linked for Windows either way. Six tests outside `http`
fail there, all predating the job and none socket-related — they are what stands
between this and the full suite:
- `IOSymlinkTest` (3): uni raises `createSymlink is not supported on Scala Native
+ Windows`; the tests need skipping on that platform.
- `IOPathTest.resolve child path`: the expectation is Windows-naive.
- `JSONTest` / `YAMLFormatterTest`: their `stripMargin` literals arrive CRLF (the
repo has no `.gitattributes`, and `actions/checkout` leaves Windows'
`core.autocrlf=true`), while the formatters emit LF. `* text=auto eol=lf` would
fix both.
- That job runs the full `projectNative/test`. It first landed scoped to
`wvlet.uni.http.*`, because six non-socket tests failed on Windows — all
predating the job, surfaced only once the binary could run there. They were then
fixed so the job could widen:
- `IOSymlinkTest` (3): symlinks are unsupported on Scala Native + Windows (uni's
own `createSymlink` / `readSymlink` throw there), so the tests `skip` when
`IOPath.isWindows`.
- `IOPathTest.resolve child path`: the expectation mixed a literal `/` prefix with
`IOPath.separator`; `.path` renders every separator with the platform's, so on
Windows it is `\home\user\...`. Built the expectation with `separator`
throughout, matching the sibling assertion.
- `JSONTest` / `YAMLFormatterTest`: their `stripMargin` literals arrived CRLF
(`actions/checkout` honours Windows' `core.autocrlf=true`) while the formatters
emit LF. A repo `.gitattributes` (`* text=auto eol=lf`) forces LF everywhere.
- `NativeSocket` no longer imports `scalanative.posix.poll` or
`scalanative.posix.unistd`. Re-adding either would re-break Windows; the CI job
is what notices.
Expand Down
6 changes: 5 additions & 1 deletion uni/src/test/scala/wvlet/uni/io/IOPathTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ class IOPathTest extends UniTest:
test("resolve child path") {
val base = IOPath.parse("/home/user")
val child = base.resolve("docs/file.txt")
child.path shouldBe s"/home/user${IOPath.separator}docs${IOPath.separator}file.txt"
// `.path` renders every separator with the platform one, the leading segment included, so build
// the expectation the same way — on Windows this is `\home\user\docs\file.txt`. `.posixPath` is
// the forward-slash form.
val sep = IOPath.separator
child.path shouldBe s"${sep}home${sep}user${sep}docs${sep}file.txt"
child.posixPath shouldBe "/home/user/docs/file.txt"
}

Expand Down
10 changes: 10 additions & 0 deletions uni/src/test/scala/wvlet/uni/io/IOSymlinkTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@ class IOSymlinkTest extends UniTest:

private lazy val testDir: IOPath = FileSystem.createTempDirectory("symlink-test")

// Scala Native on Windows has no POSIX symlink support: FileSystem.createSymlink / readSymlink
// throw UnsupportedOperationException there by design (MSVC's CRT exports no `symlink`/`readlink`).
// `inline` so `skip`'s TestSource resolves to the calling test, not this helper.
private inline def requireSymlinkSupport(): Unit =
if IOPath.isWindows then
skip("Symlinks are not supported on Scala Native + Windows")

test("createSymlink and readSymlink for a file") {
requireSymlinkSupport()
val target = testDir / "target.txt"
val link = testDir / "link.txt"

Expand All @@ -33,6 +41,7 @@ class IOSymlinkTest extends UniTest:
}

test("info reports SymbolicLink type") {
requireSymlinkSupport()
val target = testDir / "info-target.txt"
val link = testDir / "info-link.txt"

Expand All @@ -44,6 +53,7 @@ class IOSymlinkTest extends UniTest:
}

test("createSymlink for a directory") {
requireSymlinkSupport()
val targetDir = testDir / "target-dir"
val linkDir = testDir / "link-dir"

Expand Down
Loading