f858f3a9fc
- 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].
70 lines
2.6 KiB
C++
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));
|
|
}
|