on de035fa help sign in
unity8/tests/utils/modules/Unity/Test/UnityTestCase.qml
356 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) {
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 function touchEvent() {
206 return UT.Util.touchEvent()
207 }
209 // speed is in pixels/second
210 function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
211 // Make sure the item is rendered
212 waitForRendering(item);
214 // Default to true for beginTouch if not present
215 beginTouch = (beginTouch !== undefined) ? beginTouch : true
217 // Default to true for endTouch if not present
218 endTouch = (endTouch !== undefined) ? endTouch : true
220 // Set a default speed if not specified
221 speed = (speed !== undefined) ? speed : units.gu(10)
223 // Set a default iterations if not specified
224 var iterations = (iterations !== undefined) ? iterations : 5
226 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
227 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
229 var timeStep = totalTime / iterations
230 var diffX = (toX - x) / iterations
231 var diffY = (toY - y) / iterations
232 if (beginTouch) {
233 fakeDateTime.currentTimeMs += timeStep
235 var event = touchEvent()
236 event.press(0 /* touchId */, x, y)
237 event.commit()
238 }
239 for (var i = 0; i < iterations; ++i) {
240 fakeDateTime.currentTimeMs += timeStep
241 if (i === iterations - 1) {
242 // Avoid any rounding errors by making the last move be at precisely
243 // the point specified
244 wait(iterations / speed)
245 var event = touchEvent()
246 event.move(0 /* touchId */, toX, toY)
247 event.commit()
248 } else {
249 wait(iterations / speed)
250 var event = touchEvent()
251 event.move(0 /* touchId */, x + (i + 1) * diffX, y + (i + 1) * diffY)
252 event.commit()
253 }
254 }
255 if (endTouch) {
256 fakeDateTime.currentTimeMs += timeStep
257 var event = touchEvent()
258 event.release(0 /* touchId */, toX, toY)
259 event.commit()
260 }
261 }
263 function touchPinch(item, x1Start, y1Start, x1End, y1End, x2Start, y2Start, x2End, y2End) {
264 // Make sure the item is rendered
265 waitForRendering(item);
267 var event1 = touchEvent();
268 // first finger
269 event1.press(0, x1Start, y1Start);
270 event1.commit();
271 // second finger
272 event1.stationary(0);
273 event1.press(1, x2Start, y2Start);
274 event1.commit();
276 // pinch
277 for (var i = 0.0; i < 1.0; i += 0.02) {
278 event1.move(0, x1Start + (x1End - x1Start) * i, y1Start + (y1End - y1Start) * i);
279 event1.move(1, x2Start + (x2End - x2Start) * i, y2Start + (y2End - y2Start) * i);
280 event1.commit();
281 }
283 // release
284 event1.release(0, x1End, y1End);
285 event1.release(1, x2End, y2End);
286 event1.commit();
287 }
289 function fetchRootItem(item) {
290 if (item.parent)
291 return fetchRootItem(item.parent)
292 else
293 return item
294 }
296 function touchPress(item, x, y) {
297 var root = fetchRootItem(item)
298 var rootPoint = item.mapToItem(root, x, y)
300 var event = touchEvent()
301 event.press(0 /* touchId */, rootPoint.x, rootPoint.y)
302 event.commit()
303 }
305 function touchRelease(item, x, y) {
306 var root = fetchRootItem(item)
307 var rootPoint = item.mapToItem(root, x, y)
309 var event = touchEvent()
310 event.release(0 /* touchId */, rootPoint.x, rootPoint.y)
311 event.commit()
312 }
314 function tap(item, x, y) {
315 var event = touchEvent()
316 event.press(0 /* touchId */, x, y)
317 event.commit()
319 event = touchEvent()
320 event.release(0 /* touchId */, x, y)
321 event.commit()
322 }
324 Component.onCompleted: {
325 var rootItem = parent;
326 while (rootItem.parent != undefined) {
327 rootItem = rootItem.parent;
328 }
329 removeTimeConstraintsFromDirectionalDragAreas(rootItem);
330 }
332 /*
333 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
334 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
335 Thus to remove a variable that qmltests cannot really control, namely time, this
336 function removes all constraints from DirectionalDragAreas that are sensible to
337 elapsed time.
339 This effectively makes DirectionalDragAreas easier to fool.
340 */
341 function removeTimeConstraintsFromDirectionalDragAreas(item) {
343 // use duck-typing to identify a DirectionalDragArea
344 if (item.minSpeed != undefined
345 && item.maxSilenceTime != undefined
346 && item.compositionTime != undefined) {
347 item.minSpeed = 0;
348 item.maxSilenceTime = 60 * 60 * 1000;
349 item.compositionTime = 0;
350 } else {
351 for (var i in item.children) {
352 removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
353 }
354 }
355 }