//! A test to confirm that `bevy` doesn't regress its system ambiguities count when using [`DefaultPlugins`]. //! This is run in CI. //! //! Note that because this test requires rendering, it isn't actually an integration test! //! Instead, it's secretly an example: you can run this test manually using `cargo run --example ambiguity_detection`. use bevy::{ ecs::schedule::{InternedScheduleLabel, LogLevel, ScheduleBuildSettings}, prelude::*, render::pipelined_rendering::RenderExtractApp, utils::HashMap, }; fn main() { let mut app = App::new(); app.add_plugins(DefaultPlugins); let main_app = app.main_mut(); configure_ambiguity_detection(main_app); let render_extract_app = app.sub_app_mut(RenderExtractApp); configure_ambiguity_detection(render_extract_app); // Ambiguities in the RenderApp are currently allowed. // Eventually, we should forbid these: see https://github.com/bevyengine/bevy/issues/7386 // Uncomment the lines below to show the current ambiguities in the RenderApp. // let sub_app = app.sub_app_mut(bevy_render::RenderApp); // configure_ambiguity_detection(sub_app); app.finish(); app.cleanup(); app.update(); let main_app_ambiguities = count_ambiguities(app.main()); assert_eq!( main_app_ambiguities.total(), 0, "Main app has unexpected ambiguities among the following schedules: \n{main_app_ambiguities:#?}.", ); // RenderApp is not checked here, because it is not within the App at this point. let render_extract_ambiguities = count_ambiguities(app.sub_app(RenderExtractApp)); assert_eq!( render_extract_ambiguities.total(), 0, "RenderExtract app has unexpected ambiguities among the following schedules: \n{render_extract_ambiguities:#?}", ); } /// Contains the number of conflicting systems per schedule. #[derive(Debug, Deref, DerefMut)] struct AmbiguitiesCount(pub HashMap); impl AmbiguitiesCount { fn total(&self) -> usize { self.values().sum() } } fn configure_ambiguity_detection(sub_app: &mut SubApp) { let mut schedules = sub_app.world_mut().resource_mut::(); for (_, schedule) in schedules.iter_mut() { schedule.set_build_settings(ScheduleBuildSettings { // NOTE: you can change this to `LogLevel::Ignore` to easily see the current number of ambiguities. ambiguity_detection: LogLevel::Warn, use_shortnames: false, ..default() }); } } /// Returns the number of conflicting systems per schedule. fn count_ambiguities(sub_app: &SubApp) -> AmbiguitiesCount { let schedules = sub_app.world().resource::(); let mut ambiguities = HashMap::new(); for (_, schedule) in schedules.iter() { let ambiguities_in_schedule = schedule.graph().conflicting_systems().len(); ambiguities.insert(schedule.label(), ambiguities_in_schedule); } AmbiguitiesCount(ambiguities) }