test(plot): region removal re-indexes the ids and the statistics cache

This commit is contained in:
Martino Ferrari committed 2026-09-28 13:53:26 +02:00
1 parent 5e610bc138
commit 4e0e0ae0b3
1 file changed
+51
+51
View File
@@ -1590,3 +1590,54 @@ PLOT_TEST(region_stats_track_a_sliding_streaming_window) {
PLOT_CHECK_NEAR(step.mean, 0.5 * (step.min + 60.0), 1e-9); PLOT_CHECK_NEAR(step.mean, 0.5 * (step.min + 60.0), 1e-9);
} }
} }
/// Region ids are vector indices, so removing one shifts every id above it -- and the
/// statistics cache is keyed by that index, so it has to be re-indexed with the vector
/// rather than left naming the regions it was filled for. A stale key here would answer
/// for a *different* interval than the one asked about, which a count alone cannot see:
/// the three intervals below are all 11 samples wide, so these assertions are about the
/// extremes each id actually names.
PLOT_TEST(removing_a_region_shifts_the_ids_and_keeps_the_statistics) {
plot::data::ArraySeries s(ramp(100), 0.0, 1.0);
plot::Plot p;
p.set_viewport({0.0f, 0.0f, 800.0f, 400.0f});
const u32 ax = p.add_x_axis({"t", {0.0, 99.0}, false, plot::AxisPlace::Bottom, false});
const u32 ay = p.add_y_axis({"v", {0.0, 99.0}, false, plot::AxisPlace::Left, false});
const u32 tr = p.add_trace({&s, plot::Color::hex(0xFFFFFF), 1.0f, ax, ay});
plot::Region bounds;
bounds.snap = plot::RegionSnap::Free; // the intervals under test are these numbers
bounds.x0 = 10.0;
bounds.x1 = 20.0;
const u32 a = p.add_region(bounds);
bounds.x0 = 30.0;
bounds.x1 = 40.0;
const u32 b = p.add_region(bounds);
bounds.x0 = 50.0;
bounds.x1 = 60.0;
const u32 c = p.add_region(bounds);
PLOT_CHECK(a == 0u && b == 1u && c == 2u);
PLOT_CHECK(p.region_count() == 3u);
// Filled on demand, in the order the caller asks: three entries, one per pair.
PLOT_CHECK_NEAR(p.region_stats(a, tr).min, 10.0, 1e-9);
PLOT_CHECK_NEAR(p.region_stats(b, tr).min, 30.0, 1e-9);
PLOT_CHECK_NEAR(p.region_stats(c, tr).min, 50.0, 1e-9);
p.remove_region(a);
PLOT_CHECK(p.region_count() == 2u);
PLOT_CHECK_NEAR(p.region(0).x0, 30.0, 1e-12); // the old region 1
PLOT_CHECK_NEAR(p.region(1).x0, 50.0, 1e-12); // the old region 2
// The surviving entries follow their regions down, so each id still answers for its own
// interval rather than for the one that used to hold that index.
PLOT_CHECK_NEAR(p.region_stats(0u, tr).min, 30.0, 1e-9);
PLOT_CHECK_NEAR(p.region_stats(0u, tr).max, 40.0, 1e-9);
PLOT_CHECK_NEAR(p.region_stats(1u, tr).min, 50.0, 1e-9);
PLOT_CHECK_NEAR(p.region_stats(1u, tr).max, 60.0, 1e-9);
// The id the removed region held now names the region that shifted into it -- there is
// no hole in the vector -- and an id past the end names nothing and reads a default
// rather than out of range. Neither has any statistics.
PLOT_CHECK_NEAR(p.region(0u).x0, 30.0, 1e-12);
PLOT_CHECK_NEAR(p.region(2u).x0, 0.0, 1e-12);
PLOT_CHECK(!p.region_stats(2u, tr).valid);
PLOT_CHECK(!p.region_stats(9u, tr).valid);
}