1mod access;
123mod adapter_system;
124mod builder;
125mod combinator;
126mod commands;
127mod function_system;
128mod input;
129mod observer_system;
130mod query;
131mod schedule_system;
132mod system;
133mod system_name;
134mod system_param;
135mod system_registry;
136
137use core::any::TypeId;
138
139pub use access::*;
140pub use adapter_system::*;
141pub use builder::*;
142pub use combinator::*;
143pub use commands::*;
144pub use function_system::*;
145pub use input::*;
146pub use observer_system::*;
147pub use query::*;
148pub use schedule_system::*;
149pub use system::*;
150pub use system_name::*;
151pub use system_param::*;
152pub use system_registry::*;
153
154use crate::world::{FromWorld, World};
155
156#[diagnostic::on_unimplemented(
180 message = "`{Self}` is not a valid system with input `{In}` and output `{Out}`",
181 label = "invalid system"
182)]
183pub trait IntoSystem<In: SystemInput, Out, Marker>: Sized {
184 type System: System<In = In, Out = Out>;
186
187 fn into_system(this: Self) -> Self::System;
189
190 fn pipe<B, BIn, BOut, MarkerB>(self, system: B) -> IntoPipeSystem<Self, B>
204 where
205 Out: 'static,
206 B: IntoSystem<BIn, BOut, MarkerB>,
207 for<'a> BIn: SystemInput<Inner<'a> = Out>,
208 {
209 IntoPipeSystem::new(self, system)
210 }
211
212 fn map<T, F>(self, f: F) -> IntoAdapterSystem<F, Self>
232 where
233 F: Send + Sync + 'static + FnMut(Out) -> T,
234 {
235 IntoAdapterSystem::new(f, self)
236 }
237
238 fn with_input<T>(self, value: T) -> WithInputWrapper<Self::System, T>
261 where
262 for<'i> In: SystemInput<Inner<'i> = &'i mut T>,
263 T: Send + Sync + 'static,
264 {
265 WithInputWrapper::new(self, value)
266 }
267
268 fn with_input_from<T>(self) -> WithInputFromWrapper<Self::System, T>
302 where
303 for<'i> In: SystemInput<Inner<'i> = &'i mut T>,
304 T: FromWorld + Send + Sync + 'static,
305 {
306 WithInputFromWrapper::new(self)
307 }
308
309 #[inline]
311 fn system_type_id(&self) -> TypeId {
312 TypeId::of::<Self::System>()
313 }
314}
315
316impl<T: System> IntoSystem<T::In, T::Out, ()> for T {
318 type System = T;
319 fn into_system(this: Self) -> Self {
320 this
321 }
322}
323
324pub fn assert_is_system<In: SystemInput, Out: 'static, Marker>(
349 system: impl IntoSystem<In, Out, Marker>,
350) {
351 let mut system = IntoSystem::into_system(system);
352
353 let mut world = World::new();
355 system.initialize(&mut world);
356}
357
358pub fn assert_is_read_only_system<In, Out, Marker, S>(system: S)
382where
383 In: SystemInput,
384 Out: 'static,
385 S: IntoSystem<In, Out, Marker>,
386 S::System: ReadOnlySystem,
387{
388 assert_is_system(system);
389}
390
391pub fn assert_system_does_not_conflict<Out, Params, S: IntoSystem<(), Out, Params>>(sys: S) {
397 let mut world = World::new();
398 let mut system = IntoSystem::into_system(sys);
399 system.initialize(&mut world);
400 system.run((), &mut world).unwrap();
401}
402
403#[cfg(test)]
404#[expect(clippy::print_stdout, reason = "Allowed in tests.")]
405mod tests {
406 use alloc::{vec, vec::Vec};
407 use bevy_utils::default;
408 use core::any::TypeId;
409 use std::println;
410
411 use crate::{
412 archetype::Archetypes,
413 bundle::Bundles,
414 change_detection::DetectChanges,
415 component::{Component, Components},
416 entity::{Entities, Entity},
417 error::Result,
418 lifecycle::RemovedComponents,
419 name::Name,
420 prelude::{Add, AnyOf, EntityRef, On},
421 query::{Added, Changed, NestedQuery, Or, SpawnDetails, Spawned, With, Without},
422 resource::Resource,
423 schedule::{
424 common_conditions::resource_exists, ApplyDeferred, IntoScheduleConfigs, Schedule,
425 SystemCondition,
426 },
427 system::{
428 Commands, In, InMut, IntoSystem, Local, NonSend, NonSendMut, ParamSet, Query, Res,
429 ResMut, Single, StaticSystemParam, System, SystemState,
430 },
431 world::{DeferredWorld, EntityMut, FromWorld, World},
432 };
433
434 use super::ScheduleSystem;
435
436 #[derive(Resource, PartialEq, Debug)]
437 enum SystemRan {
438 Yes,
439 No,
440 }
441
442 #[derive(Component, Debug, Eq, PartialEq, Default)]
443 struct A;
444 #[derive(Component)]
445 struct B;
446 #[derive(Component)]
447 struct C;
448 #[derive(Component)]
449 struct D;
450 #[derive(Component)]
451 struct E;
452 #[derive(Component)]
453 struct F;
454
455 #[derive(Resource)]
456 struct ResA;
457 #[derive(Resource)]
458 struct ResB;
459 #[derive(Resource)]
460 struct ResC;
461 #[derive(Resource)]
462 struct ResD;
463 #[derive(Resource)]
464 struct ResE;
465 #[derive(Resource)]
466 struct ResF;
467
468 #[derive(Component, Debug)]
469 struct W<T>(T);
470
471 #[test]
472 fn simple_system() {
473 fn sys(query: Query<&A>) {
474 for a in &query {
475 println!("{a:?}");
476 }
477 }
478
479 let mut system = IntoSystem::into_system(sys);
480 let mut world = World::new();
481 world.spawn(A);
482
483 system.initialize(&mut world);
484 system.run((), &mut world).unwrap();
485 }
486
487 fn run_system<Marker, S: IntoScheduleConfigs<ScheduleSystem, Marker>>(
488 world: &mut World,
489 system: S,
490 ) {
491 let mut schedule = Schedule::default();
492 schedule.add_systems(system);
493 schedule.run(world);
494 }
495
496 #[test]
497 fn get_many_is_ordered() {
498 use crate::resource::Resource;
499 const ENTITIES_COUNT: usize = 1000;
500
501 #[derive(Resource)]
502 struct EntitiesArray(Vec<Entity>);
503
504 fn query_system(
505 mut ran: ResMut<SystemRan>,
506 entities_array: Res<EntitiesArray>,
507 q: Query<&W<usize>>,
508 ) {
509 let entities_array: [Entity; ENTITIES_COUNT] =
510 entities_array.0.clone().try_into().unwrap();
511
512 for (i, w) in (0..ENTITIES_COUNT).zip(q.get_many(entities_array).unwrap()) {
513 assert_eq!(i, w.0);
514 }
515
516 *ran = SystemRan::Yes;
517 }
518
519 fn query_system_mut(
520 mut ran: ResMut<SystemRan>,
521 entities_array: Res<EntitiesArray>,
522 mut q: Query<&mut W<usize>>,
523 ) {
524 let entities_array: [Entity; ENTITIES_COUNT] =
525 entities_array.0.clone().try_into().unwrap();
526
527 for (i, w) in (0..ENTITIES_COUNT).zip(q.get_many_mut(entities_array).unwrap()) {
528 assert_eq!(i, w.0);
529 }
530
531 *ran = SystemRan::Yes;
532 }
533
534 let mut world = World::default();
535 world.insert_resource(SystemRan::No);
536 let entity_ids = (0..ENTITIES_COUNT)
537 .map(|i| world.spawn(W(i)).id())
538 .collect();
539 world.insert_resource(EntitiesArray(entity_ids));
540
541 run_system(&mut world, query_system);
542 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
543
544 world.insert_resource(SystemRan::No);
545 run_system(&mut world, query_system_mut);
546 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
547 }
548
549 #[test]
550 fn or_param_set_system() {
551 fn query_system(
553 mut ran: ResMut<SystemRan>,
554 mut set: ParamSet<(
555 Query<(), Or<(Changed<A>, Changed<B>)>>,
556 Query<(), Or<(Added<A>, Added<B>)>>,
557 )>,
558 ) {
559 let changed = set.p0().iter().count();
560 let added = set.p1().iter().count();
561
562 assert_eq!(changed, 1);
563 assert_eq!(added, 1);
564
565 *ran = SystemRan::Yes;
566 }
567
568 let mut world = World::default();
569 world.insert_resource(SystemRan::No);
570 world.spawn((A, B));
571
572 run_system(&mut world, query_system);
573
574 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
575 }
576
577 #[test]
578 fn changed_resource_system() {
579 use crate::resource::Resource;
580
581 #[derive(Resource)]
582 struct Flipper(bool);
583
584 #[derive(Resource)]
585 struct Added(usize);
586
587 #[derive(Resource)]
588 struct Changed(usize);
589
590 fn incr_e_on_flip(
591 value: Res<Flipper>,
592 mut changed: ResMut<Changed>,
593 mut added: ResMut<Added>,
594 ) {
595 if value.is_added() {
596 added.0 += 1;
597 }
598
599 if value.is_changed() {
600 changed.0 += 1;
601 }
602 }
603
604 let mut world = World::default();
605 world.insert_resource(Flipper(false));
606 world.insert_resource(Added(0));
607 world.insert_resource(Changed(0));
608
609 let mut schedule = Schedule::default();
610
611 schedule.add_systems((incr_e_on_flip, ApplyDeferred, World::clear_trackers).chain());
612
613 schedule.run(&mut world);
614 assert_eq!(world.resource::<Added>().0, 1);
615 assert_eq!(world.resource::<Changed>().0, 1);
616
617 schedule.run(&mut world);
618 assert_eq!(world.resource::<Added>().0, 1);
619 assert_eq!(world.resource::<Changed>().0, 1);
620
621 world.resource_mut::<Flipper>().0 = true;
622 schedule.run(&mut world);
623 assert_eq!(world.resource::<Added>().0, 1);
624 assert_eq!(world.resource::<Changed>().0, 2);
625 }
626
627 #[test]
628 #[should_panic = "error[B0001]"]
629 fn option_has_no_filter_with() {
630 fn sys(_: Query<(Option<&A>, &mut B)>, _: Query<&mut B, Without<A>>) {}
631 let mut world = World::default();
632 run_system(&mut world, sys);
633 }
634
635 #[test]
636 fn option_doesnt_remove_unrelated_filter_with() {
637 fn sys(_: Query<(Option<&A>, &mut B, &A)>, _: Query<&mut B, Without<A>>) {}
638 let mut world = World::default();
639 run_system(&mut world, sys);
640 }
641
642 #[test]
643 fn any_of_working() {
644 fn sys(_: Query<AnyOf<(&mut A, &B)>>) {}
645 let mut world = World::default();
646 run_system(&mut world, sys);
647 }
648
649 #[test]
650 fn any_of_with_and_without_common() {
651 fn sys(_: Query<(&mut D, &C, AnyOf<(&A, &B)>)>, _: Query<&mut D, Without<C>>) {}
652 let mut world = World::default();
653 run_system(&mut world, sys);
654 }
655
656 #[test]
657 #[should_panic]
658 fn any_of_with_mut_and_ref() {
659 fn sys(_: Query<AnyOf<(&mut A, &A)>>) {}
660 let mut world = World::default();
661 run_system(&mut world, sys);
662 }
663
664 #[test]
665 #[should_panic]
666 fn any_of_with_ref_and_mut() {
667 fn sys(_: Query<AnyOf<(&A, &mut A)>>) {}
668 let mut world = World::default();
669 run_system(&mut world, sys);
670 }
671
672 #[test]
673 #[should_panic]
674 fn any_of_with_mut_and_option() {
675 fn sys(_: Query<AnyOf<(&mut A, Option<&A>)>>) {}
676 let mut world = World::default();
677 run_system(&mut world, sys);
678 }
679
680 #[test]
681 fn any_of_with_entity_and_mut() {
682 fn sys(_: Query<AnyOf<(Entity, &mut A)>>) {}
683 let mut world = World::default();
684 run_system(&mut world, sys);
685 }
686
687 #[test]
688 fn any_of_with_empty_and_mut() {
689 fn sys(_: Query<AnyOf<((), &mut A)>>) {}
690 let mut world = World::default();
691 run_system(&mut world, sys);
692 }
693
694 #[test]
695 #[should_panic = "error[B0001]"]
696 fn any_of_has_no_filter_with() {
697 fn sys(_: Query<(AnyOf<(&A, ())>, &mut B)>, _: Query<&mut B, Without<A>>) {}
698 let mut world = World::default();
699 run_system(&mut world, sys);
700 }
701
702 #[test]
703 #[should_panic]
704 fn any_of_with_conflicting() {
705 fn sys(_: Query<AnyOf<(&mut A, &mut A)>>) {}
706 let mut world = World::default();
707 run_system(&mut world, sys);
708 }
709
710 #[test]
711 fn any_of_has_filter_with_when_both_have_it() {
712 fn sys(_: Query<(AnyOf<(&A, &A)>, &mut B)>, _: Query<&mut B, Without<A>>) {}
713 let mut world = World::default();
714 run_system(&mut world, sys);
715 }
716
717 #[test]
718 fn any_of_doesnt_remove_unrelated_filter_with() {
719 fn sys(_: Query<(AnyOf<(&A, ())>, &mut B, &A)>, _: Query<&mut B, Without<A>>) {}
720 let mut world = World::default();
721 run_system(&mut world, sys);
722 }
723
724 #[test]
725 fn any_of_and_without() {
726 fn sys(_: Query<(AnyOf<(&A, &B)>, &mut C)>, _: Query<&mut C, (Without<A>, Without<B>)>) {}
727 let mut world = World::default();
728 run_system(&mut world, sys);
729 }
730
731 #[test]
732 #[should_panic = "error[B0001]"]
733 fn or_has_no_filter_with() {
734 fn sys(_: Query<&mut B, Or<(With<A>, With<B>)>>, _: Query<&mut B, Without<A>>) {}
735 let mut world = World::default();
736 run_system(&mut world, sys);
737 }
738
739 #[test]
740 fn or_has_filter_with_when_both_have_it() {
741 fn sys(_: Query<&mut B, Or<(With<A>, With<A>)>>, _: Query<&mut B, Without<A>>) {}
742 let mut world = World::default();
743 run_system(&mut world, sys);
744 }
745
746 #[test]
747 fn or_has_filter_with() {
748 fn sys(
749 _: Query<&mut C, Or<(With<A>, With<B>)>>,
750 _: Query<&mut C, (Without<A>, Without<B>)>,
751 ) {
752 }
753 let mut world = World::default();
754 run_system(&mut world, sys);
755 }
756
757 #[test]
758 fn or_expanded_with_and_without_common() {
759 fn sys(_: Query<&mut D, (With<A>, Or<(With<B>, With<C>)>)>, _: Query<&mut D, Without<A>>) {}
760 let mut world = World::default();
761 run_system(&mut world, sys);
762 }
763
764 #[test]
765 fn or_expanded_nested_with_and_without_common() {
766 fn sys(
767 _: Query<&mut E, (Or<((With<B>, With<C>), (With<C>, With<D>))>, With<A>)>,
768 _: Query<&mut E, (Without<B>, Without<D>)>,
769 ) {
770 }
771 let mut world = World::default();
772 run_system(&mut world, sys);
773 }
774
775 #[test]
776 #[should_panic = "error[B0001]"]
777 fn or_expanded_nested_with_and_disjoint_without() {
778 fn sys(
779 _: Query<&mut E, (Or<((With<B>, With<C>), (With<C>, With<D>))>, With<A>)>,
780 _: Query<&mut E, Without<D>>,
781 ) {
782 }
783 let mut world = World::default();
784 run_system(&mut world, sys);
785 }
786
787 #[test]
788 #[should_panic = "error[B0001]"]
789 fn or_expanded_nested_or_with_and_disjoint_without() {
790 fn sys(
791 _: Query<&mut D, Or<(Or<(With<A>, With<B>)>, Or<(With<A>, With<C>)>)>>,
792 _: Query<&mut D, Without<A>>,
793 ) {
794 }
795 let mut world = World::default();
796 run_system(&mut world, sys);
797 }
798
799 #[test]
800 fn or_expanded_nested_with_and_common_nested_without() {
801 fn sys(
802 _: Query<&mut D, Or<((With<A>, With<B>), (With<B>, With<C>))>>,
803 _: Query<&mut D, Or<(Without<D>, Without<B>)>>,
804 ) {
805 }
806 let mut world = World::default();
807 run_system(&mut world, sys);
808 }
809
810 #[test]
811 fn or_with_without_and_compatible_with_without() {
812 fn sys(
813 _: Query<&mut C, Or<(With<A>, Without<B>)>>,
814 _: Query<&mut C, (With<B>, Without<A>)>,
815 ) {
816 }
817 let mut world = World::default();
818 run_system(&mut world, sys);
819 }
820
821 #[test]
822 #[should_panic = "error[B0001]"]
823 fn with_and_disjoint_or_empty_without() {
824 fn sys(_: Query<&mut B, With<A>>, _: Query<&mut B, Or<((), Without<A>)>>) {}
825 let mut world = World::default();
826 run_system(&mut world, sys);
827 }
828
829 #[test]
830 #[should_panic = "error[B0001]"]
831 fn or_expanded_with_and_disjoint_nested_without() {
832 fn sys(
833 _: Query<&mut D, Or<(With<A>, With<B>)>>,
834 _: Query<&mut D, Or<(Without<A>, Without<B>)>>,
835 ) {
836 }
837 let mut world = World::default();
838 run_system(&mut world, sys);
839 }
840
841 #[test]
842 #[should_panic = "error[B0001]"]
843 fn or_expanded_nested_with_and_disjoint_nested_without() {
844 fn sys(
845 _: Query<&mut D, Or<((With<A>, With<B>), (With<B>, With<C>))>>,
846 _: Query<&mut D, Or<(Without<A>, Without<B>)>>,
847 ) {
848 }
849 let mut world = World::default();
850 run_system(&mut world, sys);
851 }
852
853 #[test]
854 fn or_doesnt_remove_unrelated_filter_with() {
855 fn sys(_: Query<&mut B, (Or<(With<A>, With<B>)>, With<A>)>, _: Query<&mut B, Without<A>>) {}
856 let mut world = World::default();
857 run_system(&mut world, sys);
858 }
859
860 #[test]
861 #[should_panic]
862 fn conflicting_query_mut_system() {
863 fn sys(_q1: Query<&mut A>, _q2: Query<&mut A>) {}
864
865 let mut world = World::default();
866 run_system(&mut world, sys);
867 }
868
869 #[test]
870 fn disjoint_query_mut_system() {
871 fn sys(_q1: Query<&mut A, With<B>>, _q2: Query<&mut A, Without<B>>) {}
872
873 let mut world = World::default();
874 run_system(&mut world, sys);
875 }
876
877 #[test]
878 fn disjoint_query_mut_read_component_system() {
879 fn sys(_q1: Query<(&mut A, &B)>, _q2: Query<&mut A, Without<B>>) {}
880
881 let mut world = World::default();
882 run_system(&mut world, sys);
883 }
884
885 #[test]
886 #[should_panic]
887 fn conflicting_query_immut_system() {
888 fn sys(_q1: Query<&A>, _q2: Query<&mut A>) {}
889
890 let mut world = World::default();
891 run_system(&mut world, sys);
892 }
893
894 #[test]
895 #[should_panic]
896 fn changed_trackers_or_conflict() {
897 fn sys(_: Query<&mut A>, _: Query<(), Or<(Changed<A>,)>>) {}
898
899 let mut world = World::default();
900 run_system(&mut world, sys);
901 }
902
903 #[test]
904 #[should_panic = "error[B0001]"]
905 fn nested_query_conflicts_with_main_query() {
906 fn sys(_: Query<(&mut A, NestedQuery<&A>)>) {}
907
908 let mut world = World::default();
909 run_system(&mut world, sys);
910 }
911
912 #[test]
913 #[should_panic = "error[B0001]"]
914 fn nested_query_conflicts_with_earlier_query() {
915 fn sys(_: Query<&mut A>, _: Query<NestedQuery<&A>>) {}
916
917 let mut world = World::default();
918 run_system(&mut world, sys);
919 }
920
921 #[test]
922 #[should_panic = "error[B0001]"]
923 fn nested_query_conflicts_with_later_query() {
924 fn sys(_: Query<NestedQuery<&A>>, _: Query<&mut A>) {}
925
926 let mut world = World::default();
927 run_system(&mut world, sys);
928 }
929
930 #[test]
931 fn query_set_system() {
932 fn sys(mut _set: ParamSet<(Query<&mut A>, Query<&A>)>) {}
933 let mut world = World::default();
934 run_system(&mut world, sys);
935 }
936
937 #[test]
938 #[should_panic]
939 fn conflicting_query_with_query_set_system() {
940 fn sys(_query: Query<&mut A>, _set: ParamSet<(Query<&mut A>, Query<&B>)>) {}
941
942 let mut world = World::default();
943 run_system(&mut world, sys);
944 }
945
946 #[test]
947 #[should_panic]
948 fn conflicting_query_sets_system() {
949 fn sys(_set_1: ParamSet<(Query<&mut A>,)>, _set_2: ParamSet<(Query<&mut A>, Query<&B>)>) {}
950
951 let mut world = World::default();
952 run_system(&mut world, sys);
953 }
954
955 #[derive(Default, Resource)]
956 struct BufferRes {
957 _buffer: Vec<u8>,
958 }
959
960 fn test_for_conflicting_resources<Marker, S: IntoSystem<(), (), Marker>>(sys: S) {
961 let mut world = World::default();
962 world.insert_resource(BufferRes::default());
963 world.insert_resource(ResA);
964 world.insert_resource(ResB);
965 run_system(&mut world, sys);
966 }
967
968 #[test]
969 #[should_panic]
970 fn conflicting_system_resources() {
971 fn sys(_: ResMut<BufferRes>, _: Res<BufferRes>) {}
972 test_for_conflicting_resources(sys);
973 }
974
975 #[test]
976 #[should_panic]
977 fn conflicting_system_resources_reverse_order() {
978 fn sys(_: Res<BufferRes>, _: ResMut<BufferRes>) {}
979 test_for_conflicting_resources(sys);
980 }
981
982 #[test]
983 #[should_panic]
984 fn conflicting_system_resources_multiple_mutable() {
985 fn sys(_: ResMut<BufferRes>, _: ResMut<BufferRes>) {}
986 test_for_conflicting_resources(sys);
987 }
988
989 #[test]
990 fn nonconflicting_system_resources() {
991 fn sys(_: Local<BufferRes>, _: ResMut<BufferRes>, _: Local<A>, _: ResMut<ResA>) {}
992 test_for_conflicting_resources(sys);
993 }
994
995 #[test]
996 fn local_system() {
997 let mut world = World::default();
998 world.insert_resource(ProtoFoo { value: 1 });
999 world.insert_resource(SystemRan::No);
1000
1001 struct Foo {
1002 value: u32,
1003 }
1004
1005 #[derive(Resource)]
1006 struct ProtoFoo {
1007 value: u32,
1008 }
1009
1010 impl FromWorld for Foo {
1011 fn from_world(world: &mut World) -> Self {
1012 Foo {
1013 value: world.resource::<ProtoFoo>().value + 1,
1014 }
1015 }
1016 }
1017
1018 fn sys(local: Local<Foo>, mut system_ran: ResMut<SystemRan>) {
1019 assert_eq!(local.value, 2);
1020 *system_ran = SystemRan::Yes;
1021 }
1022
1023 run_system(&mut world, sys);
1024
1025 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1027 }
1028
1029 #[test]
1030 #[expect(
1031 dead_code,
1032 reason = "The `NotSend1` and `NotSend2` structs is used to verify that a system will run, even if the system params include a non-Send resource. As such, the inner value doesn't matter."
1033 )]
1034 fn non_send_option_system() {
1035 let mut world = World::default();
1036
1037 world.insert_resource(SystemRan::No);
1038 struct NotSend1(alloc::rc::Rc<i32>);
1042 struct NotSend2(alloc::rc::Rc<i32>);
1043 world.insert_non_send(NotSend1(alloc::rc::Rc::new(0)));
1044
1045 fn sys(
1046 op: Option<NonSend<NotSend1>>,
1047 mut _op2: Option<NonSendMut<NotSend2>>,
1048 mut system_ran: ResMut<SystemRan>,
1049 ) {
1050 op.expect("NonSend should exist");
1051 *system_ran = SystemRan::Yes;
1052 }
1053
1054 run_system(&mut world, sys);
1055 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1057 }
1058
1059 #[test]
1060 #[expect(
1061 dead_code,
1062 reason = "The `NotSend1` and `NotSend2` structs are used to verify that a system will run, even if the system params include a non-Send resource. As such, the inner value doesn't matter."
1063 )]
1064 fn non_send_system() {
1065 let mut world = World::default();
1066
1067 world.insert_resource(SystemRan::No);
1068 struct NotSend1(alloc::rc::Rc<i32>);
1069 struct NotSend2(alloc::rc::Rc<i32>);
1070
1071 world.insert_non_send(NotSend1(alloc::rc::Rc::new(1)));
1072 world.insert_non_send(NotSend2(alloc::rc::Rc::new(2)));
1073
1074 fn sys(
1075 _op: NonSend<NotSend1>,
1076 mut _op2: NonSendMut<NotSend2>,
1077 mut system_ran: ResMut<SystemRan>,
1078 ) {
1079 *system_ran = SystemRan::Yes;
1080 }
1081
1082 run_system(&mut world, sys);
1083 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1084 }
1085
1086 #[test]
1087 fn removal_tracking() {
1088 let mut world = World::new();
1089
1090 let entity_to_despawn = world.spawn(W(1)).id();
1091 let entity_to_remove_w_from = world.spawn(W(2)).id();
1092 let spurious_entity = world.spawn_empty().id();
1093
1094 #[derive(Resource)]
1096 struct Despawned(Entity);
1097 world.insert_resource(Despawned(entity_to_despawn));
1098
1099 #[derive(Resource)]
1100 struct Removed(Entity);
1101 world.insert_resource(Removed(entity_to_remove_w_from));
1102
1103 #[derive(Default, Resource)]
1105 struct NSystems(usize);
1106 world.insert_resource(NSystems::default());
1107
1108 world.entity_mut(entity_to_despawn).despawn();
1110 world.entity_mut(spurious_entity).despawn();
1111
1112 fn validate_despawn(
1113 mut removed_i32: RemovedComponents<W<i32>>,
1114 despawned: Res<Despawned>,
1115 mut n_systems: ResMut<NSystems>,
1116 ) {
1117 assert_eq!(
1118 removed_i32.read().collect::<Vec<_>>(),
1119 &[despawned.0],
1120 "despawning causes the correct entity to show up in the 'RemovedComponent' system parameter."
1121 );
1122
1123 n_systems.0 += 1;
1124 }
1125
1126 run_system(&mut world, validate_despawn);
1127
1128 world.clear_trackers();
1131
1132 world.spawn(W(3));
1134 world.spawn(W(4));
1135 world.entity_mut(entity_to_remove_w_from).remove::<W<i32>>();
1136
1137 fn validate_remove(
1138 mut removed_i32: RemovedComponents<W<i32>>,
1139 despawned: Res<Despawned>,
1140 removed: Res<Removed>,
1141 mut n_systems: ResMut<NSystems>,
1142 ) {
1143 assert_eq!(
1146 removed_i32.read().collect::<Vec<_>>(),
1147 &[despawned.0, removed.0],
1148 "removing a component causes the correct entity to show up in the 'RemovedComponent' system parameter."
1149 );
1150
1151 n_systems.0 += 1;
1152 }
1153
1154 run_system(&mut world, validate_remove);
1155
1156 assert_eq!(world.resource::<NSystems>().0, 2);
1158 }
1159
1160 #[test]
1161 fn world_collections_system() {
1162 let mut world = World::default();
1163 world.insert_resource(SystemRan::No);
1164 world.spawn((W(42), W(true)));
1165 fn sys(
1166 archetypes: &Archetypes,
1167 components: &Components,
1168 entities: &Entities,
1169 bundles: &Bundles,
1170 query: Query<Entity, With<W<i32>>>,
1171 mut system_ran: ResMut<SystemRan>,
1172 ) {
1173 assert_eq!(query.iter().count(), 1, "entity exists");
1174 for entity in &query {
1175 let location = entities.get_spawned(entity).unwrap();
1176 let archetype = archetypes.get(location.archetype_id).unwrap();
1177 let archetype_components = archetype.components();
1178 let bundle_id = bundles
1179 .get_id(TypeId::of::<(W<i32>, W<bool>)>())
1180 .expect("Bundle used to spawn entity should exist");
1181 let bundle_info = bundles.get(bundle_id).unwrap();
1182 let mut bundle_components = bundle_info.contributed_components().to_vec();
1183 bundle_components.sort();
1184 for component_id in &bundle_components {
1185 assert!(
1186 components.get_info(*component_id).is_some(),
1187 "every bundle component exists in Components"
1188 );
1189 }
1190 assert_eq!(
1191 bundle_components, archetype_components,
1192 "entity's bundle components exactly match entity's archetype components"
1193 );
1194 }
1195 *system_ran = SystemRan::Yes;
1196 }
1197
1198 run_system(&mut world, sys);
1199
1200 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1202 }
1203
1204 #[test]
1205 fn get_system_conflicts() {
1206 fn sys_x(_: Res<ResA>, _: Res<ResB>, _: Query<(&C, &D)>) {}
1207
1208 fn sys_y(_: Res<ResA>, _: ResMut<ResB>, _: Query<(&C, &mut D)>) {}
1209
1210 let mut world = World::default();
1211 let mut x = IntoSystem::into_system(sys_x);
1212 let mut y = IntoSystem::into_system(sys_y);
1213 let x_access = x.initialize(&mut world);
1214 let y_access = y.initialize(&mut world);
1215
1216 let conflicts = x_access.get_conflicts(&y_access);
1217 let b_id = world.components().get_id(TypeId::of::<ResB>()).unwrap();
1218 let d_id = world.components().get_id(TypeId::of::<D>()).unwrap();
1219 assert_eq!(conflicts, vec![b_id, d_id].into());
1220 }
1221
1222 #[test]
1223 fn query_is_empty() {
1224 fn without_filter(not_empty: Query<&A>, empty: Query<&B>) {
1225 assert!(!not_empty.is_empty());
1226 assert!(empty.is_empty());
1227 }
1228
1229 fn with_filter(not_empty: Query<&A, With<C>>, empty: Query<&A, With<D>>) {
1230 assert!(!not_empty.is_empty());
1231 assert!(empty.is_empty());
1232 }
1233
1234 let mut world = World::default();
1235 world.spawn(A).insert(C);
1236
1237 let mut without_filter = IntoSystem::into_system(without_filter);
1238 without_filter.initialize(&mut world);
1239 without_filter.run((), &mut world).unwrap();
1240
1241 let mut with_filter = IntoSystem::into_system(with_filter);
1242 with_filter.initialize(&mut world);
1243 with_filter.run((), &mut world).unwrap();
1244 }
1245
1246 #[test]
1247 fn can_have_16_parameters() {
1248 fn sys_x(
1249 _: Res<ResA>,
1250 _: Res<ResB>,
1251 _: Res<ResC>,
1252 _: Res<ResD>,
1253 _: Res<ResE>,
1254 _: Res<ResF>,
1255 _: Query<&A>,
1256 _: Query<&B>,
1257 _: Query<&C>,
1258 _: Query<&D>,
1259 _: Query<&E>,
1260 _: Query<&F>,
1261 _: Query<(&A, &B)>,
1262 _: Query<(&C, &D)>,
1263 _: Query<(&E, &F)>,
1264 ) {
1265 }
1266 fn sys_y(
1267 _: (
1268 Res<ResA>,
1269 Res<ResB>,
1270 Res<ResC>,
1271 Res<ResD>,
1272 Res<ResE>,
1273 Res<ResF>,
1274 Query<&A>,
1275 Query<&B>,
1276 Query<&C>,
1277 Query<&D>,
1278 Query<&E>,
1279 Query<&F>,
1280 Query<(&A, &B)>,
1281 Query<(&C, &D)>,
1282 Query<(&E, &F)>,
1283 ),
1284 ) {
1285 }
1286 let mut world = World::default();
1287 let mut x = IntoSystem::into_system(sys_x);
1288 let mut y = IntoSystem::into_system(sys_y);
1289 x.initialize(&mut world);
1290 y.initialize(&mut world);
1291 }
1292
1293 #[test]
1294 fn read_system_state() {
1295 #[derive(Eq, PartialEq, Debug, Resource)]
1296 struct A(usize);
1297
1298 #[derive(Component, Eq, PartialEq, Debug)]
1299 struct B(usize);
1300
1301 let mut world = World::default();
1302 world.insert_resource(A(42));
1303 world.spawn(B(7));
1304
1305 let mut system_state: SystemState<(
1306 Res<A>,
1307 Option<Single<&B>>,
1308 ParamSet<(Query<&C>, Query<&D>)>,
1309 )> = SystemState::new(&mut world);
1310 let (a, query, _) = system_state.get(&world).unwrap();
1311 assert_eq!(*a, A(42), "returned resource matches initial value");
1312 assert_eq!(
1313 **query.unwrap(),
1314 B(7),
1315 "returned component matches initial value"
1316 );
1317 }
1318
1319 #[test]
1320 fn write_system_state() {
1321 #[derive(Resource, Eq, PartialEq, Debug)]
1322 struct A(usize);
1323
1324 #[derive(Component, Eq, PartialEq, Debug)]
1325 struct B(usize);
1326
1327 let mut world = World::default();
1328 world.insert_resource(A(42));
1329 world.spawn(B(7));
1330
1331 let mut system_state: SystemState<(ResMut<A>, Option<Single<&mut B>>)> =
1332 SystemState::new(&mut world);
1333
1334 let (a, query) = system_state.get_mut(&mut world).unwrap();
1338 assert_eq!(*a, A(42), "returned resource matches initial value");
1339 assert_eq!(
1340 **query.unwrap(),
1341 B(7),
1342 "returned component matches initial value"
1343 );
1344 }
1345
1346 #[test]
1347 fn system_state_change_detection() {
1348 #[derive(Component, Eq, PartialEq, Debug)]
1349 struct A(usize);
1350
1351 let mut world = World::default();
1352 let entity = world.spawn(A(1)).id();
1353
1354 let mut system_state: SystemState<Option<Single<&A, Changed<A>>>> =
1355 SystemState::new(&mut world);
1356 {
1357 let query = system_state.get(&world).unwrap();
1358 assert_eq!(**query.unwrap(), A(1));
1359 }
1360
1361 {
1362 let query = system_state.get(&world).unwrap();
1363 assert!(query.is_none());
1364 }
1365
1366 world.entity_mut(entity).get_mut::<A>().unwrap().0 = 2;
1367 {
1368 let query = system_state.get(&world).unwrap();
1369 assert_eq!(**query.unwrap(), A(2));
1370 }
1371 }
1372
1373 #[test]
1374 fn system_state_spawned() {
1375 let mut world = World::default();
1376 world.spawn(A);
1377 let spawn_tick = world.change_tick();
1378
1379 let mut system_state: SystemState<Option<Single<(&A, SpawnDetails), Spawned>>> =
1380 SystemState::new(&mut world);
1381 {
1382 let query = system_state.get(&world).unwrap();
1383 assert_eq!(query.unwrap().1.spawn_tick(), spawn_tick);
1384 }
1385
1386 {
1387 let query = system_state.get(&world).unwrap();
1388 assert!(query.is_none());
1389 }
1390 }
1391
1392 #[test]
1393 #[should_panic]
1394 fn system_state_invalid_world() {
1395 let mut world = World::default();
1396 let mut system_state = SystemState::<Query<&A>>::new(&mut world);
1397 let mismatched_world = World::default();
1398 system_state.get(&mismatched_world).unwrap();
1399 }
1400
1401 #[test]
1402 fn system_state_archetype_update() {
1403 #[derive(Component, Eq, PartialEq, Debug)]
1404 struct A(usize);
1405
1406 #[derive(Component, Eq, PartialEq, Debug)]
1407 struct B(usize);
1408
1409 let mut world = World::default();
1410 world.spawn(A(1));
1411
1412 let mut system_state = SystemState::<Query<&A>>::new(&mut world);
1413 {
1414 let query = system_state.get(&world).unwrap();
1415 assert_eq!(
1416 query.iter().collect::<Vec<_>>(),
1417 vec![&A(1)],
1418 "exactly one component returned"
1419 );
1420 }
1421
1422 world.spawn((A(2), B(2)));
1423 {
1424 let query = system_state.get(&world).unwrap();
1425 assert_eq!(
1426 query.iter().collect::<Vec<_>>(),
1427 vec![&A(1), &A(2)],
1428 "components from both archetypes returned"
1429 );
1430 }
1431 }
1432
1433 #[test]
1434 #[expect(
1435 dead_code,
1436 reason = "This test exists to show that read-only world-only queries can return data that lives as long as `'world`."
1437 )]
1438 fn long_life_test() {
1439 struct ResourceHolder<'w> {
1440 value: &'w ResA,
1441 }
1442
1443 struct Holder<'w> {
1444 value: &'w A,
1445 }
1446
1447 struct State {
1448 state: SystemState<Res<'static, ResA>>,
1449 state_q: SystemState<Query<'static, 'static, &'static A>>,
1450 }
1451
1452 impl State {
1453 fn hold_res<'w>(&mut self, world: &'w World) -> ResourceHolder<'w> {
1454 let a = self.state.get(world).unwrap();
1455 ResourceHolder {
1456 value: a.into_inner(),
1457 }
1458 }
1459 fn hold_component<'w>(&mut self, world: &'w World, entity: Entity) -> Holder<'w> {
1460 let q = self.state_q.get(world).unwrap();
1461 let a = q.get_inner(entity).unwrap();
1462 Holder { value: a }
1463 }
1464 fn hold_components<'w>(&mut self, world: &'w World) -> Vec<Holder<'w>> {
1465 let mut components = Vec::new();
1466 let q = self.state_q.get(world).unwrap();
1467 for a in q.iter_inner() {
1468 components.push(Holder { value: a });
1469 }
1470 components
1471 }
1472 }
1473 }
1474
1475 #[test]
1476 fn immutable_mut_test() {
1477 #[derive(Component, Eq, PartialEq, Debug, Clone, Copy)]
1478 struct A(usize);
1479
1480 let mut world = World::default();
1481 world.spawn(A(1));
1482 world.spawn(A(2));
1483
1484 let mut system_state = SystemState::<Query<&mut A>>::new(&mut world);
1485 {
1486 let mut query = system_state.get_mut(&mut world).unwrap();
1487 assert_eq!(
1488 query.iter_mut().map(|m| *m).collect::<Vec<A>>(),
1489 vec![A(1), A(2)],
1490 "both components returned by iter_mut of &mut"
1491 );
1492 assert_eq!(
1493 query.iter().collect::<Vec<&A>>(),
1494 vec![&A(1), &A(2)],
1495 "both components returned by iter of &mut"
1496 );
1497 }
1498 }
1499
1500 #[test]
1501 fn convert_mut_to_immut() {
1502 {
1503 let mut world = World::new();
1504
1505 fn mutable_query(mut query: Query<&mut A>) {
1506 for _ in &mut query {}
1507
1508 immutable_query(query.as_readonly());
1509 }
1510
1511 fn immutable_query(_: Query<&A>) {}
1512
1513 let mut sys = IntoSystem::into_system(mutable_query);
1514 sys.initialize(&mut world);
1515 }
1516
1517 {
1518 let mut world = World::new();
1519
1520 fn mutable_query(mut query: Query<Option<&mut A>>) {
1521 for _ in &mut query {}
1522
1523 immutable_query(query.as_readonly());
1524 }
1525
1526 fn immutable_query(_: Query<Option<&A>>) {}
1527
1528 let mut sys = IntoSystem::into_system(mutable_query);
1529 sys.initialize(&mut world);
1530 }
1531
1532 {
1533 let mut world = World::new();
1534
1535 fn mutable_query(mut query: Query<(&mut A, &B)>) {
1536 for _ in &mut query {}
1537
1538 immutable_query(query.as_readonly());
1539 }
1540
1541 fn immutable_query(_: Query<(&A, &B)>) {}
1542
1543 let mut sys = IntoSystem::into_system(mutable_query);
1544 sys.initialize(&mut world);
1545 }
1546
1547 {
1548 let mut world = World::new();
1549
1550 fn mutable_query(mut query: Query<(&mut A, &mut B)>) {
1551 for _ in &mut query {}
1552
1553 immutable_query(query.as_readonly());
1554 }
1555
1556 fn immutable_query(_: Query<(&A, &B)>) {}
1557
1558 let mut sys = IntoSystem::into_system(mutable_query);
1559 sys.initialize(&mut world);
1560 }
1561
1562 {
1563 let mut world = World::new();
1564
1565 fn mutable_query(mut query: Query<(&mut A, &mut B), With<C>>) {
1566 for _ in &mut query {}
1567
1568 immutable_query(query.as_readonly());
1569 }
1570
1571 fn immutable_query(_: Query<(&A, &B), With<C>>) {}
1572
1573 let mut sys = IntoSystem::into_system(mutable_query);
1574 sys.initialize(&mut world);
1575 }
1576
1577 {
1578 let mut world = World::new();
1579
1580 fn mutable_query(mut query: Query<(&mut A, &mut B), Without<C>>) {
1581 for _ in &mut query {}
1582
1583 immutable_query(query.as_readonly());
1584 }
1585
1586 fn immutable_query(_: Query<(&A, &B), Without<C>>) {}
1587
1588 let mut sys = IntoSystem::into_system(mutable_query);
1589 sys.initialize(&mut world);
1590 }
1591
1592 {
1593 let mut world = World::new();
1594
1595 fn mutable_query(mut query: Query<(&mut A, &mut B), Added<C>>) {
1596 for _ in &mut query {}
1597
1598 immutable_query(query.as_readonly());
1599 }
1600
1601 fn immutable_query(_: Query<(&A, &B), Added<C>>) {}
1602
1603 let mut sys = IntoSystem::into_system(mutable_query);
1604 sys.initialize(&mut world);
1605 }
1606
1607 {
1608 let mut world = World::new();
1609
1610 fn mutable_query(mut query: Query<(&mut A, &mut B), Changed<C>>) {
1611 for _ in &mut query {}
1612
1613 immutable_query(query.as_readonly());
1614 }
1615
1616 fn immutable_query(_: Query<(&A, &B), Changed<C>>) {}
1617
1618 let mut sys = IntoSystem::into_system(mutable_query);
1619 sys.initialize(&mut world);
1620 }
1621
1622 {
1623 let mut world = World::new();
1624
1625 fn mutable_query(mut query: Query<(&mut A, &mut B, SpawnDetails), Spawned>) {
1626 for _ in &mut query {}
1627
1628 immutable_query(query.as_readonly());
1629 }
1630
1631 fn immutable_query(_: Query<(&A, &B, SpawnDetails), Spawned>) {}
1632
1633 let mut sys = IntoSystem::into_system(mutable_query);
1634 sys.initialize(&mut world);
1635 }
1636 }
1637
1638 #[test]
1639 fn commands_param_set() {
1640 let mut world = World::new();
1642 let entity = world.spawn_empty().id();
1643
1644 run_system(
1645 &mut world,
1646 move |mut commands_set: ParamSet<(Commands, Commands)>| {
1647 commands_set.p0().entity(entity).insert(A);
1648 commands_set.p1().entity(entity).insert(B);
1649 },
1650 );
1651
1652 let entity = world.entity(entity);
1653 assert!(entity.contains::<A>());
1654 assert!(entity.contains::<B>());
1655 }
1656
1657 #[test]
1658 fn into_iter_impl() {
1659 let mut world = World::new();
1660 world.spawn(W(42u32));
1661 run_system(&mut world, |mut q: Query<&mut W<u32>>| {
1662 for mut a in &mut q {
1663 assert_eq!(a.0, 42);
1664 a.0 = 0;
1665 }
1666 for a in &q {
1667 assert_eq!(a.0, 0);
1668 }
1669 });
1670 }
1671
1672 #[test]
1673 #[should_panic]
1674 fn assert_system_does_not_conflict() {
1675 fn system(_query: Query<(&mut W<u32>, &mut W<u32>)>) {}
1676 super::assert_system_does_not_conflict(system);
1677 }
1678
1679 #[test]
1680 #[should_panic]
1681 fn assert_world_and_entity_mut_system_does_conflict_first() {
1682 fn system(_query: &World, _q2: Query<EntityMut>) {}
1683 super::assert_system_does_not_conflict(system);
1684 }
1685
1686 #[test]
1687 #[should_panic]
1688 fn assert_world_and_entity_mut_system_does_conflict_second() {
1689 fn system(_: Query<EntityMut>, _: &World) {}
1690 super::assert_system_does_not_conflict(system);
1691 }
1692
1693 #[test]
1694 #[should_panic]
1695 fn assert_entity_ref_and_entity_mut_system_does_conflict() {
1696 fn system(_query: Query<EntityRef>, _q2: Query<EntityMut>) {}
1697 super::assert_system_does_not_conflict(system);
1698 }
1699
1700 #[test]
1701 #[should_panic]
1702 fn assert_entity_mut_system_does_conflict() {
1703 fn system(_query: Query<EntityMut>, _q2: Query<EntityMut>) {}
1704 super::assert_system_does_not_conflict(system);
1705 }
1706
1707 #[test]
1708 #[should_panic]
1709 fn assert_deferred_world_and_entity_ref_system_does_conflict_first() {
1710 fn system(_world: DeferredWorld, _query: Query<EntityRef>) {}
1711 super::assert_system_does_not_conflict(system);
1712 }
1713
1714 #[test]
1715 #[should_panic]
1716 fn assert_deferred_world_and_entity_ref_system_does_conflict_second() {
1717 fn system(_query: Query<EntityRef>, _world: DeferredWorld) {}
1718 super::assert_system_does_not_conflict(system);
1719 }
1720
1721 #[test]
1722 fn assert_deferred_world_and_empty_query_does_not_conflict_first() {
1723 fn system(_world: DeferredWorld, _query: Query<Entity>) {}
1724 super::assert_system_does_not_conflict(system);
1725 }
1726
1727 #[test]
1728 fn assert_deferred_world_and_empty_query_does_not_conflict_second() {
1729 fn system(_query: Query<Entity>, _world: DeferredWorld) {}
1730 super::assert_system_does_not_conflict(system);
1731 }
1732
1733 #[test]
1734 #[should_panic]
1735 fn panic_inside_system() {
1736 let mut world = World::new();
1737 let system: fn() = || {
1738 panic!("this system panics");
1739 };
1740 run_system(&mut world, system);
1741 }
1742
1743 #[test]
1744 fn assert_systems() {
1745 use core::str::FromStr;
1746
1747 use crate::{prelude::*, system::assert_is_system};
1748
1749 fn returning<T>() -> T {
1751 unimplemented!()
1752 }
1753
1754 fn exclusive_in_out<A, B>(_: In<A>, _: &mut World) -> B {
1756 unimplemented!()
1757 }
1758
1759 fn static_system_param(_: StaticSystemParam<Query<'static, 'static, &W<u32>>>) {
1760 unimplemented!()
1761 }
1762
1763 fn exclusive_with_state(
1764 _: &mut World,
1765 _: Local<bool>,
1766 _: (&mut QueryState<&W<i32>>, &mut SystemState<Query<&W<u32>>>),
1767 _: (),
1768 ) {
1769 unimplemented!()
1770 }
1771
1772 fn not(In(val): In<bool>) -> bool {
1773 !val
1774 }
1775
1776 assert_is_system(returning::<Result<u32, std::io::Error>>.map(Result::unwrap));
1777 assert_is_system(returning::<Option<()>>.map(drop));
1778 assert_is_system(returning::<&str>.map(u64::from_str).map(Result::unwrap));
1779 assert_is_system(static_system_param);
1780 assert_is_system(
1781 exclusive_in_out::<(), Result<(), std::io::Error>>.map(|_out| {
1782 #[cfg(feature = "trace")]
1783 if let Err(error) = _out {
1784 tracing::error!("{}", error);
1785 }
1786 }),
1787 );
1788 assert_is_system(exclusive_with_state);
1789 assert_is_system(returning::<bool>.pipe(exclusive_in_out::<bool, ()>));
1790
1791 let _ = returning::<()>.run_if(returning::<bool>.pipe(not));
1793 }
1794
1795 #[test]
1796 fn pipe_change_detection() {
1797 #[derive(Resource, Default)]
1798 struct Flag;
1799
1800 #[derive(Default)]
1801 struct Info {
1802 do_first: bool,
1804 do_second: bool,
1805
1806 first_flag: bool,
1808 second_flag: bool,
1809 }
1810
1811 fn first(In(mut info): In<Info>, mut flag: ResMut<Flag>) -> Info {
1812 if flag.is_changed() {
1813 info.first_flag = true;
1814 }
1815 if info.do_first {
1816 *flag = Flag;
1817 }
1818
1819 info
1820 }
1821
1822 fn second(In(mut info): In<Info>, mut flag: ResMut<Flag>) -> Info {
1823 if flag.is_changed() {
1824 info.second_flag = true;
1825 }
1826 if info.do_second {
1827 *flag = Flag;
1828 }
1829
1830 info
1831 }
1832
1833 let mut world = World::new();
1834 world.init_resource::<Flag>();
1835 let mut sys = IntoSystem::into_system(first.pipe(second));
1836 sys.initialize(&mut world);
1837
1838 sys.run(default(), &mut world).unwrap();
1839
1840 let info = sys
1842 .run(
1843 Info {
1844 do_first: true,
1845 ..default()
1846 },
1847 &mut world,
1848 )
1849 .unwrap();
1850 assert!(!info.first_flag);
1851 assert!(info.second_flag);
1852
1853 let info1 = sys
1856 .run(
1857 Info {
1858 do_second: true,
1859 ..default()
1860 },
1861 &mut world,
1862 )
1863 .unwrap();
1864 let info2 = sys.run(default(), &mut world).unwrap();
1865 assert!(!info1.first_flag);
1866 assert!(!info1.second_flag);
1867 assert!(info2.first_flag);
1868 assert!(!info2.second_flag);
1869 }
1870
1871 #[test]
1872 fn test_combinator_clone() {
1873 let mut world = World::new();
1874 #[derive(Resource)]
1875 struct A;
1876 #[derive(Resource)]
1877 struct B;
1878 #[derive(Resource, PartialEq, Eq, Debug)]
1879 struct C(i32);
1880
1881 world.insert_resource(A);
1882 world.insert_resource(C(0));
1883 let mut sched = Schedule::default();
1884 sched.add_systems(
1885 (
1886 |mut res: ResMut<C>| {
1887 res.0 += 1;
1888 },
1889 |mut res: ResMut<C>| {
1890 res.0 += 2;
1891 },
1892 )
1893 .distributive_run_if(resource_exists::<A>.or_eager(resource_exists::<B>)),
1894 );
1895 sched.initialize(&mut world).unwrap();
1896 sched.run(&mut world);
1897 assert_eq!(world.get_resource(), Some(&C(3)));
1898 }
1899
1900 #[test]
1901 #[cfg_attr(not(feature = "debug"), ignore)]
1902 #[should_panic(
1903 expected = "Encountered an error in system `bevy_ecs::system::tests::simple_fallible_system::sys`: error"
1904 )]
1905 fn simple_fallible_system() {
1906 fn sys() -> Result {
1907 Err("error")?;
1908 Ok(())
1909 }
1910
1911 let mut world = World::new();
1912 run_system(&mut world, sys);
1913 }
1914
1915 #[test]
1916 #[cfg_attr(not(feature = "debug"), ignore)]
1917 #[should_panic(
1918 expected = "Encountered an error in system `bevy_ecs::system::tests::simple_fallible_exclusive_system::sys`: error"
1919 )]
1920 fn simple_fallible_exclusive_system() {
1921 fn sys(_world: &mut World) -> Result {
1922 Err("error")?;
1923 Ok(())
1924 }
1925
1926 let mut world = World::new();
1927 run_system(&mut world, sys);
1928 }
1929
1930 #[test]
1944 fn nondiverging_never_trait_impls() {
1945 let mut world = World::new();
1950 let mut schedule = Schedule::default();
1951
1952 fn sys(_query: Query<&Name>) {
1953 todo!()
1954 }
1955
1956 schedule.add_systems(sys);
1957 schedule.add_systems(|_query: Query<&Name>| {});
1958 schedule.add_systems(|_query: Query<&Name>| todo!());
1959 schedule.add_systems(|_query: Query<&Name>| -> () { todo!() });
1960
1961 fn obs(_event: On<Add<Name>>) {
1962 todo!()
1963 }
1964
1965 world.add_observer(obs);
1966 world.add_observer(|_event: On<Add<Name>>| {});
1967 world.add_observer(|_event: On<Add<Name>>| todo!());
1968 world.add_observer(|_event: On<Add<Name>>| -> () { todo!() });
1969
1970 fn my_command(_world: &mut World) {
1971 todo!()
1972 }
1973
1974 world.commands().queue(my_command);
1975 world.commands().queue(|_world: &mut World| {});
1976 world.commands().queue(|_world: &mut World| todo!());
1977 world
1978 .commands()
1979 .queue(|_world: &mut World| -> () { todo!() });
1980 }
1981
1982 #[test]
1983 fn with_input() {
1984 fn sys(InMut(v): InMut<usize>) {
1985 *v += 1;
1986 }
1987
1988 let mut world = World::new();
1989 let mut system = IntoSystem::into_system(sys.with_input(42));
1990 system.initialize(&mut world);
1991 system.run((), &mut world).unwrap();
1992 assert_eq!(*system.value(), 43);
1993 }
1994
1995 #[test]
1996 fn with_input_from() {
1997 struct TestData(usize);
1998
1999 impl FromWorld for TestData {
2000 fn from_world(_world: &mut World) -> Self {
2001 Self(5)
2002 }
2003 }
2004
2005 fn sys(InMut(v): InMut<TestData>) {
2006 v.0 += 1;
2007 }
2008
2009 let mut world = World::new();
2010 let mut system = IntoSystem::into_system(sys.with_input_from::<TestData>());
2011 assert!(system.value().is_none());
2012 system.initialize(&mut world);
2013 assert!(system.value().is_some());
2014 system.run((), &mut world).unwrap();
2015 assert_eq!(system.value().unwrap().0, 6);
2016 }
2017}