Skip to content

Commit d91d652

Browse files
committed
updated test that tests all combinators against simple rust operators
1 parent 762a09a commit d91d652

File tree

1 file changed

+217
-44
lines changed

1 file changed

+217
-44
lines changed

crates/bevy_ecs/src/schedule/condition.rs

Lines changed: 217 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,73 +1365,246 @@ mod tests {
13651365
}
13661366

13671367
#[test]
1368-
fn run_fallible_condition() {
1368+
fn combinators_with_maybe_failing_condition() {
1369+
use crate::system::RunSystemOnce;
13691370
use alloc::sync::Arc;
13701371
use core::sync::atomic::{AtomicUsize, Ordering};
13711372

1373+
// Things that should be tested:
1374+
// - the final result of the combinator is correct
1375+
// - the systems that are expected to run do run
1376+
// - the systems that are expected to not run do not run
1377+
13721378
#[derive(Component)]
13731379
struct Vacant;
13741380

1381+
// SystemConditions don't have mutable access to the world, so we use a
1382+
// `Res<AtomicCounter>` to count invocations.
13751383
#[derive(Resource, Default)]
13761384
struct AtomicCounter(Arc<AtomicUsize>);
13771385

1378-
fn is_true() -> bool {
1379-
true
1380-
}
1386+
// The following constants are used to represent a system having run.
1387+
// both are prime so that when multiplied they give a unique value for any TRUE^n*FALSE^m
1388+
const FALSE: usize = 2;
1389+
const TRUE: usize = 3;
13811390

1391+
// this is a system, but has the same side effect as `test_true`
13821392
fn is_true_inc(counter: Res<AtomicCounter>) -> bool {
1383-
counter.0.fetch_add(1, Ordering::SeqCst);
1384-
true
1393+
test_true(&counter)
13851394
}
13861395

1387-
fn noop() {}
1396+
// this is a system, but has the same side effect as `test_false`
1397+
fn is_false_inc(counter: Res<AtomicCounter>) -> bool {
1398+
test_false(&counter)
1399+
}
13881400

1389-
// This condition will always return true false, because `Vacant` is never present.
1401+
// This condition will always yield `false`, because `Vacant` is never present.
13901402
fn vacant(_: crate::system::Single<&Vacant>) -> bool {
13911403
true
13921404
}
13931405

1394-
let mut world = World::new();
1395-
world.init_resource::<Counter>();
1396-
world.init_resource::<AtomicCounter>();
1397-
let mut schedule = Schedule::default();
1406+
fn test_true(counter: &AtomicCounter) -> bool {
1407+
_ = counter
1408+
.0
1409+
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |v| Some(v * TRUE));
1410+
true
1411+
}
13981412

1399-
// This system should fail
1400-
assert!(crate::system::RunSystemOnce::run_system_once(&mut world, vacant).is_err());
1413+
fn test_false(counter: &AtomicCounter) -> bool {
1414+
_ = counter
1415+
.0
1416+
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |v| Some(v * FALSE));
1417+
false
1418+
}
14011419

1402-
schedule.add_systems(
1403-
(
1404-
increment_counter.run_if(is_true.or(vacant)),
1405-
increment_counter.run_if(is_true.xor(vacant)),
1406-
increment_counter.run_if(is_true.and(vacant)),
1407-
// vacant first
1408-
increment_counter.run_if(vacant.or(is_true)),
1409-
increment_counter.run_if(vacant.xor(is_true)),
1410-
increment_counter.run_if(vacant.and(is_true)),
1411-
)
1412-
.chain(),
1413-
);
1414-
schedule.add_systems(
1415-
(
1416-
increment_counter.run_if(is_true_inc.and(vacant)),
1417-
increment_counter.run_if(is_true_inc.xor(vacant)),
1418-
increment_counter.run_if(is_true_inc.or(vacant)),
1419-
noop.run_if(is_true_inc.or(vacant)),
1420-
// vacant first
1421-
increment_counter.run_if(vacant.and(is_true_inc)),
1422-
increment_counter.run_if(vacant.xor(is_true_inc)),
1423-
increment_counter.run_if(vacant.or(is_true_inc)),
1424-
noop.run_if(vacant.or(is_true_inc)),
1425-
)
1426-
.chain(),
1427-
);
1420+
// Helper function that runs a logic call and returns the result, as
1421+
// well as the prime factorization of the calls.
1422+
fn logic_call_result(f: impl FnOnce(&AtomicCounter) -> bool) -> (usize, bool) {
1423+
let counter = AtomicCounter(Arc::new(AtomicUsize::new(1)));
1424+
let result = f(&counter);
1425+
(counter.0.load(Ordering::SeqCst), result)
1426+
}
14281427

1429-
schedule.run(&mut world);
1430-
assert_eq!(world.resource::<Counter>().0, 8);
1428+
// we expect `true() || false()` to yield `true`, and short circuit after `true()`
14311429
assert_eq!(
1432-
world.resource::<AtomicCounter>().0.load(Ordering::SeqCst),
1433-
7
1430+
logic_call_result(|c| test_true(c) || test_false(c)),
1431+
(TRUE.pow(1) * FALSE.pow(0), true)
14341432
);
1433+
1434+
let mut world = World::new();
1435+
world.init_resource::<AtomicCounter>();
1436+
1437+
// ensure there are no `Vacant` entities
1438+
assert!(world.query::<&Vacant>().iter(&world).next().is_none());
1439+
assert!(matches!(
1440+
world.run_system_once((|| true).or(vacant)),
1441+
Ok(true)
1442+
));
1443+
1444+
// This system should fail
1445+
assert!(RunSystemOnce::run_system_once(&mut world, vacant).is_err());
1446+
1447+
#[track_caller]
1448+
fn assert_system<Marker>(
1449+
world: &mut World,
1450+
system: impl crate::system::IntoSystem<(), bool, Marker>,
1451+
equivalent_to: impl FnOnce(&AtomicCounter) -> bool,
1452+
) {
1453+
use crate::system::System;
1454+
1455+
world
1456+
.resource::<AtomicCounter>()
1457+
.0
1458+
.store(1, Ordering::SeqCst);
1459+
1460+
let system = crate::system::IntoSystem::into_system(system);
1461+
let name = system.name();
1462+
1463+
let out = RunSystemOnce::run_system_once(&mut *world, system).unwrap_or(false);
1464+
1465+
let (expected_counter, expected) = logic_call_result(equivalent_to);
1466+
let caller = std::panic::Location::caller();
1467+
let counter = world
1468+
.resource::<AtomicCounter>()
1469+
.0
1470+
.swap(1, Ordering::SeqCst);
1471+
1472+
assert_eq!(
1473+
out,
1474+
expected,
1475+
"At {}:{} System `{name}` yielded unexpected value `{out}`, expected `{expected}`",
1476+
caller.file(),
1477+
caller.line(),
1478+
);
1479+
1480+
assert_eq!(
1481+
counter, expected_counter,
1482+
"At {}:{} System `{name}` did not increment counter as expected: expected `{expected_counter}`, got `{counter}`",
1483+
caller.file(),
1484+
caller.line(),
1485+
);
1486+
}
1487+
1488+
assert_system(&mut world, is_true_inc.or(vacant), |c| {
1489+
test_true(c) || false
1490+
});
1491+
assert_system(&mut world, is_true_inc.nor(vacant), |c| {
1492+
!(test_true(c) || false)
1493+
});
1494+
assert_system(&mut world, is_true_inc.xor(vacant), |c| {
1495+
test_true(c) ^ false
1496+
});
1497+
assert_system(&mut world, is_true_inc.xnor(vacant), |c| {
1498+
!(test_true(c) ^ false)
1499+
});
1500+
assert_system(&mut world, is_true_inc.and(vacant), |c| {
1501+
test_true(c) && false
1502+
});
1503+
assert_system(&mut world, is_true_inc.nand(vacant), |c| {
1504+
!(test_true(c) && false)
1505+
});
1506+
1507+
// even if `vacant` fails as the first condition, where applicable (or,
1508+
// xor), `is_true_inc` should still be called. `and` and `nand` short
1509+
// circuit on an initial `false`.
1510+
assert_system(&mut world, vacant.or(is_true_inc), |c| {
1511+
false || test_true(c)
1512+
});
1513+
assert_system(&mut world, vacant.nor(is_true_inc), |c| {
1514+
!(false || test_true(c))
1515+
});
1516+
assert_system(&mut world, vacant.xor(is_true_inc), |c| {
1517+
false ^ test_true(c)
1518+
});
1519+
assert_system(&mut world, vacant.xnor(is_true_inc), |c| {
1520+
!(false ^ test_true(c))
1521+
});
1522+
assert_system(&mut world, vacant.and(is_true_inc), |c| {
1523+
false && test_true(c)
1524+
});
1525+
assert_system(&mut world, vacant.nand(is_true_inc), |c| {
1526+
!(false && test_true(c))
1527+
});
1528+
1529+
// the same logic ought to be the case with a condition that runs, but yields `false`:
1530+
assert_system(&mut world, is_true_inc.or(is_false_inc), |c| {
1531+
test_true(c) || test_false(c)
1532+
});
1533+
assert_system(&mut world, is_true_inc.nor(is_false_inc), |c| {
1534+
!(test_true(c) || test_false(c))
1535+
});
1536+
assert_system(&mut world, is_true_inc.xor(is_false_inc), |c| {
1537+
test_true(c) ^ test_false(c)
1538+
});
1539+
assert_system(&mut world, is_true_inc.xnor(is_false_inc), |c| {
1540+
!(test_true(c) ^ test_false(c))
1541+
});
1542+
assert_system(&mut world, is_true_inc.and(is_false_inc), |c| {
1543+
test_true(c) && test_false(c)
1544+
});
1545+
assert_system(&mut world, is_true_inc.nand(is_false_inc), |c| {
1546+
!(test_true(c) && test_false(c))
1547+
});
1548+
1549+
// and where one condition yields `false` and the other fails:
1550+
assert_system(&mut world, is_false_inc.or(vacant), |c| {
1551+
test_false(c) || false
1552+
});
1553+
assert_system(&mut world, is_false_inc.nor(vacant), |c| {
1554+
!(test_false(c) || false)
1555+
});
1556+
assert_system(&mut world, is_false_inc.xor(vacant), |c| {
1557+
test_false(c) ^ false
1558+
});
1559+
assert_system(&mut world, is_false_inc.xnor(vacant), |c| {
1560+
!(test_false(c) ^ false)
1561+
});
1562+
assert_system(&mut world, is_false_inc.and(vacant), |c| {
1563+
test_false(c) && false
1564+
});
1565+
assert_system(&mut world, is_false_inc.nand(vacant), |c| {
1566+
!(test_false(c) && false)
1567+
});
1568+
1569+
// and where both conditions yield `true`:
1570+
assert_system(&mut world, is_true_inc.or(is_true_inc), |c| {
1571+
test_true(c) || test_true(c)
1572+
});
1573+
assert_system(&mut world, is_true_inc.nor(is_true_inc), |c| {
1574+
!(test_true(c) || test_true(c))
1575+
});
1576+
assert_system(&mut world, is_true_inc.xor(is_true_inc), |c| {
1577+
test_true(c) ^ test_true(c)
1578+
});
1579+
assert_system(&mut world, is_true_inc.xnor(is_true_inc), |c| {
1580+
!(test_true(c) ^ test_true(c))
1581+
});
1582+
assert_system(&mut world, is_true_inc.and(is_true_inc), |c| {
1583+
test_true(c) && test_true(c)
1584+
});
1585+
assert_system(&mut world, is_true_inc.nand(is_true_inc), |c| {
1586+
!(test_true(c) && test_true(c))
1587+
});
1588+
1589+
// and where both conditions yield `false`:
1590+
assert_system(&mut world, is_false_inc.or(is_false_inc), |c| {
1591+
test_false(c) || test_false(c)
1592+
});
1593+
assert_system(&mut world, is_false_inc.nor(is_false_inc), |c| {
1594+
!(test_false(c) || test_false(c))
1595+
});
1596+
assert_system(&mut world, is_false_inc.xor(is_false_inc), |c| {
1597+
test_false(c) ^ test_false(c)
1598+
});
1599+
assert_system(&mut world, is_false_inc.xnor(is_false_inc), |c| {
1600+
!(test_false(c) ^ test_false(c))
1601+
});
1602+
assert_system(&mut world, is_false_inc.and(is_false_inc), |c| {
1603+
test_false(c) && test_false(c)
1604+
});
1605+
assert_system(&mut world, is_false_inc.nand(is_false_inc), |c| {
1606+
!(test_false(c) && test_false(c))
1607+
});
14351608
}
14361609

14371610
#[test]

0 commit comments

Comments
 (0)