Integrate ROM-dependent testing framework into YAZE

- Added a new RomDependentTestSuite to facilitate testing functionalities that rely on the currently loaded ROM, enhancing test coverage.
- Updated EditorManager to register the new test suite and manage the current ROM for dependent tests.
- Enhanced the IntegratedTestSuite to first check for a loaded ROM before proceeding with tests, improving robustness.
- Improved the TestManager UI to indicate ROM loading status and provide feedback for running ROM-dependent tests.
- Updated CMake configuration to include the new test suite header, ensuring proper integration into the build system.
This commit is contained in:
scawful
2025-09-25 13:44:03 -04:00
parent 8ab30dd5ad
commit c943577aff
6 changed files with 494 additions and 95 deletions

View File

@@ -151,32 +151,41 @@ class IntegratedTestSuite : public TestSuite {
result.error_message = "ROM testing disabled in configuration";
} else {
try {
// Test ROM class instantiation
Rom test_rom;
// First try to use currently loaded ROM from editor
Rom* current_rom = TestManager::Get().GetCurrentRom();
// Test with actual ROM file if available
std::string rom_path = test_rom_path_;
if (rom_path.empty()) {
rom_path = "zelda3.sfc";
}
if (std::filesystem::exists(rom_path)) {
auto status = test_rom.LoadFromFile(rom_path);
if (status.ok()) {
result.status = TestStatus::kPassed;
result.error_message = absl::StrFormat(
"ROM loaded successfully: %s (%zu bytes)",
test_rom.title().c_str(), test_rom.size());
if (current_rom && current_rom->is_loaded()) {
// Test with currently loaded ROM
result.status = TestStatus::kPassed;
result.error_message = absl::StrFormat(
"Current ROM validated: %s (%zu bytes)",
current_rom->title().c_str(), current_rom->size());
} else {
// Fallback to loading ROM file
Rom test_rom;
std::string rom_path = test_rom_path_;
if (rom_path.empty()) {
rom_path = "zelda3.sfc";
}
if (std::filesystem::exists(rom_path)) {
auto status = test_rom.LoadFromFile(rom_path);
if (status.ok()) {
result.status = TestStatus::kPassed;
result.error_message = absl::StrFormat(
"ROM loaded from file: %s (%zu bytes)",
test_rom.title().c_str(), test_rom.size());
} else {
result.status = TestStatus::kFailed;
result.error_message = "ROM loading failed: " + std::string(status.message());
}
} else if (skip_missing_rom_) {
result.status = TestStatus::kSkipped;
result.error_message = "No current ROM and file not found: " + rom_path;
} else {
result.status = TestStatus::kFailed;
result.error_message = "ROM loading failed: " + std::string(status.message());
result.error_message = "No current ROM and required file not found: " + rom_path;
}
} else if (skip_missing_rom_) {
result.status = TestStatus::kSkipped;
result.error_message = "ROM file not found: " + rom_path;
} else {
result.status = TestStatus::kFailed;
result.error_message = "Required ROM file not found: " + rom_path;
}
} catch (const std::exception& e) {

View File

@@ -0,0 +1,343 @@
#ifndef YAZE_APP_TEST_ROM_DEPENDENT_TEST_SUITE_H
#define YAZE_APP_TEST_ROM_DEPENDENT_TEST_SUITE_H
#include <chrono>
#include <memory>
#include <vector>
#include "absl/strings/str_format.h"
#include "app/test/test_manager.h"
#include "app/gfx/arena.h"
#include "app/rom.h"
#include "app/zelda3/overworld/overworld.h"
#include "app/gui/icons.h"
namespace yaze {
namespace test {
// ROM-dependent test suite that works with the currently loaded ROM
class RomDependentTestSuite : public TestSuite {
public:
RomDependentTestSuite() = default;
~RomDependentTestSuite() override = default;
std::string GetName() const override { return "ROM-Dependent Tests"; }
TestCategory GetCategory() const override { return TestCategory::kIntegration; }
absl::Status RunTests(TestResults& results) override {
Rom* current_rom = TestManager::Get().GetCurrentRom();
if (!current_rom || !current_rom->is_loaded()) {
// Add a skipped test indicating no ROM is loaded
TestResult result;
result.name = "ROM_Available_Check";
result.suite_name = GetName();
result.category = GetCategory();
result.status = TestStatus::kSkipped;
result.error_message = "No ROM currently loaded in editor";
result.duration = std::chrono::milliseconds{0};
result.timestamp = std::chrono::steady_clock::now();
results.AddResult(result);
return absl::OkStatus();
}
// Run ROM-dependent tests
RunRomHeaderValidationTest(results, current_rom);
RunRomDataAccessTest(results, current_rom);
RunRomGraphicsExtractionTest(results, current_rom);
RunRomOverworldLoadingTest(results, current_rom);
if (test_advanced_features_) {
RunRomSpriteDataTest(results, current_rom);
RunRomMusicDataTest(results, current_rom);
}
return absl::OkStatus();
}
void DrawConfiguration() override {
Rom* current_rom = TestManager::Get().GetCurrentRom();
ImGui::Text("%s ROM-Dependent Test Configuration", ICON_MD_STORAGE);
if (current_rom && current_rom->is_loaded()) {
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f),
"%s Current ROM: %s", ICON_MD_CHECK_CIRCLE, current_rom->title().c_str());
ImGui::Text("Size: %zu bytes", current_rom->size());
ImGui::Text("File: %s", current_rom->filename().c_str());
} else {
ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f),
"%s No ROM currently loaded", ICON_MD_WARNING);
ImGui::Text("Load a ROM in the editor to enable ROM-dependent tests");
}
ImGui::Separator();
ImGui::Checkbox("Test ROM header validation", &test_header_validation_);
ImGui::Checkbox("Test ROM data access", &test_data_access_);
ImGui::Checkbox("Test graphics extraction", &test_graphics_extraction_);
ImGui::Checkbox("Test overworld loading", &test_overworld_loading_);
ImGui::Checkbox("Test advanced features", &test_advanced_features_);
if (test_advanced_features_) {
ImGui::Indent();
ImGui::Checkbox("Test sprite data", &test_sprite_data_);
ImGui::Checkbox("Test music data", &test_music_data_);
ImGui::Unindent();
}
}
private:
void RunRomHeaderValidationTest(TestResults& results, Rom* rom) {
auto start_time = std::chrono::steady_clock::now();
TestResult result;
result.name = "ROM_Header_Validation_Test";
result.suite_name = GetName();
result.category = GetCategory();
result.timestamp = start_time;
if (!test_header_validation_) {
result.status = TestStatus::kSkipped;
result.error_message = "Header validation disabled in configuration";
} else {
try {
std::string title = rom->title();
size_t size = rom->size();
// Basic validation
bool valid_title = !title.empty() && title != "ZELDA3" && title.length() <= 21;
bool valid_size = size >= 1024*1024 && size <= 8*1024*1024; // 1MB to 8MB
if (valid_title && valid_size) {
result.status = TestStatus::kPassed;
result.error_message = absl::StrFormat(
"ROM header valid: '%s' (%zu bytes)", title.c_str(), size);
} else {
result.status = TestStatus::kFailed;
result.error_message = absl::StrFormat(
"ROM header validation failed: title='%s' size=%zu", title.c_str(), size);
}
} catch (const std::exception& e) {
result.status = TestStatus::kFailed;
result.error_message = "Header validation failed: " + std::string(e.what());
}
}
auto end_time = std::chrono::steady_clock::now();
result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end_time - start_time);
results.AddResult(result);
}
void RunRomDataAccessTest(TestResults& results, Rom* rom) {
auto start_time = std::chrono::steady_clock::now();
TestResult result;
result.name = "ROM_Data_Access_Test";
result.suite_name = GetName();
result.category = GetCategory();
result.timestamp = start_time;
if (!test_data_access_) {
result.status = TestStatus::kSkipped;
result.error_message = "Data access testing disabled in configuration";
} else {
try {
// Test basic ROM data access patterns
size_t bytes_tested = 0;
bool access_success = true;
// Test reading from various ROM regions
try {
[[maybe_unused]] auto header_byte = rom->ReadByte(0x7FC0);
bytes_tested++;
[[maybe_unused]] auto code_byte = rom->ReadByte(0x8000);
bytes_tested++;
[[maybe_unused]] auto data_word = rom->ReadWord(0x8002);
bytes_tested++;
} catch (...) {
access_success = false;
}
if (access_success && bytes_tested >= 3) {
result.status = TestStatus::kPassed;
result.error_message = absl::StrFormat(
"ROM data access verified: %zu operations", bytes_tested);
} else {
result.status = TestStatus::kFailed;
result.error_message = "ROM data access failed";
}
} catch (const std::exception& e) {
result.status = TestStatus::kFailed;
result.error_message = "Data access test failed: " + std::string(e.what());
}
}
auto end_time = std::chrono::steady_clock::now();
result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end_time - start_time);
results.AddResult(result);
}
void RunRomGraphicsExtractionTest(TestResults& results, Rom* rom) {
auto start_time = std::chrono::steady_clock::now();
TestResult result;
result.name = "ROM_Graphics_Extraction_Test";
result.suite_name = GetName();
result.category = GetCategory();
result.timestamp = start_time;
if (!test_graphics_extraction_) {
result.status = TestStatus::kSkipped;
result.error_message = "Graphics extraction testing disabled in configuration";
} else {
try {
auto graphics_result = LoadAllGraphicsData(*rom);
if (graphics_result.ok()) {
auto& sheets = graphics_result.value();
size_t loaded_sheets = 0;
for (const auto& sheet : sheets) {
if (sheet.is_active()) {
loaded_sheets++;
}
}
result.status = TestStatus::kPassed;
result.error_message = absl::StrFormat(
"Graphics extraction successful: %zu/%zu sheets loaded",
loaded_sheets, sheets.size());
} else {
result.status = TestStatus::kFailed;
result.error_message = "Graphics extraction failed: " +
std::string(graphics_result.status().message());
}
} catch (const std::exception& e) {
result.status = TestStatus::kFailed;
result.error_message = "Graphics extraction test failed: " + std::string(e.what());
}
}
auto end_time = std::chrono::steady_clock::now();
result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end_time - start_time);
results.AddResult(result);
}
void RunRomOverworldLoadingTest(TestResults& results, Rom* rom) {
auto start_time = std::chrono::steady_clock::now();
TestResult result;
result.name = "ROM_Overworld_Loading_Test";
result.suite_name = GetName();
result.category = GetCategory();
result.timestamp = start_time;
if (!test_overworld_loading_) {
result.status = TestStatus::kSkipped;
result.error_message = "Overworld loading testing disabled in configuration";
} else {
try {
zelda3::Overworld overworld(rom);
auto ow_status = overworld.Load(rom);
if (ow_status.ok()) {
result.status = TestStatus::kPassed;
result.error_message = "Overworld loading successful from current ROM";
} else {
result.status = TestStatus::kFailed;
result.error_message = "Overworld loading failed: " + std::string(ow_status.message());
}
} catch (const std::exception& e) {
result.status = TestStatus::kFailed;
result.error_message = "Overworld loading test failed: " + std::string(e.what());
}
}
auto end_time = std::chrono::steady_clock::now();
result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end_time - start_time);
results.AddResult(result);
}
void RunRomSpriteDataTest(TestResults& results, Rom* rom) {
auto start_time = std::chrono::steady_clock::now();
TestResult result;
result.name = "ROM_Sprite_Data_Test";
result.suite_name = GetName();
result.category = GetCategory();
result.timestamp = start_time;
if (!test_sprite_data_) {
result.status = TestStatus::kSkipped;
result.error_message = "Sprite data testing disabled in configuration";
} else {
try {
// Basic sprite data validation (simplified for now)
// In a full implementation, this would test sprite loading
result.status = TestStatus::kSkipped;
result.error_message = "Sprite data testing not yet implemented";
} catch (const std::exception& e) {
result.status = TestStatus::kFailed;
result.error_message = "Sprite data test failed: " + std::string(e.what());
}
}
auto end_time = std::chrono::steady_clock::now();
result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end_time - start_time);
results.AddResult(result);
}
void RunRomMusicDataTest(TestResults& results, Rom* rom) {
auto start_time = std::chrono::steady_clock::now();
TestResult result;
result.name = "ROM_Music_Data_Test";
result.suite_name = GetName();
result.category = GetCategory();
result.timestamp = start_time;
if (!test_music_data_) {
result.status = TestStatus::kSkipped;
result.error_message = "Music data testing disabled in configuration";
} else {
try {
// Basic music data validation (simplified for now)
// In a full implementation, this would test music loading
result.status = TestStatus::kSkipped;
result.error_message = "Music data testing not yet implemented";
} catch (const std::exception& e) {
result.status = TestStatus::kFailed;
result.error_message = "Music data test failed: " + std::string(e.what());
}
}
auto end_time = std::chrono::steady_clock::now();
result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
end_time - start_time);
results.AddResult(result);
}
// Configuration
bool test_header_validation_ = true;
bool test_data_access_ = true;
bool test_graphics_extraction_ = true;
bool test_overworld_loading_ = true;
bool test_advanced_features_ = false;
bool test_sprite_data_ = false;
bool test_music_data_ = false;
};
} // namespace test
} // namespace yaze
#endif // YAZE_APP_TEST_ROM_DEPENDENT_TEST_SUITE_H

View File

@@ -1,7 +1,9 @@
#include "app/test/test_manager.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_cat.h"
#include "app/gfx/arena.h"
#include "app/gui/icons.h"
#include "imgui/imgui.h"
#ifdef YAZE_ENABLE_IMGUI_TEST_ENGINE
@@ -274,6 +276,17 @@ void TestManager::DrawTestDashboard() {
ImGui::Begin("Test Dashboard", &show_dashboard_, ImGuiWindowFlags_MenuBar);
// ROM status indicator
bool has_rom = current_rom_ && current_rom_->is_loaded();
if (has_rom) {
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f),
"%s ROM Loaded: %s", ICON_MD_CHECK_CIRCLE, current_rom_->title().c_str());
} else {
ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f),
"%s No ROM loaded - ROM-dependent tests will be skipped", ICON_MD_WARNING);
}
ImGui::Separator();
// Menu bar
if (ImGui::BeginMenuBar()) {
if (ImGui::BeginMenu("Run")) {
@@ -321,25 +334,46 @@ void TestManager::DrawTestDashboard() {
// Enhanced test execution status
if (is_running_) {
ImGui::PushStyleColor(ImGuiCol_Text, GetTestStatusColor(TestStatus::kRunning));
ImGui::Text(" Running: %s", current_test_name_.c_str());
ImGui::Text("%s Running: %s", ICON_MD_PLAY_CIRCLE_FILLED, current_test_name_.c_str());
ImGui::PopStyleColor();
ImGui::ProgressBar(progress_, ImVec2(-1, 0),
absl::StrFormat("%.0f%%", progress_ * 100.0f).c_str());
} else {
// Enhanced control buttons
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.7f, 0.2f, 1.0f));
if (ImGui::Button("🚀 Run All Tests", ImVec2(140, 0))) {
if (ImGui::Button(absl::StrCat(ICON_MD_PLAY_ARROW, " Run All Tests").c_str(), ImVec2(140, 0))) {
[[maybe_unused]] auto status = RunAllTests();
}
ImGui::PopStyleColor();
ImGui::SameLine();
if (ImGui::Button("🧪 Quick Test", ImVec2(100, 0))) {
if (ImGui::Button(absl::StrCat(ICON_MD_SPEED, " Quick Test").c_str(), ImVec2(100, 0))) {
[[maybe_unused]] auto status = RunTestsByCategory(TestCategory::kMemory);
}
ImGui::SameLine();
if (ImGui::Button("🗑️ Clear", ImVec2(80, 0))) {
bool has_rom = current_rom_ && current_rom_->is_loaded();
if (has_rom) {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.5f, 0.8f, 1.0f));
}
if (ImGui::Button(absl::StrCat(ICON_MD_STORAGE, " ROM Tests").c_str(), ImVec2(100, 0))) {
if (has_rom) {
[[maybe_unused]] auto status = RunTestsByCategory(TestCategory::kIntegration);
}
}
if (has_rom) {
ImGui::PopStyleColor();
}
if (ImGui::IsItemHovered()) {
if (has_rom) {
ImGui::SetTooltip("Run tests on current ROM: %s", current_rom_->title().c_str());
} else {
ImGui::SetTooltip("Load a ROM to enable ROM-dependent tests");
}
}
ImGui::SameLine();
if (ImGui::Button(absl::StrCat(ICON_MD_CLEAR, " Clear").c_str(), ImVec2(80, 0))) {
ClearResults();
}
}
@@ -349,7 +383,7 @@ void TestManager::DrawTestDashboard() {
// Enhanced test results summary with better visuals
if (last_results_.total_tests > 0) {
// Test summary header
ImGui::Text("📊 Test Results Summary");
ImGui::Text("%s Test Results Summary", ICON_MD_ASSESSMENT);
// Progress bar showing pass rate
float pass_rate = last_results_.GetPassRate();
@@ -363,18 +397,18 @@ void TestManager::DrawTestDashboard() {
ImGui::PopStyleColor();
// Test counts with icons
ImGui::Text("📈 Total: %zu", last_results_.total_tests);
ImGui::Text("%s Total: %zu", ICON_MD_ANALYTICS, last_results_.total_tests);
ImGui::SameLine();
ImGui::TextColored(GetTestStatusColor(TestStatus::kPassed),
" %zu", last_results_.passed_tests);
"%s %zu", ICON_MD_CHECK_CIRCLE, last_results_.passed_tests);
ImGui::SameLine();
ImGui::TextColored(GetTestStatusColor(TestStatus::kFailed),
" %zu", last_results_.failed_tests);
"%s %zu", ICON_MD_ERROR, last_results_.failed_tests);
ImGui::SameLine();
ImGui::TextColored(GetTestStatusColor(TestStatus::kSkipped),
"⏭️ %zu", last_results_.skipped_tests);
"%s %zu", ICON_MD_SKIP_NEXT, last_results_.skipped_tests);
ImGui::Text("⏱️ Duration: %lld ms", last_results_.total_duration.count());
ImGui::Text("%s Duration: %lld ms", ICON_MD_TIMER, last_results_.total_duration.count());
// Test suite breakdown
if (ImGui::CollapsingHeader("Test Suite Breakdown")) {
@@ -399,7 +433,7 @@ void TestManager::DrawTestDashboard() {
ImGui::Separator();
// Enhanced test filter with category selection
ImGui::Text("🔍 Filter & View Options");
ImGui::Text("%s Filter & View Options", ICON_MD_FILTER_LIST);
// Category filter
const char* categories[] = {"All", "Unit", "Integration", "UI", "Performance", "Memory"};
@@ -449,12 +483,12 @@ void TestManager::DrawTestDashboard() {
ImGui::PushID(&result);
// Status icon and test name
const char* status_icon = "";
const char* status_icon = ICON_MD_HELP;
switch (result.status) {
case TestStatus::kPassed: status_icon = ""; break;
case TestStatus::kFailed: status_icon = ""; break;
case TestStatus::kSkipped: status_icon = "⏭️"; break;
case TestStatus::kRunning: status_icon = ""; break;
case TestStatus::kPassed: status_icon = ICON_MD_CHECK_CIRCLE; break;
case TestStatus::kFailed: status_icon = ICON_MD_ERROR; break;
case TestStatus::kSkipped: status_icon = ICON_MD_SKIP_NEXT; break;
case TestStatus::kRunning: status_icon = ICON_MD_PLAY_CIRCLE_FILLED; break;
default: break;
}
@@ -475,7 +509,7 @@ void TestManager::DrawTestDashboard() {
if (result.status == TestStatus::kFailed && !result.error_message.empty()) {
ImGui::Indent();
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.8f, 1.0f));
ImGui::TextWrapped("💥 %s", result.error_message.c_str());
ImGui::TextWrapped("%s %s", ICON_MD_ERROR_OUTLINE, result.error_message.c_str());
ImGui::PopStyleColor();
ImGui::Unindent();
}
@@ -484,7 +518,7 @@ void TestManager::DrawTestDashboard() {
if (result.status == TestStatus::kPassed && !result.error_message.empty()) {
ImGui::Indent();
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 1.0f, 0.8f, 1.0f));
ImGui::TextWrapped(" %s", result.error_message.c_str());
ImGui::TextWrapped("%s %s", ICON_MD_INFO, result.error_message.c_str());
ImGui::PopStyleColor();
ImGui::Unindent();
}
@@ -499,14 +533,14 @@ void TestManager::DrawTestDashboard() {
// Resource monitor window
if (show_resource_monitor_) {
ImGui::Begin("Resource Monitor", &show_resource_monitor_);
ImGui::Begin(absl::StrCat(ICON_MD_MONITOR, " Resource Monitor").c_str(), &show_resource_monitor_);
if (!resource_history_.empty()) {
const auto& latest = resource_history_.back();
ImGui::Text("Textures: %zu", latest.texture_count);
ImGui::Text("Surfaces: %zu", latest.surface_count);
ImGui::Text("Memory: %zu MB", latest.memory_usage_mb);
ImGui::Text("FPS: %.1f", latest.frame_rate);
ImGui::Text("%s Textures: %zu", ICON_MD_TEXTURE, latest.texture_count);
ImGui::Text("%s Surfaces: %zu", ICON_MD_LAYERS, latest.surface_count);
ImGui::Text("%s Memory: %zu MB", ICON_MD_MEMORY, latest.memory_usage_mb);
ImGui::Text("%s FPS: %.1f", ICON_MD_SPEED, latest.frame_rate);
// Simple plot of resource usage over time
if (resource_history_.size() > 1) {

View File

@@ -1,13 +1,14 @@
#ifndef YAZE_APP_TEST_TEST_MANAGER_H
#define YAZE_APP_TEST_TEST_MANAGER_H
#include <chrono>
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
#include <chrono>
#include <vector>
#include "absl/status/status.h"
#include "app/rom.h"
#include "imgui/imgui.h"
#ifdef YAZE_ENABLE_IMGUI_TEST_ENGINE
@@ -21,22 +22,10 @@ namespace yaze {
namespace test {
// Test execution status
enum class TestStatus {
kNotRun,
kRunning,
kPassed,
kFailed,
kSkipped
};
enum class TestStatus { kNotRun, kRunning, kPassed, kFailed, kSkipped };
// Test categories for organization
enum class TestCategory {
kUnit,
kIntegration,
kUI,
kPerformance,
kMemory
};
enum class TestCategory { kUnit, kIntegration, kUI, kPerformance, kMemory };
// Individual test result
struct TestResult {
@@ -57,27 +46,35 @@ struct TestResults {
size_t failed_tests = 0;
size_t skipped_tests = 0;
std::chrono::milliseconds total_duration{0};
void AddResult(const TestResult& result) {
individual_results.push_back(result);
total_tests++;
switch (result.status) {
case TestStatus::kPassed: passed_tests++; break;
case TestStatus::kFailed: failed_tests++; break;
case TestStatus::kSkipped: skipped_tests++; break;
default: break;
case TestStatus::kPassed:
passed_tests++;
break;
case TestStatus::kFailed:
failed_tests++;
break;
case TestStatus::kSkipped:
skipped_tests++;
break;
default:
break;
}
total_duration += result.duration;
}
void Clear() {
individual_results.clear();
total_tests = passed_tests = failed_tests = skipped_tests = 0;
total_duration = std::chrono::milliseconds{0};
}
float GetPassRate() const {
return total_tests > 0 ? static_cast<float>(passed_tests) / total_tests : 0.0f;
return total_tests > 0 ? static_cast<float>(passed_tests) / total_tests
: 0.0f;
}
};
@@ -91,7 +88,7 @@ class TestSuite {
virtual void DrawConfiguration() {}
virtual bool IsEnabled() const { return enabled_; }
virtual void SetEnabled(bool enabled) { enabled_ = enabled; }
protected:
bool enabled_ = true;
};
@@ -109,41 +106,40 @@ struct ResourceStats {
class TestManager {
public:
static TestManager& Get();
// Core test execution
absl::Status RunAllTests();
absl::Status RunTestsByCategory(TestCategory category);
absl::Status RunTestSuite(const std::string& suite_name);
// Test suite management
void RegisterTestSuite(std::unique_ptr<TestSuite> suite);
std::vector<std::string> GetTestSuiteNames() const;
TestSuite* GetTestSuite(const std::string& name);
// Results access
const TestResults& GetLastResults() const { return last_results_; }
void ClearResults() { last_results_.Clear(); }
// Configuration
void SetMaxConcurrentTests(size_t max_concurrent) {
max_concurrent_tests_ = max_concurrent;
void SetMaxConcurrentTests(size_t max_concurrent) {
max_concurrent_tests_ = max_concurrent;
}
void SetTestTimeout(std::chrono::seconds timeout) {
test_timeout_ = timeout;
}
void SetTestTimeout(std::chrono::seconds timeout) { test_timeout_ = timeout; }
// Resource monitoring
void UpdateResourceStats();
const std::vector<ResourceStats>& GetResourceHistory() const {
return resource_history_;
const std::vector<ResourceStats>& GetResourceHistory() const {
return resource_history_;
}
// UI Testing (ImGui Test Engine integration)
#ifdef YAZE_ENABLE_IMGUI_TEST_ENGINE
ImGuiTestEngine* GetUITestEngine() { return ui_test_engine_; }
void InitializeUITesting();
void StopUITesting(); // Stop test engine while ImGui context is valid
void DestroyUITestingContext(); // Destroy test engine after ImGui context is destroyed
void DestroyUITestingContext(); // Destroy test engine after ImGui context is
// destroyed
void ShutdownUITesting(); // Complete shutdown (calls both Stop and Destroy)
#else
void* GetUITestEngine() { return nullptr; }
@@ -152,54 +148,61 @@ class TestManager {
void DestroyUITestingContext() {}
void ShutdownUITesting() {}
#endif
// Status queries
bool IsTestRunning() const { return is_running_; }
const std::string& GetCurrentTestName() const { return current_test_name_; }
float GetProgress() const { return progress_; }
// UI Interface
void DrawTestDashboard();
// ROM-dependent testing
void SetCurrentRom(Rom* rom) { current_rom_ = rom; }
Rom* GetCurrentRom() const { return current_rom_; }
private:
TestManager();
~TestManager();
// Test execution helpers
absl::Status ExecuteTestSuite(TestSuite* suite);
void UpdateProgress();
// Resource monitoring helpers
void CollectResourceStats();
void TrimResourceHistory();
// Member variables
std::vector<std::unique_ptr<TestSuite>> test_suites_;
std::unordered_map<std::string, TestSuite*> suite_lookup_;
TestResults last_results_;
bool is_running_ = false;
std::string current_test_name_;
float progress_ = 0.0f;
// Configuration
size_t max_concurrent_tests_ = 1;
std::chrono::seconds test_timeout_{30};
// Resource monitoring
std::vector<ResourceStats> resource_history_;
static constexpr size_t kMaxResourceHistorySize = 1000;
// UI Testing
#ifdef YAZE_ENABLE_IMGUI_TEST_ENGINE
ImGuiTestEngine* ui_test_engine_ = nullptr;
#endif
// UI State
bool show_dashboard_ = false;
bool show_resource_monitor_ = false;
std::string test_filter_;
TestCategory category_filter_ = TestCategory::kUnit;
// ROM-dependent testing
Rom* current_rom_ = nullptr;
};
// Utility functions for test result formatting