Merge lp:~elopio/autopilot/fix1257055-slow_drag into lp:~elopio/autopilot/fix1266601-Pointer-pressed-move
- fix1257055-slow_drag
- Merge into fix1266601-Pointer-pressed...
Proposed by
Leo Arias
Status: | Superseded |
---|---|
Proposed branch: | lp:~elopio/autopilot/fix1257055-slow_drag |
Merge into: | lp:~elopio/autopilot/fix1266601-Pointer-pressed-move |
Diff against target: |
295 lines (+212/-16) (has conflicts) 3 files modified
autopilot/input/_X11.py (+2/-2) autopilot/input/_uinput.py (+22/-12) autopilot/tests/unit/test_input.py (+188/-2) Text conflict in autopilot/tests/unit/test_input.py |
To merge this branch: | bzr merge lp:~elopio/autopilot/fix1257055-slow_drag |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Leo Arias | Pending | ||
Review via email: mp+202203@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-01-19.
Commit message
Added the drags with rate.
Description of the change
To post a comment you must log in.
- 421. By Leo Arias
-
Updated the copyright years.
- 422. By Leo Arias
-
Added the rate to the Pointer drag.
- 423. By Leo Arias
-
Renamed MockTouch to MockUinputTouch.
- 424. By Leo Arias
-
Merged with trunk.
- 425. By Leo Arias
-
Added python-evdev as a build-dep.
- 426. By Leo Arias
-
Merged with prerequisite branch.
- 427. By Leo Arias
-
Fixed the imports.
- 428. By Leo Arias
-
Added comments for the rate parameter.
- 429. By Leo Arias
-
Updated the tests.
- 430. By Leo Arias
-
Removed unused import.
- 431. By Leo Arias
-
Removed extra line.
- 432. By Leo Arias
-
s/should/must
- 433. By Leo Arias
-
Added a test with time_between_
events. - 434. By Leo Arias
-
We can't use the real Mouse, so switch to touch backend for now.
- 435. By Leo Arias
-
Updated the fake.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'autopilot/input/_X11.py' | |||
2 | --- autopilot/input/_X11.py 2013-11-07 05:53:36 +0000 | |||
3 | +++ autopilot/input/_X11.py 2014-01-19 00:39:05 +0000 | |||
4 | @@ -455,7 +455,7 @@ | |||
5 | 455 | x, y = coord["root_x"], coord["root_y"] | 455 | x, y = coord["root_x"], coord["root_y"] |
6 | 456 | return x, y | 456 | return x, y |
7 | 457 | 457 | ||
9 | 458 | def drag(self, x1, y1, x2, y2): | 458 | def drag(self, x1, y1, x2, y2, rate=10): |
10 | 459 | """Performs a press, move and release. | 459 | """Performs a press, move and release. |
11 | 460 | 460 | ||
12 | 461 | This is to keep a common API between Mouse and Finger as long as | 461 | This is to keep a common API between Mouse and Finger as long as |
13 | @@ -464,7 +464,7 @@ | |||
14 | 464 | """ | 464 | """ |
15 | 465 | self.move(x1, y1) | 465 | self.move(x1, y1) |
16 | 466 | self.press() | 466 | self.press() |
18 | 467 | self.move(x2, y2) | 467 | self.move(x2, y2, rate=rate) |
19 | 468 | self.release() | 468 | self.release() |
20 | 469 | 469 | ||
21 | 470 | @classmethod | 470 | @classmethod |
22 | 471 | 471 | ||
23 | === modified file 'autopilot/input/_uinput.py' | |||
24 | --- autopilot/input/_uinput.py 2013-11-07 05:53:36 +0000 | |||
25 | +++ autopilot/input/_uinput.py 2014-01-19 00:39:05 +0000 | |||
26 | @@ -361,23 +361,33 @@ | |||
27 | 361 | raise RuntimeError("Attempting to move without finger being down.") | 361 | raise RuntimeError("Attempting to move without finger being down.") |
28 | 362 | self._finger_move(x, y) | 362 | self._finger_move(x, y) |
29 | 363 | 363 | ||
31 | 364 | def drag(self, x1, y1, x2, y2): | 364 | def drag(self, x1, y1, x2, y2, rate=10): |
32 | 365 | """Perform a drag gesture from (x1,y1) to (x2,y2)""" | 365 | """Perform a drag gesture from (x1,y1) to (x2,y2)""" |
33 | 366 | logger.debug("Dragging from %d,%d to %d,%d", x1, y1, x2, y2) | 366 | logger.debug("Dragging from %d,%d to %d,%d", x1, y1, x2, y2) |
34 | 367 | self._finger_down(x1, y1) | 367 | self._finger_down(x1, y1) |
35 | 368 | 368 | ||
43 | 369 | # Let's drag in 100 steps for now... | 369 | current_x, current_y = x1, y1 |
44 | 370 | dx = 1.0 * (x2 - x1) / 100 | 370 | while current_x != x2 or current_y != y2: |
45 | 371 | dy = 1.0 * (y2 - y1) / 100 | 371 | dx = abs(x2 - current_x) |
46 | 372 | cur_x = x1 + dx | 372 | dy = abs(y2 - current_y) |
47 | 373 | cur_y = y1 + dy | 373 | |
48 | 374 | for i in range(0, 100): | 374 | intx = float(dx) / max(dx, dy) |
49 | 375 | self._finger_move(int(cur_x), int(cur_y)) | 375 | inty = float(dy) / max(dx, dy) |
50 | 376 | |||
51 | 377 | step_x = min(rate * intx, dx) | ||
52 | 378 | step_y = min(rate * inty, dy) | ||
53 | 379 | |||
54 | 380 | if x2 < current_x: | ||
55 | 381 | step_x *= -1 | ||
56 | 382 | if y2 < current_y: | ||
57 | 383 | step_y *= -1 | ||
58 | 384 | |||
59 | 385 | current_x += step_x | ||
60 | 386 | current_y += step_y | ||
61 | 387 | self._finger_move(current_x, current_y) | ||
62 | 388 | |||
63 | 376 | sleep(0.002) | 389 | sleep(0.002) |
68 | 377 | cur_x += dx | 390 | |
65 | 378 | cur_y += dy | ||
66 | 379 | # Make sure we actually end up at target | ||
67 | 380 | self._finger_move(x2, y2) | ||
69 | 381 | self._finger_up() | 391 | self._finger_up() |
70 | 382 | 392 | ||
71 | 383 | def _finger_down(self, x, y): | 393 | def _finger_down(self, x, y): |
72 | 384 | 394 | ||
73 | === modified file 'autopilot/tests/unit/test_input.py' | |||
74 | --- autopilot/tests/unit/test_input.py 2014-01-07 00:21:08 +0000 | |||
75 | +++ autopilot/tests/unit/test_input.py 2014-01-19 00:39:05 +0000 | |||
76 | @@ -1,7 +1,7 @@ | |||
77 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
78 | 2 | # | 2 | # |
79 | 3 | # Autopilot Functional Test Tool | 3 | # Autopilot Functional Test Tool |
81 | 4 | # Copyright (C) 2013 Canonical | 4 | # Copyright (C) 2013, 2014 Canonical |
82 | 5 | # | 5 | # |
83 | 6 | # This program is free software: you can redistribute it and/or modify | 6 | # This program is free software: you can redistribute it and/or modify |
84 | 7 | # it under the terms of the GNU General Public License as published by | 7 | # it under the terms of the GNU General Public License as published by |
85 | @@ -17,12 +17,18 @@ | |||
86 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
87 | 18 | # | 18 | # |
88 | 19 | 19 | ||
90 | 20 | from mock import patch | 20 | import testscenarios |
91 | 21 | |||
92 | 22 | from mock import call, Mock, patch | ||
93 | 21 | from testtools import TestCase | 23 | from testtools import TestCase |
94 | 22 | from testtools.matchers import raises | 24 | from testtools.matchers import raises |
95 | 23 | 25 | ||
96 | 26 | <<<<<<< TREE | ||
97 | 24 | from autopilot import input | 27 | from autopilot import input |
98 | 25 | from autopilot.input import _uinput | 28 | from autopilot.input import _uinput |
99 | 29 | ======= | ||
100 | 30 | from autopilot.input import _uinput, _X11 | ||
101 | 31 | >>>>>>> MERGE-SOURCE | ||
102 | 26 | from autopilot.input._common import get_center_point | 32 | from autopilot.input._common import get_center_point |
103 | 27 | 33 | ||
104 | 28 | 34 | ||
105 | @@ -153,6 +159,7 @@ | |||
106 | 153 | 159 | ||
107 | 154 | self.assertEqual(123, x) | 160 | self.assertEqual(123, x) |
108 | 155 | self.assertEqual(345, y) | 161 | self.assertEqual(345, y) |
109 | 162 | <<<<<<< TREE | ||
110 | 156 | 163 | ||
111 | 157 | 164 | ||
112 | 158 | class PointerWithTouchBackendTestCase(TestCase): | 165 | class PointerWithTouchBackendTestCase(TestCase): |
113 | @@ -182,3 +189,182 @@ | |||
114 | 182 | self.pointer.move(1, 1) | 189 | self.pointer.move(1, 1) |
115 | 183 | 190 | ||
116 | 184 | self.assertFalse(mock_move.called) | 191 | self.assertFalse(mock_move.called) |
117 | 192 | ======= | ||
118 | 193 | |||
119 | 194 | |||
120 | 195 | class PartialMock(object): | ||
121 | 196 | """Mock some of the methods of an object, and record their calls.""" | ||
122 | 197 | |||
123 | 198 | def __init__(self, real_object, *args): | ||
124 | 199 | super(PartialMock, self).__init__() | ||
125 | 200 | self._mock_manager = Mock() | ||
126 | 201 | self._real_object = real_object | ||
127 | 202 | self.patched_attributes = args | ||
128 | 203 | |||
129 | 204 | def __getattr__(self, name): | ||
130 | 205 | """Forward all the calls to the real object.""" | ||
131 | 206 | return self._real_object.__getattribute__(name) | ||
132 | 207 | |||
133 | 208 | @property | ||
134 | 209 | def mock_calls(self): | ||
135 | 210 | """Return the calls recorded for the mocked attributes.""" | ||
136 | 211 | return self._mock_manager.mock_calls | ||
137 | 212 | |||
138 | 213 | def __enter__(self): | ||
139 | 214 | self._start_patchers() | ||
140 | 215 | return self | ||
141 | 216 | |||
142 | 217 | def _start_patchers(self): | ||
143 | 218 | self._patchers = [] | ||
144 | 219 | for attribute in self.patched_attributes: | ||
145 | 220 | patcher = patch.object(self._real_object, attribute) | ||
146 | 221 | self._patchers.append(patcher) | ||
147 | 222 | |||
148 | 223 | self._mock_manager.attach_mock(patcher.start(), attribute) | ||
149 | 224 | |||
150 | 225 | def __exit__(self, exc_type, exc_val, exc_tb): | ||
151 | 226 | self._stop_patchers() | ||
152 | 227 | |||
153 | 228 | def _stop_patchers(self): | ||
154 | 229 | for patcher in self._patchers: | ||
155 | 230 | patcher.stop() | ||
156 | 231 | |||
157 | 232 | |||
158 | 233 | class MockX11Mouse(PartialMock): | ||
159 | 234 | """Mock for the X11 Mouse Touch. | ||
160 | 235 | |||
161 | 236 | It records the calls to press, release and move, but doesn't perform them. | ||
162 | 237 | |||
163 | 238 | """ | ||
164 | 239 | |||
165 | 240 | def __init__(self): | ||
166 | 241 | super(MockX11Mouse, self).__init__( | ||
167 | 242 | _X11.Mouse(), 'press', 'release', 'move') | ||
168 | 243 | |||
169 | 244 | def get_move_call_args_list(self): | ||
170 | 245 | return self._mock_manager.move.call_args_list | ||
171 | 246 | |||
172 | 247 | |||
173 | 248 | class X11MouseTestCase(TestCase): | ||
174 | 249 | |||
175 | 250 | def test_drag_should_call_move_with_rate(self): | ||
176 | 251 | expected_first_move_call = call(0, 0) | ||
177 | 252 | expected_second_move_call = call(100, 100, rate=1) | ||
178 | 253 | with MockX11Mouse() as mock_mouse: | ||
179 | 254 | mock_mouse.drag(0, 0, 100, 100, rate=1) | ||
180 | 255 | |||
181 | 256 | self.assertEqual( | ||
182 | 257 | [expected_first_move_call, expected_second_move_call], | ||
183 | 258 | mock_mouse.get_move_call_args_list()) | ||
184 | 259 | |||
185 | 260 | def test_drag_with_default_rate(self): | ||
186 | 261 | expected_first_move_call = call(0, 0) | ||
187 | 262 | expected_second_move_call = call(100, 100, rate=10) | ||
188 | 263 | with MockX11Mouse() as mock_mouse: | ||
189 | 264 | mock_mouse.drag(0, 0, 100, 100) | ||
190 | 265 | |||
191 | 266 | self.assertEqual( | ||
192 | 267 | [expected_first_move_call, expected_second_move_call], | ||
193 | 268 | mock_mouse.get_move_call_args_list()) | ||
194 | 269 | |||
195 | 270 | |||
196 | 271 | class MockTouch(PartialMock): | ||
197 | 272 | """Mock for the uinput Touch. | ||
198 | 273 | |||
199 | 274 | It records the calls to _finger_down, _finger_up and _finger_move, but | ||
200 | 275 | doesn't perform them. | ||
201 | 276 | |||
202 | 277 | """ | ||
203 | 278 | |||
204 | 279 | def __init__(self): | ||
205 | 280 | super(MockTouch, self).__init__( | ||
206 | 281 | _uinput.Touch(), '_finger_down', '_finger_up', '_finger_move') | ||
207 | 282 | |||
208 | 283 | def get_finger_move_call_args_list(self): | ||
209 | 284 | return self._mock_manager._finger_move.call_args_list | ||
210 | 285 | |||
211 | 286 | |||
212 | 287 | class UinputTouchTestCase(TestCase): | ||
213 | 288 | |||
214 | 289 | def test_drag_finger_actions(self): | ||
215 | 290 | expected_finger_calls = [ | ||
216 | 291 | call._finger_down(0, 0), | ||
217 | 292 | call._finger_move(10, 10), | ||
218 | 293 | call._finger_up() | ||
219 | 294 | ] | ||
220 | 295 | with MockTouch() as mock_touch: | ||
221 | 296 | mock_touch.drag(0, 0, 10, 10) | ||
222 | 297 | self.assertEqual(mock_touch.mock_calls, expected_finger_calls) | ||
223 | 298 | |||
224 | 299 | def test_drag_should_call_move_with_rate(self): | ||
225 | 300 | expected_move_calls = [call(5, 5), call(10, 10), call(15, 15)] | ||
226 | 301 | with MockTouch() as mock_touch: | ||
227 | 302 | mock_touch.drag(0, 0, 15, 15, rate=5) | ||
228 | 303 | |||
229 | 304 | self.assertEqual( | ||
230 | 305 | expected_move_calls, mock_touch.get_finger_move_call_args_list()) | ||
231 | 306 | |||
232 | 307 | def test_drag_with_default_rate(self): | ||
233 | 308 | expected_move_calls = [call(10, 10), call(20, 20)] | ||
234 | 309 | with MockTouch() as mock_touch: | ||
235 | 310 | mock_touch.drag(0, 0, 20, 20) | ||
236 | 311 | |||
237 | 312 | self.assertEqual( | ||
238 | 313 | expected_move_calls, mock_touch.get_finger_move_call_args_list()) | ||
239 | 314 | |||
240 | 315 | def test_drag_to_same_place_should_not_move(self): | ||
241 | 316 | expected_finger_calls = [ | ||
242 | 317 | call._finger_down(0, 0), | ||
243 | 318 | call._finger_up() | ||
244 | 319 | ] | ||
245 | 320 | with MockTouch() as mock_touch: | ||
246 | 321 | mock_touch.drag(0, 0, 0, 0) | ||
247 | 322 | self.assertEqual(mock_touch.mock_calls, expected_finger_calls) | ||
248 | 323 | |||
249 | 324 | |||
250 | 325 | class DragUinputTouchTestCase(testscenarios.TestWithScenarios, TestCase): | ||
251 | 326 | |||
252 | 327 | scenarios = [ | ||
253 | 328 | ('drag to top', dict( | ||
254 | 329 | start_x=50, start_y=50, stop_x=50, stop_y=30, | ||
255 | 330 | expected_moves=[call(50, 40), call(50, 30)])), | ||
256 | 331 | ('drag to bottom', dict( | ||
257 | 332 | start_x=50, start_y=50, stop_x=50, stop_y=70, | ||
258 | 333 | expected_moves=[call(50, 60), call(50, 70)])), | ||
259 | 334 | ('drag to left', dict( | ||
260 | 335 | start_x=50, start_y=50, stop_x=30, stop_y=50, | ||
261 | 336 | expected_moves=[call(40, 50), call(30, 50)])), | ||
262 | 337 | ('drag to right', dict( | ||
263 | 338 | start_x=50, start_y=50, stop_x=70, stop_y=50, | ||
264 | 339 | expected_moves=[call(60, 50), call(70, 50)])), | ||
265 | 340 | |||
266 | 341 | ('drag to top-left', dict( | ||
267 | 342 | start_x=50, start_y=50, stop_x=30, stop_y=30, | ||
268 | 343 | expected_moves=[call(40, 40), call(30, 30)])), | ||
269 | 344 | ('drag to top-right', dict( | ||
270 | 345 | start_x=50, start_y=50, stop_x=70, stop_y=30, | ||
271 | 346 | expected_moves=[call(60, 40), call(70, 30)])), | ||
272 | 347 | ('drag to bottom-left', dict( | ||
273 | 348 | start_x=50, start_y=50, stop_x=30, stop_y=70, | ||
274 | 349 | expected_moves=[call(40, 60), call(30, 70)])), | ||
275 | 350 | ('drag to bottom-right', dict( | ||
276 | 351 | start_x=50, start_y=50, stop_x=70, stop_y=70, | ||
277 | 352 | expected_moves=[call(60, 60), call(70, 70)])), | ||
278 | 353 | |||
279 | 354 | ('drag less than rate', dict( | ||
280 | 355 | start_x=50, start_y=50, stop_x=55, stop_y=55, | ||
281 | 356 | expected_moves=[call(55, 55)])), | ||
282 | 357 | |||
283 | 358 | ('drag with last move less than rate', dict( | ||
284 | 359 | start_x=50, start_y=50, stop_x=65, stop_y=65, | ||
285 | 360 | expected_moves=[call(60, 60), call(65, 65)])), | ||
286 | 361 | ] | ||
287 | 362 | |||
288 | 363 | def test_drag_moves(self): | ||
289 | 364 | with MockTouch() as mock_touch: | ||
290 | 365 | mock_touch.drag( | ||
291 | 366 | self.start_x, self.start_y, self.stop_x, self.stop_y) | ||
292 | 367 | |||
293 | 368 | self.assertEqual( | ||
294 | 369 | self.expected_moves, mock_touch.get_finger_move_call_args_list()) | ||
295 | 370 | >>>>>>> MERGE-SOURCE |