From afe2a71e59a3d09942dcb6fa40241e2cb8ada9ff Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 11 Nov 2026 15:03:07 -0800 Subject: [PATCH] Tests: the empty-params command sweeps leave plug-in caches alone every_command_survives_empty_params and read_only_commands_read_the_instance_of_a_picked_object run every command with {}. That includes plugin.clearCache, which without an id empties the cache of every plug-in installed in the process. When either sweep ran during plugin_storage_is_capped_and_survives_a_damaged_settings_file (called from plugins_keep_settings_and_a_cache_of_their_own_in_the_store), it deleted that test's cache entries Tile and tile. The test's st.clear_cache() == MAX_CACHE_BYTES + 3 assertion after the MAX_CACHE_SCAN folders then failed with 536870912 bytes freed. Both sweeps now leave plugin.clearCache out. tests/plugin_clear_cache.rs already runs it with {} in a test binary of its own. A new test runs the other plug-in commands with {} in the selection states that every_command_survives_empty_params uses, and checks that an installed plug-in's cache keeps its 3 bytes. --- crates/engine/src/lib.rs | 9 ++++++ crates/engine/src/tests.rs | 2 +- crates/engine/src/tests/dynamic_symbols.rs | 2 +- crates/engine/src/tests/plugins.rs | 34 ++++++++++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/lib.rs b/crates/engine/src/lib.rs index 091348a6b..c3eeaa277 100644 --- a/crates/engine/src/lib.rs +++ b/crates/engine/src/lib.rs @@ -347,6 +347,15 @@ pub(crate) fn adding_fonts() -> std::sync::MutexGuard<'static, ()> { FONTS.lock().unwrap_or_else(std::sync::PoisonError::into_inner) } +/// Whether the tests that run every command with `{}` run command `id`. `plugin.clearCache` is +/// left out: without an id it empties the cache of every plug-in installed in the process, which +/// includes the caches that the plug-in storage tests check while they run. +/// `tests/plugin_clear_cache.rs` runs it with `{}` in a test binary of its own. +#[cfg(test)] +pub(crate) fn runs_with_empty_params(id: &str) -> bool { + id != "plugin.clearCache" +} + #[cfg(test)] use tests::{ adjust as tests_adjust, clip as tests_clip, colormgmt as tests_colormgmt, expand as tests_expand, large_edits as tests_large_edits, diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index ca0501c8f..2cf0031a3 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -3160,7 +3160,7 @@ fn every_command_survives_empty_params() { // The view toggles among them flip the process-wide proof view. let _proof_view = crate::tests_colormgmt::GLOBAL.lock().unwrap_or_else(|e| e.into_inner()); for sel in [false, true] { - for c in command_specs() { + for c in command_specs().iter().filter(|c| crate::runs_with_empty_params(c.id)) { let mut s = session(); let a = rect(&mut s, 0.0, 0.0, 10.0, 10.0); rect(&mut s, 20.0, 0.0, 10.0, 10.0); diff --git a/crates/engine/src/tests/dynamic_symbols.rs b/crates/engine/src/tests/dynamic_symbols.rs index f4ae97bb1..278d979ef 100644 --- a/crates/engine/src/tests/dynamic_symbols.rs +++ b/crates/engine/src/tests/dynamic_symbols.rs @@ -1309,7 +1309,7 @@ fn a_lent_selection_tool_moves_the_instance_of_a_picked_object() { #[test] fn read_only_commands_read_the_instance_of_a_picked_object() { let mut failures = Vec::new(); - for spec in crate::cmd::command_specs().iter().filter(|c| !c.journal) { + for spec in crate::cmd::command_specs().iter().filter(|c| !c.journal && crate::runs_with_empty_params(c.id)) { let mut s = session(); let inst = pair(&mut s, "dynamic"); s.execute("symbol.instance.selectPart", &json!({"id": inst.0, "path": [1]})).unwrap(); diff --git a/crates/engine/src/tests/plugins.rs b/crates/engine/src/tests/plugins.rs index a4be6e554..dc52243e3 100644 --- a/crates/engine/src/tests/plugins.rs +++ b/crates/engine/src/tests/plugins.rs @@ -3242,6 +3242,40 @@ fn removing_an_id_that_is_not_installed_deletes_its_storage() { assert!(s.execute("plugin.remove", &json!({"id": id})).is_err(), "nothing left to remove"); } +/// The `plugin.*` commands that the tests running every command with `{}` run +/// ([`crate::runs_with_empty_params`]) leave the cache of an installed plug-in as it is, so +/// those tests can run beside the ones here that check a cache. Each command runs with `{}` in a +/// document with two rectangles, one or both selected, as `every_command_survives_empty_params` +/// runs it. +#[test] +fn plugin_commands_run_with_empty_params_keep_other_plugins_caches() { + let folder = crate::tests_links::Folder::new("plugin-storage-empty-params"); + let id = "test.engine.storageemptyparams"; + let mut s = session(); + s.attach_plugin_store(folder.0.clone()); + install_storing(&mut s, id, WRITES); + run(&mut s, "plugin.run", json!({"id": id, "ids": []})); + assert_eq!(run(&mut s, "plugin.info", json!({"id": id}))["cacheBytes"], json!(3)); + let mut ran = vec![]; + for all in [false, true] { + for c in crate::cmd::command_specs().iter().filter(|c| c.id.starts_with("plugin.") && crate::runs_with_empty_params(c.id)) { + let mut other = session(); + let a = rect(&mut other, 10.0, "#ff0000"); + rect(&mut other, 40.0, "#0000ff"); + if all { + run(&mut other, "select.all", json!({})); + } else { + run(&mut other, "select.set", json!({"ids": [a.0]})); + } + let _ = other.execute(c.id, &json!({})); + ran.push(c.id); + assert_eq!(run(&mut s, "plugin.info", json!({"id": id}))["cacheBytes"], json!(3), "after {}", c.id); + } + } + assert!(ran.contains(&"plugin.list"), "{ran:?}"); + run(&mut s, "plugin.remove", json!({"id": id})); +} + /// The settings file and the cache are checked: a file that doesn't read is moved aside and the /// settings start empty; a write past a cap fails and changes nothing; cache entries whose names /// differ only in case are two files; a removed plug-in's storage takes no more writes.