Files
tables_qa/tab_events.cpp
T
egutierrez b15106fc09 chore: auto-commit (23 archivos)
- CMakeLists.txt
- app.md
- appicon.ico
- main.cpp
- perf_tests.cpp
- perf_tests.h
- qa_panel.cpp
- qa_panel.h
- qa_state.cpp
- qa_state.h
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:31:32 +02:00

210 lines
6.5 KiB
C++

// tab_events — inyector de TableEvents sinteticos para auto-test del event sink.
// Issue 0108 fase 2.
//
// Patron: se construye un vector<TableEvent> LOCAL y se llama qa::consume_events
// directamente — sin worker thread. Los counters de qa::counters() se incrementan
// como si el usuario hubiera clickado. Ademas se renderiza la tabla real para que
// eventos reales y sinteticos cuenten igual.
//
// Inspirado en altsnap_jitter_test: fakear eventos de bajo nivel directamente
// sobre el estado interno del subsistema, sin depender de la UI.
#include "tabs.h"
#include "qa_state.h"
#include "data_table/data_table.h"
#include <imgui.h>
#include <chrono>
namespace tables_qa::tabs {
namespace {
qa::TabState g_st;
int g_events_injected_total = 0;
char g_burst_msg[128] = "";
void seed() {
// 6 filas x 5 columnas: id, name, status (CategoricalChip), action (Button), value (Float)
g_st.back = {
// id name status action value
"1", "task-alpha", "ok", "Activate", "1.25",
"2", "task-beta", "error", "Activate", "0.50",
"3", "task-gamma", "running", "Activate", "3.14",
"4", "task-delta", "pending", "Activate", "2.71",
"5", "task-epsilon", "ok", "Activate", "0.99",
"6", "task-zeta", "error", "Activate", "4.20",
};
qa::rebuild_ptrs(g_st);
}
// Helper: construye un ButtonClick sintetico y lo consume.
void inject_button_click(const char* action_id, int row) {
data_table::TableEvent ev;
ev.kind = data_table::TableEventKind::ButtonClick;
ev.row = row;
ev.col = 3;
ev.column_id = "action";
ev.action_id = action_id;
ev.value = "Activate";
std::vector<data_table::TableEvent> batch = {ev};
qa::consume_events(batch);
g_events_injected_total++;
}
// Helper: construye un RowDoubleClick sintetico y lo consume.
void inject_row_double_click(int row) {
data_table::TableEvent ev;
ev.kind = data_table::TableEventKind::RowDoubleClick;
ev.row = row;
ev.col = -1;
std::vector<data_table::TableEvent> batch = {ev};
qa::consume_events(batch);
g_events_injected_total++;
}
// Helper: construye un RowRightClick sintetico y lo consume.
void inject_row_right_click(int row) {
data_table::TableEvent ev;
ev.kind = data_table::TableEventKind::RowRightClick;
ev.row = row;
ev.col = -1;
std::vector<data_table::TableEvent> batch = {ev};
qa::consume_events(batch);
g_events_injected_total++;
}
} // anon
void render_events() {
// 1. Seed si vacio
if (g_st.back.empty()) seed();
const auto& c = qa::counters();
// 2. Panel de control — inyectores sinteticos
ImGui::Text("Synthetic event injectors:");
ImGui::Spacing();
// Fila 1: ButtonClick injectors
if (ImGui::Button("Inject ButtonClick (retry) row=0")) {
inject_button_click("retry", 0);
}
ImGui::SameLine();
if (ImGui::Button("Inject ButtonClick (cancel) row=1")) {
inject_button_click("cancel", 1);
}
// Fila 2: Row events
if (ImGui::Button("Inject RowDoubleClick row=2")) {
inject_row_double_click(2);
}
ImGui::SameLine();
if (ImGui::Button("Inject RowRightClick row=3")) {
inject_row_right_click(3);
}
// Fila 3: Burst + reset
if (ImGui::Button("Inject 100x ButtonClick burst")) {
std::vector<data_table::TableEvent> burst;
burst.reserve(100);
for (int i = 0; i < 100; i++) {
data_table::TableEvent ev;
ev.kind = data_table::TableEventKind::ButtonClick;
ev.row = i % 6;
ev.col = 3;
ev.column_id = "action";
ev.action_id = "activate";
ev.value = "Activate";
burst.push_back(ev);
}
auto t0 = std::chrono::steady_clock::now();
qa::consume_events(burst);
auto t1 = std::chrono::steady_clock::now();
long long us = std::chrono::duration_cast<std::chrono::microseconds>(t1 - t0).count();
g_events_injected_total += 100;
snprintf(g_burst_msg, sizeof(g_burst_msg),
"100 events processed in %lld us", us);
}
ImGui::SameLine();
if (ImGui::Button("Reset counters")) {
auto& mut = qa::counters();
mut.button_clicks = 0;
mut.row_double_click = 0;
mut.row_right_click = 0;
g_events_injected_total = 0;
g_burst_msg[0] = '\0';
}
// Fila 4: mensajes de estado
if (g_burst_msg[0] != '\0') {
ImGui::SameLine();
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "%s", g_burst_msg);
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// 3. Counters vivos
ImGui::Text("Global counters — button_clicks: %d row_double_click: %d row_right_click: %d",
c.button_clicks, c.row_double_click, c.row_right_click);
ImGui::Text("events_injected_total (esta tab): %d", g_events_injected_total);
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
// 4. Tabla real — eventos reales del usuario tambien cuentan
data_table::TableInput tbl;
tbl.name = "events";
tbl.headers = {"id", "name", "status", "action", "value"};
tbl.types = {
data_table::ColumnType::Int,
data_table::ColumnType::String,
data_table::ColumnType::String,
data_table::ColumnType::String,
data_table::ColumnType::Float,
};
tbl.cells = g_st.ptrs.data();
tbl.rows = 6;
tbl.cols = 5;
tbl.column_specs.resize(tbl.cols);
for (int i = 0; i < tbl.cols; i++) tbl.column_specs[i].id = tbl.headers[i];
// status: CategoricalChip
{
auto& cs = tbl.column_specs[2];
cs.renderer = data_table::CellRenderer::CategoricalChip;
cs.chips = {
{"ok", "#22c55e"},
{"error", "#ef4444"},
{"running", "#f59e0b"},
{"pending", "#a3a3a3"},
};
}
// action: Button
{
auto& cs = tbl.column_specs[3];
cs.renderer = data_table::CellRenderer::Button;
cs.button_action = "activate";
cs.button_color_hex = "#3b82f6";
}
ImGui::BeginChild("##events_host", ImVec2(-1, -1));
g_st.last_events.clear();
data_table::render("##events_tbl", {tbl}, g_st.dt,
&g_st.last_events, qa::toggles().show_chrome);
ImGui::EndChild();
// 5. Consumir eventos reales (incrementa los mismos counters globales)
qa::consume_events(g_st.last_events);
}
} // namespace tables_qa::tabs