yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
core_systems_test_suite.h
Go to the documentation of this file.
1#ifndef YAZE_APP_TEST_CORE_SYSTEMS_TEST_SUITE_H_
2#define YAZE_APP_TEST_CORE_SYSTEMS_TEST_SUITE_H_
3
4#include <chrono>
5#include <memory>
6#include <string>
7#include <vector>
8
9#include "absl/strings/str_format.h"
15#include "rom/rom.h"
16
17namespace yaze {
18namespace test {
19
27 public:
29 ~CoreSystemsTestSuite() override = default;
30
31 std::string GetName() const override { return "Core Systems Tests"; }
32 TestCategory GetCategory() const override { return TestCategory::kUnit; }
33
34 absl::Status RunTests(TestResults& results) override {
35 // ContentRegistry tests
41
42 // EventBus tests
48
49 return absl::OkStatus();
50 }
51
52 void DrawConfiguration() override {
53 ImGui::Text("Core Systems Test Configuration");
54 ImGui::Checkbox("Test ContentRegistry", &test_content_registry_);
55 ImGui::Checkbox("Test EventBus", &test_event_bus_);
56 ImGui::Checkbox("Test Core Events", &test_core_events_);
57 }
58
59 private:
60 // ===========================================================================
61 // ContentRegistry Tests
62 // ===========================================================================
63
66 AddSkippedResult(results, "ContentRegistry_Context_SetRom",
67 "ContentRegistry testing disabled");
68 return;
69 }
70
71 auto start_time = std::chrono::steady_clock::now();
72 TestResult result = CreateResult("ContentRegistry_Context_SetRom",
73 start_time);
74
75 try {
76 // Save original state
78
79 // Test with a mock ROM pointer (we just need to verify pointer storage)
80 Rom test_rom;
82
84 if (retrieved == &test_rom) {
86 result.error_message = "ContentRegistry::Context::SetRom works correctly";
87 } else {
89 result.error_message = "ContentRegistry returned wrong ROM pointer";
90 }
91
92 // Restore original state
94
95 } catch (const std::exception& e) {
97 result.error_message =
98 "ContentRegistry SetRom test failed: " + std::string(e.what());
99 }
100
101 FinalizeResult(result, start_time, results);
102 }
103
106 AddSkippedResult(results, "ContentRegistry_Context_Clear",
107 "ContentRegistry testing disabled");
108 return;
109 }
110
111 auto start_time = std::chrono::steady_clock::now();
112 TestResult result = CreateResult("ContentRegistry_Context_Clear",
113 start_time);
114
115 try {
116 // Save original state
118
119 // Set a ROM, then clear
120 Rom test_rom;
123
125 if (retrieved == nullptr) {
127 result.error_message = "ContentRegistry::Context::Clear works correctly";
128 } else {
130 result.error_message = "ContentRegistry::Context::Clear did not reset ROM";
131 }
132
133 // Restore original state
135
136 } catch (const std::exception& e) {
138 result.error_message =
139 "ContentRegistry Clear test failed: " + std::string(e.what());
140 }
141
142 FinalizeResult(result, start_time, results);
143 }
144
147 AddSkippedResult(results, "ContentRegistry_Panel_Registration",
148 "ContentRegistry testing disabled");
149 return;
150 }
151
152 auto start_time = std::chrono::steady_clock::now();
153 TestResult result = CreateResult("ContentRegistry_Panel_Registration",
154 start_time);
155
156 try {
157 // Get current panel count
158 auto panels_before = editor::ContentRegistry::Panels::GetAll();
159 size_t count_before = panels_before.size();
160
161 // We can't easily create a mock panel without including more headers,
162 // so we just verify the API doesn't crash
163 auto panels_after = editor::ContentRegistry::Panels::GetAll();
164
166 result.error_message = absl::StrFormat(
167 "Panel registry API accessible: %zu panels registered",
168 panels_after.size());
169
170 } catch (const std::exception& e) {
172 result.error_message =
173 "Panel registration test failed: " + std::string(e.what());
174 }
175
176 FinalizeResult(result, start_time, results);
177 }
178
181 AddSkippedResult(results, "ContentRegistry_Thread_Safety",
182 "ContentRegistry testing disabled");
183 return;
184 }
185
186 auto start_time = std::chrono::steady_clock::now();
187 TestResult result = CreateResult("ContentRegistry_Thread_Safety",
188 start_time);
189
190 try {
191 // Save original state
193
194 // Test rapid set/get operations (simulates concurrent access patterns)
195 Rom test_rom1, test_rom2;
196 bool all_reads_valid = true;
197
198 for (int i = 0; i < 100; ++i) {
199 editor::ContentRegistry::Context::SetRom(i % 2 == 0 ? &test_rom1 : &test_rom2);
201 if (read != &test_rom1 && read != &test_rom2) {
202 all_reads_valid = false;
203 break;
204 }
205 }
206
207 if (all_reads_valid) {
209 result.error_message = "ContentRegistry handles rapid access patterns";
210 } else {
212 result.error_message = "ContentRegistry returned invalid pointer during rapid access";
213 }
214
215 // Restore original state
217
218 } catch (const std::exception& e) {
220 result.error_message =
221 "Thread safety test failed: " + std::string(e.what());
222 }
223
224 FinalizeResult(result, start_time, results);
225 }
226
229 AddSkippedResult(results, "PanelManager_Scope_Registration",
230 "ContentRegistry testing disabled");
231 return;
232 }
233
234 auto start_time = std::chrono::steady_clock::now();
235 TestResult result = CreateResult("PanelManager_Scope_Registration",
236 start_time);
237
238 try {
239 class TestSessionPanel final : public editor::EditorPanel {
240 public:
241 std::string GetId() const override { return "test.session_panel"; }
242 std::string GetDisplayName() const override { return "Test Session"; }
243 std::string GetIcon() const override { return ""; }
244 std::string GetEditorCategory() const override { return "Test"; }
245 void Draw(bool*) override {}
246 };
247
248 class TestGlobalPanel final : public editor::EditorPanel {
249 public:
250 std::string GetId() const override { return "test.global_panel"; }
251 std::string GetDisplayName() const override { return "Test Global"; }
252 std::string GetIcon() const override { return ""; }
253 std::string GetEditorCategory() const override { return "Test"; }
254 editor::PanelScope GetScope() const override {
255 return editor::PanelScope::kGlobal;
256 }
257 void Draw(bool*) override {}
258 };
259
260 PanelManager panel_manager;
261 panel_manager.RegisterRegistryPanel(std::make_unique<TestSessionPanel>());
262 panel_manager.RegisterRegistryPanel(std::make_unique<TestGlobalPanel>());
263 panel_manager.RegisterRegistryPanelsForSession(0);
264 panel_manager.RegisterRegistryPanelsForSession(1);
265
266 const auto* session0 =
267 panel_manager.GetPanelDescriptor(0, "test.session_panel");
268 const auto* session1 =
269 panel_manager.GetPanelDescriptor(1, "test.session_panel");
270 const auto* global0 =
271 panel_manager.GetPanelDescriptor(0, "test.global_panel");
272 const auto* global1 =
273 panel_manager.GetPanelDescriptor(1, "test.global_panel");
274
275 bool all_ok = (session0 && session1 && global0 && global1);
276 if (all_ok) {
277 all_ok &= (session0->card_id != session1->card_id);
278 all_ok &= (global0->card_id == "test.global_panel");
279 all_ok &= (global1->card_id == "test.global_panel");
280 }
281
282 if (all_ok) {
284 result.error_message =
285 "PanelManager registers session/global descriptors correctly";
286 } else {
288 result.error_message =
289 "Panel scope registration did not create expected descriptors";
290 }
291 } catch (const std::exception& e) {
293 result.error_message =
294 "Panel scope registration test failed: " + std::string(e.what());
295 }
296
297 FinalizeResult(result, start_time, results);
298 }
299
300 // ===========================================================================
301 // EventBus Tests
302 // ===========================================================================
303
305 if (!test_event_bus_) {
306 AddSkippedResult(results, "EventBus_Subscribe_Publish",
307 "EventBus testing disabled");
308 return;
309 }
310
311 auto start_time = std::chrono::steady_clock::now();
312 TestResult result = CreateResult("EventBus_Subscribe_Publish", start_time);
313
314 try {
315 EventBus bus;
316 int call_count = 0;
317 int received_value = 0;
318
319 // Subscribe to RomLoadedEvent
321 [&](const editor::RomLoadedEvent& e) {
322 call_count++;
323 received_value = static_cast<int>(e.session_id);
324 });
325
326 // Publish event
327 auto event = editor::RomLoadedEvent::Create(nullptr, "test.sfc", 42);
328 bus.Publish(event);
329
330 if (call_count == 1 && received_value == 42) {
332 result.error_message = "EventBus subscribe/publish works correctly";
333 } else {
335 result.error_message = absl::StrFormat(
336 "EventBus failed: call_count=%d (expected 1), received=%d (expected 42)",
337 call_count, received_value);
338 }
339
340 } catch (const std::exception& e) {
342 result.error_message =
343 "EventBus subscribe/publish test failed: " + std::string(e.what());
344 }
345
346 FinalizeResult(result, start_time, results);
347 }
348
350 if (!test_event_bus_) {
351 AddSkippedResult(results, "EventBus_Unsubscribe",
352 "EventBus testing disabled");
353 return;
354 }
355
356 auto start_time = std::chrono::steady_clock::now();
357 TestResult result = CreateResult("EventBus_Unsubscribe", start_time);
358
359 try {
360 EventBus bus;
361 int call_count = 0;
362
363 // Subscribe and get handler ID
364 auto handler_id = bus.Subscribe<editor::SessionClosedEvent>(
365 [&](const editor::SessionClosedEvent&) { call_count++; });
366
367 // Publish - should increment
369 int count_after_first = call_count;
370
371 // Unsubscribe
372 bus.Unsubscribe(handler_id);
373
374 // Publish again - should NOT increment
376 int count_after_second = call_count;
377
378 if (count_after_first == 1 && count_after_second == 1) {
380 result.error_message = "EventBus unsubscribe works correctly";
381 } else {
383 result.error_message = absl::StrFormat(
384 "Unsubscribe failed: after_first=%d, after_second=%d (expected 1, 1)",
385 count_after_first, count_after_second);
386 }
387
388 } catch (const std::exception& e) {
390 result.error_message =
391 "EventBus unsubscribe test failed: " + std::string(e.what());
392 }
393
394 FinalizeResult(result, start_time, results);
395 }
396
398 if (!test_event_bus_) {
399 AddSkippedResult(results, "EventBus_Multiple_Subscribers",
400 "EventBus testing disabled");
401 return;
402 }
403
404 auto start_time = std::chrono::steady_clock::now();
405 TestResult result = CreateResult("EventBus_Multiple_Subscribers",
406 start_time);
407
408 try {
409 EventBus bus;
410 int subscriber1_calls = 0;
411 int subscriber2_calls = 0;
412 int subscriber3_calls = 0;
413
414 // Register multiple subscribers
416 [&](const editor::FrameGuiBeginEvent&) { subscriber1_calls++; });
418 [&](const editor::FrameGuiBeginEvent&) { subscriber2_calls++; });
420 [&](const editor::FrameGuiBeginEvent&) { subscriber3_calls++; });
421
422 // Publish once
424
425 if (subscriber1_calls == 1 && subscriber2_calls == 1 &&
426 subscriber3_calls == 1) {
428 result.error_message = "All 3 subscribers received the event";
429 } else {
431 result.error_message = absl::StrFormat(
432 "Multiple subscribers failed: s1=%d, s2=%d, s3=%d (expected 1,1,1)",
433 subscriber1_calls, subscriber2_calls, subscriber3_calls);
434 }
435
436 } catch (const std::exception& e) {
438 result.error_message =
439 "Multiple subscribers test failed: " + std::string(e.what());
440 }
441
442 FinalizeResult(result, start_time, results);
443 }
444
446 if (!test_event_bus_) {
447 AddSkippedResult(results, "EventBus_Type_Safety",
448 "EventBus testing disabled");
449 return;
450 }
451
452 auto start_time = std::chrono::steady_clock::now();
453 TestResult result = CreateResult("EventBus_Type_Safety", start_time);
454
455 try {
456 EventBus bus;
457 int rom_loaded_calls = 0;
458 int session_closed_calls = 0;
459
460 // Subscribe to different event types
462 [&](const editor::RomLoadedEvent&) { rom_loaded_calls++; });
464 [&](const editor::SessionClosedEvent&) { session_closed_calls++; });
465
466 // Publish only RomLoadedEvent
467 bus.Publish(editor::RomLoadedEvent::Create(nullptr, "test.sfc", 1));
468
469 if (rom_loaded_calls == 1 && session_closed_calls == 0) {
471 result.error_message =
472 "EventBus correctly routes events by type";
473 } else {
475 result.error_message = absl::StrFormat(
476 "Type safety failed: rom_loaded=%d, session_closed=%d (expected 1, 0)",
477 rom_loaded_calls, session_closed_calls);
478 }
479
480 } catch (const std::exception& e) {
482 result.error_message =
483 "Type safety test failed: " + std::string(e.what());
484 }
485
486 FinalizeResult(result, start_time, results);
487 }
488
490 if (!test_core_events_) {
491 AddSkippedResult(results, "Core_Events_Creation",
492 "Core events testing disabled");
493 return;
494 }
495
496 auto start_time = std::chrono::steady_clock::now();
497 TestResult result = CreateResult("Core_Events_Creation", start_time);
498
499 try {
500 // Test factory methods for all core event types
501 auto rom_loaded = editor::RomLoadedEvent::Create(nullptr, "test.sfc", 1);
502 auto rom_unloaded = editor::RomUnloadedEvent::Create(2);
503 auto rom_modified = editor::RomModifiedEvent::Create(nullptr, 3, 0x1000, 16);
504 auto session_switched = editor::SessionSwitchedEvent::Create(0, 1, nullptr);
505 auto session_created = editor::SessionCreatedEvent::Create(4, nullptr);
506 auto session_closed = editor::SessionClosedEvent::Create(5);
507 auto editor_switched = editor::EditorSwitchedEvent::Create(1, nullptr);
508 auto frame_begin = editor::FrameBeginEvent::Create(0.016f);
509 auto frame_gui_begin = editor::FrameGuiBeginEvent::Create(0.016f);
510 auto frame_end = editor::FrameEndEvent::Create(0.016f);
511
512 // Verify values
513 bool all_correct = true;
514 all_correct &= (rom_loaded.filename == "test.sfc");
515 all_correct &= (rom_loaded.session_id == 1);
516 all_correct &= (rom_unloaded.session_id == 2);
517 all_correct &= (rom_modified.address == 0x1000);
518 all_correct &= (rom_modified.byte_count == 16);
519 all_correct &= (session_switched.old_index == 0);
520 all_correct &= (session_switched.new_index == 1);
521 all_correct &= (session_created.index == 4);
522 all_correct &= (session_closed.index == 5);
523 all_correct &= (editor_switched.editor_type == 1);
524 all_correct &= (frame_begin.delta_time > 0.0f);
525 all_correct &= (frame_gui_begin.delta_time > 0.0f);
526 all_correct &= (frame_end.delta_time > 0.0f);
527
528 if (all_correct) {
530 result.error_message =
531 "All core event factory methods work correctly";
532 } else {
534 result.error_message = "Some event factory methods returned wrong values";
535 }
536
537 } catch (const std::exception& e) {
539 result.error_message =
540 "Core events creation test failed: " + std::string(e.what());
541 }
542
543 FinalizeResult(result, start_time, results);
544 }
545
546 // ===========================================================================
547 // Helper Methods
548 // ===========================================================================
549
551 const std::string& name,
552 std::chrono::time_point<std::chrono::steady_clock> start_time) {
553 TestResult result;
554 result.name = name;
555 result.suite_name = GetName();
556 result.category = GetCategory();
557 result.timestamp = start_time;
558 return result;
559 }
560
562 TestResult& result,
563 std::chrono::time_point<std::chrono::steady_clock> start_time,
564 TestResults& results) {
565 auto end_time = std::chrono::steady_clock::now();
566 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
567 end_time - start_time);
568 results.AddResult(result);
569 }
570
571 void AddSkippedResult(TestResults& results, const std::string& name,
572 const std::string& reason) {
573 TestResult result;
574 result.name = name;
575 result.suite_name = GetName();
576 result.category = GetCategory();
578 result.error_message = reason;
579 result.duration = std::chrono::milliseconds{0};
580 result.timestamp = std::chrono::steady_clock::now();
581 results.AddResult(result);
582 }
583
584 // Configuration flags
586 bool test_event_bus_ = true;
587 bool test_core_events_ = true;
588};
589
590} // namespace test
591} // namespace yaze
592
593#endif // YAZE_APP_TEST_CORE_SYSTEMS_TEST_SUITE_H_
void Publish(const T &event)
Definition event_bus.h:35
void Unsubscribe(HandlerId id)
Definition event_bus.h:45
HandlerId Subscribe(std::function< void(const T &)> handler)
Definition event_bus.h:22
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
Base interface for all logical panel components.
Test suite for core infrastructure: ContentRegistry and EventBus.
void RunEventBusTypeSafetyTest(TestResults &results)
std::string GetName() const override
void RunEventBusUnsubscribeTest(TestResults &results)
void RunCoreEventsCreationTest(TestResults &results)
void RunContentRegistryPanelRegistrationTest(TestResults &results)
void RunEventBusMultipleSubscribersTest(TestResults &results)
void RunContentRegistryContextClearTest(TestResults &results)
void AddSkippedResult(TestResults &results, const std::string &name, const std::string &reason)
~CoreSystemsTestSuite() override=default
absl::Status RunTests(TestResults &results) override
TestCategory GetCategory() const override
void FinalizeResult(TestResult &result, std::chrono::time_point< std::chrono::steady_clock > start_time, TestResults &results)
TestResult CreateResult(const std::string &name, std::chrono::time_point< std::chrono::steady_clock > start_time)
void RunContentRegistryThreadSafetyTest(TestResults &results)
void RunPanelScopeRegistrationTest(TestResults &results)
void RunContentRegistryContextSetRomTest(TestResults &results)
void RunEventBusSubscribePublishTest(TestResults &results)
Rom * rom()
Get the current ROM instance.
void SetRom(Rom *rom)
Set the current ROM instance.
void Clear()
Clear all context state.
std::vector< EditorPanel * > GetAll()
Get all registered panels.
PanelScope
Defines whether a panel is session-scoped or global.
static EditorSwitchedEvent Create(int type, void *ed)
static FrameBeginEvent Create(float dt)
static FrameEndEvent Create(float dt)
Published after ImGui::NewFrame and dockspace creation.
static FrameGuiBeginEvent Create(float dt)
Published when a ROM is successfully loaded into a session.
Definition core_events.h:27
static RomLoadedEvent Create(Rom *r, const std::string &file, size_t session)
Definition core_events.h:32
static RomModifiedEvent Create(Rom *r, size_t session, uint32_t addr=0, size_t bytes=0)
Definition core_events.h:68
static RomUnloadedEvent Create(size_t session)
Definition core_events.h:49
Published when a session is closed.
static SessionClosedEvent Create(size_t idx)
static SessionCreatedEvent Create(size_t idx, RomSession *sess)
static SessionSwitchedEvent Create(size_t old_idx, size_t new_idx, RomSession *sess)
Definition core_events.h:93
std::chrono::milliseconds duration
std::string error_message
std::chrono::time_point< std::chrono::steady_clock > timestamp
void AddResult(const TestResult &result)