Files
yaze/docs/z3ed/archive/FILE_MODIFICATION_CHECKLIST.md
scawful 286efdec6a Enhance ImGuiTestHarness with dynamic test integration and end-to-end validation
- Updated README.md to reflect the completion of IT-01 and the transition to end-to-end validation phase.
- Introduced a new end-to-end test script (scripts/test_harness_e2e.sh) for validating all RPC methods of the ImGuiTestHarness gRPC service.
- Implemented dynamic test functionality in ImGuiTestHarnessService for Type, Wait, and Assert methods, utilizing ImGuiTestEngine.
- Enhanced error handling and response messages for better clarity during test execution.
- Updated existing methods to support dynamic test registration and execution, ensuring robust interaction with the GUI elements.
2025-10-02 00:49:28 -04:00

8.1 KiB

IT-01 Phase 2: File Modification Checklist

Quick Reference: Exactly which files to edit and what to change

Files to Modify (4 files)

1. src/app/core/imgui_test_harness_service.h

What to change: Add TestManager member to service class

Line ~20-30 (in ImGuiTestHarnessServiceImpl class):

class ImGuiTestHarnessServiceImpl {
 public:
  // ADD THIS LINE:
  explicit ImGuiTestHarnessServiceImpl(TestManager* test_manager)
      : test_manager_(test_manager) {}

  absl::Status Ping(const PingRequest* request, PingResponse* response);
  absl::Status Click(const ClickRequest* request, ClickResponse* response);
  absl::Status Type(const TypeRequest* request, TypeResponse* response);
  absl::Status Wait(const WaitRequest* request, WaitResponse* response);
  absl::Status Assert(const AssertRequest* request, AssertResponse* response);
  absl::Status Screenshot(const ScreenshotRequest* request,
                         ScreenshotResponse* response);

 private:
  TestManager* test_manager_;  // ADD THIS LINE
};

Line ~50 (in ImGuiTestHarnessServer class):

class ImGuiTestHarnessServer {
 public:
  static ImGuiTestHarnessServer& Instance();

  // CHANGE THIS LINE - add second parameter:
  absl::Status Start(int port, TestManager* test_manager);
  
  // ... rest stays the same
};

2. src/app/core/imgui_test_harness_service.cc

What to change: Add includes and implement Click handler

Top of file (after existing includes, around line 10):

// ADD THESE INCLUDES:
#include "app/test/test_manager.h"
#include "imgui_test_engine/imgui_te_engine.h"
#include "imgui_test_engine/imgui_te_context.h"

In Start() method (around line 100):

absl::Status ImGuiTestHarnessServer::Start(int port, TestManager* test_manager) {
  if (server_) {
    return absl::FailedPreconditionError("Server already running");
  }

  // ADD THESE LINES:
  if (!test_manager) {
    return absl::InvalidArgumentError("TestManager cannot be null");
  }

  // CHANGE THIS LINE to pass test_manager:
  service_ = std::make_unique<ImGuiTestHarnessServiceImpl>(test_manager);

  // ... rest of method stays the same

In Click() method (around line 130):

Replace the entire stub implementation with the code from IT-01-PHASE2-IMPLEMENTATION-GUIDE.md (Step 2.2).

Quick version (see full guide for complete code):

absl::Status ImGuiTestHarnessServiceImpl::Click(
    const ClickRequest* request,
    ClickResponse* response) {
  
  auto start = std::chrono::steady_clock::now();

  // Get TestEngine
  ImGuiTestEngine* engine = test_manager_->GetUITestEngine();
  if (!engine) {
    response->set_success(false);
    response->set_message("ImGuiTestEngine not initialized");
    return absl::OkStatus();
  }

  // Parse target: "button:Open ROM"
  std::string target = request->target();
  size_t colon_pos = target.find(':');
  if (colon_pos == std::string::npos) {
    response->set_success(false);
    response->set_message("Invalid target format. Use 'type:label'");
    return absl::OkStatus();
  }

  std::string widget_label = target.substr(colon_pos + 1);

  // Create test context
  std::string context_name = absl::StrFormat("grpc_click_%lld", 
      std::chrono::system_clock::now().time_since_epoch().count());
  ImGuiTestContext* ctx = ImGuiTestEngine_CreateContext(engine, context_name.c_str());

  if (!ctx) {
    response->set_success(false);
    response->set_message("Failed to create test context");
    return absl::OkStatus();
  }

  // Find widget
  ImGuiTestItemInfo* item = ImGuiTestEngine_FindItemByLabel(
      ctx, widget_label.c_str(), NULL);

  bool success = false;
  std::string message;

  if (!item) {
    message = absl::StrFormat("Widget not found: %s", widget_label);
  } else {
    // Convert click type
    ImGuiMouseButton mouse_button = ImGuiMouseButton_Left;
    switch (request->type()) {
      case ClickRequest::LEFT: mouse_button = ImGuiMouseButton_Left; break;
      case ClickRequest::RIGHT: mouse_button = ImGuiMouseButton_Right; break;
      case ClickRequest::MIDDLE: mouse_button = ImGuiMouseButton_Middle; break;
    }
    
    // Click it!
    ImGuiTestEngine_ItemClick(ctx, item->ID, mouse_button);
    success = true;
    message = absl::StrFormat("Clicked '%s'", widget_label);
  }

  // Cleanup
  ImGuiTestEngine_DestroyContext(ctx);

  auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
      std::chrono::steady_clock::now() - start);

  response->set_success(success);
  response->set_message(message);
  response->set_execution_time_ms(elapsed.count());

  return absl::OkStatus();
}

3. src/app/main.cc

What to change: Pass TestManager when starting gRPC server

Find the section with #ifdef YAZE_WITH_GRPC (probably around line 200-300):

#ifdef YAZE_WITH_GRPC
  if (absl::GetFlag(FLAGS_enable_test_harness)) {
    // ADD THESE LINES:
    auto* test_manager = yaze::test::TestManager::GetInstance();
    if (!test_manager) {
      std::cerr << "ERROR: TestManager not initialized. "
                << "Cannot start test harness.\n";
      return 1;
    }

    auto& harness = yaze::test::ImGuiTestHarnessServer::Instance();
    
    // CHANGE THIS LINE to pass test_manager:
    auto status = harness.Start(
        absl::GetFlag(FLAGS_test_harness_port),
        test_manager  // ADD THIS ARGUMENT
    );
    
    if (!status.ok()) {
      std::cerr << "Failed to start test harness: " 
                << status.message() << "\n";
      return 1;
    }
  }
#endif

4. Build and Test

After making the above changes:

# Rebuild
cd /Users/scawful/Code/yaze
cmake --build build-grpc-test --target yaze -j8

# Should compile without errors
# If compilation fails, check:
# - Include paths are correct
# - TestManager header is found
# - ImGuiTestEngine headers are found

# Start YAZE with test harness
./build-grpc-test/bin/yaze.app/Contents/MacOS/yaze --enable_test_harness &

# Wait for startup (2-3 seconds)
sleep 3

# Test Ping first
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
  -d '{"message":"Hello"}' 127.0.0.1:50051 yaze.test.ImGuiTestHarness/Ping

# Should return: {"message":"Pong: Hello", "timestampMs":"...", "yazeVersion":"0.3.2"}

# Test Click (adjust button label to match YAZE UI)
grpcurl -plaintext -import-path src/app/core/proto -proto imgui_test_harness.proto \
  -d '{"target":"button:Overworld","type":"LEFT"}' \
  127.0.0.1:50051 yaze.test.ImGuiTestHarness/Click

# Expected: {"success":true, "message":"Clicked 'Overworld'", "executionTimeMs":5}
# And in YAZE GUI: The Overworld button should actually click!

Compilation Troubleshooting

Error: "TestManager not found"

Fix: Add include to service file:

#include "app/test/test_manager.h"

Error: "ImGuiTestEngine_CreateContext not declared"

Fix: Add includes:

#include "imgui_test_engine/imgui_te_engine.h"
#include "imgui_test_engine/imgui_te_context.h"

Error: "no matching function for call to Start"

Fix: Update main.cc to pass test_manager as second argument.

Linker error: "undefined reference to ImGuiTestEngine"

Fix: Ensure CMake links ImGuiTestEngine:

if(YAZE_WITH_GRPC AND TARGET ImGuiTestEngine)
  target_link_libraries(yaze PRIVATE ImGuiTestEngine)
endif()

Testing Checklist

After compilation succeeds:

  • Server starts without errors
  • Ping RPC returns version
  • Click RPC with fake button returns "Widget not found" (expected)
  • Click RPC with real button returns success
  • Button actually clicks in YAZE GUI

If first 4 work but button doesn't click:

  • Check button label is exact match
  • Try with a different button
  • Enable ImGuiTestEngine debug output

What's Next

Once Click works:

  1. Implement Type handler (similar pattern)
  2. Implement Wait handler (polling loop)
  3. Implement Assert handler (state queries)
  4. Create end-to-end test script

See IT-01-PHASE2-IMPLEMENTATION-GUIDE.md for full implementations.


Estimated Time:

  • Code changes: 1-2 hours
  • Testing/debugging: 1-2 hours
  • Total: 2-4 hours for Click handler working end-to-end

Good luck! 🚀