From 109e4dabd320a828840ab3cc88b0ed0739ef0bca Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 07:25:39 +0000 Subject: [PATCH 1/2] Windows: compare exported paths as paths in the same-folder export test same_folder_as_original_exports_next_to_each_photo compared path strings. The export joins the subfolder with '/', so on Windows it reports C:\...\A/Exports/IMG_1.jpg (a valid path) while the test expected C:\...\A\Exports/IMG_1.jpg. Found by running the tests on windows-latest (gap 9). Test-only change. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK --- crates/engine/src/tests_export.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/tests_export.rs b/crates/engine/src/tests_export.rs index 2f1a05116..e01e7fbd5 100644 --- a/crates/engine/src/tests_export.rs +++ b/crates/engine/src/tests_export.rs @@ -991,8 +991,9 @@ fn same_folder_as_original_exports_next_to_each_photo() { let exists = |p: &str| std::path::Path::new(p).exists(); let files = crate::export::export_batch(&mut s, &ids, &o, &to, &mut crate::export::write_file, &exists).unwrap(); let written: Vec<&str> = files.iter().map(|f| f["path"].as_str().unwrap()).collect(); - let mut want = vec![a.join("Exports/IMG_1.jpg").to_string_lossy().to_string(), b.join("Exports/IMG_1.jpg").to_string_lossy().to_string()]; - let mut got: Vec = written.iter().map(|p| p.to_string()).collect(); + // compared as paths: on Windows the export joins the subfolder with `/`, which `Path` treats as `\` + let mut want = vec![a.join("Exports").join("IMG_1.jpg"), b.join("Exports").join("IMG_1.jpg")]; + let mut got: Vec = written.iter().map(std::path::PathBuf::from).collect(); want.sort(); got.sort(); assert_eq!(got, want); From 5902a07354a7cccde55c2ff3e4cb18176550812c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 08:25:46 +0000 Subject: [PATCH 2/2] Windows: folder-drop tests name folders as the Folders tree does; offline test waits for its worker tests_folder_drop built widget ids from OS paths (C:\...), but the Folders tree names folders with '/' on every platform (libfolder:C:/Users/...), so 8 tests found no row on Windows. tests_offline asserted that the background probe had run without waiting for the worker thread; it now waits up to 5 s. Found by running the tests on windows-latest (gap 9). Test-only changes. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK --- crates/ui-egui/src/tests_folder_drop.rs | 15 ++++++++++----- crates/ui-egui/src/tests_offline.rs | 5 +++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/ui-egui/src/tests_folder_drop.rs b/crates/ui-egui/src/tests_folder_drop.rs index 9b4cb860a..0bb844d58 100644 --- a/crates/ui-egui/src/tests_folder_drop.rs +++ b/crates/ui-egui/src/tests_folder_drop.rs @@ -50,8 +50,13 @@ fn widget(h: &Headless, id: &str) -> Option { h.app.widgets.iter().find(|(w, _)| w == id).map(|(_, r)| *r) } +/// A folder as the Folders tree names it: `/`-separated on every platform. +fn tree_path(dir: &Path) -> String { + dir.to_string_lossy().replace('\\', "/") +} + fn folder_row(h: &Headless, dir: &Path) -> Option { - widget(h, &format!("source:libfolder:{}", dir.to_string_lossy())) + widget(h, &format!("source:libfolder:{}", tree_path(dir))) } fn id_of(h: &Headless, file: &str) -> u64 { @@ -180,7 +185,7 @@ fn photos_already_in_the_folder_stay_put() { let (root, trip, home) = folders("here"); let mut h = app(&[(trip.join("beach.png"), false), (home.join("garden.png"), false)]); // open the folder holding both - let toggle = widget(&h, &format!("libraryFolderToggle:{}", root.to_string_lossy())).unwrap(); + let toggle = widget(&h, &format!("libraryFolderToggle:{}", tree_path(&root))).unwrap(); h.app.synthetic.push(egui::Event::PointerMoved(toggle.center())); h.app.synthetic.push(egui::Event::PointerButton { pos: toggle.center(), @@ -284,7 +289,7 @@ fn cancelling_the_question_moves_nothing() { let target = if folder_row(&h, &home).is_some() { target } else { - click(&mut h, &format!("libraryFolderToggle:{}", root.to_string_lossy())); + click(&mut h, &format!("libraryFolderToggle:{}", tree_path(&root))); folder_row(&h, &home).unwrap() }; let undo = h.app.session.undo.len(); @@ -302,7 +307,7 @@ fn dont_ask_again_moves_the_next_drop_at_once() { let (root, trip, home) = folders("dont-ask"); std::fs::copy(trip.join("beach.png"), trip.join("dunes.png")).unwrap(); let mut h = app(&[(trip.join("beach.png"), false), (trip.join("dunes.png"), false), (home.join("garden.png"), false)]); - click(&mut h, &format!("libraryFolderToggle:{}", root.to_string_lossy())); + click(&mut h, &format!("libraryFolderToggle:{}", tree_path(&root))); let target = folder_row(&h, &home).unwrap(); let beach = id_of(&h, "beach.png"); h.app.session.selection = lightcraft_engine::Selection::single(lightcraft_catalog::PhotoId(beach)); @@ -327,7 +332,7 @@ fn dont_ask_again_moves_the_next_drop_at_once() { fn a_question_left_open_while_another_library_opens_moves_nothing() { let (root, trip, home) = folders("other-library"); let mut h = app(&[(trip.join("beach.png"), false), (home.join("garden.png"), false)]); - click(&mut h, &format!("libraryFolderToggle:{}", root.to_string_lossy())); + click(&mut h, &format!("libraryFolderToggle:{}", tree_path(&root))); let beach = id_of(&h, "beach.png"); let target = folder_row(&h, &home).unwrap(); drop_beach(&mut h, beach, target); diff --git a/crates/ui-egui/src/tests_offline.rs b/crates/ui-egui/src/tests_offline.rs index 9e0b85b78..5327412d1 100644 --- a/crates/ui-egui/src/tests_offline.rs +++ b/crates/ui-egui/src/tests_offline.rs @@ -155,6 +155,11 @@ fn offline_originals_never_block_a_frame() { h.app.session.execute("library.source", &json!({"kind": "missing"})).unwrap(); assert_eq!(h.app.session.source, LibrarySource::Missing); frames_while_asleep(&mut h, &nas, 20, "Missing Photos"); + // the probe runs on the background worker: give it time to start on a loaded machine + let asked = std::time::Instant::now(); + while calls.n.load(Ordering::SeqCst) == 0 && asked.elapsed() < std::time::Duration::from_secs(5) { + std::thread::sleep(std::time::Duration::from_millis(10)); + } assert!(calls.n.load(Ordering::SeqCst) > 0, "the probe was asked"); assert_eq!(h.app.session.visible().len(), 0, "unknown files count as there");