yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
test_manager.h
Go to the documentation of this file.
1#ifndef YAZE_APP_TEST_TEST_MANAGER_H
2#define YAZE_APP_TEST_TEST_MANAGER_H
3
4#include <chrono>
5#include <deque>
6#include <functional>
7#include <map>
8#include <memory>
9#include <string>
10#include <unordered_map>
11#include <vector>
12
13#include "absl/status/status.h"
14#include "absl/status/statusor.h"
15#include "absl/strings/string_view.h"
16#include "absl/synchronization/mutex.h"
17#include "absl/time/time.h"
18#include "rom/rom.h"
19
20#define IMGUI_DEFINE_MATH_OPERATORS
21#include "imgui.h"
22#include "util/log.h"
23
24// Forward declarations
25namespace yaze {
26namespace editor {
27class EditorManager;
28}
29} // namespace yaze
30
31#if defined(YAZE_ENABLE_IMGUI_TEST_ENGINE) && YAZE_ENABLE_IMGUI_TEST_ENGINE
32#if __has_include("imgui_test_engine/imgui_te_engine.h")
33#include "imgui_test_engine/imgui_te_engine.h"
34#elif __has_include("imgui_te_engine.h")
35#include "imgui_te_engine.h"
36#else
37#error "ImGui Test Engine headers not found"
38#endif
39#else
40// Forward declaration when ImGui Test Engine is not available
41struct ImGuiTestEngine;
42#endif
43
44namespace yaze {
45namespace test {
46
47// Test execution status
49
50// Test categories for organization
52
53// Individual test result
54struct TestResult {
55 std::string name;
56 std::string suite_name;
59 std::string error_message;
60 std::chrono::milliseconds duration;
61 std::chrono::time_point<std::chrono::steady_clock> timestamp;
62};
63
64// Overall test results summary
66 std::vector<TestResult> individual_results;
67 size_t total_tests = 0;
68 size_t passed_tests = 0;
69 size_t failed_tests = 0;
70 size_t skipped_tests = 0;
71 std::chrono::milliseconds total_duration{0};
72
73 void AddResult(const TestResult& result) {
74 individual_results.push_back(result);
76 switch (result.status) {
79 break;
82 break;
85 break;
86 default:
87 break;
88 }
89 total_duration += result.duration;
90 }
91
92 void Clear() {
93 individual_results.clear();
95 total_duration = std::chrono::milliseconds{0};
96 }
97
98 float GetPassRate() const {
99 return total_tests > 0 ? static_cast<float>(passed_tests) / total_tests
100 : 0.0f;
101 }
102};
103
104// Base class for test suites
106 public:
107 virtual ~TestSuite() = default;
108 virtual std::string GetName() const = 0;
109 virtual TestCategory GetCategory() const = 0;
110 virtual absl::Status RunTests(TestResults& results) = 0;
111 virtual void DrawConfiguration() {}
112 virtual bool IsEnabled() const { return enabled_; }
113 virtual void SetEnabled(bool enabled) { enabled_ = enabled; }
114
115 protected:
116 bool enabled_ = true;
117};
118
119// Resource monitoring for performance and memory tests
121 size_t texture_count = 0;
122 size_t surface_count = 0;
123 size_t memory_usage_mb = 0;
124 float frame_rate = 0.0f;
125 std::chrono::time_point<std::chrono::steady_clock> timestamp;
126};
127
128// Test harness execution tracking for gRPC automation (IT-05)
129#if defined(YAZE_WITH_GRPC)
130enum class HarnessTestStatus {
131 kUnspecified,
132 kQueued,
133 kRunning,
134 kPassed,
135 kFailed,
136 kTimeout,
137};
138
139const char* HarnessStatusToString(HarnessTestStatus status);
140HarnessTestStatus HarnessStatusFromString(absl::string_view status);
141
142struct HarnessTestExecution {
143 std::string test_id;
144 std::string name;
145 std::string category;
146 HarnessTestStatus status = HarnessTestStatus::kUnspecified;
147 absl::Time queued_at;
148 absl::Time started_at;
149 absl::Time completed_at;
150 absl::Duration duration = absl::ZeroDuration();
151 std::string error_message;
152 std::vector<std::string> assertion_failures;
153 std::vector<std::string> logs;
154 std::map<std::string, int32_t> metrics;
155
156 // IT-08b: Failure diagnostics
157 std::string screenshot_path;
158 int64_t screenshot_size_bytes = 0;
159 std::string failure_context;
160 std::string widget_state; // IT-08c (future)
161};
162
163struct HarnessTestSummary {
164 HarnessTestExecution latest_execution;
165 int total_runs = 0;
166 int pass_count = 0;
167 int fail_count = 0;
168 absl::Duration total_duration = absl::ZeroDuration();
169};
170
171class HarnessListener {
172 public:
173 virtual ~HarnessListener() = default;
174 virtual void OnHarnessTestUpdated(const HarnessTestExecution& execution) = 0;
175 virtual void OnHarnessPlanSummary(const std::string& summary) = 0;
176};
177#endif // defined(YAZE_WITH_GRPC)
178
179// Main test manager - singleton
181 public:
182 static TestManager& Get();
183
184 // Core test execution
185 absl::Status RunAllTests();
186 absl::Status RunTestsByCategory(TestCategory category);
187 absl::Status RunTestSuite(const std::string& suite_name);
188
189 // Test suite management
190 void RegisterTestSuite(std::unique_ptr<TestSuite> suite);
191 std::vector<std::string> GetTestSuiteNames() const;
192 TestSuite* GetTestSuite(const std::string& name);
193
194 // Results access
195 const TestResults& GetLastResults() const { return last_results_; }
197
198 // Configuration
199 void SetMaxConcurrentTests(size_t max_concurrent) {
200 max_concurrent_tests_ = max_concurrent;
201 }
202 void SetTestTimeout(std::chrono::seconds timeout) { test_timeout_ = timeout; }
203
204 // Resource monitoring
205 void UpdateResourceStats();
206 const std::vector<ResourceStats>& GetResourceHistory() const {
207 return resource_history_;
208 }
209
210 // UI Testing (ImGui Test Engine integration)
211#if defined(YAZE_ENABLE_IMGUI_TEST_ENGINE) && YAZE_ENABLE_IMGUI_TEST_ENGINE
212 ImGuiTestEngine* GetUITestEngine() { return ui_test_engine_; }
213 void InitializeUITesting();
214 void OnPostSwap();
215 void StopUITesting(); // Stop test engine while ImGui context is valid
216 void DestroyUITestingContext(); // Destroy test engine after ImGui context is
217 // destroyed
218 void ShutdownUITesting(); // Complete shutdown (calls both Stop and Destroy)
219#else
220 void* GetUITestEngine() { return nullptr; }
222 void OnPostSwap() {}
226#endif
227
228 // Status queries
229 bool IsTestRunning() const { return is_running_; }
230 const std::string& GetCurrentTestName() const { return current_test_name_; }
231 float GetProgress() const { return progress_; }
232
233 // UI Interface
234 void DrawTestDashboard(bool* show_dashboard = nullptr);
235
236 // ROM-dependent testing
237 void SetCurrentRom(Rom* rom) {
238 LOG_INFO("TestManager", "SetCurrentRom called with ROM: %p", (void*)rom);
239 if (rom) {
240 LOG_INFO("TestManager", "ROM title: '%s', loaded: %s",
241 rom->title().c_str(), rom->is_loaded() ? "true" : "false");
242 }
243 current_rom_ = rom;
244 }
245 Rom* GetCurrentRom() const { return current_rom_; }
246 void RefreshCurrentRom(); // Refresh ROM pointer from editor manager
247 // Remove EditorManager dependency to avoid circular includes
248
249 // Enhanced ROM testing
250 absl::Status LoadRomForTesting(const std::string& filename);
251 void ShowRomComparisonResults(const Rom& before, const Rom& after);
252
253 // Test ROM management
254 absl::Status CreateTestRomCopy(Rom* source_rom,
255 std::unique_ptr<Rom>& test_rom);
256 std::string GenerateTestRomFilename(const std::string& base_name);
257 void OfferTestSessionCreation(const std::string& test_rom_path);
258
259 public:
260 // ROM testing methods (work on copies, not originals)
261 absl::Status TestRomSaveLoad(Rom* rom);
262 absl::Status TestRomDataIntegrity(Rom* rom);
263 absl::Status TestRomWithCopy(Rom* source_rom,
264 std::function<absl::Status(Rom*)> test_function);
265
266 // Test configuration management
267 void DisableTest(const std::string& test_name) {
268 disabled_tests_[test_name] = true;
269 }
270 void EnableTest(const std::string& test_name) {
271 disabled_tests_[test_name] = false;
272 }
273 bool IsTestEnabled(const std::string& test_name) const {
274 auto it = disabled_tests_.find(test_name);
275 return it == disabled_tests_.end() || !it->second;
276 }
277 // File dialog mode now uses global feature flags
278
279 // Harness test introspection (IT-05)
280#if defined(YAZE_WITH_GRPC)
281 std::string RegisterHarnessTest(const std::string& name,
282 const std::string& category)
283 ABSL_LOCKS_EXCLUDED(harness_history_mutex_);
284 void MarkHarnessTestRunning(const std::string& test_id)
285 ABSL_LOCKS_EXCLUDED(harness_history_mutex_);
286 void MarkHarnessTestCompleted(
287 const std::string& test_id, HarnessTestStatus status,
288 const std::string& error_message = "",
289 const std::vector<std::string>& assertion_failures = {},
290 const std::vector<std::string>& logs = {},
291 const std::map<std::string, int32_t>& metrics = {})
292 ABSL_LOCKS_EXCLUDED(harness_history_mutex_);
293 void AppendHarnessTestLog(const std::string& test_id,
294 const std::string& log_entry)
295 ABSL_LOCKS_EXCLUDED(harness_history_mutex_);
296 absl::StatusOr<HarnessTestExecution> GetHarnessTestExecution(
297 const std::string& test_id) const
298 ABSL_LOCKS_EXCLUDED(harness_history_mutex_);
299 std::vector<HarnessTestSummary> ListHarnessTestSummaries(
300 const std::string& category_filter = "") const
301 ABSL_LOCKS_EXCLUDED(harness_history_mutex_);
302
303 // IT-08b: Capture failure diagnostics
304 void CaptureFailureContext(const std::string& test_id)
305 ABSL_LOCKS_EXCLUDED(harness_history_mutex_);
306
307 void SetHarnessListener(HarnessListener* listener);
308
309 absl::Status ReplayLastPlan();
310#else
311 // Stub implementations when GRPC is not available
312 std::string RegisterHarnessTest(const std::string& name,
313 const std::string& category);
314 void CaptureFailureContext(const std::string& test_id);
315 absl::Status ReplayLastPlan();
316#endif
317
318 // These methods are always available
319 absl::Status ShowHarnessDashboard();
320 absl::Status ShowHarnessActiveTests();
321 void RecordPlanSummary(const std::string& summary);
322
323 private:
324 TestManager();
325 ~TestManager();
326
327 // Test execution helpers
328 absl::Status ExecuteTestSuite(TestSuite* suite);
329 void UpdateProgress();
330
331 // Resource monitoring helpers
333 void TrimResourceHistory();
334
335 // Member variables
336 std::vector<std::unique_ptr<TestSuite>> test_suites_;
337 std::unordered_map<std::string, TestSuite*> suite_lookup_;
338
340 bool is_running_ = false;
342 float progress_ = 0.0f;
343
344 // Configuration
346 std::chrono::seconds test_timeout_{30};
347
348 // Resource monitoring
349 std::vector<ResourceStats> resource_history_;
350 static constexpr size_t kMaxResourceHistorySize = 1000;
351
352 // UI Testing
353#ifdef YAZE_ENABLE_IMGUI_TEST_ENGINE
354 ImGuiTestEngine* ui_test_engine_ = nullptr;
355#endif
356
357 // UI State
358 bool show_dashboard_ = false;
360 std::string test_filter_;
362
363 // ROM-dependent testing
364 Rom* current_rom_ = nullptr;
365 // Removed editor_manager_ to avoid circular dependency
366
367 // UI state
368 bool show_google_tests_ = false;
374
375 // Test selection and configuration
376 std::unordered_map<std::string, bool> disabled_tests_;
377
378 // Harness test tracking
379#if defined(YAZE_WITH_GRPC)
380 struct HarnessAggregate {
381 int total_runs = 0;
382 int pass_count = 0;
383 int fail_count = 0;
384 absl::Duration total_duration = absl::ZeroDuration();
385 std::string category;
386 absl::Time last_run;
387 HarnessTestExecution latest_execution;
388 };
389
390 std::unordered_map<std::string, HarnessTestExecution> harness_history_
391 ABSL_GUARDED_BY(harness_history_mutex_);
392 std::unordered_map<std::string, HarnessAggregate> harness_aggregates_
393 ABSL_GUARDED_BY(harness_history_mutex_);
394 std::deque<std::string> harness_history_order_;
395 size_t harness_history_limit_ = 200;
396 mutable absl::Mutex harness_history_mutex_;
397#if defined(YAZE_WITH_GRPC)
398 HarnessListener* harness_listener_ ABSL_GUARDED_BY(mutex_) = nullptr;
399#endif
400#endif // defined(YAZE_WITH_GRPC)
401
402#if defined(YAZE_WITH_GRPC)
403 std::string GenerateHarnessTestIdLocked(absl::string_view prefix)
404 ABSL_EXCLUSIVE_LOCKS_REQUIRED(harness_history_mutex_);
405 void TrimHarnessHistoryLocked()
406 ABSL_EXCLUSIVE_LOCKS_REQUIRED(harness_history_mutex_);
407#endif
408
409 absl::Mutex mutex_;
410};
411
412// Utility functions for test result formatting
413const char* TestStatusToString(TestStatus status);
414const char* TestCategoryToString(TestCategory category);
415ImVec4 GetTestStatusColor(TestStatus status);
416
417} // namespace test
418} // namespace yaze
419
420#endif // YAZE_APP_TEST_TEST_MANAGER_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
bool is_loaded() const
Definition rom.h:132
auto title() const
Definition rom.h:137
std::string GenerateTestRomFilename(const std::string &base_name)
void CaptureFailureContext(const std::string &test_id)
std::string current_test_name_
Rom * GetCurrentRom() const
const TestResults & GetLastResults() const
absl::Status ShowHarnessActiveTests()
TestCategory category_filter_
absl::Status ShowHarnessDashboard()
std::vector< ResourceStats > resource_history_
void RegisterTestSuite(std::unique_ptr< TestSuite > suite)
void RecordPlanSummary(const std::string &summary)
absl::Status TestRomWithCopy(Rom *source_rom, std::function< absl::Status(Rom *)> test_function)
std::unordered_map< std::string, TestSuite * > suite_lookup_
absl::Status CreateTestRomCopy(Rom *source_rom, std::unique_ptr< Rom > &test_rom)
bool IsTestEnabled(const std::string &test_name) const
absl::Status RunTestSuite(const std::string &suite_name)
std::string RegisterHarnessTest(const std::string &name, const std::string &category)
absl::Status ExecuteTestSuite(TestSuite *suite)
void SetCurrentRom(Rom *rom)
std::string test_rom_path_for_session_
absl::Status TestRomDataIntegrity(Rom *rom)
static constexpr size_t kMaxResourceHistorySize
float GetProgress() const
void DrawTestDashboard(bool *show_dashboard=nullptr)
TestSuite * GetTestSuite(const std::string &name)
absl::Status RunAllTests()
static TestManager & Get()
void OfferTestSessionCreation(const std::string &test_rom_path)
void EnableTest(const std::string &test_name)
const std::vector< ResourceStats > & GetResourceHistory() const
void DisableTest(const std::string &test_name)
void SetTestTimeout(std::chrono::seconds timeout)
std::vector< std::unique_ptr< TestSuite > > test_suites_
absl::Status TestRomSaveLoad(Rom *rom)
void SetMaxConcurrentTests(size_t max_concurrent)
std::chrono::seconds test_timeout_
absl::Status RunTestsByCategory(TestCategory category)
void ShowRomComparisonResults(const Rom &before, const Rom &after)
std::unordered_map< std::string, bool > disabled_tests_
const std::string & GetCurrentTestName() const
absl::Status ReplayLastPlan()
std::vector< std::string > GetTestSuiteNames() const
absl::Status LoadRomForTesting(const std::string &filename)
virtual void DrawConfiguration()
virtual ~TestSuite()=default
virtual void SetEnabled(bool enabled)
virtual std::string GetName() const =0
virtual bool IsEnabled() const
virtual TestCategory GetCategory() const =0
virtual absl::Status RunTests(TestResults &results)=0
#define LOG_INFO(category, format,...)
Definition log.h:105
const char * TestStatusToString(TestStatus status)
const char * TestCategoryToString(TestCategory category)
ImVec4 GetTestStatusColor(TestStatus status)
std::chrono::time_point< std::chrono::steady_clock > timestamp
std::chrono::milliseconds duration
std::string error_message
std::chrono::time_point< std::chrono::steady_clock > timestamp
std::vector< TestResult > individual_results
std::chrono::milliseconds total_duration
void AddResult(const TestResult &result)
float GetPassRate() const