Files
punktfunk/crates/punktfunk-core/tests/c_abi.rs
T
enricobuehler 6575dddac7 fix: keep the workspace green on macOS after the mic/touch/rich-input batch
The new features were Linux-built only and broke the documented macOS gate
(cargo build/test/clippy --workspace) four ways, all fixed following the existing
platform-gating conventions:

- m3.rs: mic_service_thread split into the Linux worker and a non-Linux stub that
  drains and drops (sessions still count the datagrams) — opus/PipeWire are
  Linux-gated deps, same pattern as audio_thread.
- punktfunk-client-rs: the new `opus` dependency moved into the Linux target table and
  --mic-test gated with a warn-and-skip stub (only the synthetic-tone test rig needs
  the encoder; the mic uplink itself is portable).
- gamestream/audio.rs: SAMPLE_RATE import gated to any(linux, test) (the frame_sizing
  test uses it everywhere, the data plane only on Linux).
- tests/c_abi.rs: the harness's macOS link flags gained Security + CoreFoundation —
  the quic feature now pulls rustls's platform verifier into the staticlib.

Also: two clippy match-ref-pats lints in the new rich-input/HID-output decoders
(clippy -D warnings is the repo gate), the regenerated punktfunk_core.h committed (the
checked-in copy predated the rich-input/HID-output constants — CI fails on drift), and
web's inlang cache dir gitignored.

cargo build/test/clippy/fmt --workspace: green on macOS, 122 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 09:07:48 +02:00

95 lines
3.3 KiB
Rust

//! Runs the C ABI harness under `cargo test`: compiles `tests/c/harness.c`, links it
//! against the freshly built `libpunktfunk_core.a`, and asserts it round-trips frames
//! through the lossy loopback. The cross-platform canonical path (querying rustc for
//! link flags) is `tests/c/run.sh`; this mirrors it so `cargo test` alone covers the
//! C boundary.
use std::path::{Path, PathBuf};
use std::process::Command;
/// Native libs the Rust staticlib needs, minus the ones `cc` already links by default
/// (`-lSystem`/`-lc`), to avoid duplicate-library linker warnings. See
/// `rustc --print native-static-libs`.
fn native_libs() -> &'static [&'static str] {
if cfg!(target_os = "macos") {
// The workspace build unifies features into the staticlib, and `quic` pulls
// rustls's platform verifier → Security/CoreFoundation.
&[
"-liconv",
"-lm",
"-framework",
"Security",
"-framework",
"CoreFoundation",
]
} else if cfg!(target_os = "linux") {
&["-lgcc_s", "-lutil", "-lrt", "-lpthread", "-lm", "-ldl"]
} else {
&[]
}
}
fn ensure_staticlib(profile_dir: &Path) -> PathBuf {
let staticlib = profile_dir.join("libpunktfunk_core.a");
if !staticlib.exists() {
// `cargo test` doesn't always emit the standalone staticlib; build it. The
// outer cargo's build lock is released during test execution, so this is safe.
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into());
let _ = Command::new(cargo)
.args(["build", "-p", "punktfunk-core"])
.status();
}
staticlib
}
#[test]
fn c_abi_harness_round_trips() {
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR")); // crates/punktfunk-core
let harness = manifest.join("tests/c/harness.c");
let include = manifest.join("../../include");
let exe = std::env::current_exe().expect("current_exe");
// .../target/<profile>/deps/c_abi-<hash> -> target/<profile>
let profile_dir = exe
.parent()
.and_then(Path::parent)
.expect("profile dir")
.to_path_buf();
let staticlib = ensure_staticlib(&profile_dir);
assert!(
staticlib.exists(),
"staticlib not found at {} (run `cargo build -p punktfunk-core`)",
staticlib.display()
);
assert!(
include.join("punktfunk_core.h").exists(),
"generated header missing; build punktfunk-core to regenerate it"
);
let cc = std::env::var("CC").unwrap_or_else(|_| "cc".into());
let out = profile_dir.join("punktfunk_c_harness");
let mut compile = Command::new(&cc);
compile
.args(["-std=c11", "-Wall", "-Wextra", "-O2", "-I"])
.arg(&include)
.arg(&harness)
.arg(&staticlib)
.args(native_libs())
.arg("-o")
.arg(&out);
match compile.status() {
Ok(s) => assert!(s.success(), "C harness failed to compile/link"),
Err(e) => {
// No C toolchain (unusual) — don't fail the whole suite; run.sh covers CI.
eprintln!("skipping C ABI test: cannot invoke `{cc}`: {e}");
return;
}
}
let run = Command::new(&out).status().expect("run C harness");
assert!(run.success(), "C harness reported a round-trip failure");
}