Add Native File Dialog support and enhance file dialog management

- Introduced a feature flag to toggle between Native File Dialog (NFD) and bespoke file dialog implementations.
- Updated FileDialogWrapper to utilize the feature flag for opening files and folders, improving cross-platform compatibility.
- Enhanced the UI to allow users to configure the file dialog mode, providing better user control over file handling.
- Added new methods for testing both NFD and bespoke implementations directly from the UI, improving testing capabilities.
- Updated test management to include options for enabling/disabling individual tests, enhancing flexibility in test execution.
This commit is contained in:
scawful
2025-09-25 17:07:44 -04:00
parent a5ed2f4d27
commit aaa7af9f07
7 changed files with 413 additions and 18 deletions

View File

@@ -56,13 +56,44 @@ class RomDependentTestSuite : public TestSuite {
return absl::OkStatus();
}
// Run ROM-dependent tests
RunRomHeaderValidationTest(results, current_rom);
RunRomDataAccessTest(results, current_rom);
RunRomGraphicsExtractionTest(results, current_rom);
RunRomOverworldLoadingTest(results, current_rom);
RunTile16EditorTest(results, current_rom);
RunComprehensiveSaveTest(results, current_rom);
// Run ROM-dependent tests (only if enabled)
auto& test_manager = TestManager::Get();
if (test_manager.IsTestEnabled("ROM_Header_Validation_Test")) {
RunRomHeaderValidationTest(results, current_rom);
} else {
AddSkippedTest(results, "ROM_Header_Validation_Test", "Test disabled by user");
}
if (test_manager.IsTestEnabled("ROM_Data_Access_Test")) {
RunRomDataAccessTest(results, current_rom);
} else {
AddSkippedTest(results, "ROM_Data_Access_Test", "Test disabled by user");
}
if (test_manager.IsTestEnabled("ROM_Graphics_Extraction_Test")) {
RunRomGraphicsExtractionTest(results, current_rom);
} else {
AddSkippedTest(results, "ROM_Graphics_Extraction_Test", "Test disabled by user");
}
if (test_manager.IsTestEnabled("ROM_Overworld_Loading_Test")) {
RunRomOverworldLoadingTest(results, current_rom);
} else {
AddSkippedTest(results, "ROM_Overworld_Loading_Test", "Test disabled by user");
}
if (test_manager.IsTestEnabled("Tile16_Editor_Test")) {
RunTile16EditorTest(results, current_rom);
} else {
AddSkippedTest(results, "Tile16_Editor_Test", "Test disabled by user");
}
if (test_manager.IsTestEnabled("Comprehensive_Save_Test")) {
RunComprehensiveSaveTest(results, current_rom);
} else {
AddSkippedTest(results, "Comprehensive_Save_Test", "Test disabled by user (known to crash)");
}
if (test_advanced_features_) {
RunRomSpriteDataTest(results, current_rom);
@@ -102,8 +133,21 @@ class RomDependentTestSuite : public TestSuite {
ImGui::Unindent();
}
}
private:
// Helper method to add skipped test results
void AddSkippedTest(TestResults& results, const std::string& test_name, const std::string& reason) {
TestResult result;
result.name = test_name;
result.suite_name = GetName();
result.category = GetCategory();
result.status = TestStatus::kSkipped;
result.error_message = reason;
result.duration = std::chrono::milliseconds{0};
result.timestamp = std::chrono::steady_clock::now();
results.AddResult(result);
}
void RunRomHeaderValidationTest(TestResults& results, Rom* rom) {
auto start_time = std::chrono::steady_clock::now();

View File

@@ -2,6 +2,8 @@
#include "absl/strings/str_format.h"
#include "absl/strings/str_cat.h"
#include "app/core/features.h"
#include "app/core/platform/file_dialog.h"
#include "app/gfx/arena.h"
#include "app/gui/icons.h"
#include "imgui/imgui.h"
@@ -443,8 +445,14 @@ void TestManager::DrawTestDashboard() {
}
if (ImGui::BeginMenu("Configure")) {
if (ImGui::MenuItem("Test Settings")) {
// Show configuration for all test suites
if (ImGui::MenuItem("Test Configuration")) {
show_test_configuration_ = true;
}
ImGui::Separator();
bool nfd_mode = core::FeatureFlags::get().kUseNativeFileDialog;
if (ImGui::MenuItem("Use NFD File Dialog", nullptr, &nfd_mode)) {
core::FeatureFlags::get().kUseNativeFileDialog = nfd_mode;
util::logf("Global file dialog mode changed to: %s", nfd_mode ? "NFD" : "Bespoke");
}
ImGui::EndMenu();
}
@@ -452,6 +460,29 @@ void TestManager::DrawTestDashboard() {
ImGui::EndMenuBar();
}
// Show test configuration status
int enabled_count = 0;
int total_count = 0;
static const std::vector<std::string> all_test_names = {
"ROM_Header_Validation_Test", "ROM_Data_Access_Test", "ROM_Graphics_Extraction_Test",
"ROM_Overworld_Loading_Test", "Tile16_Editor_Test", "Comprehensive_Save_Test",
"ROM_Sprite_Data_Test", "ROM_Music_Data_Test"
};
for (const auto& test_name : all_test_names) {
total_count++;
if (IsTestEnabled(test_name)) {
enabled_count++;
}
}
ImGui::Text("%s Test Status: %d/%d enabled", ICON_MD_CHECKLIST, enabled_count, total_count);
if (enabled_count < total_count) {
ImGui::SameLine();
ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f),
"(Some tests disabled - check Configuration)");
}
// Enhanced test execution status
if (is_running_) {
ImGui::PushStyleColor(ImGuiCol_Text, GetTestStatusColor(TestStatus::kRunning));
@@ -497,6 +528,11 @@ void TestManager::DrawTestDashboard() {
if (ImGui::Button(absl::StrCat(ICON_MD_CLEAR, " Clear").c_str(), ImVec2(80, 0))) {
ClearResults();
}
ImGui::SameLine();
if (ImGui::Button(absl::StrCat(ICON_MD_SETTINGS, " Config").c_str(), ImVec2(80, 0))) {
show_test_configuration_ = true;
}
}
ImGui::Separator();
@@ -799,6 +835,210 @@ void TestManager::DrawTestDashboard() {
ImGui::End();
}
// Test Configuration Window
if (show_test_configuration_) {
ImGui::SetNextWindowSize(ImVec2(600, 500), ImGuiCond_FirstUseEver);
if (ImGui::Begin("Test Configuration", &show_test_configuration_)) {
ImGui::Text("%s Test Configuration", ICON_MD_SETTINGS);
ImGui::Separator();
// File Dialog Configuration
if (ImGui::CollapsingHeader("File Dialog Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Text("File Dialog Implementation:");
bool nfd_mode = core::FeatureFlags::get().kUseNativeFileDialog;
if (ImGui::RadioButton("NFD (Native File Dialog)", nfd_mode)) {
core::FeatureFlags::get().kUseNativeFileDialog = true;
util::logf("Global file dialog mode set to: NFD");
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Use NFD library for native OS file dialogs (global setting)");
}
if (ImGui::RadioButton("Bespoke Implementation", !nfd_mode)) {
core::FeatureFlags::get().kUseNativeFileDialog = false;
util::logf("Global file dialog mode set to: Bespoke");
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Use custom file dialog implementation (global setting)");
}
ImGui::Separator();
ImGui::Text("Current Mode: %s", core::FeatureFlags::get().kUseNativeFileDialog ? "NFD" : "Bespoke");
ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Note: This setting affects ALL file dialogs in the application");
if (ImGui::Button("Test Current File Dialog")) {
// Test the current file dialog implementation
util::logf("Testing global file dialog mode: %s",
core::FeatureFlags::get().kUseNativeFileDialog ? "NFD" : "Bespoke");
// Actually test the file dialog
auto result = core::FileDialogWrapper::ShowOpenFileDialog();
if (!result.empty()) {
util::logf("File dialog test successful: %s", result.c_str());
} else {
util::logf("File dialog test: No file selected or dialog canceled");
}
}
ImGui::SameLine();
if (ImGui::Button("Test NFD Directly")) {
auto result = core::FileDialogWrapper::ShowOpenFileDialogNFD();
if (!result.empty()) {
util::logf("NFD test successful: %s", result.c_str());
} else {
util::logf("NFD test: No file selected, canceled, or error occurred");
}
}
ImGui::SameLine();
if (ImGui::Button("Test Bespoke Directly")) {
auto result = core::FileDialogWrapper::ShowOpenFileDialogBespoke();
if (!result.empty()) {
util::logf("Bespoke test successful: %s", result.c_str());
} else {
util::logf("Bespoke test: No file selected or not implemented");
}
}
}
// Test Selection Configuration
if (ImGui::CollapsingHeader("Test Selection", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Text("Enable/Disable Individual Tests:");
ImGui::Separator();
// List of known tests with their risk levels
static const std::vector<std::pair<std::string, std::string>> known_tests = {
{"ROM_Header_Validation_Test", "Safe - Read-only ROM header validation"},
{"ROM_Data_Access_Test", "Safe - Basic ROM data access testing"},
{"ROM_Graphics_Extraction_Test", "Safe - Graphics data extraction testing"},
{"ROM_Overworld_Loading_Test", "Safe - Overworld data loading testing"},
{"Tile16_Editor_Test", "Moderate - Tile16 editor initialization"},
{"Comprehensive_Save_Test", "DANGEROUS - Known to crash, uses ROM copies"},
{"ROM_Sprite_Data_Test", "Safe - Sprite data validation"},
{"ROM_Music_Data_Test", "Safe - Music data validation"}
};
// Initialize problematic tests as disabled by default
static bool initialized_defaults = false;
if (!initialized_defaults) {
DisableTest("Comprehensive_Save_Test"); // Disable crash-prone test by default
initialized_defaults = true;
}
if (ImGui::BeginTable("TestSelection", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("Test Name", ImGuiTableColumnFlags_WidthFixed, 200);
ImGui::TableSetupColumn("Risk Level", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Status", ImGuiTableColumnFlags_WidthFixed, 80);
ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_WidthFixed, 100);
ImGui::TableHeadersRow();
for (const auto& [test_name, description] : known_tests) {
bool enabled = IsTestEnabled(test_name);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", test_name.c_str());
ImGui::TableNextColumn();
// Color-code the risk level
if (description.find("DANGEROUS") != std::string::npos) {
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "%s", description.c_str());
} else if (description.find("Moderate") != std::string::npos) {
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.0f, 1.0f), "%s", description.c_str());
} else {
ImGui::TextColored(ImVec4(0.0f, 0.8f, 0.0f, 1.0f), "%s", description.c_str());
}
ImGui::TableNextColumn();
if (enabled) {
ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "%s ON", ICON_MD_CHECK);
} else {
ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f), "%s OFF", ICON_MD_BLOCK);
}
ImGui::TableNextColumn();
ImGui::PushID(test_name.c_str());
if (enabled) {
if (ImGui::Button("Disable")) {
DisableTest(test_name);
util::logf("Disabled test: %s", test_name.c_str());
}
} else {
if (ImGui::Button("Enable")) {
EnableTest(test_name);
util::logf("Enabled test: %s", test_name.c_str());
}
}
ImGui::PopID();
}
ImGui::EndTable();
}
ImGui::Separator();
ImGui::Text("Quick Actions:");
if (ImGui::Button("Enable Safe Tests Only")) {
for (const auto& [test_name, description] : known_tests) {
if (description.find("Safe") != std::string::npos) {
EnableTest(test_name);
} else {
DisableTest(test_name);
}
}
util::logf("Enabled only safe tests");
}
ImGui::SameLine();
if (ImGui::Button("Enable All Tests")) {
for (const auto& [test_name, description] : known_tests) {
EnableTest(test_name);
}
util::logf("Enabled all tests (including dangerous ones)");
}
ImGui::SameLine();
if (ImGui::Button("Disable All Tests")) {
for (const auto& [test_name, description] : known_tests) {
DisableTest(test_name);
}
util::logf("Disabled all tests");
}
ImGui::Separator();
ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.0f, 1.0f),
"⚠️ Recommendation: Use 'Enable Safe Tests Only' to avoid crashes");
}
// Platform-specific settings
if (ImGui::CollapsingHeader("Platform Settings")) {
ImGui::Text("macOS Tahoe Compatibility:");
ImGui::BulletText("NFD may have issues on macOS Sequoia+");
ImGui::BulletText("Bespoke dialog provides fallback option");
ImGui::BulletText("Global setting affects File → Open, Project dialogs, etc.");
ImGui::Separator();
ImGui::Text("Test Both Implementations:");
if (ImGui::Button("Quick Test NFD")) {
auto result = core::FileDialogWrapper::ShowOpenFileDialogNFD();
util::logf("NFD test result: %s", result.empty() ? "Failed/Canceled" : result.c_str());
}
ImGui::SameLine();
if (ImGui::Button("Quick Test Bespoke")) {
auto result = core::FileDialogWrapper::ShowOpenFileDialogBespoke();
util::logf("Bespoke test result: %s", result.empty() ? "Failed/Not Implemented" : result.c_str());
}
ImGui::Separator();
ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
"Note: These tests don't change the global setting");
}
}
ImGui::End();
}
// Test Session Creation Dialog
if (show_test_session_dialog_) {
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));

View File

@@ -192,6 +192,15 @@ class TestManager {
absl::Status TestRomSaveLoad(Rom* rom);
absl::Status TestRomDataIntegrity(Rom* rom);
absl::Status TestRomWithCopy(Rom* source_rom, std::function<absl::Status(Rom*)> test_function);
// Test configuration management
void DisableTest(const std::string& test_name) { disabled_tests_[test_name] = true; }
void EnableTest(const std::string& test_name) { disabled_tests_[test_name] = false; }
bool IsTestEnabled(const std::string& test_name) const {
auto it = disabled_tests_.find(test_name);
return it == disabled_tests_.end() || !it->second;
}
// File dialog mode now uses global feature flags
private:
TestManager();
@@ -242,7 +251,11 @@ class TestManager {
bool show_rom_test_results_ = false;
bool show_rom_file_dialog_ = false;
bool show_test_session_dialog_ = false;
bool show_test_configuration_ = false;
std::string test_rom_path_for_session_;
// Test selection and configuration
std::unordered_map<std::string, bool> disabled_tests_;
};
// Utility functions for test result formatting