77#include < vector>
88#include < atomic>
99#include < mutex>
10- #include < condition_variable>
1110
1211#include " TestElements.h"
1312#include " ../../src/Mouse.h"
@@ -31,9 +30,14 @@ enum class TestState {
3130
3231class MouseTests {
3332public:
34- MouseTests (SDL_Renderer* renderer, SDL_Window* window)
33+ MouseTests (SDL_Renderer* renderer, SDL_Window* window, bool ciMode = false )
3534 : renderer(renderer), window(window), testPassed(false ),
36- testState (TestState::IDLE), testNeedsRendering(false ) {
35+ testState (TestState::IDLE), testNeedsRendering(false ),
36+ ciMode(ciMode) {
37+
38+ if (ciMode) {
39+ std::cout << " MouseTests running in CI mode - will use simulated mouse events" << std::endl;
40+ }
3741
3842 // Initialize drag elements for testing - make it larger and more visible
3943 dragElements.push_back (DragElement (
@@ -60,47 +64,33 @@ class MouseTests {
6064 dragElement.draw (renderer);
6165 }
6266
63- // Get window position
64- int windowX, windowY;
65- SDL_GetWindowPosition (window, &windowX, &windowY);
67+ // In CI mode, we don't need to draw mouse position
68+ if (!ciMode) {
69+ // Get window position
70+ int windowX, windowY;
71+ SDL_GetWindowPosition (window, &windowX, &windowY);
6672
67- // Get global mouse position
68- Robot::Point globalMousePos = Robot::Mouse::GetPosition ();
73+ // Get global mouse position
74+ Robot::Point globalMousePos = Robot::Mouse::GetPosition ();
6975
70- // Calculate local mouse position (relative to window)
71- int localMouseX = globalMousePos.x - windowX;
72- int localMouseY = globalMousePos.y - windowY;
76+ // Calculate local mouse position (relative to window)
77+ int localMouseX = globalMousePos.x - windowX;
78+ int localMouseY = globalMousePos.y - windowY;
7379
74- // Draw mouse position indicator - a red crosshair at the current mouse position
75- SDL_SetRenderDrawColor (renderer, 255 , 0 , 0 , 255 );
76- SDL_RenderDrawLine (renderer, localMouseX-10 , localMouseY, localMouseX+10 , localMouseY);
77- SDL_RenderDrawLine (renderer, localMouseX, localMouseY-10 , localMouseX, localMouseY+10 );
80+ // Draw mouse position indicator - a red crosshair at the current mouse position
81+ SDL_SetRenderDrawColor (renderer, 255 , 0 , 0 , 255 );
82+ SDL_RenderDrawLine (renderer, localMouseX-10 , localMouseY, localMouseX+10 , localMouseY);
83+ SDL_RenderDrawLine (renderer, localMouseX, localMouseY-10 , localMouseX, localMouseY+10 );
84+ }
7885
79- // Draw status box with info about mouse position
86+ // Draw status box with info about test state
8087 SDL_Rect posRect = {10 , 10 , 280 , 40 };
8188 SDL_SetRenderDrawColor (renderer, 40 , 40 , 40 , 255 );
8289 SDL_RenderFillRect (renderer, &posRect);
8390
8491 // Draw border around status box
8592 SDL_SetRenderDrawColor (renderer, 100 , 100 , 100 , 255 );
8693 SDL_RenderDrawRect (renderer, &posRect);
87-
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
10494 }
10595
10696 void handleEvent (const SDL_Event& event) {
@@ -153,8 +143,39 @@ class MouseTests {
153143 return {x + windowX, y + windowY};
154144 }
155145
146+ // Directly inject mouse events for CI mode
147+ void injectMouseEvent (int type, int x, int y, int button = SDL_BUTTON_LEFT) {
148+ SDL_Event event;
149+
150+ switch (type) {
151+ case SDL_MOUSEBUTTONDOWN:
152+ event.type = SDL_MOUSEBUTTONDOWN;
153+ event.button .button = button;
154+ event.button .x = x;
155+ event.button .y = y;
156+ event.button .state = SDL_PRESSED;
157+ break ;
158+
159+ case SDL_MOUSEBUTTONUP:
160+ event.type = SDL_MOUSEBUTTONUP;
161+ event.button .button = button;
162+ event.button .x = x;
163+ event.button .y = y;
164+ event.button .state = SDL_RELEASED;
165+ break ;
166+
167+ case SDL_MOUSEMOTION:
168+ event.type = SDL_MOUSEMOTION;
169+ event.motion .x = x;
170+ event.motion .y = y;
171+ event.motion .state = SDL_PRESSED;
172+ break ;
173+ }
174+
175+ SDL_PushEvent (&event);
176+ }
177+
156178 // This function runs in a separate thread and performs the mouse actions
157- // without directly calling SDL functions
158179 void runDragTestThread () {
159180 std::cout << " Starting mouse drag test in a thread..." << std::endl;
160181
@@ -165,7 +186,7 @@ class MouseTests {
165186 // Wait for main thread to process this state
166187 std::this_thread::sleep_for (std::chrono::milliseconds (500 ));
167188
168- // Get first drag element position (we'll calculate using window coordinates in main thread)
189+ // Get first drag element position
169190 int startX = 0 , startY = 0 , expectedX = 0 , expectedY = 0 ;
170191 {
171192 std::lock_guard<std::mutex> lock (testMutex);
@@ -189,48 +210,86 @@ class MouseTests {
189210 expectedY = startRect.y + 50 ; // 50px down
190211 }
191212
192- // Convert to screen coordinates
193- Robot::Point startPos = windowToScreen (startX, startY);
194- Robot::Point endPos = windowToScreen (startX + 100 , startY + 50 );
195-
196- std::cout << " Start position (screen): (" << startPos.x << " , " << startPos.y << " )" << std::endl;
197- std::cout << " End position (screen): (" << endPos.x << " , " << endPos.y << " )" << std::endl;
198-
199- // Move to start position
200- testState = TestState::MOVING_TO_START;
201- testNeedsRendering = true ;
202- std::cout << " Moving to start position..." << std::endl;
203- Robot::Mouse::Move (startPos);
204- Robot::delay (300 );
205-
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;
210- Robot::Mouse::Click (Robot::MouseButton::LEFT_BUTTON);
211- Robot::delay (300 );
212-
213- // Perform drag operation with states for main thread rendering
214- std::cout << " Starting drag operation..." << std::endl;
215-
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
213+ // End position for drag
214+ int endX = startX + 100 ;
215+ int endY = startY + 50 ;
216+
217+ if (ciMode) {
218+ // In CI mode, directly inject SDL events
219+ std::cout << " CI Mode: Using simulated mouse events" << std::endl;
220+
221+ testState = TestState::MOVING_TO_START;
222+ testNeedsRendering = true ;
223+ std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
224+
225+ testState = TestState::CLICKING;
226+ testNeedsRendering = true ;
227+ injectMouseEvent (SDL_MOUSEMOTION, startX, startY);
228+ std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
229+ injectMouseEvent (SDL_MOUSEBUTTONDOWN, startX, startY);
230+ std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
231+ injectMouseEvent (SDL_MOUSEBUTTONUP, startX, startY);
232+ std::this_thread::sleep_for (std::chrono::milliseconds (300 ));
233+
234+ testState = TestState::PRESSING_MOUSE;
235+ testNeedsRendering = true ;
236+ injectMouseEvent (SDL_MOUSEBUTTONDOWN, startX, startY);
237+ std::this_thread::sleep_for (std::chrono::milliseconds (300 ));
238+
239+ testState = TestState::MOVING_TO_END;
240+ testNeedsRendering = true ;
241+ injectMouseEvent (SDL_MOUSEMOTION, endX, endY);
242+ std::this_thread::sleep_for (std::chrono::milliseconds (300 ));
243+
244+ testState = TestState::RELEASING_MOUSE;
245+ testNeedsRendering = true ;
246+ injectMouseEvent (SDL_MOUSEBUTTONUP, endX, endY);
247+ std::this_thread::sleep_for (std::chrono::milliseconds (500 ));
248+ } else {
249+ // Normal mode - use Robot library for real mouse automation
250+ // Convert to screen coordinates
251+ Robot::Point startPos = windowToScreen (startX, startY);
252+ Robot::Point endPos = windowToScreen (endX, endY);
253+
254+ std::cout << " Start position (screen): (" << startPos.x << " , " << startPos.y << " )" << std::endl;
255+ std::cout << " End position (screen): (" << endPos.x << " , " << endPos.y << " )" << std::endl;
256+
257+ // Move to start position
258+ testState = TestState::MOVING_TO_START;
259+ testNeedsRendering = true ;
260+ std::cout << " Moving to start position..." << std::endl;
261+ Robot::Mouse::Move (startPos);
262+ Robot::delay (300 );
263+
264+ // Click to ensure element is ready for dragging
265+ testState = TestState::CLICKING;
266+ testNeedsRendering = true ;
267+ std::cout << " Clicking to select drag element..." << std::endl;
268+ Robot::Mouse::Click (Robot::MouseButton::LEFT_BUTTON);
269+ Robot::delay (300 );
270+
271+ // Perform drag operation with states for main thread rendering
272+ std::cout << " Starting drag operation..." << std::endl;
273+
274+ // Press the mouse button
275+ testState = TestState::PRESSING_MOUSE;
276+ testNeedsRendering = true ;
277+ Robot::Mouse::ToggleButton (true , Robot::MouseButton::LEFT_BUTTON);
278+ Robot::delay (300 );
279+
280+ // Move to the target position
281+ testState = TestState::MOVING_TO_END;
282+ testNeedsRendering = true ;
283+ std::cout << " Moving to end position..." << std::endl;
284+ Robot::Mouse::Move (endPos);
285+ Robot::delay (300 );
286+
287+ // Release the mouse button
288+ testState = TestState::RELEASING_MOUSE;
289+ testNeedsRendering = true ;
290+ Robot::Mouse::ToggleButton (false , Robot::MouseButton::LEFT_BUTTON);
291+ Robot::delay (500 ); // Give time for the drag to complete
292+ }
234293
235294 // Validate results
236295 testState = TestState::VALIDATING;
@@ -334,6 +393,7 @@ class MouseTests {
334393 std::atomic<TestState> testState;
335394 std::atomic<bool > testNeedsRendering;
336395 std::mutex testMutex;
396+ bool ciMode; // Flag for CI environment
337397};
338398
339399} // namespace RobotTest
0 commit comments