Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
74 lines
2.2 KiB
C++
74 lines
2.2 KiB
C++
#include "Decimate.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
using namespace udpscope;
|
|
|
|
TEST(MinMaxDecimate, PassesShortInputThroughUnchanged) {
|
|
const std::vector<double> t{0.0, 1.0, 2.0};
|
|
const std::vector<double> v{5.0, 6.0, 7.0};
|
|
Series out;
|
|
|
|
MinMaxDecimate(t.data(), v.data(), t.size(), 100, out);
|
|
|
|
EXPECT_EQ(out.t, t);
|
|
EXPECT_EQ(out.v, v);
|
|
}
|
|
|
|
// The whole reason for preferring min/max over LTTB: a single-sample spike is
|
|
// usually the thing the user is looking for, and it must survive decimation.
|
|
TEST(MinMaxDecimate, PreservesAnIsolatedSpike) {
|
|
std::vector<double> t(1000), v(1000, 0.0);
|
|
for (size_t i = 0; i < t.size(); i++) { t[i] = static_cast<double>(i); }
|
|
v[437] = 42.0;
|
|
Series out;
|
|
|
|
MinMaxDecimate(t.data(), v.data(), t.size(), 50, out);
|
|
|
|
ASSERT_FALSE(out.v.empty());
|
|
EXPECT_EQ(*std::max_element(out.v.begin(), out.v.end()), 42.0);
|
|
}
|
|
|
|
TEST(MinMaxDecimate, PreservesTheExtremesOfEveryBucket) {
|
|
std::vector<double> t(100), v(100);
|
|
for (size_t i = 0; i < t.size(); i++) {
|
|
t[i] = static_cast<double>(i);
|
|
v[i] = (i % 10 == 3) ? -9.0 : ((i % 10 == 7) ? 9.0 : 0.0);
|
|
}
|
|
Series out;
|
|
|
|
MinMaxDecimate(t.data(), v.data(), t.size(), 20, out);
|
|
|
|
EXPECT_EQ(*std::min_element(out.v.begin(), out.v.end()), -9.0);
|
|
EXPECT_EQ(*std::max_element(out.v.begin(), out.v.end()), 9.0);
|
|
}
|
|
|
|
// A ring whose timestamps are not monotonic breaks any later binary search by
|
|
// time, so the pair emitted per bucket must be ordered by time, not by value.
|
|
TEST(MinMaxDecimate, EmitsPointsInTimeOrder) {
|
|
std::vector<double> t(400), v(400);
|
|
for (size_t i = 0; i < t.size(); i++) {
|
|
t[i] = static_cast<double>(i);
|
|
v[i] = (i % 2 == 0) ? -static_cast<double>(i) : static_cast<double>(i);
|
|
}
|
|
Series out;
|
|
|
|
MinMaxDecimate(t.data(), v.data(), t.size(), 40, out);
|
|
|
|
ASSERT_GT(out.t.size(), 1u);
|
|
for (size_t i = 1; i < out.t.size(); i++) {
|
|
EXPECT_LE(out.t[i - 1], out.t[i]) << "at index " << i;
|
|
}
|
|
}
|
|
|
|
TEST(MinMaxDecimate, HandlesEmptyInput) {
|
|
Series out;
|
|
out.t.push_back(1.0); // must be cleared
|
|
MinMaxDecimate(nullptr, nullptr, 0, 10, out);
|
|
EXPECT_TRUE(out.t.empty());
|
|
EXPECT_TRUE(out.v.empty());
|
|
}
|