//! Test helpers for working with Salsa databases use std::fmt; use std::marker::PhantomData; use salsa::id::AsId; use salsa::ingredient::Ingredient; use salsa::storage::HasIngredientsFor; /// Assert that the Salsa query described by the generic parameter `C` /// was executed at least once with the input `input` /// in the history span represented by `events`. pub fn assert_function_query_was_run<'db, C, Db, Jar>( db: &'db Db, to_function: impl FnOnce(&C) -> &salsa::function::FunctionIngredient, input: &C::Input<'db>, events: &[salsa::Event], ) where C: salsa::function::Configuration + salsa::storage::IngredientsFor, Jar: HasIngredientsFor, Db: salsa::DbWithJar, C::Input<'db>: AsId, { function_query_was_run(db, to_function, input, events, true); } /// Assert that there were no executions with the input `input` /// of the Salsa query described by the generic parameter `C` /// in the history span represented by `events`. pub fn assert_function_query_was_not_run<'db, C, Db, Jar>( db: &'db Db, to_function: impl FnOnce(&C) -> &salsa::function::FunctionIngredient, input: &C::Input<'db>, events: &[salsa::Event], ) where C: salsa::function::Configuration + salsa::storage::IngredientsFor, Jar: HasIngredientsFor, Db: salsa::DbWithJar, C::Input<'db>: AsId, { function_query_was_run(db, to_function, input, events, false); } fn function_query_was_run<'db, C, Db, Jar>( db: &'db Db, to_function: impl FnOnce(&C) -> &salsa::function::FunctionIngredient, input: &C::Input<'db>, events: &[salsa::Event], should_have_run: bool, ) where C: salsa::function::Configuration + salsa::storage::IngredientsFor, Jar: HasIngredientsFor, Db: salsa::DbWithJar, C::Input<'db>: AsId, { let (jar, _) = <_ as salsa::storage::HasJar<::Jar>>::jar(db); let ingredient = jar.ingredient(); let function_ingredient = to_function(ingredient); let ingredient_index = as Ingredient>::ingredient_index( function_ingredient, ); let did_run = events.iter().any(|event| { if let salsa::EventKind::WillExecute { database_key } = event.kind { database_key.ingredient_index() == ingredient_index && database_key.key_index() == input.as_id() } else { false } }); if should_have_run && !did_run { panic!( "Expected query {:?} to have run but it didn't", DebugIdx { db: PhantomData::, value_id: input.as_id(), ingredient: function_ingredient, } ); } else if !should_have_run && did_run { panic!( "Expected query {:?} not to have run but it did", DebugIdx { db: PhantomData::, value_id: input.as_id(), ingredient: function_ingredient, } ); } } struct DebugIdx<'a, I, Db> where I: Ingredient, { value_id: salsa::Id, ingredient: &'a I, db: PhantomData, } impl<'a, I, Db> fmt::Debug for DebugIdx<'a, I, Db> where I: Ingredient, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { self.ingredient.fmt_index(Some(self.value_id), f) } }