Merge pull request #579 from KattKnight/windows-test-fixes

This commit is contained in:
Claude committed 2026-10-10 12:49:56 +00:00
commit 0df89c84ec
4 files changed
+41 -6

No files matched your search

+3 -1
View File
@@ -373,7 +373,9 @@ fn mcp_autosave_survives_kill_and_restart_without_touching_desktop_settings() {
assert_eq!(manifest["ended"], false);
let mut restarted = McpChild::start(&config, true);
let init = restarted.rpc("initialize", json!({}));
assert!(init["instructions"].as_str().unwrap().contains(path));
// The instructions carry the auto-save state as JSON, where a Windows path's backslashes
// are escaped.
assert!(init["instructions"].as_str().unwrap().contains(&Value::from(path).to_string()));
assert_eq!(init["_meta"]["effectcraftAutoSave"]["previousSessions"][0]["autosave"], path);
restarted.tool("open_project", json!({"path":path}));
let comp = restarted.tool("get_comp", json!({"comp":"Survives restart"}));
+3 -1
View File
@@ -269,7 +269,9 @@ fn autosave_is_durable_before_reply_and_queries_do_not_rotate() {
drop(s); // Abrupt process loss has no EOF cleanup; the checkpoint already exists.
let mut restarted = server().with_autosave(&dir).unwrap();
let init = rpc(&mut restarted, 1, "initialize", json!({}));
assert!(init["instructions"].as_str().unwrap().contains(path));
// The instructions carry the auto-save state as JSON, where a Windows path's backslashes
// are escaped.
assert!(init["instructions"].as_str().unwrap().contains(&Value::from(path).to_string()));
assert_eq!(init["_meta"]["effectcraftAutoSave"]["previousSessions"][0]["autosave"], path);
call_json(&mut restarted, "open_project", json!({"path": path}));
assert_eq!(call_json(&mut restarted, "get_project", json!({}))["items"][0]["name"], "Durable");
+7 -1
View File
@@ -119,7 +119,13 @@ fn cmd_dragging_the_current_time_scrubs_and_an_idle_scrub_closes() {
#[test]
fn preview_with_audio_shows_every_frame_and_sounds_once_cached() {
let fake = Fake::default();
let (app, cid) = setup(true, &fake);
let (mut app, cid) = setup(true, &fake);
// Playback requests at most twice as many frames ahead per step as there are render threads.
// Four times that many frames take at least four steps to cache, so frames are shown silently
// first however fast the renderer is (with a fixed 2 s comp, a machine with many cores cached
// all of it before the first step and the sound started at once).
let ahead = (app.frames.parallelism() * 2).max(4);
app.session.execute("comp.settings", json!({"comp": cid.0, "duration": (4 * ahead) as f64 / 30.0})).unwrap();
// A little under one frame of input time per step.
let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).with_step_dt(1.0 / 31.0).build_eframe(|_| app);
h.run_steps(2);
+28 -3
View File
@@ -19,20 +19,45 @@ fn settle(h: &mut Harness<'_, EffectcraftApp>) {
}
}
/// egui_kittest's wgpu setup on the adapter the headless compositor picked (`name (Backend)`),
/// like the desktop app's window. Left alone, egui_kittest prefers a CPU adapter, which on
/// Windows is WARP on DirectX 12, where FXC fails to compile the compositor's kernels: the
/// viewer would stay on the CPU and the comparison would never run.
fn same_adapter(name: String) -> eframe::egui_wgpu::WgpuSetup {
let mut setup = egui_kittest::wgpu::default_wgpu_setup();
if let eframe::egui_wgpu::WgpuSetup::CreateNew(c) = &mut setup {
let fallback = c.native_adapter_selector.take();
c.native_adapter_selector = Some(std::sync::Arc::new(move |adapters, surface| {
let named = |a: &&eframe::wgpu::Adapter| format!("{} ({:?})", a.get_info().name, a.get_info().backend) == name;
match (adapters.iter().find(named), &fallback) {
(Some(a), _) => Ok(a.clone()),
(None, Some(f)) => f(adapters, surface),
(None, None) => adapters.first().cloned().ok_or_else(|| "No adapter found".to_owned()),
}
}));
}
setup
}
#[test]
fn viewer_draws_gpu_frames_that_match_the_cpu() {
let Some(probe) = effectcraft_gpu::Gpu::headless() else {
eprintln!("no GPU adapter: skipping");
return;
};
eprintln!("headless compositor adapter: {}", effectcraft_engine::render::Accelerator::name(&probe));
let adapter = effectcraft_engine::render::Accelerator::name(&probe);
eprintln!("headless compositor adapter: {adapter}");
// egui-wgpu creates its GL device with WebGL2's limits, which the compositor declines.
let gl = effectcraft_engine::render::Accelerator::name(&probe).ends_with("(Gl)");
let gl = adapter.ends_with("(Gl)");
drop(probe);
let mut s = Session::default();
s.execute("file.openDemoProject", json!({})).unwrap();
s.execute("time.set", json!({"time": 2.0})).unwrap();
let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).with_pixels_per_point(1.0).wgpu().build_eframe(|_| EffectcraftApp::new(s));
let mut h = Harness::builder()
.with_size(egui::vec2(1400.0, 900.0))
.with_pixels_per_point(1.0)
.wgpu_setup(same_adapter(adapter))
.build_eframe(|_| EffectcraftApp::new(s));
settle(&mut h);
if gl && h.state().gpu_adapter().is_none() {
eprintln!("egui-wgpu's GL device has WebGL2 limits: the viewer stays on the CPU, skipping");