Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
test_statistics_utils.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
10#include <gtest/gtest.h>
12
13#include <chrono>
14#include <vector>
15
16using namespace kcenon::monitoring::stats;
17
18class StatisticsUtilsTest : public ::testing::Test {
19protected:
20 void SetUp() override {}
21 void TearDown() override {}
22};
23
24// =========================================================================
25// Percentile Tests with Double Values
26// =========================================================================
27
28TEST_F(StatisticsUtilsTest, PercentileEmptyVector) {
29 std::vector<double> empty;
30 EXPECT_DOUBLE_EQ(percentile(empty, 50.0), 0.0);
31}
32
33TEST_F(StatisticsUtilsTest, PercentileSingleValue) {
34 std::vector<double> single = {42.0};
35 EXPECT_DOUBLE_EQ(percentile(single, 0.0), 42.0);
36 EXPECT_DOUBLE_EQ(percentile(single, 50.0), 42.0);
37 EXPECT_DOUBLE_EQ(percentile(single, 100.0), 42.0);
38}
39
40TEST_F(StatisticsUtilsTest, PercentileTwoValues) {
41 std::vector<double> values = {10.0, 20.0};
42 EXPECT_DOUBLE_EQ(percentile(values, 0.0), 10.0);
43 EXPECT_DOUBLE_EQ(percentile(values, 50.0), 15.0);
44 EXPECT_DOUBLE_EQ(percentile(values, 100.0), 20.0);
45}
46
47TEST_F(StatisticsUtilsTest, PercentileFiveValues) {
48 std::vector<double> values = {1.0, 2.0, 3.0, 4.0, 5.0};
49 EXPECT_DOUBLE_EQ(percentile(values, 0.0), 1.0);
50 EXPECT_DOUBLE_EQ(percentile(values, 25.0), 2.0);
51 EXPECT_DOUBLE_EQ(percentile(values, 50.0), 3.0);
52 EXPECT_DOUBLE_EQ(percentile(values, 75.0), 4.0);
53 EXPECT_DOUBLE_EQ(percentile(values, 100.0), 5.0);
54}
55
56TEST_F(StatisticsUtilsTest, PercentileP95P99) {
57 std::vector<double> values;
58 for (int i = 1; i <= 100; ++i) {
59 values.push_back(static_cast<double>(i));
60 }
61
62 double p95 = percentile(values, 95.0);
63 double p99 = percentile(values, 99.0);
64
65 EXPECT_GE(p95, 94.0);
66 EXPECT_LE(p95, 96.0);
67 EXPECT_GE(p99, 98.0);
68 EXPECT_LE(p99, 100.0);
69}
70
71TEST_F(StatisticsUtilsTest, PercentileBoundaryValues) {
72 std::vector<double> values = {1.0, 2.0, 3.0, 4.0, 5.0};
73 EXPECT_DOUBLE_EQ(percentile(values, -10.0), 1.0);
74 EXPECT_DOUBLE_EQ(percentile(values, 110.0), 5.0);
75}
76
77// =========================================================================
78// Percentile Tests with Chrono Duration
79// =========================================================================
80
81TEST_F(StatisticsUtilsTest, PercentileChronoEmpty) {
82 std::vector<std::chrono::nanoseconds> empty;
83 EXPECT_EQ(percentile(empty, 50.0), std::chrono::nanoseconds::zero());
84}
85
86TEST_F(StatisticsUtilsTest, PercentileChronoValues) {
87 std::vector<std::chrono::nanoseconds> values = {
88 std::chrono::nanoseconds(100),
89 std::chrono::nanoseconds(200),
90 std::chrono::nanoseconds(300),
91 std::chrono::nanoseconds(400),
92 std::chrono::nanoseconds(500)
93 };
94
95 auto p0 = percentile(values, 0.0);
96 auto p50 = percentile(values, 50.0);
97 auto p100 = percentile(values, 100.0);
98
99 EXPECT_EQ(p0, std::chrono::nanoseconds(100));
100 EXPECT_EQ(p50, std::chrono::nanoseconds(300));
101 EXPECT_EQ(p100, std::chrono::nanoseconds(500));
102}
103
104// =========================================================================
105// Compute Statistics Tests with Double Values
106// =========================================================================
107
108TEST_F(StatisticsUtilsTest, ComputeEmptyVector) {
109 std::vector<double> empty;
110 auto stats = compute(empty);
111
112 EXPECT_EQ(stats.count, 0);
113 EXPECT_DOUBLE_EQ(stats.min, 0.0);
114 EXPECT_DOUBLE_EQ(stats.max, 0.0);
115 EXPECT_DOUBLE_EQ(stats.mean, 0.0);
116 EXPECT_DOUBLE_EQ(stats.total, 0.0);
117}
118
119TEST_F(StatisticsUtilsTest, ComputeSingleValue) {
120 std::vector<double> single = {42.0};
121 auto stats = compute(single);
122
123 EXPECT_EQ(stats.count, 1);
124 EXPECT_DOUBLE_EQ(stats.min, 42.0);
125 EXPECT_DOUBLE_EQ(stats.max, 42.0);
126 EXPECT_DOUBLE_EQ(stats.mean, 42.0);
127 EXPECT_DOUBLE_EQ(stats.median, 42.0);
128 EXPECT_DOUBLE_EQ(stats.total, 42.0);
129}
130
131TEST_F(StatisticsUtilsTest, ComputeFiveValues) {
132 std::vector<double> values = {1.0, 2.0, 3.0, 4.0, 5.0};
133 auto stats = compute(values);
134
135 EXPECT_EQ(stats.count, 5);
136 EXPECT_DOUBLE_EQ(stats.min, 1.0);
137 EXPECT_DOUBLE_EQ(stats.max, 5.0);
138 EXPECT_DOUBLE_EQ(stats.mean, 3.0);
139 EXPECT_DOUBLE_EQ(stats.median, 3.0);
140 EXPECT_DOUBLE_EQ(stats.total, 15.0);
141}
142
143TEST_F(StatisticsUtilsTest, ComputeUnsortedValues) {
144 std::vector<double> values = {5.0, 1.0, 3.0, 2.0, 4.0};
145 auto stats = compute(values);
146
147 EXPECT_EQ(stats.count, 5);
148 EXPECT_DOUBLE_EQ(stats.min, 1.0);
149 EXPECT_DOUBLE_EQ(stats.max, 5.0);
150 EXPECT_DOUBLE_EQ(stats.mean, 3.0);
151 EXPECT_DOUBLE_EQ(stats.median, 3.0);
152}
153
155 std::vector<double> values;
156 for (int i = 1; i <= 100; ++i) {
157 values.push_back(static_cast<double>(i));
158 }
159 auto stats = compute(values);
160
161 EXPECT_EQ(stats.count, 100);
162 EXPECT_DOUBLE_EQ(stats.min, 1.0);
163 EXPECT_DOUBLE_EQ(stats.max, 100.0);
164 EXPECT_DOUBLE_EQ(stats.mean, 50.5);
165
166 EXPECT_GE(stats.p95, 94.0);
167 EXPECT_LE(stats.p95, 96.0);
168 EXPECT_GE(stats.p99, 98.0);
169 EXPECT_LE(stats.p99, 100.0);
170}
171
172// =========================================================================
173// Compute Statistics Tests with Chrono Duration
174// =========================================================================
175
176TEST_F(StatisticsUtilsTest, ComputeChronoEmpty) {
177 std::vector<std::chrono::nanoseconds> empty;
178 auto stats = compute(empty);
179
180 EXPECT_EQ(stats.count, 0);
181 EXPECT_EQ(stats.min, std::chrono::nanoseconds::zero());
182 EXPECT_EQ(stats.max, std::chrono::nanoseconds::zero());
183 EXPECT_EQ(stats.mean, std::chrono::nanoseconds::zero());
184}
185
186TEST_F(StatisticsUtilsTest, ComputeChronoValues) {
187 std::vector<std::chrono::nanoseconds> values = {
188 std::chrono::nanoseconds(1000000),
189 std::chrono::nanoseconds(2000000),
190 std::chrono::nanoseconds(3000000),
191 std::chrono::nanoseconds(4000000),
192 std::chrono::nanoseconds(5000000)
193 };
194 auto stats = compute(values);
195
196 EXPECT_EQ(stats.count, 5);
197 EXPECT_EQ(stats.min, std::chrono::nanoseconds(1000000));
198 EXPECT_EQ(stats.max, std::chrono::nanoseconds(5000000));
199 EXPECT_EQ(stats.mean, std::chrono::nanoseconds(3000000));
200 EXPECT_EQ(stats.median, std::chrono::nanoseconds(3000000));
201 EXPECT_EQ(stats.total, std::chrono::nanoseconds(15000000));
202}
203
204TEST_F(StatisticsUtilsTest, ComputeChronoPercentiles) {
205 std::vector<std::chrono::nanoseconds> values;
206 for (int i = 1; i <= 100; ++i) {
207 values.push_back(std::chrono::nanoseconds(i * 1000000));
208 }
209 auto stats = compute(values);
210
211 EXPECT_EQ(stats.count, 100);
212 EXPECT_EQ(stats.min.count(), 1000000);
213 EXPECT_EQ(stats.max.count(), 100000000);
214
215 EXPECT_GE(stats.p95.count(), 94000000);
216 EXPECT_LE(stats.p95.count(), 96000000);
217 EXPECT_GE(stats.p99.count(), 98000000);
218 EXPECT_LE(stats.p99.count(), 100000000);
219}
220
221// =========================================================================
222// Compute Sorted and Inplace Tests
223// =========================================================================
224
225TEST_F(StatisticsUtilsTest, ComputeSortedValues) {
226 std::vector<double> sorted = {1.0, 2.0, 3.0, 4.0, 5.0};
227 auto stats = compute_sorted(sorted);
228
229 EXPECT_EQ(stats.count, 5);
230 EXPECT_DOUBLE_EQ(stats.min, 1.0);
231 EXPECT_DOUBLE_EQ(stats.max, 5.0);
232 EXPECT_DOUBLE_EQ(stats.mean, 3.0);
233}
234
235TEST_F(StatisticsUtilsTest, ComputeInplaceModifiesInput) {
236 std::vector<double> values = {5.0, 1.0, 3.0, 2.0, 4.0};
237 auto stats = compute_inplace(values);
238
239 EXPECT_EQ(stats.count, 5);
240 EXPECT_DOUBLE_EQ(stats.min, 1.0);
241 EXPECT_DOUBLE_EQ(stats.max, 5.0);
242
243 EXPECT_DOUBLE_EQ(values[0], 1.0);
244 EXPECT_DOUBLE_EQ(values[4], 5.0);
245}
246
247// =========================================================================
248// Edge Cases
249// =========================================================================
250
251TEST_F(StatisticsUtilsTest, ComputeNegativeValues) {
252 std::vector<double> values = {-5.0, -3.0, -1.0, 1.0, 3.0, 5.0};
253 auto stats = compute(values);
254
255 EXPECT_EQ(stats.count, 6);
256 EXPECT_DOUBLE_EQ(stats.min, -5.0);
257 EXPECT_DOUBLE_EQ(stats.max, 5.0);
258 EXPECT_DOUBLE_EQ(stats.mean, 0.0);
259 EXPECT_DOUBLE_EQ(stats.total, 0.0);
260}
261
262TEST_F(StatisticsUtilsTest, ComputeAllSameValues) {
263 std::vector<double> values = {42.0, 42.0, 42.0, 42.0, 42.0};
264 auto stats = compute(values);
265
266 EXPECT_EQ(stats.count, 5);
267 EXPECT_DOUBLE_EQ(stats.min, 42.0);
268 EXPECT_DOUBLE_EQ(stats.max, 42.0);
269 EXPECT_DOUBLE_EQ(stats.mean, 42.0);
270 EXPECT_DOUBLE_EQ(stats.median, 42.0);
271 EXPECT_DOUBLE_EQ(stats.p95, 42.0);
272 EXPECT_DOUBLE_EQ(stats.p99, 42.0);
273}
274
275TEST_F(StatisticsUtilsTest, ComputeLargeValues) {
276 std::vector<double> values;
277 for (int i = 0; i < 10000; ++i) {
278 values.push_back(static_cast<double>(i));
279 }
280 auto stats = compute(values);
281
282 EXPECT_EQ(stats.count, 10000);
283 EXPECT_DOUBLE_EQ(stats.min, 0.0);
284 EXPECT_DOUBLE_EQ(stats.max, 9999.0);
285 EXPECT_DOUBLE_EQ(stats.mean, 4999.5);
286}
statistics< T > compute_sorted(const std::vector< T > &sorted_values)
Compute statistics from sorted values.
Definition statistics.h:173
statistics< T > compute_inplace(std::vector< T > &values)
Compute statistics in place (modifies input)
Definition statistics.h:248
T percentile(const std::vector< T > &sorted_values, double percentile_value)
Definition statistics.h:130
statistics< T > compute(const std::vector< T > &values)
Definition statistics.h:228
Generic statistics utilities for percentile calculations.
TEST_F(StatisticsUtilsTest, PercentileEmptyVector)