Four suites at different layers. All are independent of the full cmake build — each compiles with a single g++ command. Makefile.transport-tests drives them. See also: story/06-testing.
File: src/test/TransportTest.cpp → compiled into coretest binary
Run: cd build && ctest -R Coretests --output-on-failure
Covers: pws_is_transport_url, extract_scheme, file: plugin end-to-end via PWScore.
File: src/test/transport_standalone_test.cpp
Build: g++ -std=c++17 -DDEVELOPMENT -I src -o /tmp/transport_standalone_test src/test/transport_standalone_test.cpp src/os/unix/transport.cpp -ldl
No network required. 9 sections, 59 assertions. Covers plugin loading, scheme detection, file: round-trips, cache path generation, FILE* map, identity pre-scan rejection, roundtrip byte identity.
File: src/test/transport_webdav_test.cpp — 11 sections, 59 assertions
Build: g++ -std=c++17 -o /tmp/transport_webdav_test src/test/transport_webdav_test.cpp -ldl
Skips (exit 77) if PWSAFE_WEBDAV_TEST_URL is unset. Run from build/: PWSAFE_WEBDAV_TEST_URL=https://webdav.critchley.biz/test /tmp/transport_webdav_test
Key sections:
• §7 — store while locked: the If: (<token>) header regression. Server returns 423 if the header is missing; this was the original data-loss bug.
• §11 — lock contention: EBUSY when another client holds the lock; failed lock must not populate token_out or affect the internal map.
File: src/test/transport_lock_lifecycle_test.cpp — 6 sections (A–F), 49 assertions (15 offline, 34 live)
Build: g++ -std=c++17 -DDEVELOPMENT -I src -o /tmp/transport_lock_lifecycle_test src/test/transport_lock_lifecycle_test.cpp src/os/unix/transport.cpp src/os/unix/transport_lockd.cpp -ldl
Links transport.cpp and transport_lockd.cpp directly — tests the full daemon IPC.
Key sections:
• §A — registry unit tests: pws_lock_register/has_lock/unregister in isolation, no network
• §C — crash simulation: registry cleared without plugin unlock → server lock still held; subsequent lock() returns EBUSY
• §D — SafeUnlockFile simulation: the exact guard (if IsLockedFile → UnlockFile) that was broken before the fix
• §E — daemon EBUSY path: lock contention propagated correctly through the pipe round-trip
• §F — store regression: t->store() directly in parent → EBUSY (demonstrates the bug); pws_lockd_store() → 0 (demonstrates the fix)
# Offline tests only (default):
make -f Makefile.transport-tests
# All suites with a local wsgidav server (no remote dependency):
make -f Makefile.transport-tests local-live
# All suites against the remote server:
make -f Makefile.transport-tests live
.NOTPARALLEL in the Makefile ensures suites run sequentially — they share /tmp paths and ~/.cache/pwsafe/, and suite 3 forks the lock daemon which would conflict with a concurrent run.
Files: src/test/webdav_test_server.py + src/test/run_local_webdav_tests.sh
Uses wsgidav 4.3.3 + cheroot 11.1.2. DAV class 2 (locking), anonymous write access. Pre-seeds pwsafe_test.psafe3 (required by suite 2 §2 and §4). Prints READY once the port accepts connections.
run_local_webdav_tests.sh starts the server, polls for readiness, runs suites 2 and 3 with PWSAFE_WEBDAV_TEST_URL=http://127.0.0.1:18080, tears down via trap cleanup EXIT.
Install wsgidav (if needed): ALL_PROXY=socks5h://127.0.0.1:1080 pip install --user --break-system-packages wsgidav cheroot