b15106fc09
- 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>
210 lines
6.5 KiB
C++
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
|