on ef63f10 help sign in
unity8/tests/utils/modules/Unity/Test/UnityTestCase.qml
362 lines 12 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, timeout) {
182 var timeSpent = 0
183 if (timeout === undefined)
184 timeout = 5000;
185 var success = false
186 var actualResult
187 while (timeSpent < timeout && !success) {
188 actualResult = func()
189 success = qtest_compareInternal(actualResult, expectedResult)
190 if (success === false) {
191 wait(50)
192 timeSpent += 50
193 }
194 }
196 var act = qtest_results.stringify(actualResult)
197 var exp = qtest_results.stringify(expectedResult)
198 if (!qtest_results.compare(success,
199 "function returned unexpected result",
200 act, exp,
201 util.callerFile(), util.callerLine())) {
202 throw new Error("QtQuickTest::fail")
203 }
204 }
206 function touchEvent() {
207 return UT.Util.touchEvent()
208 }
210 // speed is in pixels/second
211 function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
212 // Make sure the item is rendered
213 waitForRendering(item);
215 // Default to true for beginTouch if not present
216 beginTouch = (beginTouch !== undefined) ? beginTouch : true
218 // Default to true for endTouch if not present
219 endTouch = (endTouch !== undefined) ? endTouch : true
221 // Set a default speed if not specified
222 speed = (speed !== undefined) ? speed : units.gu(10)
224 // Set a default iterations if not specified
225 var iterations = (iterations !== undefined) ? iterations : 5
227 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
228 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
230 var timeStep = totalTime / iterations
231 var diffX = (toX - x) / iterations
232 var diffY = (toY - y) / iterations
233 if (beginTouch) {
234 fakeDateTime.currentTimeMs += timeStep
236 var event = touchEvent()
237 event.press(0 /* touchId */, x, y)
238 event.commit()
239 }
240 for (var i = 0; i < iterations; ++i) {
241 fakeDateTime.currentTimeMs += timeStep
242 if (i === iterations - 1) {
243 // Avoid any rounding errors by making the last move be at precisely
244 // the point specified
245 wait(iterations / speed)
246 var event = touchEvent()
247 event.move(0 /* touchId */, toX, toY)
248 event.commit()
249 } else {
250 wait(iterations / speed)
251 var event = touchEvent()
252 event.move(0 /* touchId */, x + (i + 1) * diffX, y + (i + 1) * diffY)
253 event.commit()
254 }
255 }
256 if (endTouch) {
257 fakeDateTime.currentTimeMs += timeStep
258 var event = touchEvent()
259 event.release(0 /* touchId */, toX, toY)
260 event.commit()
261 }
262 }
264 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
265 // Make sure the item is rendered
266 waitForRendering(item);
268 var event1 = touchEvent();
269 // first finger
270 event1.press(0, x1Start, y1Start);
271 event1.commit();
272 // second finger
273 event1.stationary(0);
274 event1.press(1, x2Start, y2Start);
275 event1.commit();
277 // pinch
278 for (var i = 0.0; i < 1.0; i += 0.02) {
279 event1.move(0, x1Start + (x1End - x1Start) * i, y1Start + (y1End - y1Start) * i);
280 event1.move(1, x2Start + (x2End - x2Start) * i, y2Start + (y2End - y2Start) * i);
281 event1.commit();
282 }
284 // release
285 event1.release(0, x1End, y1End);
286 event1.release(1, x2End, y2End);
287 event1.commit();
288 }
290 function fetchRootItem(item) {
291 if (item.parent)
292 return fetchRootItem(item.parent)
293 else
294 return item
295 }
297 function touchPress(item, x, y) {
298 var root = fetchRootItem(item)
299 var rootPoint = item.mapToItem(root, x, y)
301 var event = touchEvent()
302 event.press(0 /* touchId */, rootPoint.x, rootPoint.y)
303 event.commit()
304 }
306 function touchRelease(item, x, y) {
307 var root = fetchRootItem(item)
308 var rootPoint = item.mapToItem(root, x, y)
310 var event = touchEvent()
311 event.release(0 /* touchId */, rootPoint.x, rootPoint.y)
312 event.commit()
313 }
315 function tap(item, x, y) {
316 var root = fetchRootItem(item)
317 var rootPoint = item.mapToItem(root, x, y)
319 var event = touchEvent()
320 event.press(0 /* touchId */, rootPoint.x, rootPoint.y)
321 event.commit()
323 event = touchEvent()
324 event.release(0 /* touchId */, rootPoint.x, rootPoint.y)
325 event.commit()
326 }
328 Component.onCompleted: {
329 UT.Util.ensureTouchRegistryInstalled();
331 var rootItem = parent;
332 while (rootItem.parent != undefined) {
333 rootItem = rootItem.parent;
334 }
335 removeTimeConstraintsFromDirectionalDragAreas(rootItem);
336 }
338 /*
339 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
340 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
341 Thus to remove a variable that qmltests cannot really control, namely time, this
342 function removes all constraints from DirectionalDragAreas that are sensible to
343 elapsed time.
345 This effectively makes DirectionalDragAreas easier to fool.
346 */
347 function removeTimeConstraintsFromDirectionalDragAreas(item) {
349 // use duck-typing to identify a DirectionalDragArea
350 if (item.minSpeed != undefined
351 && item.maxSilenceTime != undefined
352 && item.compositionTime != undefined) {
353 item.minSpeed = 0;
354 item.maxSilenceTime = 60 * 60 * 1000;
355 item.compositionTime = 0;
356 } else {
357 for (var i in item.children) {
358 removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
359 }
360 }
361 }