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"
16#include "rom/rom.h"
17
18namespace yaze {
19namespace test {
20
28 public:
30 ~CoreSystemsTestSuite() override = default;
31
32 std::string GetName() const override { return "Core Systems Tests"; }
33 TestCategory GetCategory() const override { return TestCategory::kUnit; }
34
35 absl::Status RunTests(TestResults& results) override {
36 // ContentRegistry tests
42
43 // EventBus tests
49
50 return absl::OkStatus();
51 }
52
53 void DrawConfiguration() override {
54 ImGui::Text("Core Systems Test Configuration");
55 ImGui::Checkbox("Test ContentRegistry", &test_content_registry_);
56 ImGui::Checkbox("Test EventBus", &test_event_bus_);
57 ImGui::Checkbox("Test Core Events", &test_core_events_);
58 }
59
60 private:
61 // ===========================================================================
62 // ContentRegistry Tests
63 // ===========================================================================
64
67 AddSkippedResult(results, "ContentRegistry_Context_SetRom",
68 "ContentRegistry testing disabled");
69 return;
70 }
71
72 auto start_time = std::chrono::steady_clock::now();
73 TestResult result =
74 CreateResult("ContentRegistry_Context_SetRom", start_time);
75
76 try {
77 // Save original state
79
80 // Test with a mock ROM pointer (we just need to verify pointer storage)
81 Rom test_rom;
83
85 if (retrieved == &test_rom) {
87 result.error_message =
88 "ContentRegistry::Context::SetRom works correctly";
89 } else {
91 result.error_message = "ContentRegistry returned wrong ROM pointer";
92 }
93
94 // Restore original state
96
97 } catch (const std::exception& e) {
99 result.error_message =
100 "ContentRegistry SetRom test failed: " + std::string(e.what());
101 }
102
103 FinalizeResult(result, start_time, results);
104 }
105
108 AddSkippedResult(results, "ContentRegistry_Context_Clear",
109 "ContentRegistry testing disabled");
110 return;
111 }
112
113 auto start_time = std::chrono::steady_clock::now();
114 TestResult result =
115 CreateResult("ContentRegistry_Context_Clear", start_time);
116
117 try {
118 // Save original state
120
121 // Set a ROM, then clear
122 Rom test_rom;
125
127 if (retrieved == nullptr) {
129 result.error_message =
130 "ContentRegistry::Context::Clear works correctly";
131 } else {
133 result.error_message =
134 "ContentRegistry::Context::Clear did not reset ROM";
135 }
136
137 // Restore original state
139
140 } catch (const std::exception& e) {
142 result.error_message =
143 "ContentRegistry Clear test failed: " + std::string(e.what());
144 }
145
146 FinalizeResult(result, start_time, results);
147 }
148
151 AddSkippedResult(results, "ContentRegistry_Panel_Registration",
152 "ContentRegistry testing disabled");
153 return;
154 }
155
156 auto start_time = std::chrono::steady_clock::now();
157 TestResult result =
158 CreateResult("ContentRegistry_Panel_Registration", start_time);
159
160 try {
161 // Get current panel count
162 auto panels_before = editor::ContentRegistry::Panels::GetAll();
163 size_t count_before = panels_before.size();
164
165 // We can't easily create a mock panel without including more headers,
166 // so we just verify the API doesn't crash
167 auto panels_after = editor::ContentRegistry::Panels::GetAll();
168
170 result.error_message = absl::StrFormat(
171 "Panel registry API accessible: %zu panels registered",
172 panels_after.size());
173
174 } catch (const std::exception& e) {
176 result.error_message =
177 "Panel registration test failed: " + std::string(e.what());
178 }
179
180 FinalizeResult(result, start_time, results);
181 }
182
185 AddSkippedResult(results, "ContentRegistry_Thread_Safety",
186 "ContentRegistry testing disabled");
187 return;
188 }
189
190 auto start_time = std::chrono::steady_clock::now();
191 TestResult result =
192 CreateResult("ContentRegistry_Thread_Safety", start_time);
193
194 try {
195 // Save original state
197
198 // Test rapid set/get operations (simulates concurrent access patterns)
199 Rom test_rom1, test_rom2;
200 bool all_reads_valid = true;
201
202 for (int i = 0; i < 100; ++i) {
203 editor::ContentRegistry::Context::SetRom(i % 2 == 0 ? &test_rom1
204 : &test_rom2);
206 if (read != &test_rom1 && read != &test_rom2) {
207 all_reads_valid = false;
208 break;
209 }
210 }
211
212 if (all_reads_valid) {
214 result.error_message = "ContentRegistry handles rapid access patterns";
215 } else {
217 result.error_message =
218 "ContentRegistry returned invalid pointer during rapid access";
219 }
220
221 // Restore original state
223
224 } catch (const std::exception& e) {
226 result.error_message =
227 "Thread safety test failed: " + std::string(e.what());
228 }
229
230 FinalizeResult(result, start_time, results);
231 }
232
235 AddSkippedResult(results, "PanelManager_Scope_Registration",
236 "ContentRegistry testing disabled");
237 return;
238 }
239
240 auto start_time = std::chrono::steady_clock::now();
241 TestResult result =
242 CreateResult("PanelManager_Scope_Registration", start_time);
243
244 try {
245 class TestSessionPanel final : public editor::WindowContent {
246 public:
247 std::string GetId() const override { return "test.session_panel"; }
248 std::string GetDisplayName() const override { return "Test Session"; }
249 std::string GetIcon() const override { return ""; }
250 std::string GetEditorCategory() const override { return "Test"; }
251 void Draw(bool*) override {}
252 };
253
254 class TestGlobalPanel final : public editor::WindowContent {
255 public:
256 std::string GetId() const override { return "test.global_panel"; }
257 std::string GetDisplayName() const override { return "Test Global"; }
258 std::string GetIcon() const override { return ""; }
259 std::string GetEditorCategory() const override { return "Test"; }
260 editor::WindowScope GetScope() const override {
261 return editor::WindowScope::kGlobal;
262 }
263 void Draw(bool*) override {}
264 };
265
266 PanelManager panel_manager;
267 panel_manager.RegisterRegistryPanel(std::make_unique<TestSessionPanel>());
268 panel_manager.RegisterRegistryPanel(std::make_unique<TestGlobalPanel>());
269 panel_manager.RegisterRegistryPanelsForSession(0);
270 panel_manager.RegisterRegistryPanelsForSession(1);
271
272 const auto* session0 =
273 panel_manager.GetPanelDescriptor(0, "test.session_panel");
274 const auto* session1 =
275 panel_manager.GetPanelDescriptor(1, "test.session_panel");
276 const auto* global0 =
277 panel_manager.GetPanelDescriptor(0, "test.global_panel");
278 const auto* global1 =
279 panel_manager.GetPanelDescriptor(1, "test.global_panel");
280
281 bool all_ok = (session0 && session1 && global0 && global1);
282 if (all_ok) {
283 all_ok &= (session0->card_id != session1->card_id);
284 all_ok &= (global0->card_id == "test.global_panel");
285 all_ok &= (global1->card_id == "test.global_panel");
286 }
287
288 if (all_ok) {
290 result.error_message =
291 "PanelManager registers session/global descriptors correctly";
292 } else {
294 result.error_message =
295 "Panel scope registration did not create expected descriptors";
296 }
297 } catch (const std::exception& e) {
299 result.error_message =
300 "Panel scope registration test failed: " + std::string(e.what());
301 }
302
303 FinalizeResult(result, start_time, results);
304 }
305
306 // ===========================================================================
307 // EventBus Tests
308 // ===========================================================================
309
311 if (!test_event_bus_) {
312 AddSkippedResult(results, "EventBus_Subscribe_Publish",
313 "EventBus testing disabled");
314 return;
315 }
316
317 auto start_time = std::chrono::steady_clock::now();
318 TestResult result = CreateResult("EventBus_Subscribe_Publish", start_time);
319
320 try {
321 EventBus bus;
322 int call_count = 0;
323 int received_value = 0;
324
325 // Subscribe to RomLoadedEvent
327 [&](const editor::RomLoadedEvent& e) {
328 call_count++;
329 received_value = static_cast<int>(e.session_id);
330 });
331
332 // Publish event
333 auto event = editor::RomLoadedEvent::Create(nullptr, "test.sfc", 42);
334 bus.Publish(event);
335
336 if (call_count == 1 && received_value == 42) {
338 result.error_message = "EventBus subscribe/publish works correctly";
339 } else {
341 result.error_message = absl::StrFormat(
342 "EventBus failed: call_count=%d (expected 1), received=%d "
343 "(expected 42)",
344 call_count, received_value);
345 }
346
347 } catch (const std::exception& e) {
349 result.error_message =
350 "EventBus subscribe/publish test failed: " + std::string(e.what());
351 }
352
353 FinalizeResult(result, start_time, results);
354 }
355
357 if (!test_event_bus_) {
358 AddSkippedResult(results, "EventBus_Unsubscribe",
359 "EventBus testing disabled");
360 return;
361 }
362
363 auto start_time = std::chrono::steady_clock::now();
364 TestResult result = CreateResult("EventBus_Unsubscribe", start_time);
365
366 try {
367 EventBus bus;
368 int call_count = 0;
369
370 // Subscribe and get handler ID
371 auto handler_id = bus.Subscribe<editor::SessionClosedEvent>(
372 [&](const editor::SessionClosedEvent&) { call_count++; });
373
374 // Publish - should increment
376 int count_after_first = call_count;
377
378 // Unsubscribe
379 bus.Unsubscribe(handler_id);
380
381 // Publish again - should NOT increment
383 int count_after_second = call_count;
384
385 if (count_after_first == 1 && count_after_second == 1) {
387 result.error_message = "EventBus unsubscribe works correctly";
388 } else {
390 result.error_message = absl::StrFormat(
391 "Unsubscribe failed: after_first=%d, after_second=%d (expected 1, "
392 "1)",
393 count_after_first, count_after_second);
394 }
395
396 } catch (const std::exception& e) {
398 result.error_message =
399 "EventBus unsubscribe test failed: " + std::string(e.what());
400 }
401
402 FinalizeResult(result, start_time, results);
403 }
404
406 if (!test_event_bus_) {
407 AddSkippedResult(results, "EventBus_Multiple_Subscribers",
408 "EventBus testing disabled");
409 return;
410 }
411
412 auto start_time = std::chrono::steady_clock::now();
413 TestResult result =
414 CreateResult("EventBus_Multiple_Subscribers", start_time);
415
416 try {
417 EventBus bus;
418 int subscriber1_calls = 0;
419 int subscriber2_calls = 0;
420 int subscriber3_calls = 0;
421
422 // Register multiple subscribers
424 [&](const editor::FrameGuiBeginEvent&) { subscriber1_calls++; });
426 [&](const editor::FrameGuiBeginEvent&) { subscriber2_calls++; });
428 [&](const editor::FrameGuiBeginEvent&) { subscriber3_calls++; });
429
430 // Publish once
432
433 if (subscriber1_calls == 1 && subscriber2_calls == 1 &&
434 subscriber3_calls == 1) {
436 result.error_message = "All 3 subscribers received the event";
437 } else {
439 result.error_message = absl::StrFormat(
440 "Multiple subscribers failed: s1=%d, s2=%d, s3=%d (expected 1,1,1)",
441 subscriber1_calls, subscriber2_calls, subscriber3_calls);
442 }
443
444 } catch (const std::exception& e) {
446 result.error_message =
447 "Multiple subscribers test failed: " + std::string(e.what());
448 }
449
450 FinalizeResult(result, start_time, results);
451 }
452
454 if (!test_event_bus_) {
455 AddSkippedResult(results, "EventBus_Type_Safety",
456 "EventBus testing disabled");
457 return;
458 }
459
460 auto start_time = std::chrono::steady_clock::now();
461 TestResult result = CreateResult("EventBus_Type_Safety", start_time);
462
463 try {
464 EventBus bus;
465 int rom_loaded_calls = 0;
466 int session_closed_calls = 0;
467
468 // Subscribe to different event types
470 [&](const editor::RomLoadedEvent&) { rom_loaded_calls++; });
472 [&](const editor::SessionClosedEvent&) { session_closed_calls++; });
473
474 // Publish only RomLoadedEvent
475 bus.Publish(editor::RomLoadedEvent::Create(nullptr, "test.sfc", 1));
476
477 if (rom_loaded_calls == 1 && session_closed_calls == 0) {
479 result.error_message = "EventBus correctly routes events by type";
480 } else {
482 result.error_message = absl::StrFormat(
483 "Type safety failed: rom_loaded=%d, session_closed=%d (expected 1, "
484 "0)",
485 rom_loaded_calls, session_closed_calls);
486 }
487
488 } catch (const std::exception& e) {
490 result.error_message =
491 "Type safety test failed: " + std::string(e.what());
492 }
493
494 FinalizeResult(result, start_time, results);
495 }
496
498 if (!test_core_events_) {
499 AddSkippedResult(results, "Core_Events_Creation",
500 "Core events testing disabled");
501 return;
502 }
503
504 auto start_time = std::chrono::steady_clock::now();
505 TestResult result = CreateResult("Core_Events_Creation", start_time);
506
507 try {
508 // Test factory methods for all core event types
509 auto rom_loaded = editor::RomLoadedEvent::Create(nullptr, "test.sfc", 1);
510 auto rom_unloaded = editor::RomUnloadedEvent::Create(2);
511 auto rom_modified =
512 editor::RomModifiedEvent::Create(nullptr, 3, 0x1000, 16);
513 auto session_switched =
515 auto session_created = editor::SessionCreatedEvent::Create(4, nullptr);
516 auto session_closed = editor::SessionClosedEvent::Create(5);
517 auto editor_switched = editor::EditorSwitchedEvent::Create(1, nullptr);
518 auto frame_begin = editor::FrameBeginEvent::Create(0.016f);
519 auto frame_gui_begin = editor::FrameGuiBeginEvent::Create(0.016f);
520 auto frame_end = editor::FrameEndEvent::Create(0.016f);
521
522 // Verify values
523 bool all_correct = true;
524 all_correct &= (rom_loaded.filename == "test.sfc");
525 all_correct &= (rom_loaded.session_id == 1);
526 all_correct &= (rom_unloaded.session_id == 2);
527 all_correct &= (rom_modified.address == 0x1000);
528 all_correct &= (rom_modified.byte_count == 16);
529 all_correct &= (session_switched.old_index == 0);
530 all_correct &= (session_switched.new_index == 1);
531 all_correct &= (session_created.index == 4);
532 all_correct &= (session_closed.index == 5);
533 all_correct &= (editor_switched.editor_type == 1);
534 all_correct &= (frame_begin.delta_time > 0.0f);
535 all_correct &= (frame_gui_begin.delta_time > 0.0f);
536 all_correct &= (frame_end.delta_time > 0.0f);
537
538 if (all_correct) {
540 result.error_message = "All core event factory methods work correctly";
541 } else {
543 result.error_message =
544 "Some event factory methods returned wrong values";
545 }
546
547 } catch (const std::exception& e) {
549 result.error_message =
550 "Core events creation test failed: " + std::string(e.what());
551 }
552
553 FinalizeResult(result, start_time, results);
554 }
555
556 // ===========================================================================
557 // Helper Methods
558 // ===========================================================================
559
561 const std::string& name,
562 std::chrono::time_point<std::chrono::steady_clock> start_time) {
563 TestResult result;
564 result.name = name;
565 result.suite_name = GetName();
566 result.category = GetCategory();
567 result.timestamp = start_time;
568 return result;
569 }
570
572 TestResult& result,
573 std::chrono::time_point<std::chrono::steady_clock> start_time,
574 TestResults& results) {
575 auto end_time = std::chrono::steady_clock::now();
576 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
577 end_time - start_time);
578 results.AddResult(result);
579 }
580
581 void AddSkippedResult(TestResults& results, const std::string& name,
582 const std::string& reason) {
583 TestResult result;
584 result.name = name;
585 result.suite_name = GetName();
586 result.category = GetCategory();
588 result.error_message = reason;
589 result.duration = std::chrono::milliseconds{0};
590 result.timestamp = std::chrono::steady_clock::now();
591 results.AddResult(result);
592 }
593
594 // Configuration flags
596 bool test_event_bus_ = true;
597 bool test_core_events_ = true;
598};
599
600} // namespace test
601} // namespace yaze
602
603#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 window content 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< WindowContent * > GetAll()
Get all registered panels.
WindowScope
Defines whether a window 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)