From d74d667a58e006ccf50ba6694d0b5d8f30424de5 Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Tue, 29 Sep 2026 14:41:14 +0200 Subject: [PATCH] test(fonts): serialise the tests that read the shared font generation FONT_GENERATION is one global counter and cargo runs tests in parallel, so a test reading it, calling something, and reading it again could have a sibling bump it in between. loading_an_empty_font_list_does_not_throw_ away_every_threads_cache failed that way on a full-workspace run while every scoped run of the same module stayed green, which is what made it look like someone else's regression. The five tests that read or move the counter now take one mutex. Six consecutive full runs of the crate pass where one in a handful failed before. My own defect, introduced with the counter in #416. --- crates/rustmotion-core/src/engine/renderer/fonts.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/crates/rustmotion-core/src/engine/renderer/fonts.rs b/crates/rustmotion-core/src/engine/renderer/fonts.rs index f995275..cad9714 100644 --- a/crates/rustmotion-core/src/engine/renderer/fonts.rs +++ b/crates/rustmotion-core/src/engine/renderer/fonts.rs @@ -479,6 +479,14 @@ mod cache_invalidation_reaches_every_thread_tests { use rayon::prelude::*; use std::sync::atomic::Ordering; + static GENERATION_IS_SHARED: Mutex<()> = Mutex::new(()); + + fn hold_the_generation_still() -> std::sync::MutexGuard<'static, ()> { + GENERATION_IS_SHARED + .lock() + .unwrap_or_else(|e| e.into_inner()) + } + fn a_face(marker: u8) -> Vec { let mut data = vec![ 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, @@ -496,6 +504,7 @@ mod cache_invalidation_reaches_every_thread_tests { #[test] fn a_rayon_worker_drops_its_own_copy_when_the_generation_moves() { + let _serialised = hold_the_generation_still(); let before: Vec = (0..256) .into_par_iter() .map(|_| fill_this_threads_fallback_cache()) @@ -522,6 +531,7 @@ mod cache_invalidation_reaches_every_thread_tests { #[test] fn a_generation_cache_holds_its_entries_until_the_generation_moves() { + let _serialised = hold_the_generation_still(); let mut cache: GenerationCache = GenerationCache::new(); cache.current().insert(1, 10); cache.current().insert(2, 20); @@ -541,6 +551,7 @@ mod cache_invalidation_reaches_every_thread_tests { #[test] fn a_second_file_in_the_same_load_does_not_clobber_the_first() { + let _serialised = hold_the_generation_still(); let family = "rm-test-same-load"; invalidate_font_caches(); register_custom_font_variant(family, a_face(1), 400, false); @@ -555,6 +566,7 @@ mod cache_invalidation_reaches_every_thread_tests { #[test] fn the_next_load_supersedes_the_variant_the_previous_one_registered() { + let _serialised = hold_the_generation_still(); let family = "rm-test-reload"; invalidate_font_caches(); register_custom_font_variant(family, a_face(1), 400, false); @@ -571,6 +583,7 @@ mod cache_invalidation_reaches_every_thread_tests { #[test] fn loading_an_empty_font_list_does_not_throw_away_every_threads_cache() { + let _serialised = hold_the_generation_still(); let generation = FONT_GENERATION.load(Ordering::Acquire); load_custom_fonts(&[]); assert_eq!(