yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
test_ai_tile_placement.cc
Go to the documentation of this file.
1#include "gtest/gtest.h"
2
3#include "absl/strings/str_format.h"
7
8#ifdef YAZE_WITH_GRPC
11#endif
12
13namespace yaze {
14namespace test {
15
25class AITilePlacementTest : public ::testing::Test {
26 protected:
27 void SetUp() override {
28 // These tests require YAZE GUI to be running with gRPC test harness
29 // Skip if not available
30 }
31};
32
33TEST_F(AITilePlacementTest, ParsePlaceTileCommand) {
34 using namespace cli::ai;
35
36 // Test basic tile placement command
37 auto result = AIActionParser::ParseCommand(
38 "Place tile 0x42 at overworld position (5, 7)");
39
40 ASSERT_TRUE(result.ok()) << result.status().message();
41 EXPECT_EQ(result->size(), 3); // Select, Place, Save
42
43 // Check first action (Select)
44 EXPECT_EQ(result->at(0).type, AIActionType::kSelectTile);
45 EXPECT_EQ(result->at(0).parameters.at("tile_id"), "66"); // 0x42 = 66
46
47 // Check second action (Place)
48 EXPECT_EQ(result->at(1).type, AIActionType::kPlaceTile);
49 EXPECT_EQ(result->at(1).parameters.at("x"), "5");
50 EXPECT_EQ(result->at(1).parameters.at("y"), "7");
51 EXPECT_EQ(result->at(1).parameters.at("map_id"), "0");
52
53 // Check third action (Save)
54 EXPECT_EQ(result->at(2).type, AIActionType::kSaveTile);
55}
56
57TEST_F(AITilePlacementTest, ParseSelectTileCommand) {
58 using namespace cli::ai;
59
60 auto result = AIActionParser::ParseCommand("Select tile 100");
61
62 ASSERT_TRUE(result.ok());
63 EXPECT_EQ(result->size(), 1);
64 EXPECT_EQ(result->at(0).type, AIActionType::kSelectTile);
65 EXPECT_EQ(result->at(0).parameters.at("tile_id"), "100");
66}
67
68TEST_F(AITilePlacementTest, ParseOpenEditorCommand) {
69 using namespace cli::ai;
70
71 auto result = AIActionParser::ParseCommand("Open the overworld editor");
72
73 ASSERT_TRUE(result.ok());
74 EXPECT_EQ(result->size(), 1);
75 EXPECT_EQ(result->at(0).type, AIActionType::kOpenEditor);
76 EXPECT_EQ(result->at(0).parameters.at("editor"), "overworld");
77}
78
79TEST_F(AITilePlacementTest, ActionToStringRoundtrip) {
80 using namespace cli::ai;
81
82 AIAction action(AIActionType::kPlaceTile, {
83 {"x", "5"},
84 {"y", "7"},
85 {"tile_id", "42"}
86 });
87
88 std::string str = AIActionParser::ActionToString(action);
89 EXPECT_FALSE(str.empty());
90 EXPECT_TRUE(str.find("5") != std::string::npos);
91 EXPECT_TRUE(str.find("7") != std::string::npos);
92}
93
94#ifdef YAZE_WITH_GRPC
95
96TEST_F(AITilePlacementTest, DISABLED_VisionAnalysisBasic) {
97 // This test requires Gemini API key
98 const char* api_key = std::getenv("GEMINI_API_KEY");
99 if (!api_key || std::string(api_key).empty()) {
100 GTEST_SKIP() << "GEMINI_API_KEY not set";
101 }
102
103 cli::GeminiConfig config;
104 config.api_key = api_key;
105 config.model = "gemini-2.5-flash";
106
107 cli::GeminiAIService gemini_service(config);
108 cli::ai::VisionActionRefiner refiner(&gemini_service);
109
110 // Would need actual screenshots for real test
111 // This is a structure test
112 EXPECT_TRUE(true);
113}
114
115TEST_F(AITilePlacementTest, DISABLED_FullAIControlLoop) {
116 // This test requires:
117 // 1. YAZE GUI running with gRPC test harness
118 // 2. Gemini API key for vision
119 // 3. Test ROM loaded
120
121 const char* api_key = std::getenv("GEMINI_API_KEY");
122 if (!api_key || std::string(api_key).empty()) {
123 GTEST_SKIP() << "GEMINI_API_KEY not set";
124 }
125
126 // Initialize services
127 cli::GeminiConfig gemini_config;
128 gemini_config.api_key = api_key;
129 cli::GeminiAIService gemini_service(gemini_config);
130
131 cli::GuiAutomationClient gui_client("localhost:50051");
132 auto connect_status = gui_client.Connect();
133 if (!connect_status.ok()) {
134 GTEST_SKIP() << "GUI test harness not available: "
135 << connect_status.message();
136 }
137
138 // Create AI controller
139 cli::ai::AIGUIController controller(&gemini_service, &gui_client);
140 cli::ai::ControlLoopConfig config;
141 config.max_iterations = 5;
142 config.enable_vision_verification = true;
143 controller.Initialize(config);
144
145 // Execute command
146 auto result = controller.ExecuteCommand(
147 "Place tile 0x42 at overworld position (5, 7)");
148
149 if (result.ok()) {
150 EXPECT_TRUE(result->success);
151 EXPECT_GT(result->iterations_performed, 0);
152 }
153}
154
155#endif // YAZE_WITH_GRPC
156
157TEST_F(AITilePlacementTest, ActionRefinement) {
158 using namespace cli::ai;
159
160 // Test refinement logic with a failed action
161 VisionAnalysisResult analysis;
162 analysis.action_successful = false;
163 analysis.error_message = "Element not found";
164
165 AIAction original_action(AIActionType::kClickButton, {
166 {"button", "save"}
167 });
168
169 // Would need VisionActionRefiner for real test
170 // This verifies the structure compiles
171 EXPECT_TRUE(true);
172}
173
174TEST_F(AITilePlacementTest, MultipleCommandsParsing) {
175 using namespace cli::ai;
176
177 // Test that we can parse multiple commands in sequence
178 std::vector<std::string> commands = {
179 "Open overworld editor",
180 "Select tile 0x42",
181 "Place tile at position (5, 7)",
182 "Save changes"
183 };
184
185 for (const auto& cmd : commands) {
186 auto result = AIActionParser::ParseCommand(cmd);
187 // At least some should parse successfully
188 if (result.ok()) {
189 EXPECT_FALSE(result->empty());
190 }
191 }
192}
193
194TEST_F(AITilePlacementTest, HexAndDecimalParsing) {
195 using namespace cli::ai;
196
197 // Test hex notation
198 auto hex_result = AIActionParser::ParseCommand("Select tile 0xFF");
199 if (hex_result.ok() && !hex_result->empty()) {
200 EXPECT_EQ(hex_result->at(0).parameters.at("tile_id"), "255");
201 }
202
203 // Test decimal notation
204 auto dec_result = AIActionParser::ParseCommand("Select tile 255");
205 if (dec_result.ok() && !dec_result->empty()) {
206 EXPECT_EQ(dec_result->at(0).parameters.at("tile_id"), "255");
207 }
208}
209
210} // namespace test
211} // namespace yaze
Integration tests for AI-controlled tile placement.
TEST_F(DungeonObjectRenderingE2ETests, RunAllTests)
Main namespace for the application.