Skip to content

Commit bf80365

Browse files
committed
test: simple working test
1 parent 8463cb1 commit bf80365

File tree

2 files changed

+227
-60
lines changed

2 files changed

+227
-60
lines changed

tests/sdl/MouseTests.h

Lines changed: 181 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,35 @@
55
#include <thread>
66
#include <iostream>
77
#include <vector>
8+
#include <atomic>
9+
#include <mutex>
10+
#include <condition_variable>
811

912
#include "TestElements.h"
1013
#include "../../src/Mouse.h"
1114
#include "../../src/Utils.h"
1215

1316
namespace RobotTest {
1417

18+
// Test states for thread communication
19+
enum class TestState {
20+
IDLE,
21+
INITIALIZING,
22+
MOVING_TO_START,
23+
CLICKING,
24+
PRESSING_MOUSE,
25+
MOVING_TO_END,
26+
RELEASING_MOUSE,
27+
VALIDATING,
28+
COMPLETED,
29+
FAILED
30+
};
31+
1532
class MouseTests {
1633
public:
1734
MouseTests(SDL_Renderer* renderer, SDL_Window* window)
18-
: renderer(renderer), window(window) {
35+
: renderer(renderer), window(window), testPassed(false),
36+
testState(TestState::IDLE), testNeedsRendering(false) {
1937

2038
// Initialize drag elements for testing - make it larger and more visible
2139
dragElements.push_back(DragElement(
@@ -59,16 +77,30 @@ class MouseTests {
5977
SDL_RenderDrawLine(renderer, localMouseX, localMouseY-10, localMouseX, localMouseY+10);
6078

6179
// Draw status box with info about mouse position
62-
SDL_Rect posRect = {10, 10, 180, 40};
80+
SDL_Rect posRect = {10, 10, 280, 40};
6381
SDL_SetRenderDrawColor(renderer, 40, 40, 40, 255);
6482
SDL_RenderFillRect(renderer, &posRect);
6583

6684
// Draw border around status box
6785
SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255);
6886
SDL_RenderDrawRect(renderer, &posRect);
6987

70-
// Unfortunately, we can't draw text directly as we're not using SDL_ttf library
71-
// But we leave the box to show where coordinates would be displayed
88+
// Optional: Draw test state information
89+
std::string stateText;
90+
switch (testState) {
91+
case TestState::IDLE: stateText = "IDLE"; break;
92+
case TestState::INITIALIZING: stateText = "INITIALIZING"; break;
93+
case TestState::MOVING_TO_START: stateText = "MOVING TO START"; break;
94+
case TestState::CLICKING: stateText = "CLICKING"; break;
95+
case TestState::PRESSING_MOUSE: stateText = "PRESSING MOUSE"; break;
96+
case TestState::MOVING_TO_END: stateText = "MOVING TO END"; break;
97+
case TestState::RELEASING_MOUSE: stateText = "RELEASING MOUSE"; break;
98+
case TestState::VALIDATING: stateText = "VALIDATING"; break;
99+
case TestState::COMPLETED: stateText = "COMPLETED"; break;
100+
case TestState::FAILED: stateText = "FAILED"; break;
101+
}
102+
103+
// Draw test state - in a real app we'd use SDL_ttf, but we're just showing the approach
72104
}
73105

74106
void handleEvent(const SDL_Event& event) {
@@ -121,96 +153,187 @@ class MouseTests {
121153
return {x + windowX, y + windowY};
122154
}
123155

124-
// Test drag functionality
125-
bool testMouseDragging() {
126-
std::cout << "Testing mouse dragging..." << std::endl;
127-
reset();
156+
// This function runs in a separate thread and performs the mouse actions
157+
// without directly calling SDL functions
158+
void runDragTestThread() {
159+
std::cout << "Starting mouse drag test in a thread..." << std::endl;
128160

129-
if (dragElements.empty()) {
130-
std::cout << "No drag elements to test" << std::endl;
131-
return false;
132-
}
161+
// Set initial state
162+
testState = TestState::INITIALIZING;
163+
testNeedsRendering = true;
133164

134-
// Get first drag element
135-
auto& dragElement = dragElements[0];
136-
SDL_Rect startRect = dragElement.getRect();
165+
// Wait for main thread to process this state
166+
std::this_thread::sleep_for(std::chrono::milliseconds(500));
137167

138-
// Process pending SDL events
139-
SDL_Event event;
140-
while (SDL_PollEvent(&event)) {
141-
handleEvent(event);
142-
}
168+
// Get first drag element position (we'll calculate using window coordinates in main thread)
169+
int startX = 0, startY = 0, expectedX = 0, expectedY = 0;
170+
{
171+
std::lock_guard<std::mutex> lock(testMutex);
143172

144-
// Get window position
145-
int windowX, windowY;
146-
SDL_GetWindowPosition(window, &windowX, &windowY);
147-
std::cout << "Window position: (" << windowX << ", " << windowY << ")" << std::endl;
173+
if (dragElements.empty()) {
174+
std::cout << "No drag elements to test" << std::endl;
175+
testState = TestState::FAILED;
176+
testNeedsRendering = true;
177+
return;
178+
}
148179

149-
// Start position (center of element) in window coordinates
150-
int startX = startRect.x + startRect.w/2;
151-
int startY = startRect.y + startRect.h/2;
180+
auto& dragElement = dragElements[0];
181+
SDL_Rect startRect = dragElement.getRect();
182+
183+
// Start position (center of element) in window coordinates
184+
startX = startRect.x + startRect.w/2;
185+
startY = startRect.y + startRect.h/2;
186+
187+
// Calculate expected end position
188+
expectedX = startRect.x + 100; // 100px to the right
189+
expectedY = startRect.y + 50; // 50px down
190+
}
152191

153192
// Convert to screen coordinates
154193
Robot::Point startPos = windowToScreen(startX, startY);
155-
156-
// End position (100px to the right) in screen coordinates
157194
Robot::Point endPos = windowToScreen(startX + 100, startY + 50);
158195

159196
std::cout << "Start position (screen): (" << startPos.x << ", " << startPos.y << ")" << std::endl;
160197
std::cout << "End position (screen): (" << endPos.x << ", " << endPos.y << ")" << std::endl;
161198

162199
// Move to start position
200+
testState = TestState::MOVING_TO_START;
201+
testNeedsRendering = true;
202+
std::cout << "Moving to start position..." << std::endl;
163203
Robot::Mouse::Move(startPos);
164204
Robot::delay(300);
165205

166-
// click on the screen
167-
Robot::Mouse::Click(Robot::MouseButton::LEFT_BUTTON);
206+
// Click to ensure element is ready for dragging
207+
testState = TestState::CLICKING;
208+
testNeedsRendering = true;
209+
std::cout << "Clicking to select drag element..." << std::endl;
168210
Robot::Mouse::Click(Robot::MouseButton::LEFT_BUTTON);
169-
Robot::Mouse::Click(Robot::MouseButton::LEFT_BUTTON);
170-
Robot::delay(3000);
211+
Robot::delay(300);
171212

172-
// Perform drag operation
173-
Robot::Mouse::Drag(endPos);
174-
Robot::delay(500); // Give a bit more time for the drag to complete
213+
// Perform drag operation with states for main thread rendering
214+
std::cout << "Starting drag operation..." << std::endl;
175215

176-
// Process events to register the drag
177-
while (SDL_PollEvent(&event)) {
178-
handleEvent(event);
216+
// Press the mouse button
217+
testState = TestState::PRESSING_MOUSE;
218+
testNeedsRendering = true;
219+
Robot::Mouse::ToggleButton(true, Robot::MouseButton::LEFT_BUTTON);
220+
Robot::delay(300);
221+
222+
// Move to the target position
223+
testState = TestState::MOVING_TO_END;
224+
testNeedsRendering = true;
225+
std::cout << "Moving to end position..." << std::endl;
226+
Robot::Mouse::Move(endPos);
227+
Robot::delay(300);
228+
229+
// Release the mouse button
230+
testState = TestState::RELEASING_MOUSE;
231+
testNeedsRendering = true;
232+
Robot::Mouse::ToggleButton(false, Robot::MouseButton::LEFT_BUTTON);
233+
Robot::delay(500); // Give time for the drag to complete
234+
235+
// Validate results
236+
testState = TestState::VALIDATING;
237+
testNeedsRendering = true;
238+
std::this_thread::sleep_for(std::chrono::milliseconds(500));
239+
240+
// Let the main thread process events before evaluating results
241+
std::this_thread::sleep_for(std::chrono::milliseconds(500));
242+
243+
// Validate the results (in a thread-safe way)
244+
{
245+
std::lock_guard<std::mutex> lock(testMutex);
246+
247+
if (dragElements.empty()) {
248+
testPassed = false;
249+
testState = TestState::FAILED;
250+
testNeedsRendering = true;
251+
return;
252+
}
253+
254+
auto& dragElement = dragElements[0];
255+
SDL_Rect currentRect = dragElement.getRect();
256+
257+
std::cout << "Element position after drag: (" << currentRect.x << ", " << currentRect.y << ")" << std::endl;
258+
259+
// Check if element was dragged (should be close to the target position)
260+
const int tolerance = 20; // pixels
261+
262+
if (abs(currentRect.x - expectedX) > tolerance ||
263+
abs(currentRect.y - expectedY) > tolerance) {
264+
std::cout << "Drag test failed. Expected pos: (" << expectedX << ", " << expectedY
265+
<< "), Actual: (" << currentRect.x << ", " << currentRect.y << ")" << std::endl;
266+
testPassed = false;
267+
testState = TestState::FAILED;
268+
} else {
269+
std::cout << "Mouse dragging test passed" << std::endl;
270+
testPassed = true;
271+
testState = TestState::COMPLETED;
272+
}
179273
}
180274

181-
// Additional processing to ensure events are processed
182-
SDL_PumpEvents();
183-
Robot::delay(200);
275+
testNeedsRendering = true;
276+
}
184277

185-
// Get new position
186-
SDL_Rect currentRect = dragElement.getRect();
187-
std::cout << "Element position after drag: (" << currentRect.x << ", " << currentRect.y << ")" << std::endl;
278+
// Start test in a separate thread and return immediately
279+
void startDragTest() {
280+
// Reset test state
281+
testState = TestState::IDLE;
282+
testPassed = false;
283+
testNeedsRendering = true;
188284

189-
// Check if element was dragged (should be close to the target position)
190-
const int tolerance = 20; // pixels (increased tolerance slightly)
191-
int expectedX = startRect.x + 100; // 100px to the right
192-
int expectedY = startRect.y + 50; // 50px down
285+
// Start the test thread
286+
if (testThread.joinable()) {
287+
testThread.join();
288+
}
193289

194-
if (abs(currentRect.x - expectedX) > tolerance ||
195-
abs(currentRect.y - expectedY) > tolerance) {
196-
std::cout << "Drag test failed. Expected pos: (" << expectedX << ", " << expectedY
197-
<< "), Actual: (" << currentRect.x << ", " << currentRect.y << ")" << std::endl;
198-
return false;
290+
testThread = std::thread(&MouseTests::runDragTestThread, this);
291+
}
292+
293+
// Process any test-related events/updates in the main thread
294+
void updateFromMainThread() {
295+
// No SDL API calls in test thread - just handle any pending state changes
296+
if (testNeedsRendering) {
297+
testNeedsRendering = false;
298+
// Main thread has now processed this state
199299
}
300+
}
200301

201-
std::cout << "Mouse dragging test passed" << std::endl;
202-
return true;
302+
// Check if test is completed
303+
bool isTestCompleted() const {
304+
return (testState == TestState::COMPLETED || testState == TestState::FAILED);
305+
}
306+
307+
// Get test result
308+
bool getTestResult() const {
309+
return testPassed;
310+
}
311+
312+
// Clean up test thread
313+
void cleanup() {
314+
if (testThread.joinable()) {
315+
testThread.join();
316+
}
203317
}
204318

205319
bool runAllTests() {
206-
// Only run the drag test
207-
return testMouseDragging();
320+
startDragTest();
321+
322+
// Main thread will handle SDL events and rendering
323+
// This function will be used by RobotTestApp
324+
325+
return true; // Return value not used - test status is checked separately
208326
}
209327

210328
private:
211329
SDL_Renderer* renderer;
212330
SDL_Window* window;
213331
std::vector<DragElement> dragElements;
332+
std::thread testThread;
333+
std::atomic<bool> testPassed;
334+
std::atomic<TestState> testState;
335+
std::atomic<bool> testNeedsRendering;
336+
std::mutex testMutex;
214337
};
215338

216339
} // namespace RobotTest

tests/sdl/SDLTestApp.cpp

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <chrono>
66
#include <thread>
77
#include <memory>
8+
#include <atomic>
89

910
#include "TestElements.h"
1011
#include "MouseTests.h"
@@ -60,6 +61,11 @@ class RobotTestApp {
6061
}
6162

6263
~RobotTestApp() {
64+
// Clean up any running tests
65+
if (mouseTests) {
66+
mouseTests->cleanup();
67+
}
68+
6369
SDL_DestroyRenderer(renderer);
6470
SDL_DestroyWindow(window);
6571
SDL_Quit();
@@ -85,13 +91,51 @@ class RobotTestApp {
8591

8692
// Run mouse tests - only drag test
8793
std::cout << "\n----- Mouse Drag Test -----" << std::endl;
88-
if (!mouseTests->runAllTests()) {
94+
95+
// Start the test in a separate thread
96+
mouseTests->startDragTest();
97+
98+
// Run SDL event loop while tests are executing
99+
auto startTime = std::chrono::steady_clock::now();
100+
auto timeout = std::chrono::seconds(30); // 30 seconds timeout
101+
102+
std::cout << "Running SDL event loop during test execution..." << std::endl;
103+
104+
// Keep going until the test is completed or timeout
105+
while (!mouseTests->isTestCompleted()) {
106+
// Process SDL events - THIS MUST BE ON MAIN THREAD
107+
handleEvents();
108+
109+
// Update test state from main thread
110+
mouseTests->updateFromMainThread();
111+
112+
// Render the screen
113+
render();
114+
115+
// Check if we've timed out
116+
auto elapsed = std::chrono::steady_clock::now() - startTime;
117+
if (elapsed > timeout) {
118+
std::cout << "Test execution timed out!" << std::endl;
119+
break;
120+
}
121+
122+
// Don't hog the CPU
123+
SDL_Delay(16); // ~60 FPS
124+
}
125+
126+
// Get test result
127+
bool testPassed = mouseTests->getTestResult();
128+
129+
if (!testPassed) {
89130
std::cout << "❌ Mouse drag test failed" << std::endl;
90131
allTestsPassed = false;
91132
} else {
92133
std::cout << "✅ Mouse drag test passed" << std::endl;
93134
}
94135

136+
// Make sure we clean up the test thread
137+
mouseTests->cleanup();
138+
95139
// Final results
96140
std::cout << "\n===== Test Results =====" << std::endl;
97141
std::cout << (allTestsPassed ? "✅ ALL TESTS PASSED" : "❌ TEST FAILED") << std::endl;
@@ -172,7 +216,7 @@ class RobotTestApp {
172216
};
173217

174218
int main(int argc, char* argv[]) {
175-
bool runTests = false;
219+
bool runTests = true;
176220
int waitTime = 2000; // Default wait time in ms before tests
177221

178222
// Parse command line arguments

0 commit comments

Comments
 (0)