mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-21 01:01:43 +00:00
[wpilib] Make BooleanEvent more consistent (#5436)
Co-authored-by: Tyler Veness <calcmogul@gmail.com> Co-authored-by: Joseph Eng <91924258+KangarooKoala@users.noreply.github.com>
This commit is contained in:
487
wpilibc/src/test/native/cpp/event/BooleanEventTest.cpp
Normal file
487
wpilibc/src/test/native/cpp/event/BooleanEventTest.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "frc/event/BooleanEvent.h"
|
||||
#include "frc/event/EventLoop.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
TEST(BooleanEventTest, BinaryCompositions) {
|
||||
EventLoop loop;
|
||||
int andCounter = 0;
|
||||
int orCounter = 0;
|
||||
|
||||
EXPECT_EQ(0, andCounter);
|
||||
EXPECT_EQ(0, orCounter);
|
||||
|
||||
(BooleanEvent(&loop, [] { return true; }) && BooleanEvent(&loop, [] {
|
||||
return false;
|
||||
})).IfHigh([&] { ++andCounter; });
|
||||
(BooleanEvent(&loop, [] { return true; }) || BooleanEvent(&loop, [] {
|
||||
return false;
|
||||
})).IfHigh([&] { ++orCounter; });
|
||||
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(0, andCounter);
|
||||
EXPECT_EQ(1, orCounter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that composed edge events only execute on edges (two
|
||||
* rising edge events composed with and() should only execute when both signals
|
||||
* are on the rising edge)
|
||||
*/
|
||||
TEST(BooleanEventTest, BinaryCompositionsWithEdgeDecorators) {
|
||||
EventLoop loop;
|
||||
bool boolean1 = false;
|
||||
bool boolean2 = false;
|
||||
bool boolean3 = false;
|
||||
bool boolean4 = false;
|
||||
int counter = 0;
|
||||
|
||||
auto event1 = BooleanEvent(&loop, [&] { return boolean1; }).Rising();
|
||||
auto event2 = BooleanEvent(&loop, [&] { return boolean2; }).Rising();
|
||||
auto event3 = BooleanEvent(&loop, [&] { return boolean3; }).Rising();
|
||||
auto event4 = BooleanEvent(&loop, [&] { return boolean4; }).Rising();
|
||||
(event1 && event2).IfHigh([&] { ++counter; });
|
||||
(event3 || event4).IfHigh([&] { ++counter; });
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
boolean1 = true;
|
||||
boolean2 = true;
|
||||
boolean3 = true;
|
||||
boolean4 = true;
|
||||
loop.Poll(); // Both actions execute
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
loop.Poll(); // Nothing should happen since nothing is on rising edge
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean1 = false;
|
||||
boolean2 = false;
|
||||
boolean3 = false;
|
||||
boolean4 = false;
|
||||
loop.Poll(); // Nothing should happen
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean1 = true;
|
||||
loop.Poll(); // Nothing should happen since only Bool 1 is on rising edge
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean2 = true;
|
||||
loop.Poll(); // Bool 2 is on rising edge, but Bool 1 isn't, nothing should
|
||||
// happen
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean1 = false;
|
||||
boolean2 = false;
|
||||
loop.Poll(); // Nothing should happen
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean1 = true;
|
||||
boolean2 = true;
|
||||
loop.Poll(); // Bool 1 and 2 are on rising edge, increments counter once
|
||||
|
||||
EXPECT_EQ(3, counter);
|
||||
|
||||
boolean3 = true;
|
||||
loop.Poll(); // Bool 3 is on rising edge, increments counter once
|
||||
|
||||
EXPECT_EQ(4, counter);
|
||||
|
||||
loop.Poll(); // Nothing should happen, Bool 3 isn't on rising edge
|
||||
|
||||
EXPECT_EQ(4, counter);
|
||||
|
||||
boolean4 = true;
|
||||
loop.Poll(); // Bool 4 is on rising edge, increments counter once
|
||||
|
||||
EXPECT_EQ(5, counter);
|
||||
|
||||
loop.Poll(); // Nothing should happen, Bool 4 isn't on rising edge
|
||||
|
||||
EXPECT_EQ(5, counter);
|
||||
}
|
||||
|
||||
TEST(BooleanEventTest, BinaryCompositionLoopSemantics) {
|
||||
EventLoop loop1;
|
||||
EventLoop loop2;
|
||||
bool boolean1 = true;
|
||||
bool boolean2 = true;
|
||||
int counter1 = 0;
|
||||
int counter2 = 0;
|
||||
|
||||
(BooleanEvent(&loop1, [&] { return boolean1; }) && BooleanEvent(&loop2, [&] {
|
||||
return boolean2;
|
||||
})).IfHigh([&] { ++counter1; });
|
||||
(BooleanEvent(&loop2, [&] { return boolean2; }) && BooleanEvent(&loop1, [&] {
|
||||
return boolean1;
|
||||
})).IfHigh([&] { ++counter2; });
|
||||
|
||||
EXPECT_EQ(0, counter1);
|
||||
EXPECT_EQ(0, counter2);
|
||||
|
||||
loop1
|
||||
.Poll(); // 1st event executes, Bool 1 and 2 are true, increments counter
|
||||
|
||||
EXPECT_EQ(1, counter1);
|
||||
EXPECT_EQ(0, counter2);
|
||||
|
||||
loop2
|
||||
.Poll(); // 2nd event executes, Bool 1 and 2 are true, increments counter
|
||||
|
||||
EXPECT_EQ(1, counter1);
|
||||
EXPECT_EQ(1, counter2);
|
||||
|
||||
boolean2 = false;
|
||||
loop1.Poll(); // 1st event executes, Bool 2 is still true because loop 2
|
||||
// hasn't updated it, increments counter
|
||||
|
||||
EXPECT_EQ(2, counter1);
|
||||
EXPECT_EQ(1, counter2);
|
||||
|
||||
loop2.Poll(); // 2nd event executes, Bool 2 is now false because this loop
|
||||
// updated it, does nothing
|
||||
|
||||
EXPECT_EQ(2, counter1);
|
||||
EXPECT_EQ(1, counter2);
|
||||
|
||||
loop1.Poll(); // All bools are updated at this point, nothing should happen
|
||||
|
||||
EXPECT_EQ(2, counter1);
|
||||
EXPECT_EQ(1, counter2);
|
||||
|
||||
boolean2 = true;
|
||||
loop2.Poll(); // 2nd event executes, Bool 2 is true because this loop updated
|
||||
// it, increments counter
|
||||
|
||||
EXPECT_EQ(2, counter1);
|
||||
EXPECT_EQ(2, counter2);
|
||||
|
||||
loop1.Poll(); // 1st event executes, Bool 2 is true because loop 2 updated
|
||||
// it, increments counter
|
||||
|
||||
EXPECT_EQ(3, counter1);
|
||||
EXPECT_EQ(2, counter2);
|
||||
|
||||
boolean1 = false;
|
||||
loop2.Poll(); // 2nd event executes, Bool 1 is still true because loop 1
|
||||
// hasn't updated it, increments counter
|
||||
|
||||
EXPECT_EQ(3, counter1);
|
||||
EXPECT_EQ(3, counter2);
|
||||
|
||||
loop1.Poll(); // 1st event executes, Bool 1 is false because this loop
|
||||
// updated it, does nothing
|
||||
|
||||
EXPECT_EQ(3, counter1);
|
||||
EXPECT_EQ(3, counter2);
|
||||
|
||||
loop2.Poll(); // All bools are updated at this point, nothing should happen
|
||||
|
||||
EXPECT_EQ(3, counter1);
|
||||
EXPECT_EQ(3, counter2);
|
||||
}
|
||||
|
||||
/** Tests the order of actions bound to an event loop. */
|
||||
TEST(BooleanEventTest, PollOrdering) {
|
||||
EventLoop loop;
|
||||
bool boolean1 = true;
|
||||
bool boolean2 = true;
|
||||
bool enableAssert = false;
|
||||
int counter = 0;
|
||||
|
||||
(BooleanEvent( // This event binds an action to the event loop first
|
||||
&loop,
|
||||
[&] {
|
||||
if (enableAssert) {
|
||||
++counter;
|
||||
EXPECT_EQ(1, counter % 3);
|
||||
}
|
||||
return boolean1;
|
||||
}) && // The composed event binds an action to the event loop third
|
||||
// This event binds an action to the event loop second
|
||||
BooleanEvent(&loop, [&] {
|
||||
if (enableAssert) {
|
||||
++counter;
|
||||
EXPECT_EQ(2, counter % 3);
|
||||
}
|
||||
return boolean2;
|
||||
// This binds an action to the event loop fourth
|
||||
})).IfHigh([&] {
|
||||
if (enableAssert) {
|
||||
++counter;
|
||||
EXPECT_EQ(0, counter % 3);
|
||||
}
|
||||
});
|
||||
enableAssert = true;
|
||||
loop.Poll();
|
||||
loop.Poll();
|
||||
loop.Poll();
|
||||
loop.Poll();
|
||||
}
|
||||
|
||||
TEST(BooleanEventTest, EdgeDecorators) {
|
||||
EventLoop loop;
|
||||
bool boolean = false;
|
||||
int counter = 0;
|
||||
|
||||
BooleanEvent(&loop, [&] { return boolean; }).Falling().IfHigh([&] {
|
||||
--counter;
|
||||
});
|
||||
BooleanEvent(&loop, [&] { return boolean; }).Rising().IfHigh([&] {
|
||||
++counter;
|
||||
});
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
boolean = false;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(1, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(1, counter);
|
||||
|
||||
boolean = false;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that binding actions to the same edge event will result in all actions
|
||||
* executing.
|
||||
*/
|
||||
TEST(BooleanEventTest, EdgeReuse) {
|
||||
EventLoop loop;
|
||||
bool boolean = false;
|
||||
int counter = 0;
|
||||
|
||||
auto event = BooleanEvent(&loop, [&] { return boolean; }).Rising();
|
||||
event.IfHigh([&] { ++counter; });
|
||||
event.IfHigh([&] { ++counter; });
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean = false;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(4, counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that all actions execute on separate edge events constructed from the
|
||||
* original event.
|
||||
*/
|
||||
TEST(BooleanEventTest, EdgeReconstruct) {
|
||||
EventLoop loop;
|
||||
bool boolean = false;
|
||||
int counter = 0;
|
||||
|
||||
auto event = BooleanEvent(&loop, [&] { return boolean; });
|
||||
event.Rising().IfHigh([&] { ++counter; });
|
||||
event.Rising().IfHigh([&] { ++counter; });
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean = false;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(4, counter);
|
||||
}
|
||||
|
||||
/** Tests that all actions bound to an event will still execute even if the
|
||||
* signal is changed during the loop poll */
|
||||
TEST(BooleanEventTest, MidLoopBooleanChange) {
|
||||
EventLoop loop;
|
||||
bool boolean = false;
|
||||
int counter = 0;
|
||||
|
||||
auto event = BooleanEvent(&loop, [&] { return boolean; }).Rising();
|
||||
event.IfHigh([&] {
|
||||
boolean = false;
|
||||
++counter;
|
||||
});
|
||||
event.IfHigh([&] { ++counter; });
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean = false;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(4, counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that all actions bound to composed events will still execute even if
|
||||
* the composed signal changes during the loop poll.
|
||||
*/
|
||||
TEST(BooleanEventTest, MidLoopBooleanChangeWithComposedEvents) {
|
||||
EventLoop loop;
|
||||
bool boolean1 = false;
|
||||
bool boolean2 = false;
|
||||
bool boolean3 = false;
|
||||
bool boolean4 = false;
|
||||
int counter = 0;
|
||||
|
||||
auto event1 = BooleanEvent(&loop, [&] { return boolean1; });
|
||||
auto event2 = BooleanEvent(&loop, [&] { return boolean2; });
|
||||
auto event3 = BooleanEvent(&loop, [&] { return boolean3; });
|
||||
auto event4 = BooleanEvent(&loop, [&] { return boolean4; });
|
||||
event1.IfHigh([&] {
|
||||
boolean2 = false;
|
||||
boolean3 = false;
|
||||
++counter;
|
||||
});
|
||||
(event3 || event4).IfHigh([&] {
|
||||
boolean1 = false;
|
||||
++counter;
|
||||
});
|
||||
(event1 && event2).IfHigh([&] {
|
||||
boolean4 = false;
|
||||
++counter;
|
||||
});
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
boolean1 = true;
|
||||
boolean2 = true;
|
||||
boolean3 = true;
|
||||
boolean4 = true;
|
||||
loop.Poll(); // All three actions execute, incrementing the counter three
|
||||
// times and setting all booleans to false
|
||||
|
||||
EXPECT_EQ(3, counter);
|
||||
|
||||
loop.Poll(); // Nothing should happen since everything was set to false
|
||||
|
||||
EXPECT_EQ(3, counter);
|
||||
|
||||
boolean1 = true;
|
||||
boolean2 = true;
|
||||
loop.Poll(); // Bool 1 and 2 are true, increments counter twice, Bool 2 gets
|
||||
// set to false
|
||||
|
||||
EXPECT_EQ(5, counter);
|
||||
|
||||
boolean1 = false;
|
||||
loop.Poll(); // Nothing should happen
|
||||
|
||||
EXPECT_EQ(5, counter);
|
||||
|
||||
boolean1 = true;
|
||||
boolean3 = true;
|
||||
loop.Poll(); // Bool 1 and 3 are true, increments counter twice, Bool 3 gets
|
||||
// set to false
|
||||
|
||||
EXPECT_EQ(7, counter);
|
||||
|
||||
boolean1 = false;
|
||||
boolean4 = true;
|
||||
loop.Poll(); // Bool 4 is true, increments counter once
|
||||
|
||||
EXPECT_EQ(8, counter);
|
||||
}
|
||||
|
||||
TEST(BooleanEventTest, Negation) {
|
||||
EventLoop loop;
|
||||
bool boolean = false;
|
||||
int counter = 0;
|
||||
|
||||
(!BooleanEvent(&loop, [&] { return boolean; })).IfHigh([&] { ++counter; });
|
||||
|
||||
EXPECT_EQ(0, counter);
|
||||
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(1, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(1, counter);
|
||||
|
||||
boolean = false;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
|
||||
boolean = true;
|
||||
loop.Poll();
|
||||
|
||||
EXPECT_EQ(2, counter);
|
||||
}
|
||||
Reference in New Issue
Block a user