#include "harness.hpp" #include #include #include #include #include #include PLOT_TEST(array_series_bounds_and_gather) { std::vector y{1, 5, -2, 3}; plot::data::ArraySeries s(std::move(y), /*x0=*/10.0, /*dx=*/0.5); PLOT_CHECK(s.size() == 4); PLOT_CHECK_NEAR(s.x_bounds().min, 10.0, 1e-9); PLOT_CHECK_NEAR(s.x_bounds().max, 11.5, 1e-9); PLOT_CHECK_NEAR(s.y_bounds().min, -2.0, 1e-6); std::vector out; s.gather(0, 0, 4, out); PLOT_CHECK(out.size() == 8); // interleaved x,y PLOT_CHECK_NEAR(out[0], 10.0, 1e-6); PLOT_CHECK_NEAR(out[1], 1.0, 1e-6); PLOT_CHECK_NEAR(out[6], 11.5, 1e-6); } PLOT_TEST(stream_series_acquire_publishes_snapshot) { plot::data::StreamSeries s(1 << 12, /*x0=*/0.0, /*dx=*/1e-6); for (int i = 0; i < 100; ++i) s.push(f32(i)); PLOT_CHECK(s.produced() == 100); s.acquire(); PLOT_CHECK(s.size() == 100); // Pyramid must track the published samples. PLOT_CHECK_NEAR(s.pyramid().reduce(0, 100).max, 99.0, 1e-4); for (int i = 100; i < 250; ++i) s.push(f32(i)); s.acquire(); PLOT_CHECK(s.size() == 250); } PLOT_TEST(stream_series_drops_oldest_when_full) { plot::data::StreamSeries s(256, 0.0, 1.0); for (int i = 0; i < 1000; ++i) s.push(f32(i)); s.acquire(); PLOT_CHECK(s.size() <= 256); PLOT_CHECK_NEAR(s.y_bounds().max, 999.0, 1e-4); } PLOT_TEST(array_series_exact_range_queries_match_bruteforce) { // The strong test for the exactness split: arbitrary, deliberately // unaligned ranges must match a brute-force scan of the raw samples. std::mt19937 rng(7); std::uniform_real_distribution d(-5.0f, 5.0f); std::vector y(4000); for (auto& v : y) v = d(rng); plot::data::ArraySeries s(y, 0.0, 1.0); for (u64 a = 0; a < 4000; a += 173) { for (u64 b = a + 1; b <= 4000; b += 331) { float lo = y[a], hi = y[a]; double sum = 0.0, sq = 0.0; for (u64 i = a; i < b; ++i) { lo = std::min(lo, y[i]); hi = std::max(hi, y[i]); sum += y[i]; sq += double(y[i]) * double(y[i]); } const plot::Range r = s.reduce(a, b); PLOT_CHECK_NEAR(r.min, lo, 1e-4); PLOT_CHECK_NEAR(r.max, hi, 1e-4); PLOT_CHECK_NEAR(s.sum(a, b), sum, 1e-2); PLOT_CHECK_NEAR(s.sumsq(a, b), sq, 1e-1); } } } PLOT_TEST(stream_series_exact_queries_survive_ring_wrap) { plot::data::StreamSeries s(1u << 10, 0.0, 1.0); for (int i = 0; i < 3000; ++i) s.push(f32(i % 97)); // wraps the ring twice s.acquire(); const u64 n = s.size(); const plot::Range r = s.reduce(0, n); // retained window, wrapped PLOT_CHECK_NEAR(r.max, 96.0, 1e-4); PLOT_CHECK_NEAR(r.min, 0.0, 1e-4); }