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:
@@ -26,5 +26,6 @@ set(
|
||||
app/editor/system/popup_manager.cc
|
||||
app/test/test_manager.cc
|
||||
app/test/integrated_test_suite.h
|
||||
app/test/rom_dependent_test_suite.h
|
||||
app/test/unit_test_suite.h
|
||||
)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "app/rom.h"
|
||||
#include "app/test/test_manager.h"
|
||||
#include "app/test/integrated_test_suite.h"
|
||||
#include "app/test/rom_dependent_test_suite.h"
|
||||
#ifdef YAZE_ENABLE_GTEST
|
||||
#include "app/test/unit_test_suite.h"
|
||||
#endif
|
||||
@@ -118,6 +119,7 @@ void EditorManager::InitializeTestSuites() {
|
||||
test_manager.RegisterTestSuite(std::make_unique<test::PerformanceTestSuite>());
|
||||
test_manager.RegisterTestSuite(std::make_unique<test::UITestSuite>());
|
||||
test_manager.RegisterTestSuite(std::make_unique<test::ArenaTestSuite>());
|
||||
test_manager.RegisterTestSuite(std::make_unique<test::RomDependentTestSuite>());
|
||||
|
||||
// Register Google Test suite if available
|
||||
#ifdef YAZE_ENABLE_GTEST
|
||||
@@ -833,6 +835,9 @@ absl::Status EditorManager::LoadRom() {
|
||||
}
|
||||
current_rom_ = &session.rom;
|
||||
current_editor_set_ = &session.editors;
|
||||
|
||||
// Update test manager with current ROM for ROM-dependent tests
|
||||
test::TestManager::Get().SetCurrentRom(current_rom_);
|
||||
|
||||
static RecentFilesManager manager("recent_files.txt");
|
||||
manager.Load();
|
||||
@@ -956,6 +961,10 @@ absl::Status EditorManager::SetCurrentRom(Rom *rom) {
|
||||
if (&session.rom == rom) {
|
||||
current_rom_ = &session.rom;
|
||||
current_editor_set_ = &session.editors;
|
||||
|
||||
// Update test manager with current ROM for ROM-dependent tests
|
||||
test::TestManager::Get().SetCurrentRom(current_rom_);
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
343
src/app/test/rom_dependent_test_suite.h
Normal file
343
src/app/test/rom_dependent_test_suite.h
Normal 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
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user