Files
fn_registry/cpp/tests/test_kpi_card_math.cpp
egutierrez 0779c34ca8 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].
2026-04-28 23:42:22 +02:00

70 lines
2.6 KiB
C++

// Tests para la logica de calculo del KPI card.
//
// kpi_card es un componente UI tightly coupled con ImGui (`ImGui::BeginGroup`,
// formatting, sparkline rendering...). La logica testeable es trivial:
// - delta_percent positivo -> "trending up"
// - delta_percent negativo -> "trending down"
// - delta_percent ~ 0 -> "flat"
//
// Aqui replicamos la funcion de clasificacion para garantizar que el signo
// del delta se interpreta correctamente. La parte visual (color, icono) se
// cubre en la primitives_gallery (issue 0048).
#define CATCH_CONFIG_MAIN
#include "catch_amalgamated.hpp"
#include <cmath>
namespace {
enum class Trend { Down, Flat, Up };
Trend classify_delta(float delta_percent, float flat_threshold = 0.05f) {
if (std::fabs(delta_percent) <= flat_threshold) return Trend::Flat;
return (delta_percent > 0.0f) ? Trend::Up : Trend::Down;
}
float pct_change(float current, float previous) {
if (previous == 0.0f) return 0.0f;
return 100.0f * (current - previous) / previous;
}
} // namespace
TEST_CASE("kpi_card: classify_delta positive -> Up", "[kpi_card]") {
REQUIRE(classify_delta(0.5f) == Trend::Up);
REQUIRE(classify_delta(12.5f) == Trend::Up);
REQUIRE(classify_delta(100.0f) == Trend::Up);
}
TEST_CASE("kpi_card: classify_delta negative -> Down", "[kpi_card]") {
REQUIRE(classify_delta(-0.5f) == Trend::Down);
REQUIRE(classify_delta(-15.0f) == Trend::Down);
REQUIRE(classify_delta(-100.0f) == Trend::Down);
}
TEST_CASE("kpi_card: classify_delta near zero -> Flat", "[kpi_card]") {
REQUIRE(classify_delta(0.0f) == Trend::Flat);
REQUIRE(classify_delta(0.01f) == Trend::Flat);
REQUIRE(classify_delta(-0.01f) == Trend::Flat);
REQUIRE(classify_delta(0.05f) == Trend::Flat); // exactly threshold
}
TEST_CASE("kpi_card: pct_change basic deltas", "[kpi_card]") {
REQUIRE(pct_change(110.0f, 100.0f) == Catch::Approx(10.0f));
REQUIRE(pct_change(90.0f, 100.0f) == Catch::Approx(-10.0f));
REQUIRE(pct_change(100.0f, 100.0f) == Catch::Approx(0.0f));
REQUIRE(pct_change(200.0f, 100.0f) == Catch::Approx(100.0f));
}
TEST_CASE("kpi_card: pct_change with zero previous returns 0", "[kpi_card]") {
// Definicion: cambio porcentual de 0 a X es indefinido, devolvemos 0.
REQUIRE(pct_change(50.0f, 0.0f) == Catch::Approx(0.0f));
REQUIRE(pct_change(0.0f, 0.0f) == Catch::Approx(0.0f));
}
TEST_CASE("kpi_card: pct_change handles negative values", "[kpi_card]") {
// -10 -> -5: ((-5) - (-10)) / (-10) * 100 = 5 / -10 * 100 = -50%.
REQUIRE(pct_change(-5.0f, -10.0f) == Catch::Approx(-50.0f));
}