//! A test to confirm that `bevy` doesn't regress its system ambiguities count when using [`DefaultPlugins`].1//! This is run in CI.2//!3//! Note that because this test requires rendering, it isn't actually an integration test!4//! Instead, it's secretly an example: you can run this test manually using `cargo run --example ambiguity_detection`.56use bevy::{7ecs::schedule::{InternedScheduleLabel, LogLevel, ScheduleBuildSettings},8platform::collections::HashMap,9prelude::*,10render::{pipelined_rendering::PipelinedRenderingPlugin, RenderPlugin},11};1213fn main() {14let mut app = App::new();15app.add_plugins(16DefaultPlugins17.build()18.set(RenderPlugin {19// llvmpipe driver can cause segfaults when aborting the binary while pipelines are being20// compiled (which happens very quickly in this example since we only run for a single21// frame). Synchronous pipeline compilation helps prevent these segfaults as the22// rendering thread blocks on these pipeline compilations.23synchronous_pipeline_compilation: true,24..Default::default()25})26// We also have to disable pipelined rendering to ensure the test doesn't end while the27// rendering frame is still executing in another thread.28.disable::<PipelinedRenderingPlugin>(),29);3031let main_app = app.main_mut();32configure_ambiguity_detection(main_app);3334// Ambiguities in the RenderApp are currently allowed.35// Eventually, we should forbid these: see https://github.com/bevyengine/bevy/issues/738636// Uncomment the lines below to show the current ambiguities in the RenderApp.37// let sub_app = app.sub_app_mut(bevy_render::RenderApp);38// configure_ambiguity_detection(sub_app);3940app.finish();41app.cleanup();42app.update();4344let main_app_ambiguities = count_ambiguities(app.main());45assert_eq!(46main_app_ambiguities.total(),470,48"Main app has unexpected ambiguities among the following schedules: \n{main_app_ambiguities:#?}.",49);50}5152/// Contains the number of conflicting systems per schedule.53#[derive(Debug, Deref, DerefMut)]54struct AmbiguitiesCount(pub HashMap<InternedScheduleLabel, usize>);5556impl AmbiguitiesCount {57fn total(&self) -> usize {58self.values().sum()59}60}6162fn configure_ambiguity_detection(sub_app: &mut SubApp) {63let mut schedules = sub_app.world_mut().resource_mut::<Schedules>();64for (_, schedule) in schedules.iter_mut() {65schedule.set_build_settings(ScheduleBuildSettings {66// NOTE: you can change this to `LogLevel::Ignore` to easily see the current number of ambiguities.67ambiguity_detection: LogLevel::Warn,68use_shortnames: false,69..default()70});71}72}7374/// Returns the number of conflicting systems per schedule.75fn count_ambiguities(sub_app: &SubApp) -> AmbiguitiesCount {76let schedules = sub_app.world().resource::<Schedules>();77let mut ambiguities = <HashMap<_, _>>::default();78for (_, schedule) in schedules.iter() {79let ambiguities_in_schedule = schedule.graph().conflicting_systems().len();80ambiguities.insert(schedule.label(), ambiguities_in_schedule);81}82AmbiguitiesCount(ambiguities)83}848586