blob: 4f07bcc4fe0a8cf7b7288fa51f3bb88607a9990e [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/util/phased_loop.h"
Brian Silvermandcaa3f72015-11-29 05:32:08 +00002
3#include "gtest/gtest.h"
4
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -05005#include "aos/testing/test_logging.h"
Brian Silvermandcaa3f72015-11-29 05:32:08 +00006
7namespace aos {
8namespace time {
9namespace testing {
10
Austin Schuh8aec1ed2016-05-01 13:29:20 -070011using ::std::chrono::milliseconds;
12
Brian Silvermandcaa3f72015-11-29 05:32:08 +000013class PhasedLoopTest : public ::testing::Test {
14 protected:
Austin Schuh8aec1ed2016-05-01 13:29:20 -070015 PhasedLoopTest() { ::aos::testing::EnableTestLogging(); }
Brian Silvermandcaa3f72015-11-29 05:32:08 +000016};
17
18typedef PhasedLoopTest PhasedLoopDeathTest;
19
Austin Schuh8aec1ed2016-05-01 13:29:20 -070020monotonic_clock::time_point InMs(int ms) {
21 return monotonic_clock::time_point(::std::chrono::milliseconds(ms));
22}
23
Brian Silvermandcaa3f72015-11-29 05:32:08 +000024TEST_F(PhasedLoopTest, Reset) {
25 {
Austin Schuhd32b3622019-06-23 18:49:06 -070026 PhasedLoop loop(milliseconds(100), monotonic_clock::epoch(),
27 milliseconds(0));
Brian Silvermandcaa3f72015-11-29 05:32:08 +000028
Austin Schuh8aec1ed2016-05-01 13:29:20 -070029 loop.Reset(monotonic_clock::epoch());
30 EXPECT_EQ(InMs(0), loop.sleep_time());
31 EXPECT_EQ(1, loop.Iterate(monotonic_clock::epoch()));
32 EXPECT_EQ(InMs(100), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000033
Austin Schuh8aec1ed2016-05-01 13:29:20 -070034 loop.Reset(InMs(99));
35 EXPECT_EQ(InMs(0), loop.sleep_time());
36 EXPECT_EQ(1, loop.Iterate(InMs(99)));
37 EXPECT_EQ(InMs(100), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000038
Austin Schuh8aec1ed2016-05-01 13:29:20 -070039 loop.Reset(InMs(100));
40 EXPECT_EQ(InMs(100), loop.sleep_time());
41 EXPECT_EQ(1, loop.Iterate(InMs(199)));
42 EXPECT_EQ(InMs(200), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000043
Austin Schuh8aec1ed2016-05-01 13:29:20 -070044 loop.Reset(InMs(101));
45 EXPECT_EQ(InMs(100), loop.sleep_time());
46 EXPECT_EQ(1, loop.Iterate(InMs(101)));
47 EXPECT_EQ(InMs(200), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000048 }
49 {
Austin Schuhd32b3622019-06-23 18:49:06 -070050 PhasedLoop loop(milliseconds(100), monotonic_clock::epoch(),
51 milliseconds(1));
Austin Schuh8aec1ed2016-05-01 13:29:20 -070052 loop.Reset(monotonic_clock::epoch());
53 EXPECT_EQ(InMs(-99), loop.sleep_time());
54 EXPECT_EQ(1, loop.Iterate(monotonic_clock::epoch()));
55 EXPECT_EQ(InMs(1), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000056 }
57 {
Austin Schuhd32b3622019-06-23 18:49:06 -070058 PhasedLoop loop(milliseconds(100), monotonic_clock::epoch(),
59 milliseconds(99));
Brian Silvermandcaa3f72015-11-29 05:32:08 +000060
Austin Schuh8aec1ed2016-05-01 13:29:20 -070061 loop.Reset(monotonic_clock::epoch());
62 EXPECT_EQ(InMs(-1), loop.sleep_time());
63 EXPECT_EQ(1, loop.Iterate(monotonic_clock::epoch()));
64 EXPECT_EQ(InMs(99), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000065
Austin Schuh8aec1ed2016-05-01 13:29:20 -070066 loop.Reset(InMs(98));
67 EXPECT_EQ(InMs(-1), loop.sleep_time());
68 EXPECT_EQ(1, loop.Iterate(InMs(98)));
69 EXPECT_EQ(InMs(99), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000070
Austin Schuh8aec1ed2016-05-01 13:29:20 -070071 loop.Reset(InMs(99));
72 EXPECT_EQ(InMs(99), loop.sleep_time());
73 EXPECT_EQ(1, loop.Iterate(InMs(99)));
74 EXPECT_EQ(InMs(199), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000075
Austin Schuh8aec1ed2016-05-01 13:29:20 -070076 loop.Reset(InMs(100));
77 EXPECT_EQ(InMs(99), loop.sleep_time());
78 EXPECT_EQ(1, loop.Iterate(InMs(100)));
79 EXPECT_EQ(InMs(199), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +000080 }
81}
82
83TEST_F(PhasedLoopTest, Iterate) {
84 {
Austin Schuhd32b3622019-06-23 18:49:06 -070085 PhasedLoop loop(milliseconds(100), monotonic_clock::epoch(),
86 milliseconds(99));
Austin Schuh8aec1ed2016-05-01 13:29:20 -070087 loop.Reset(monotonic_clock::epoch());
88 EXPECT_EQ(1, loop.Iterate(monotonic_clock::epoch()));
89 EXPECT_EQ(InMs(99), loop.sleep_time());
90 EXPECT_EQ(1, loop.Iterate(InMs(100)));
91 EXPECT_EQ(InMs(199), loop.sleep_time());
92 EXPECT_EQ(0, loop.Iterate(InMs(100)));
93 EXPECT_EQ(InMs(199), loop.sleep_time());
94 EXPECT_EQ(0, loop.Iterate(InMs(101)));
95 EXPECT_EQ(InMs(199), loop.sleep_time());
96 EXPECT_EQ(0, loop.Iterate(InMs(198)));
97 EXPECT_EQ(InMs(199), loop.sleep_time());
98 EXPECT_EQ(1, loop.Iterate(InMs(199)));
99 EXPECT_EQ(InMs(299), loop.sleep_time());
100 EXPECT_EQ(1, loop.Iterate(InMs(300)));
101 EXPECT_EQ(InMs(399), loop.sleep_time());
102 EXPECT_EQ(3, loop.Iterate(InMs(600)));
103 EXPECT_EQ(InMs(699), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +0000104 }
105 {
Austin Schuhd32b3622019-06-23 18:49:06 -0700106 PhasedLoop loop(milliseconds(100), monotonic_clock::epoch(),
107 milliseconds(1));
Austin Schuh8aec1ed2016-05-01 13:29:20 -0700108 loop.Reset(monotonic_clock::epoch());
109 EXPECT_EQ(1, loop.Iterate(monotonic_clock::epoch()));
110 EXPECT_EQ(InMs(1), loop.sleep_time());
111 EXPECT_EQ(1, loop.Iterate(InMs(100)));
112 EXPECT_EQ(InMs(101), loop.sleep_time());
113 EXPECT_EQ(0, loop.Iterate(InMs(100)));
114 EXPECT_EQ(InMs(101), loop.sleep_time());
115 EXPECT_EQ(1, loop.Iterate(InMs(103)));
116 EXPECT_EQ(InMs(201), loop.sleep_time());
117 EXPECT_EQ(0, loop.Iterate(InMs(198)));
118 EXPECT_EQ(InMs(201), loop.sleep_time());
119 EXPECT_EQ(0, loop.Iterate(InMs(200)));
120 EXPECT_EQ(InMs(201), loop.sleep_time());
121 EXPECT_EQ(1, loop.Iterate(InMs(201)));
122 EXPECT_EQ(InMs(301), loop.sleep_time());
123 EXPECT_EQ(3, loop.Iterate(InMs(600)));
124 EXPECT_EQ(InMs(601), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +0000125 }
126}
127
128// Makes sure that everything works correctly when crossing zero.
129// This seems like a rare case at first, but starting from zero needs to
130// work, which means negatives should too.
131TEST_F(PhasedLoopTest, CrossingZero) {
Austin Schuhd32b3622019-06-23 18:49:06 -0700132 PhasedLoop loop(milliseconds(100), monotonic_clock::epoch(), milliseconds(1));
Austin Schuh8aec1ed2016-05-01 13:29:20 -0700133 loop.Reset(InMs(-1000));
134 EXPECT_EQ(InMs(-1099), loop.sleep_time());
135 EXPECT_EQ(9, loop.Iterate(InMs(-250)));
136 EXPECT_EQ(InMs(-199), loop.sleep_time());
137 EXPECT_EQ(1, loop.Iterate(InMs(-199)));
138 EXPECT_EQ(InMs(-99), loop.sleep_time());
139 EXPECT_EQ(1, loop.Iterate(InMs(-90)));
140 EXPECT_EQ(InMs(1), loop.sleep_time());
141 EXPECT_EQ(0, loop.Iterate(InMs(0)));
142 EXPECT_EQ(InMs(1), loop.sleep_time());
143 EXPECT_EQ(1, loop.Iterate(InMs(1)));
144 EXPECT_EQ(InMs(101), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +0000145
Austin Schuh8aec1ed2016-05-01 13:29:20 -0700146 EXPECT_EQ(0, loop.Iterate(InMs(2)));
147 EXPECT_EQ(InMs(101), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +0000148
Austin Schuh8aec1ed2016-05-01 13:29:20 -0700149 EXPECT_EQ(-2, loop.Iterate(InMs(-101)));
150 EXPECT_EQ(InMs(-99), loop.sleep_time());
151 EXPECT_EQ(1, loop.Iterate(InMs(-99)));
152 EXPECT_EQ(InMs(1), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +0000153
Austin Schuh8aec1ed2016-05-01 13:29:20 -0700154 EXPECT_EQ(0, loop.Iterate(InMs(-99)));
155 EXPECT_EQ(InMs(1), loop.sleep_time());
Brian Silvermandcaa3f72015-11-29 05:32:08 +0000156}
157
Austin Schuh5d4b0982017-04-08 14:36:08 -0700158// Tests OffsetFromIntervalAndTime for various edge conditions.
159TEST_F(PhasedLoopTest, OffsetFromIntervalAndTimeTest) {
Austin Schuhd32b3622019-06-23 18:49:06 -0700160 PhasedLoop loop(milliseconds(1000), monotonic_clock::epoch(),
161 milliseconds(300));
Austin Schuh5d4b0982017-04-08 14:36:08 -0700162
163 EXPECT_EQ(milliseconds(1),
164 loop.OffsetFromIntervalAndTime(milliseconds(1000), InMs(1001)));
165
166 EXPECT_EQ(milliseconds(0),
167 loop.OffsetFromIntervalAndTime(milliseconds(1000), InMs(1000)));
168
169 EXPECT_EQ(milliseconds(0),
170 loop.OffsetFromIntervalAndTime(milliseconds(1000), InMs(0)));
171
172 EXPECT_EQ(milliseconds(999),
173 loop.OffsetFromIntervalAndTime(milliseconds(1000), InMs(-1)));
174
175 EXPECT_EQ(milliseconds(7),
176 loop.OffsetFromIntervalAndTime(milliseconds(1000), InMs(19115007)));
177
178 EXPECT_EQ(milliseconds(7), loop.OffsetFromIntervalAndTime(milliseconds(1000),
179 InMs(-19115993)));
180}
181
Brian Silvermandcaa3f72015-11-29 05:32:08 +0000182// Tests that passing invalid values to the constructor dies correctly.
183TEST_F(PhasedLoopDeathTest, InvalidValues) {
Austin Schuhd32b3622019-06-23 18:49:06 -0700184 EXPECT_DEATH(
185 PhasedLoop(milliseconds(1), monotonic_clock::epoch(), milliseconds(2)),
186 ".*offset<interval.*");
187 EXPECT_DEATH(
188 PhasedLoop(milliseconds(1), monotonic_clock::epoch(), milliseconds(1)),
189 ".*offset<interval.*");
190 EXPECT_DEATH(
191 PhasedLoop(milliseconds(1), monotonic_clock::epoch(), milliseconds(-1)),
192 ".*offset>=monotonic_clock::duration\\(0\\).*");
193 EXPECT_DEATH(
194 PhasedLoop(milliseconds(0), monotonic_clock::epoch(), milliseconds(0)),
195 ".*interval>monotonic_clock::duration\\(0\\).*");
Brian Silvermandcaa3f72015-11-29 05:32:08 +0000196}
197
198} // namespace testing
199} // namespace time
200} // namespace aos