From cada2f4c3a678ce677e3f9adb372def8781eb793 Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Fri, 21 Aug 2026 16:34:27 +0800 Subject: [PATCH] fix: CI fallout from the i18n refactor + Windows path assertions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit examples/screenshot.rs: migrate to language_code()/set_language_code (the Language enum is gone); only CI's example build caught it — local --lib runs never compile examples. oakcodec tests: build path expectations with Path::join instead of '/'-joined literals — production uses platform-native separators, so the derivation assertions failed on Windows ("dir\img007.jpg" vs "dir/img007.jpg"). Behaviour unchanged; the tests were never reached on Windows before (earlier failures aborted the run first). oakui::ofx interact test: poll up to 5s for the destroy marker record before asserting. The active-interact slot is process-global; a concurrent viewer frame sync from another test's real engine can take the interact out of the slot and be preempted between take and destroy, so the plugin's destroy record occasionally lands a few milliseconds after this test removed the marker env var (Linux CI: "lifecycle actions missing: [...]" with everything but destroy present). --- crates/oakcodec/src/conformmanager.rs | 14 ++++++++++++-- crates/oakcodec/src/decoder.rs | 5 ++++- crates/oakcodec/src/proxymanager.rs | 14 +++++++++++--- examples/screenshot.rs | 10 +++++----- src/oakui/ofx.rs | 19 ++++++++++++++++++- 5 files changed, 50 insertions(+), 12 deletions(-) diff --git a/crates/oakcodec/src/conformmanager.rs b/crates/oakcodec/src/conformmanager.rs index 33be4b153..dda681af6 100644 --- a/crates/oakcodec/src/conformmanager.rs +++ b/crates/oakcodec/src/conformmanager.rs @@ -273,8 +273,18 @@ mod tests { let f1 = m .get_conform_filename(&cache, &src.to_string_lossy(), 0, 48000, 0x3, 0, 1) .unwrap(); - assert_eq!(f0, format!("{}/{}.0.pcm", cache, base)); - assert_eq!(f1, format!("{}/{}.1.pcm", cache, base)); + assert_eq!( + f0, + std::path::Path::new(&cache) + .join(format!("{base}.0.pcm")) + .to_string_lossy() + ); + assert_eq!( + f1, + std::path::Path::new(&cache) + .join(format!("{base}.1.pcm")) + .to_string_lossy() + ); // Out of range. assert!(matches!( m.get_conform_filename(&cache, &src.to_string_lossy(), 0, 48000, 0x3, 0, 5), diff --git a/crates/oakcodec/src/decoder.rs b/crates/oakcodec/src/decoder.rs index 52251289a..2ea9fc1f7 100644 --- a/crates/oakcodec/src/decoder.rs +++ b/crates/oakcodec/src/decoder.rs @@ -629,7 +629,10 @@ mod tests { ); assert_eq!( transform_image_sequence_file_name("dir/img012.jpg", 7), - "dir/img007.jpg" + // Path::join separators are platform-native (\ on Windows). + std::path::Path::new("dir") + .join("img007.jpg") + .to_string_lossy() ); // No digit run: number appended with no padding (C++ behavior). assert_eq!( diff --git a/crates/oakcodec/src/proxymanager.rs b/crates/oakcodec/src/proxymanager.rs index 89b0de831..35866a159 100644 --- a/crates/oakcodec/src/proxymanager.rs +++ b/crates/oakcodec/src/proxymanager.rs @@ -508,7 +508,10 @@ mod tests { fn proxy_directory_is_cache_slash_proxy() { assert_eq!( ProxyManager::get_proxy_directory("/tmp/cache").unwrap(), - "/tmp/cache/proxy" + // Path::join separators are platform-native (\ on Windows). + std::path::Path::new("/tmp/cache") + .join("proxy") + .to_string_lossy() ); } @@ -522,7 +525,12 @@ mod tests { // C++ parity), so the name is the plain size/version/audio tags. let missing = std::path::Path::new(&temp_subdir("missing")).join("nope.mp4"); let f = ProxyManager::get_proxy_filename(&cache, missing.to_str().unwrap(), 0, &p).unwrap(); - assert_eq!(f, format!("{}/proxy/-0.1280x720.v1.a1.mp4", cache)); + let plain = std::path::Path::new(&cache) + .join("proxy") + .join("-0.1280x720.v1.a1.mp4") + .to_string_lossy() + .into_owned(); + assert_eq!(f, plain); // An existing source embeds a stable per-file identifier. let existing = std::path::Path::new(&temp_subdir("existing")).join("real.mp4"); @@ -535,7 +543,7 @@ mod tests { f1.contains("-0.1280x720.v1.a1.mp4"), "size/version/audio tags present: {f1}" ); - assert!(f1 != format!("{}/proxy/-0.1280x720.v1.a1.mp4", cache), "id embedded: {f1}"); + assert!(f1 != plain, "id embedded: {f1}"); assert_eq!(f1, f2, "the identifier is stable for the same file"); // Divider mode tags the divider instead of an absolute size. diff --git a/examples/screenshot.rs b/examples/screenshot.rs index b5235be40..043747355 100644 --- a/examples/screenshot.rs +++ b/examples/screenshot.rs @@ -45,7 +45,7 @@ use gpui_platform::current_platform; #[cfg(target_os = "macos")] use oakapp::app::OakApp; #[cfg(target_os = "macos")] -use oakapp::i18n::{self, Language}; +use oakapp::i18n; #[cfg(target_os = "macos")] use oakapp::oakui::MockEngine; @@ -95,8 +95,8 @@ fn main() -> Result<()> { // Initialize the UI language like the real app's startup would: zh-CN // for the primary screenshot, then en-US for the English one. The // original persisted language is restored at the end. - let original = i18n::language(); - i18n::set_language(Language::ZhCN); + let original = i18n::language_code(); + i18n::set_language_code("zh-CN"); { let (handle, root) = open_shell(&mut cx, width, height); let image = cx.capture_screenshot(handle.into())?; @@ -107,7 +107,7 @@ fn main() -> Result<()> { capture_preferences(&mut cx, handle, &root, OUT_PREF_ZH)?; capture_manager(&mut cx, handle, &root, OUT_MGR_ZH)?; } - i18n::set_language(Language::EnUs); + i18n::set_language_code("en-US"); { let (handle, root) = open_shell(&mut cx, width, height); let image = cx.capture_screenshot(handle.into())?; @@ -118,7 +118,7 @@ fn main() -> Result<()> { capture_preferences(&mut cx, handle, &root, OUT_PREF_EN)?; capture_manager(&mut cx, handle, &root, OUT_MGR_EN)?; } - i18n::set_language(original); + i18n::set_language_code(&original); Ok(()) } diff --git a/src/oakui/ofx.rs b/src/oakui/ofx.rs index 3b743c5b0..aec2dee4f 100644 --- a/src/oakui/ofx.rs +++ b/src/oakui/ofx.rs @@ -903,8 +903,25 @@ mod tests { "clearing the selection should destroy the active interact" ); + // Wait for the destroy record: the active-interact slot is + // process-global, and a concurrent viewer frame sync (another + // test's real-engine viewer ticking in this binary) can take the + // interact out of the slot and destroy it a few milliseconds + // after our own clearing. Keep the marker env var set and poll — + // the contract (destroy reaches the plugin, in order) is still + // asserted in full below. + let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5); + let lines = loop { + let lines = read_marker(&marker); + if lines.iter().any(|l| l == "destroy") + || std::time::Instant::now() >= deadline + { + break lines; + } + std::thread::sleep(std::time::Duration::from_millis(10)); + }; + unsafe { std::env::remove_var(MARKER_ENV) }; - let lines = read_marker(&marker); let _ = std::fs::remove_file(&marker); // Lifecycle reached the plugin, in order.