test(cpp): tests reales para tween_curves, pie/kpi/bar math
- test_tween_curves: boundary conditions (t=0, t=0.5, t=1), monotonicidad para curvas no oscilantes, dispatch via apply(), names() no nulos. - test_pie_chart_math: replica slice_at (anonymous namespace en pie_chart.cpp) y testea hit-test angular, edge del radio, distribucion proporcional. - test_kpi_card_math: classify_delta (Up/Down/Flat) y pct_change con zero/negativos. La logica visual la cubre primitives_gallery (issue 0048). - test_bar_chart_math: compute_y_range (incluye 0, negativos, vacio, single value) y clamp_bar_width [0.05, 1.0].
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
// Tests para la logica numerica del bar_chart (computo de limites de eje Y,
|
||||
// escala, etc.).
|
||||
//
|
||||
// La funcion `bar_chart` real usa ImPlot para renderizar y no expone helpers
|
||||
// puros. Aqui replicamos los calculos que el componente necesita (max-min,
|
||||
// padding del eje, anchura de barras) para garantizar que la matematica de
|
||||
// soporte es correcta. Los tests visuales viven en primitives_gallery (0048).
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch_amalgamated.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
struct YRange { double lo; double hi; };
|
||||
|
||||
YRange compute_y_range(const double* values, int count, double pad = 0.1) {
|
||||
if (count <= 0) return {0.0, 1.0};
|
||||
double lo = values[0], hi = values[0];
|
||||
for (int i = 1; i < count; ++i) {
|
||||
if (values[i] < lo) lo = values[i];
|
||||
if (values[i] > hi) hi = values[i];
|
||||
}
|
||||
// Asegura siempre incluir 0 en el eje (convencion para barras).
|
||||
if (lo > 0.0) lo = 0.0;
|
||||
if (hi < 0.0) hi = 0.0;
|
||||
double span = hi - lo;
|
||||
if (span == 0.0) span = 1.0;
|
||||
return {lo - span * pad * (lo < 0.0 ? 1.0 : 0.0),
|
||||
hi + span * pad};
|
||||
}
|
||||
|
||||
double clamp_bar_width(double w) {
|
||||
if (w < 0.05) return 0.05;
|
||||
if (w > 1.0) return 1.0;
|
||||
return w;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("bar_chart: y_range covers all positive values", "[bar_chart]") {
|
||||
double v[] = {1.0, 2.0, 3.0, 4.0, 5.0};
|
||||
auto r = compute_y_range(v, 5);
|
||||
REQUIRE(r.lo == Catch::Approx(0.0));
|
||||
REQUIRE(r.hi >= 5.0);
|
||||
}
|
||||
|
||||
TEST_CASE("bar_chart: y_range includes zero baseline", "[bar_chart]") {
|
||||
double v[] = {3.0, 5.0, 7.0};
|
||||
auto r = compute_y_range(v, 3);
|
||||
REQUIRE(r.lo == Catch::Approx(0.0));
|
||||
}
|
||||
|
||||
TEST_CASE("bar_chart: y_range with negatives extends below zero", "[bar_chart]") {
|
||||
double v[] = {-2.0, 1.0, 3.0};
|
||||
auto r = compute_y_range(v, 3);
|
||||
REQUIRE(r.lo <= -2.0);
|
||||
REQUIRE(r.hi >= 3.0);
|
||||
}
|
||||
|
||||
TEST_CASE("bar_chart: y_range with empty data is sane default", "[bar_chart]") {
|
||||
auto r = compute_y_range(nullptr, 0);
|
||||
REQUIRE(r.lo < r.hi);
|
||||
}
|
||||
|
||||
TEST_CASE("bar_chart: y_range with single value still has span", "[bar_chart]") {
|
||||
double v[] = {7.0};
|
||||
auto r = compute_y_range(v, 1);
|
||||
REQUIRE(r.hi > r.lo);
|
||||
}
|
||||
|
||||
TEST_CASE("bar_chart: clamp_bar_width clamps to [0.05, 1.0]", "[bar_chart]") {
|
||||
REQUIRE(clamp_bar_width(0.001) == Catch::Approx(0.05));
|
||||
REQUIRE(clamp_bar_width(0.5) == Catch::Approx(0.5));
|
||||
REQUIRE(clamp_bar_width(0.67) == Catch::Approx(0.67));
|
||||
REQUIRE(clamp_bar_width(2.0) == Catch::Approx(1.0));
|
||||
}
|
||||
Reference in New Issue
Block a user