1*6777b538SAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/moving_window.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
8*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker namespace base {
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker namespace {
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker constexpr int kTestValues[] = {
15*6777b538SAndroid Build Coastguard Worker 33, 1, 2, 7, 5, 2, 4, 45, 1000, 1, 100, 2, 200, 2, 2, 2, 300, 4, 1,
16*6777b538SAndroid Build Coastguard Worker 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1,
17*6777b538SAndroid Build Coastguard Worker 2, 1, 4, 2, 1, 8, 1, 2, 1, 4, 1, 2, 1, 16, 1, 2, 1};
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker } // namespace
20*6777b538SAndroid Build Coastguard Worker
21*6777b538SAndroid Build Coastguard Worker class MovingMaxTest : public testing::TestWithParam<unsigned int> {};
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(All,
24*6777b538SAndroid Build Coastguard Worker MovingMaxTest,
25*6777b538SAndroid Build Coastguard Worker testing::ValuesIn({1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u,
26*6777b538SAndroid Build Coastguard Worker 10u, 17u, 20u, 100u}));
27*6777b538SAndroid Build Coastguard Worker
TEST_P(MovingMaxTest,BlanketTest)28*6777b538SAndroid Build Coastguard Worker TEST_P(MovingMaxTest, BlanketTest) {
29*6777b538SAndroid Build Coastguard Worker const size_t window_size = GetParam();
30*6777b538SAndroid Build Coastguard Worker MovingMax<int> window(window_size);
31*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kTestValues); ++i) {
32*6777b538SAndroid Build Coastguard Worker window.AddSample(kTestValues[i]);
33*6777b538SAndroid Build Coastguard Worker int slow_max = kTestValues[i];
34*6777b538SAndroid Build Coastguard Worker for (size_t j = 1; j < window_size && j <= i; ++j) {
35*6777b538SAndroid Build Coastguard Worker slow_max = std::max(slow_max, kTestValues[i - j]);
36*6777b538SAndroid Build Coastguard Worker }
37*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), slow_max);
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker }
40*6777b538SAndroid Build Coastguard Worker
TEST(MovingMax,SingleElementWindow)41*6777b538SAndroid Build Coastguard Worker TEST(MovingMax, SingleElementWindow) {
42*6777b538SAndroid Build Coastguard Worker MovingMax<int> window(1u);
43*6777b538SAndroid Build Coastguard Worker window.AddSample(100);
44*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 100);
45*6777b538SAndroid Build Coastguard Worker window.AddSample(1000);
46*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 1000);
47*6777b538SAndroid Build Coastguard Worker window.AddSample(1);
48*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 1);
49*6777b538SAndroid Build Coastguard Worker window.AddSample(3);
50*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 3);
51*6777b538SAndroid Build Coastguard Worker window.AddSample(4);
52*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 4);
53*6777b538SAndroid Build Coastguard Worker }
54*6777b538SAndroid Build Coastguard Worker
TEST(MovingMax,VeryLargeWindow)55*6777b538SAndroid Build Coastguard Worker TEST(MovingMax, VeryLargeWindow) {
56*6777b538SAndroid Build Coastguard Worker MovingMax<int> window(100u);
57*6777b538SAndroid Build Coastguard Worker window.AddSample(100);
58*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 100);
59*6777b538SAndroid Build Coastguard Worker window.AddSample(1000);
60*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 1000);
61*6777b538SAndroid Build Coastguard Worker window.AddSample(1);
62*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 1000);
63*6777b538SAndroid Build Coastguard Worker window.AddSample(3);
64*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 1000);
65*6777b538SAndroid Build Coastguard Worker window.AddSample(4);
66*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Max(), 1000);
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker
TEST(MovingMax,Counts)69*6777b538SAndroid Build Coastguard Worker TEST(MovingMax, Counts) {
70*6777b538SAndroid Build Coastguard Worker MovingMax<int> window(3u);
71*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Count(), 0u);
72*6777b538SAndroid Build Coastguard Worker window.AddSample(100);
73*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Count(), 1u);
74*6777b538SAndroid Build Coastguard Worker window.AddSample(1000);
75*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Count(), 2u);
76*6777b538SAndroid Build Coastguard Worker window.AddSample(1);
77*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Count(), 3u);
78*6777b538SAndroid Build Coastguard Worker window.AddSample(3);
79*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Count(), 4u);
80*6777b538SAndroid Build Coastguard Worker window.AddSample(4);
81*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Count(), 5u);
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker
TEST(MovingAverage,Unrounded)84*6777b538SAndroid Build Coastguard Worker TEST(MovingAverage, Unrounded) {
85*6777b538SAndroid Build Coastguard Worker MovingAverage<int, int64_t> window(4u);
86*6777b538SAndroid Build Coastguard Worker window.AddSample(1);
87*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Mean<double>(), 1.0);
88*6777b538SAndroid Build Coastguard Worker window.AddSample(2);
89*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Mean<double>(), 1.5);
90*6777b538SAndroid Build Coastguard Worker window.AddSample(3);
91*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Mean<double>(), 2.0);
92*6777b538SAndroid Build Coastguard Worker window.AddSample(4);
93*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Mean<double>(), 2.5);
94*6777b538SAndroid Build Coastguard Worker window.AddSample(101);
95*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Mean<double>(), 27.5);
96*6777b538SAndroid Build Coastguard Worker }
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker class MovingMinTest : public testing::TestWithParam<unsigned int> {};
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(All,
101*6777b538SAndroid Build Coastguard Worker MovingMinTest,
102*6777b538SAndroid Build Coastguard Worker testing::ValuesIn({1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u,
103*6777b538SAndroid Build Coastguard Worker 10u, 17u, 20u, 100u}));
104*6777b538SAndroid Build Coastguard Worker
TEST_P(MovingMinTest,BlanketTest)105*6777b538SAndroid Build Coastguard Worker TEST_P(MovingMinTest, BlanketTest) {
106*6777b538SAndroid Build Coastguard Worker const size_t window_size = GetParam();
107*6777b538SAndroid Build Coastguard Worker MovingMin<int> window(window_size);
108*6777b538SAndroid Build Coastguard Worker for (int repeats = 0; repeats < 2; ++repeats) {
109*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kTestValues); ++i) {
110*6777b538SAndroid Build Coastguard Worker window.AddSample(kTestValues[i]);
111*6777b538SAndroid Build Coastguard Worker int slow_min = kTestValues[i];
112*6777b538SAndroid Build Coastguard Worker for (size_t j = 1; j < window_size && j <= i; ++j) {
113*6777b538SAndroid Build Coastguard Worker slow_min = std::min(slow_min, kTestValues[i - j]);
114*6777b538SAndroid Build Coastguard Worker }
115*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Min(), slow_min);
116*6777b538SAndroid Build Coastguard Worker }
117*6777b538SAndroid Build Coastguard Worker window.Reset();
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker class MovingAverageTest : public testing::TestWithParam<unsigned int> {};
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(All,
124*6777b538SAndroid Build Coastguard Worker MovingAverageTest,
125*6777b538SAndroid Build Coastguard Worker testing::ValuesIn({1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u,
126*6777b538SAndroid Build Coastguard Worker 10u, 17u, 20u, 100u}));
127*6777b538SAndroid Build Coastguard Worker
TEST_P(MovingAverageTest,BlanketTest)128*6777b538SAndroid Build Coastguard Worker TEST_P(MovingAverageTest, BlanketTest) {
129*6777b538SAndroid Build Coastguard Worker const size_t window_size = GetParam();
130*6777b538SAndroid Build Coastguard Worker MovingAverage<int, int64_t> window(window_size);
131*6777b538SAndroid Build Coastguard Worker for (int repeats = 0; repeats < 2; ++repeats) {
132*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kTestValues); ++i) {
133*6777b538SAndroid Build Coastguard Worker window.AddSample(kTestValues[i]);
134*6777b538SAndroid Build Coastguard Worker int slow_mean = 0;
135*6777b538SAndroid Build Coastguard Worker for (size_t j = 0; j < window_size && j <= i; ++j) {
136*6777b538SAndroid Build Coastguard Worker slow_mean += kTestValues[i - j];
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker slow_mean /= std::min(window_size, i + 1);
139*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Mean(), slow_mean);
140*6777b538SAndroid Build Coastguard Worker }
141*6777b538SAndroid Build Coastguard Worker window.Reset();
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker }
144*6777b538SAndroid Build Coastguard Worker
145*6777b538SAndroid Build Coastguard Worker class MovingDeviationTest : public testing::TestWithParam<unsigned int> {};
146*6777b538SAndroid Build Coastguard Worker
147*6777b538SAndroid Build Coastguard Worker INSTANTIATE_TEST_SUITE_P(All,
148*6777b538SAndroid Build Coastguard Worker MovingDeviationTest,
149*6777b538SAndroid Build Coastguard Worker testing::ValuesIn({1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u,
150*6777b538SAndroid Build Coastguard Worker 10u, 17u, 20u, 100u}));
151*6777b538SAndroid Build Coastguard Worker
TEST_P(MovingDeviationTest,BlanketTest)152*6777b538SAndroid Build Coastguard Worker TEST_P(MovingDeviationTest, BlanketTest) {
153*6777b538SAndroid Build Coastguard Worker const size_t window_size = GetParam();
154*6777b538SAndroid Build Coastguard Worker MovingAverageDeviation<double> window(window_size);
155*6777b538SAndroid Build Coastguard Worker for (int repeats = 0; repeats < 2; ++repeats) {
156*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kTestValues); ++i) {
157*6777b538SAndroid Build Coastguard Worker window.AddSample(kTestValues[i]);
158*6777b538SAndroid Build Coastguard Worker double slow_deviation = 0;
159*6777b538SAndroid Build Coastguard Worker double mean = window.Mean();
160*6777b538SAndroid Build Coastguard Worker for (size_t j = 0; j < window_size && j <= i; ++j) {
161*6777b538SAndroid Build Coastguard Worker slow_deviation +=
162*6777b538SAndroid Build Coastguard Worker (kTestValues[i - j] - mean) * (kTestValues[i - j] - mean);
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker slow_deviation /= std::min(window_size, i + 1);
165*6777b538SAndroid Build Coastguard Worker slow_deviation = sqrt(slow_deviation);
166*6777b538SAndroid Build Coastguard Worker double fast_deviation = window.Deviation();
167*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(std::abs(fast_deviation - slow_deviation) < 1e-9);
168*6777b538SAndroid Build Coastguard Worker }
169*6777b538SAndroid Build Coastguard Worker window.Reset();
170*6777b538SAndroid Build Coastguard Worker }
171*6777b538SAndroid Build Coastguard Worker }
172*6777b538SAndroid Build Coastguard Worker
TEST(MovingWindowTest,Iteration)173*6777b538SAndroid Build Coastguard Worker TEST(MovingWindowTest, Iteration) {
174*6777b538SAndroid Build Coastguard Worker const size_t kWindowSize = 10;
175*6777b538SAndroid Build Coastguard Worker MovingWindow<int, base::MovingWindowFeatures::Iteration> window(kWindowSize);
176*6777b538SAndroid Build Coastguard Worker for (int repeats = 0; repeats < 2; ++repeats) {
177*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(kTestValues); ++i) {
178*6777b538SAndroid Build Coastguard Worker window.AddSample(kTestValues[i]);
179*6777b538SAndroid Build Coastguard Worker size_t j = 0;
180*6777b538SAndroid Build Coastguard Worker const size_t in_window = std::min(i + 1, kWindowSize);
181*6777b538SAndroid Build Coastguard Worker for (int value : window) {
182*6777b538SAndroid Build Coastguard Worker ASSERT_LT(j, in_window);
183*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(value, kTestValues[i + j + 1 - in_window]);
184*6777b538SAndroid Build Coastguard Worker ++j;
185*6777b538SAndroid Build Coastguard Worker }
186*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(j, in_window);
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker window.Reset();
189*6777b538SAndroid Build Coastguard Worker }
190*6777b538SAndroid Build Coastguard Worker }
191*6777b538SAndroid Build Coastguard Worker
TEST(MovingMeanDeviation,WorksWithTimeDelta)192*6777b538SAndroid Build Coastguard Worker TEST(MovingMeanDeviation, WorksWithTimeDelta) {
193*6777b538SAndroid Build Coastguard Worker MovingAverageDeviation<base::TimeDelta> window(2);
194*6777b538SAndroid Build Coastguard Worker window.AddSample(base::Milliseconds(400));
195*6777b538SAndroid Build Coastguard Worker window.AddSample(base::Milliseconds(200));
196*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Mean(), base::Milliseconds(300));
197*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Deviation(), base::Milliseconds(100));
198*6777b538SAndroid Build Coastguard Worker window.AddSample(base::Seconds(40));
199*6777b538SAndroid Build Coastguard Worker window.AddSample(base::Seconds(20));
200*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Mean(), base::Seconds(30));
201*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(window.Deviation(), base::Seconds(10));
202*6777b538SAndroid Build Coastguard Worker }
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker } // namespace base
205