on 2012c49 help sign in
unity8/tests/utils/modules/Unity/Test/UnityTestCase.qml
336 lines 11 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 var childs = new Array(0);
76 childs.push(obj)
77 while (childs.length > 0) {
78 if (childs[0].objectName == objectName) {
79 return childs[0]
80 }
81 for (var i in childs[0].children) {
82 childs.push(childs[0].children[i])
83 }
84 childs.splice(0, 1);
85 }
86 return null;
87 }
89 // Find an object with the given name in the children tree of "obj"
90 // Including invisible children like animations, timers etc.
91 // Note: you should use findChild if you're not sure you need this
92 // as this tree is much bigger and might contain stuff that goes
93 // away randomly.
94 function findInvisibleChild(obj,objectName) {
95 var childs = new Array(0);
96 childs.push(obj)
97 while (childs.length > 0) {
98 if (childs[0].objectName == objectName) {
99 return childs[0]
100 }
101 for (var i in childs[0].data) {
102 childs.push(childs[0].data[i])
103 }
104 childs.splice(0, 1);
105 }
106 return null;
107 }
109 // Type a full string instead of keyClick letter by letter
110 // TODO: this is not ugly, this is uber-ugly and does not support
111 // any special character. Remove the keyMap once keyClick(obj, char)
112 // has landed in upstream Qt.
113 function typeString(str) {
114 var keyMap = {
115 "a": Qt.Key_A,
116 "b": Qt.Key_B,
117 "c": Qt.Key_C,
118 "d": Qt.Key_D,
119 "e": Qt.Key_E,
120 "f": Qt.Key_F,
121 "g": Qt.Key_G,
122 "h": Qt.Key_H,
123 "i": Qt.Key_I,
124 "j": Qt.Key_J,
125 "k": Qt.Key_K,
126 "l": Qt.Key_L,
127 "m": Qt.Key_M,
128 "n": Qt.Key_N,
129 "o": Qt.Key_O,
130 "p": Qt.Key_P,
131 "q": Qt.Key_Q,
132 "r": Qt.Key_R,
133 "s": Qt.Key_S,
134 "t": Qt.Key_T,
135 "u": Qt.Key_U,
136 "v": Qt.Key_V,
137 "w": Qt.Key_W,
138 "x": Qt.Key_X,
139 "y": Qt.Key_Y,
140 "z": Qt.Key_Z,
141 "A": Qt.Key_A,
142 "B": Qt.Key_B,
143 "C": Qt.Key_C,
144 "D": Qt.Key_D,
145 "E": Qt.Key_E,
146 "F": Qt.Key_F,
147 "G": Qt.Key_G,
148 "H": Qt.Key_H,
149 "I": Qt.Key_I,
150 "J": Qt.Key_J,
151 "K": Qt.Key_K,
152 "L": Qt.Key_L,
153 "M": Qt.Key_M,
154 "N": Qt.Key_N,
155 "O": Qt.Key_O,
156 "P": Qt.Key_P,
157 "Q": Qt.Key_Q,
158 "R": Qt.Key_R,
159 "S": Qt.Key_S,
160 "T": Qt.Key_T,
161 "U": Qt.Key_U,
162 "V": Qt.Key_V,
163 "W": Qt.Key_W,
164 "X": Qt.Key_X,
165 "Y": Qt.Key_Y,
166 "Z": Qt.Key_Z,
167 "0": Qt.Key_0,
168 "1": Qt.Key_1,
169 "2": Qt.Key_2,
170 "3": Qt.Key_3,
171 "4": Qt.Key_4,
172 "5": Qt.Key_5,
173 "6": Qt.Key_6,
174 "7": Qt.Key_7,
175 "8": Qt.Key_8,
176 "9": Qt.Key_9,
177 " ": Qt.Key_Space,
178 }
179 for (var i = 0; i < str.length; i++) {
180 keyClick(keyMap[str[i]])
181 }
182 }
184 // Keeps executing a given parameter-less function until it returns the given
185 // expected result or the timemout is reached (in which case a test failure
186 // is generated)
187 function tryCompareFunction(func, expectedResult) {
188 var timeSpent = 0
189 var timeout = 5000
190 var success = false
191 var actualResult
192 while (timeSpent < timeout && !success) {
193 actualResult = func()
194 success = qtest_compareInternal(actualResult, expectedResult)
195 if (success === false) {
196 wait(50)
197 timeSpent += 50
198 }
199 }
201 var act = qtest_results.stringify(actualResult)
202 var exp = qtest_results.stringify(expectedResult)
203 if (!qtest_results.compare(success,
204 "function returned unexpected result",
205 act, exp,
206 util.callerFile(), util.callerLine())) {
207 throw new Error("QtQuickTest::fail")
208 }
209 }
211 function touchEvent() {
212 return UT.Util.touchEvent()
213 }
215 // speed is in pixels/second
216 function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
217 // Make sure the item is rendered
218 waitForRendering(item);
220 // Default to true for beginTouch if not present
221 beginTouch = (beginTouch !== undefined) ? beginTouch : true
223 // Default to true for endTouch if not present
224 endTouch = (endTouch !== undefined) ? endTouch : true
226 // Set a default speed if not specified
227 speed = (speed !== undefined) ? speed : units.gu(10)
229 // Set a default iterations if not specified
230 var iterations = (iterations !== undefined) ? iterations : 5
232 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
233 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
235 var timeStep = totalTime / iterations
236 var diffX = (toX - x) / iterations
237 var diffY = (toY - y) / iterations
238 if (beginTouch) {
239 fakeDateTime.currentTimeMs += timeStep
241 var event = touchEvent()
242 event.press(0 /* touchId */, x, y)
243 event.commit()
244 }
245 for (var i = 0; i < iterations; ++i) {
246 fakeDateTime.currentTimeMs += timeStep
247 if (i === iterations - 1) {
248 // Avoid any rounding errors by making the last move be at precisely
249 // the point specified
250 wait(iterations / speed)
251 var event = touchEvent()
252 event.move(0 /* touchId */, toX, toY)
253 event.commit()
254 } else {
255 wait(iterations / speed)
256 var event = touchEvent()
257 event.move(0 /* touchId */, x + (i + 1) * diffX, y + (i + 1) * diffY)
258 event.commit()
259 }
260 }
261 if (endTouch) {
262 fakeDateTime.currentTimeMs += timeStep
263 var event = touchEvent()
264 event.release(0 /* touchId */, toX, toY)
265 event.commit()
266 }
267 }
269 function fetchRootItem(item) {
270 if (item.parent)
271 return fetchRootItem(item.parent)
272 else
273 return item
274 }
276 function touchPress(item, x, y) {
277 var root = fetchRootItem(item)
278 var rootPoint = item.mapToItem(root, x, y)
280 var event = touchEvent()
281 event.press(0 /* touchId */, rootPoint.x, rootPoint.y)
282 event.commit()
283 }
285 function touchRelease(item, x, y) {
286 var root = fetchRootItem(item)
287 var rootPoint = item.mapToItem(root, x, y)
289 var event = touchEvent()
290 event.release(0 /* touchId */, rootPoint.x, rootPoint.y)
291 event.commit()
292 }
294 function tap(item, x, y) {
295 var event = touchEvent()
296 event.press(0 /* touchId */, x, y)
297 event.commit()
299 event = touchEvent()
300 event.release(0 /* touchId */, x, y)
301 event.commit()
302 }
304 Component.onCompleted: {
305 var rootItem = parent;
306 while (rootItem.parent != undefined) {
307 rootItem = rootItem.parent;
308 }
309 removeTimeConstraintsFromDirectionalDragAreas(rootItem);
310 }
312 /*
313 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
314 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
315 Thus to remove a variable that qmltests cannot really control, namely time, this
316 function removes all constraints from DirectionalDragAreas that are sensible to
317 elapsed time.
319 This effectively makes DirectionalDragAreas easier to fool.
320 */
321 function removeTimeConstraintsFromDirectionalDragAreas(item) {
323 // use duck-typing to identify a DirectionalDragArea
324 if (item.minSpeed != undefined
325 && item.maxSilenceTime != undefined
326 && item.compositionTime != undefined) {
327 item.minSpeed = 0;
328 item.maxSilenceTime = 60 * 60 * 1000;
329 item.compositionTime = 0;
330 } else {
331 for (var i in item.children) {
332 removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
333 }
334 }
335 }