on e01825c help sign in
unity8/tests/utils/modules/Unity/Test/UnityTestCase.qml
385 lines 13 kB history raw
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17import QtQuick 2.0
18import QtTest 1.0
19import Ubuntu.Components 0.1
20import Unity.Test 0.1 as UT
22TestCase {
23 TestUtil {id:util}
25 // Fake implementation to be provided to items under test
26 property var fakeDateTime: new function() {
27 this.currentTimeMs = 0
28 this.getCurrentTimeMs = function() {return this.currentTimeMs}
29 }
31 // Flickable won't recognise a single mouse move as dragging the flickable.
32 // Use 5 steps because it's what
33 // Qt uses in QQuickViewTestUtil::flick
34 // speed is in pixels/second
35 function mouseFlick(item, x, y, toX, toY, pressMouse, releaseMouse,
36 speed, iterations) {
37 pressMouse = ((pressMouse != null) ? pressMouse : true); // Default to true for pressMouse if not present
38 releaseMouse = ((releaseMouse != null) ? releaseMouse : true); // Default to true for releaseMouse if not present
40 // set a default speed if not specified
41 speed = (speed != null) ? speed : units.gu(10);
43 // set a default iterations if not specified
44 iterations = (iterations !== undefined) ? iterations : 5
46 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
47 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
49 var timeStep = totalTime / iterations
50 var diffX = (toX - x) / iterations
51 var diffY = (toY - y) / iterations
52 if (pressMouse) {
53 fakeDateTime.currentTimeMs += timeStep
54 mousePress(item, x, y)
55 }
56 for (var i = 0; i < iterations; ++i) {
57 fakeDateTime.currentTimeMs += timeStep
58 if (i === iterations - 1) {
59 // Avoid any rounding errors by making the last move be at precisely
60 // the point specified
61 mouseMove(item, toX, toY, iterations / speed)
62 } else {
63 mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, iterations / speed)
64 }
65 }
66 if (releaseMouse) {
67 fakeDateTime.currentTimeMs += timeStep
68 mouseRelease(item, toX, toY)
69 }
70 }
73 // Find an object with the given name in the children tree of "obj"
74 function findChild(obj, objectName) {
75 return findChildIn(obj, "children", objectName);
76 }
78 // Find an object with the given name in the children tree of "obj"
79 // Including invisible children like animations, timers etc.
80 // Note: you should use findChild if you're not sure you need this
81 // as this tree is much bigger and might contain stuff that goes
82 // away randomly.
83 function findInvisibleChild(obj, objectName) {
84 return findChildIn(obj, "data", objectName);
85 }
87 // Find a child in the named property
88 function findChildIn(obj, prop, objectName) {
89 var childs = new Array(0);
90 childs.push(obj)
91 while (childs.length > 0) {
92 if (childs[0].objectName == objectName) {
93 return childs[0]
94 }
95 for (var i in childs[0][prop]) {
96 childs.push(childs[0][prop][i])
97 }
98 childs.splice(0, 1);
99 }
100 return null;
101 }
103 // Type a full string instead of keyClick letter by letter
104 // TODO: this is not ugly, this is uber-ugly and does not support
105 // any special character. Remove the keyMap once keyClick(obj, char)
106 // has landed in upstream Qt.
107 function typeString(str) {
108 var keyMap = {
109 "a": Qt.Key_A,
110 "b": Qt.Key_B,
111 "c": Qt.Key_C,
112 "d": Qt.Key_D,
113 "e": Qt.Key_E,
114 "f": Qt.Key_F,
115 "g": Qt.Key_G,
116 "h": Qt.Key_H,
117 "i": Qt.Key_I,
118 "j": Qt.Key_J,
119 "k": Qt.Key_K,
120 "l": Qt.Key_L,
121 "m": Qt.Key_M,
122 "n": Qt.Key_N,
123 "o": Qt.Key_O,
124 "p": Qt.Key_P,
125 "q": Qt.Key_Q,
126 "r": Qt.Key_R,
127 "s": Qt.Key_S,
128 "t": Qt.Key_T,
129 "u": Qt.Key_U,
130 "v": Qt.Key_V,
131 "w": Qt.Key_W,
132 "x": Qt.Key_X,
133 "y": Qt.Key_Y,
134 "z": Qt.Key_Z,
135 "A": Qt.Key_A,
136 "B": Qt.Key_B,
137 "C": Qt.Key_C,
138 "D": Qt.Key_D,
139 "E": Qt.Key_E,
140 "F": Qt.Key_F,
141 "G": Qt.Key_G,
142 "H": Qt.Key_H,
143 "I": Qt.Key_I,
144 "J": Qt.Key_J,
145 "K": Qt.Key_K,
146 "L": Qt.Key_L,
147 "M": Qt.Key_M,
148 "N": Qt.Key_N,
149 "O": Qt.Key_O,
150 "P": Qt.Key_P,
151 "Q": Qt.Key_Q,
152 "R": Qt.Key_R,
153 "S": Qt.Key_S,
154 "T": Qt.Key_T,
155 "U": Qt.Key_U,
156 "V": Qt.Key_V,
157 "W": Qt.Key_W,
158 "X": Qt.Key_X,
159 "Y": Qt.Key_Y,
160 "Z": Qt.Key_Z,
161 "0": Qt.Key_0,
162 "1": Qt.Key_1,
163 "2": Qt.Key_2,
164 "3": Qt.Key_3,
165 "4": Qt.Key_4,
166 "5": Qt.Key_5,
167 "6": Qt.Key_6,
168 "7": Qt.Key_7,
169 "8": Qt.Key_8,
170 "9": Qt.Key_9,
171 " ": Qt.Key_Space,
172 }
173 for (var i = 0; i < str.length; i++) {
174 keyClick(keyMap[str[i]])
175 }
176 }
178 // Keeps executing a given parameter-less function until it returns the given
179 // expected result or the timemout is reached (in which case a test failure
180 // is generated)
181 function tryCompareFunction(func, expectedResult) {
182 var timeSpent = 0
183 var timeout = 5000
184 var success = false
185 var actualResult
186 while (timeSpent < timeout && !success) {
187 actualResult = func()
188 success = qtest_compareInternal(actualResult, expectedResult)
189 if (success === false) {
190 wait(50)
191 timeSpent += 50
192 }
193 }
195 var act = qtest_results.stringify(actualResult)
196 var exp = qtest_results.stringify(expectedResult)
197 if (!qtest_results.compare(success,
198 "function returned unexpected result",
199 act, exp,
200 util.callerFile(), util.callerLine())) {
201 throw new Error("QtQuickTest::fail")
202 }
203 }
205 // Keeps executing a given parameter-less function until it returns the given
206 // expected result or the timemout is reached (in which case a test failure
207 // is generated)
208 function tryCompareFunction2(func, expectedResultFunc) {
209 var timeSpent = 0
210 var timeout = 5000
211 var success = false
212 var actualResult
213 var expectedResult
214 while (timeSpent < timeout && !success) {
215 actualResult = func()
216 expectedResult = expectedResultFunc()
217 success = qtest_compareInternal(actualResult, expectedResult)
218 if (success === false) {
219 wait(50)
220 timeSpent += 50
221 }
222 }
224 var act = qtest_results.stringify(actualResult)
225 var exp = qtest_results.stringify(expectedResult)
226 if (!qtest_results.compare(success,
227 "function returned unexpected result",
228 act, exp,
229 util.callerFile(), util.callerLine())) {
230 throw new Error("QtQuickTest::fail")
231 }
232 }
234 function touchEvent() {
235 return UT.Util.touchEvent()
236 }
238 // speed is in pixels/second
239 function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
240 // Make sure the item is rendered
241 waitForRendering(item);
243 // Default to true for beginTouch if not present
244 beginTouch = (beginTouch !== undefined) ? beginTouch : true
246 // Default to true for endTouch if not present
247 endTouch = (endTouch !== undefined) ? endTouch : true
249 // Set a default speed if not specified
250 speed = (speed !== undefined) ? speed : units.gu(10)
252 // Set a default iterations if not specified
253 var iterations = (iterations !== undefined) ? iterations : 5
255 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
256 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
258 var timeStep = totalTime / iterations
259 var diffX = (toX - x) / iterations
260 var diffY = (toY - y) / iterations
261 if (beginTouch) {
262 fakeDateTime.currentTimeMs += timeStep
264 var event = touchEvent()
265 event.press(0 /* touchId */, x, y)
266 event.commit()
267 }
268 for (var i = 0; i < iterations; ++i) {
269 fakeDateTime.currentTimeMs += timeStep
270 if (i === iterations - 1) {
271 // Avoid any rounding errors by making the last move be at precisely
272 // the point specified
273 wait(iterations / speed)
274 var event = touchEvent()
275 event.move(0 /* touchId */, toX, toY)
276 event.commit()
277 } else {
278 wait(iterations / speed)
279 var event = touchEvent()
280 event.move(0 /* touchId */, x + (i + 1) * diffX, y + (i + 1) * diffY)
281 event.commit()
282 }
283 }
284 if (endTouch) {
285 fakeDateTime.currentTimeMs += timeStep
286 var event = touchEvent()
287 event.release(0 /* touchId */, toX, toY)
288 event.commit()
289 }
290 }
292 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
293 // Make sure the item is rendered
294 waitForRendering(item);
296 var event1 = touchEvent();
297 // first finger
298 event1.press(0, x1Start, y1Start);
299 event1.commit();
300 // second finger
301 event1.stationary(0);
302 event1.press(1, x2Start, y2Start);
303 event1.commit();
305 // pinch
306 for (var i = 0.0; i < 1.0; i += 0.02) {
307 event1.move(0, x1Start + (x1End - x1Start) * i, y1Start + (y1End - y1Start) * i);
308 event1.move(1, x2Start + (x2End - x2Start) * i, y2Start + (y2End - y2Start) * i);
309 event1.commit();
310 }
312 // release
313 event1.release(0, x1End, y1End);
314 event1.release(1, x2End, y2End);
315 event1.commit();
316 }
318 function fetchRootItem(item) {
319 if (item.parent)
320 return fetchRootItem(item.parent)
321 else
322 return item
323 }
325 function touchPress(item, x, y) {
326 var root = fetchRootItem(item)
327 var rootPoint = item.mapToItem(root, x, y)
329 var event = touchEvent()
330 event.press(0 /* touchId */, rootPoint.x, rootPoint.y)
331 event.commit()
332 }
334 function touchRelease(item, x, y) {
335 var root = fetchRootItem(item)
336 var rootPoint = item.mapToItem(root, x, y)
338 var event = touchEvent()
339 event.release(0 /* touchId */, rootPoint.x, rootPoint.y)
340 event.commit()
341 }
343 function tap(item, x, y) {
344 var event = touchEvent()
345 event.press(0 /* touchId */, x, y)
346 event.commit()
348 event = touchEvent()
349 event.release(0 /* touchId */, x, y)
350 event.commit()
351 }
353 Component.onCompleted: {
354 var rootItem = parent;
355 while (rootItem.parent != undefined) {
356 rootItem = rootItem.parent;
357 }
358 removeTimeConstraintsFromDirectionalDragAreas(rootItem);
359 }
361 /*
362 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
363 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
364 Thus to remove a variable that qmltests cannot really control, namely time, this
365 function removes all constraints from DirectionalDragAreas that are sensible to
366 elapsed time.
368 This effectively makes DirectionalDragAreas easier to fool.
369 */
370 function removeTimeConstraintsFromDirectionalDragAreas(item) {
372 // use duck-typing to identify a DirectionalDragArea
373 if (item.minSpeed != undefined
374 && item.maxSilenceTime != undefined
375 && item.compositionTime != undefined) {
376 item.minSpeed = 0;
377 item.maxSilenceTime = 60 * 60 * 1000;
378 item.compositionTime = 0;
379 } else {
380 for (var i in item.children) {
381 removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
382 }
383 }
384 }