doc: fix some typos in .qml files
[profile/ivi/qtdeclarative.git] / src / imports / testlib / TestCase.qml
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 import QtQuick 2.0
43 import QtTest 1.0
44 import "testlogger.js" as TestLogger
45
46 Item {
47     id: testCase
48     visible: false
49     TestUtil {
50         id:util
51     }
52
53     // Name of the test case to prefix the function name in messages.
54     property string name
55
56     // Set to true to start the test running.
57     property bool when: true
58
59     // Set to true once the test has completed.
60     property bool completed: false
61
62     // Set to true when the test is running but not yet complete.
63     property bool running: false
64
65     // Set to true if the test doesn't have to run (because some
66     // other test failed which this one depends on).
67     property bool optional: false
68
69     property bool windowShown: qtest.windowShown
70
71     // Internal private state.  Identifiers prefixed with qtest are reserved.
72     property bool qtest_prevWhen: true
73     property int qtest_testId: -1
74     property bool qtest_componentCompleted : false
75     property var qtest_testCaseResult
76     property var qtest_results: qtest_results_normal
77     TestResult { id: qtest_results_normal }
78     property var qtest_events: qtest_events_normal
79     TestEvent { id: qtest_events_normal }
80
81     function fail(msg) {
82         if (msg === undefined)
83             msg = "";
84         qtest_results.fail(msg, util.callerFile(), util.callerLine())
85         throw new Error("QtQuickTest::fail")
86     }
87
88     function qtest_fail(msg, frame) {
89         if (msg === undefined)
90             msg = "";
91         qtest_results.fail(msg, util.callerFile(frame), util.callerLine(frame))
92         throw new Error("QtQuickTest::fail")
93     }
94
95     function verify(cond, msg) {
96         if (msg === undefined)
97             msg = "";
98         if (!qtest_results.verify(cond, msg, util.callerFile(), util.callerLine()))
99             throw new Error("QtQuickTest::fail")
100     }
101
102     // Determine what is o.
103     // Discussions and reference: http://philrathe.com/articles/equiv
104     // Test suites: http://philrathe.com/tests/equiv
105     // Author: Philippe Rathé <prathe@gmail.com>
106     function qtest_typeof(o) {
107         if (typeof o === "undefined") {
108             return "undefined";
109
110         // consider: typeof null === object
111         } else if (o === null) {
112             return "null";
113
114         } else if (o.constructor === String) {
115             return "string";
116
117         } else if (o.constructor === Boolean) {
118             return "boolean";
119
120         } else if (o.constructor === Number) {
121
122             if (isNaN(o)) {
123                 return "nan";
124             } else {
125                 return "number";
126             }
127         // consider: typeof [] === object
128         } else if (o instanceof Array) {
129             return "array";
130
131         // consider: typeof new Date() === object
132         } else if (o instanceof Date) {
133             return "date";
134
135         // consider: /./ instanceof Object;
136         //           /./ instanceof RegExp;
137         //          typeof /./ === "function"; // => false in IE and Opera,
138         //                                          true in FF and Safari
139         } else if (o instanceof RegExp) {
140             return "regexp";
141
142         } else if (typeof o === "object") {
143             if ("mapFromItem" in o && "mapToItem" in o) {
144                 return "declarativeitem";  // @todo improve detection of declarative items
145             } else if ("x" in o && "y" in o && "z" in o) {
146                 return "vector3d"; // Qt3D vector
147             }
148             return "object";
149         } else if (o instanceof Function) {
150             return "function";
151         } else {
152             return undefined;
153         }
154     }
155
156     // Test for equality
157     // Large parts contain sources from QUnit or http://philrathe.com
158     // Discussions and reference: http://philrathe.com/articles/equiv
159     // Test suites: http://philrathe.com/tests/equiv
160     // Author: Philippe Rathé <prathe@gmail.com>
161     function qtest_compareInternal(act, exp) {
162         var success = false;
163         if (act === exp) {
164             success = true; // catch the most you can
165         } else if (act === null || exp === null || typeof act === "undefined" || typeof exp === "undefined") {
166             success = false; // don't lose time with error prone cases
167         } else {
168             var typeExp = qtest_typeof(exp), typeAct = qtest_typeof(act)
169             if (typeExp !== typeAct) {
170                 // allow object vs string comparison (e.g. for colors)
171                 // else break on different types
172                 if ((typeExp === "string" && (typeAct === "object") || typeAct == "declarativeitem")
173                  || ((typeExp === "object" || typeExp == "declarativeitem") && typeAct === "string")) {
174                     success = (act == exp)
175                 }
176             } else if (typeExp === "string" || typeExp === "boolean" ||
177                        typeExp === "null" || typeExp === "undefined") {
178                 if (exp instanceof act.constructor || act instanceof exp.constructor) {
179                     // to catch short annotaion VS 'new' annotation of act declaration
180                     // e.g. var i = 1;
181                     //      var j = new Number(1);
182                     success = (act == exp)
183                 } else {
184                     success = (act === exp)
185                 }
186             } else if (typeExp === "nan") {
187                 success = isNaN(act);
188             } else if (typeExp === "number") {
189                 // Use act fuzzy compare if the two values are floats
190                 if (Math.abs(act - exp) <= 0.00001) {
191                     success = true
192                 }
193             } else if (typeExp === "array") {
194                 success = qtest_compareInternalArrays(act, exp)
195             } else if (typeExp === "object") {
196                 success = qtest_compareInternalObjects(act, exp)
197             } else if (typeExp === "declarativeitem") {
198                 success = qtest_compareInternalObjects(act, exp) // @todo improve comparison of declarative items
199             } else if (typeExp === "vector3d") {
200                 success = (Math.abs(act.x - exp.x) <= 0.00001 &&
201                            Math.abs(act.y - exp.y) <= 0.00001 &&
202                            Math.abs(act.z - exp.z) <= 0.00001)
203             } else if (typeExp === "date") {
204                 success = (act.valueOf() === exp.valueOf())
205             } else if (typeExp === "regexp") {
206                 success = (act.source === exp.source && // the regex itself
207                            act.global === exp.global && // and its modifers (gmi) ...
208                            act.ignoreCase === exp.ignoreCase &&
209                            act.multiline === exp.multiline)
210             }
211         }
212         return success
213     }
214
215     function qtest_compareInternalObjects(act, exp) {
216         var i;
217         var eq = true; // unless we can proove it
218         var aProperties = [], bProperties = []; // collection of strings
219
220         // comparing constructors is more strict than using instanceof
221         if (act.constructor !== exp.constructor) {
222             return false;
223         }
224
225         for (i in act) { // be strict: don't ensures hasOwnProperty and go deep
226             aProperties.push(i); // collect act's properties
227             if (!qtest_compareInternal(act[i], exp[i])) {
228                 eq = false;
229                 break;
230             }
231         }
232
233         for (i in exp) {
234             bProperties.push(i); // collect exp's properties
235         }
236
237         // Ensures identical properties name
238         return eq && qtest_compareInternal(aProperties.sort(), bProperties.sort());
239
240     }
241
242     function qtest_compareInternalArrays(actual, expected) {
243         if (actual.length != expected.length) {
244             return false
245         }
246
247         for (var i = 0, len = actual.length; i < len; i++) {
248             if (!qtest_compareInternal(actual[i], expected[i])) {
249                 return false
250             }
251         }
252
253         return true
254     }
255
256     function compare(actual, expected, msg) {
257         var act = qtest_results.stringify(actual)
258         var exp = qtest_results.stringify(expected)
259
260         var success = qtest_compareInternal(actual, expected)
261         if (msg === undefined) {
262             if (success)
263                 msg = "COMPARE()"
264             else
265                 msg = "Compared values are not the same"
266         }
267         if (!qtest_results.compare(success, msg, act, exp, util.callerFile(), util.callerLine())) {
268             throw new Error("QtQuickTest::fail")
269         }
270     }
271
272     function fuzzyCompare(actual, expected, delta, msg) {
273         if (delta === undefined)
274             qtest_fail("A delta value is required for fuzzyCompare", 2)
275
276         var success = qtest_results.fuzzyCompare(actual, expected, delta)
277         if (msg === undefined) {
278             if (success)
279                 msg = "FUZZYCOMPARE()"
280             else
281                 msg = "Compared values are not the same with delta(" + delta + ")"
282         }
283
284         if (!qtest_results.compare(success, msg, actual, expected, util.callerFile(), util.callerLine())) {
285             throw new Error("QtQuickTest::fail")
286         }
287     }
288
289     function grabImage(item) {
290         return qtest_results.grabImage(item);
291     }
292
293     function tryCompare(obj, prop, value, timeout) {
294         if (!timeout)
295             timeout = 5000
296         if (!qtest_compareInternal(obj[prop], value))
297             wait(0)
298         var i = 0
299         while (i < timeout && !qtest_compareInternal(obj[prop], value)) {
300             wait(50)
301             i += 50
302         }
303         var actual = obj[prop]
304         var act = qtest_results.stringify(actual)
305         var exp = qtest_results.stringify(value)
306         var success = qtest_compareInternal(actual, value)
307         if (!qtest_results.compare(success, "property " + prop, act, exp, util.callerFile(), util.callerLine()))
308             throw new Error("QtQuickTest::fail")
309     }
310
311     function skip(msg) {
312         if (msg === undefined)
313             msg = ""
314         qtest_results.skip(msg, util.callerFile(), util.callerLine())
315         throw new Error("QtQuickTest::skip")
316     }
317
318     function expectFail(tag, msg) {
319         if (tag === undefined) {
320             warn("tag argument missing from expectFail()")
321             tag = ""
322         }
323         if (msg === undefined) {
324             warn("message argument missing from expectFail()")
325             msg = ""
326         }
327         if (!qtest_results.expectFail(tag, msg, util.callerFile(), util.callerLine()))
328             throw new Error("QtQuickTest::expectFail")
329     }
330
331     function expectFailContinue(tag, msg) {
332         if (tag === undefined) {
333             warn("tag argument missing from expectFailContinue()")
334             tag = ""
335         }
336         if (msg === undefined) {
337             warn("message argument missing from expectFailContinue()")
338             msg = ""
339         }
340         if (!qtest_results.expectFailContinue(tag, msg, util.callerFile(), util.callerLine()))
341             throw new Error("QtQuickTest::expectFail")
342     }
343
344     function warn(msg) {
345         if (msg === undefined)
346             msg = ""
347         qtest_results.warn(msg, util.callerFile(), util.callerLine());
348     }
349
350     function ignoreWarning(msg) {
351         if (msg === undefined)
352             msg = ""
353         qtest_results.ignoreWarning(msg)
354     }
355
356     function wait(ms) {
357         qtest_results.wait(ms)
358     }
359
360     function waitForRendering(item, timeout) {
361         if (timeout === undefined)
362             timeout = 5000
363         return qtest_results.waitForRendering(item, timeout)
364     }
365
366     function sleep(ms) {
367         qtest_results.sleep(ms)
368     }
369
370     function keyPress(key, modifiers, delay) {
371         if (modifiers === undefined)
372             modifiers = Qt.NoModifier
373         if (delay == undefined)
374             delay = -1
375         if (!qtest_events.keyPress(key, modifiers, delay))
376             qtest_fail("window not shown", 2)
377     }
378
379     function keyRelease(key, modifiers, delay) {
380         if (modifiers === undefined)
381             modifiers = Qt.NoModifier
382         if (delay == undefined)
383             delay = -1
384         if (!qtest_events.keyRelease(key, modifiers, delay))
385             qtest_fail("window not shown", 2)
386     }
387
388     function keyClick(key, modifiers, delay) {
389         if (modifiers === undefined)
390             modifiers = Qt.NoModifier
391         if (delay == undefined)
392             delay = -1
393         if (!qtest_events.keyClick(key, modifiers, delay))
394             qtest_fail("window not shown", 2)
395     }
396
397     function mousePress(item, x, y, button, modifiers, delay) {
398         if (button === undefined)
399             button = Qt.LeftButton
400         if (modifiers === undefined)
401             modifiers = Qt.NoModifier
402         if (delay == undefined)
403             delay = -1
404         if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
405             qtest_fail("window not shown", 2)
406     }
407
408     function mouseRelease(item, x, y, button, modifiers, delay) {
409         if (button === undefined)
410             button = Qt.LeftButton
411         if (modifiers === undefined)
412             modifiers = Qt.NoModifier
413         if (delay == undefined)
414             delay = -1
415         if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
416             qtest_fail("window not shown", 2)
417     }
418
419     function mouseDrag(item, x, y, dx, dy, button, modifiers, delay) {
420         if (item.x === undefined || item.y === undefined)
421             return
422         if (button === undefined)
423             button = Qt.LeftButton
424         if (modifiers === undefined)
425             modifiers = Qt.NoModifier
426         if (delay == undefined)
427             delay = -1
428
429         mousePress(item, x, y, button, modifiers, delay)
430         //trigger dragging
431         mouseMove(item, x + util.dragThreshold + 1, y + util.dragThreshold + 1, delay, button)
432         mouseMove(item, x + dx, y + dy, delay, button)
433     }
434
435     function mouseClick(item, x, y, button, modifiers, delay) {
436         if (button === undefined)
437             button = Qt.LeftButton
438         if (modifiers === undefined)
439             modifiers = Qt.NoModifier
440         if (delay == undefined)
441             delay = -1
442         if (!qtest_events.mouseClick(item, x, y, button, modifiers, delay))
443             qtest_fail("window not shown", 2)
444     }
445
446     function mouseDoubleClick(item, x, y, button, modifiers, delay) {
447         if (button === undefined)
448             button = Qt.LeftButton
449         if (modifiers === undefined)
450             modifiers = Qt.NoModifier
451         if (delay == undefined)
452             delay = -1
453         if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
454             qtest_fail("window not shown", 2)
455     }
456
457     function mouseMove(item, x, y, delay, buttons) {
458         if (delay == undefined)
459             delay = -1
460         if (buttons == undefined)
461             buttons = Qt.NoButton
462         if (!qtest_events.mouseMove(item, x, y, delay, buttons))
463             qtest_fail("window not shown", 2)
464     }
465
466     function mouseWheel(item, x, y, xDelta, yDelta, buttons, modifiers, delay) {
467         if (delay == undefined)
468             delay = -1
469         if (buttons == undefined)
470             buttons = Qt.NoButton
471         if (modifiers === undefined)
472             modifiers = Qt.NoModifier
473         if (xDelta == undefined)
474             xDelta = 0
475         if (yDelta == undefined)
476             yDelta = 0
477         if (!qtest_events.mouseWheel(item, x, y, buttons, modifiers, xDelta, yDelta, delay))
478             qtest_fail("window not shown", 2)
479    }
480
481
482     // Functions that can be overridden in subclasses for init/cleanup duties.
483     function initTestCase() {}
484     function cleanupTestCase() {}
485     function init() {}
486     function cleanup() {}
487
488     function qtest_runInternal(prop, arg) {
489         try {
490             qtest_testCaseResult = testCase[prop](arg)
491         } catch (e) {
492             qtest_testCaseResult = []
493             if (e.message.indexOf("QtQuickTest::") != 0) {
494                 // Test threw an unrecognized exception - fail.
495                 qtest_results.fail("Uncaught exception: " + e.message,
496                              e.fileName, e.lineNumber)
497             }
498         }
499         return !qtest_results.failed
500     }
501
502     function qtest_runFunction(prop, arg) {
503         qtest_runInternal("init")
504         if (!qtest_results.skipped) {
505             qtest_runInternal(prop, arg)
506             qtest_results.finishTestData()
507             qtest_runInternal("cleanup")
508             qtest_results.finishTestDataCleanup()
509         }
510     }
511
512     function qtest_runBenchmarkFunction(prop, arg) {
513         qtest_results.startMeasurement()
514         do {
515             qtest_results.beginDataRun()
516             do {
517                 // Run the initialization function.
518                 qtest_runInternal("init")
519                 if (qtest_results.skipped)
520                     break
521
522                 // Execute the benchmark function.
523                 if (prop.indexOf("benchmark_once_") != 0)
524                     qtest_results.startBenchmark(TestResult.RepeatUntilValidMeasurement, qtest_results.dataTag)
525                 else
526                     qtest_results.startBenchmark(TestResult.RunOnce, qtest_results.dataTag)
527                 while (!qtest_results.isBenchmarkDone()) {
528                     var success = qtest_runInternal(prop, arg)
529                     qtest_results.finishTestData()
530                     if (!success)
531                         break
532                     qtest_results.nextBenchmark()
533                 }
534                 qtest_results.stopBenchmark()
535
536                 // Run the cleanup function.
537                 qtest_runInternal("cleanup")
538                 qtest_results.finishTestDataCleanup()
539             } while (!qtest_results.measurementAccepted())
540             qtest_results.endDataRun()
541         } while (qtest_results.needsMoreMeasurements())
542     }
543
544     function qtest_run() {
545         if (util.printAvailableFunctions) {
546             completed = true
547             return
548         }
549
550         if (TestLogger.log_start_test()) {
551             qtest_results.reset()
552             qtest_results.testCaseName = name
553             qtest_results.startLogging()
554         } else {
555             qtest_results.testCaseName = name
556         }
557         running = true
558
559         // Check the run list to see if this class is mentioned.
560         var functionsToRun = qtest_results.functionsToRun
561         if (functionsToRun.length > 0) {
562             var found = false
563             var list = []
564             if (name.length > 0) {
565                 var prefix = name + "::"
566                 for (var index in functionsToRun) {
567                     if (functionsToRun[index].indexOf(prefix) == 0) {
568                         list.push(functionsToRun[index])
569                         found = true
570                     }
571                 }
572             }
573             if (!found) {
574                 completed = true
575                 if (!TestLogger.log_complete_test(qtest_testId)) {
576                     qtest_results.stopLogging()
577                     Qt.quit()
578                 }
579                 qtest_results.testCaseName = ""
580                 return
581             }
582             functionsToRun = list
583         }
584
585         // Run the initTestCase function.
586         qtest_results.functionName = "initTestCase"
587         var runTests = true
588         if (!qtest_runInternal("initTestCase"))
589             runTests = false
590         qtest_results.finishTestData()
591         qtest_results.finishTestDataCleanup()
592         qtest_results.finishTestFunction()
593
594         // Run the test methods.
595         var testList = []
596         if (runTests) {
597             for (var prop in testCase) {
598                 if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0)
599                     continue
600                 var tail = prop.lastIndexOf("_data");
601                 if (tail != -1 && tail == (prop.length - 5))
602                     continue
603                 testList.push(prop)
604             }
605             testList.sort()
606         }
607         var checkNames = (functionsToRun.length > 0)
608         for (var index in testList) {
609             var prop = testList[index]
610             var datafunc = prop + "_data"
611             var isBenchmark = (prop.indexOf("benchmark_") == 0)
612             if (checkNames) {
613                 var index = functionsToRun.indexOf(name + "::" + prop)
614                 if (index < 0)
615                     continue
616                 functionsToRun.splice(index, 1)
617             }
618             qtest_results.functionName = prop
619
620             if (!(datafunc in testCase))
621                 datafunc = "init_data";
622
623             if (datafunc in testCase) {
624                 if (qtest_runInternal(datafunc)) {
625                     var table = qtest_testCaseResult
626                     var haveData = false
627                     qtest_results.initTestTable()
628                     for (var index in table) {
629                         haveData = true
630                         var row = table[index]
631                         if (!row.tag)
632                             row.tag = "row " + index    // Must have something
633                         qtest_results.dataTag = row.tag
634                         if (isBenchmark)
635                             qtest_runBenchmarkFunction(prop, row)
636                         else
637                             qtest_runFunction(prop, row)
638                         qtest_results.dataTag = ""
639                     }
640                     if (!haveData) {
641                         if (datafunc === "init_data")
642                            qtest_runFunction(prop, null, isBenchmark)
643                         else
644                            qtest_results.warn("no data supplied for " + prop + "() by " + datafunc + "()"
645                                             , util.callerFile(), util.callerLine());
646                     }
647                     qtest_results.clearTestTable()
648                 }
649             } else if (isBenchmark) {
650                 qtest_runBenchmarkFunction(prop, null, isBenchmark)
651             } else {
652                 qtest_runFunction(prop, null, isBenchmark)
653             }
654             qtest_results.finishTestFunction()
655             qtest_results.skipped = false
656         }
657
658         // Run the cleanupTestCase function.
659         qtest_results.skipped = false
660         qtest_results.functionName = "cleanupTestCase"
661         qtest_runInternal("cleanupTestCase")
662
663         // Complain about missing functions that we were supposed to run.
664         if (functionsToRun.length > 0)
665             qtest_results.fail("Could not find functions: " + functionsToRun, "", 0)
666
667         // Clean up and exit.
668         running = false
669         completed = true
670         qtest_results.finishTestData()
671         qtest_results.finishTestDataCleanup()
672         qtest_results.finishTestFunction()
673         qtest_results.functionName = ""
674
675         // Stop if there are no more tests to be run.
676         if (!TestLogger.log_complete_test(qtest_testId)) {
677             qtest_results.stopLogging()
678             Qt.quit()
679         }
680         qtest_results.testCaseName = ""
681     }
682
683     onWhenChanged: {
684         if (when != qtest_prevWhen) {
685             qtest_prevWhen = when
686             if (when && !completed && !running && qtest_componentCompleted)
687                 qtest_run()
688         }
689     }
690
691     onOptionalChanged: {
692         if (!completed) {
693             if (optional)
694                 TestLogger.log_optional_test(qtest_testId)
695             else
696                 TestLogger.log_mandatory_test(qtest_testId)
697         }
698     }
699
700
701     Component.onCompleted: {
702         qtest.hasTestCase = true;
703         qtest_componentCompleted = true;
704
705         if (util.printAvailableFunctions) {
706             var testList = []
707             for (var prop in testCase) {
708                 if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0)
709                     continue
710                 var tail = prop.lastIndexOf("_data");
711                 if (tail != -1 && tail == (prop.length - 5))
712                     continue
713                 // Note: cannot run functions in TestCase elements
714                 // that lack a name.
715                 if (name.length > 0)
716                     testList.push(name + "::" + prop + "()")
717             }
718             testList.sort()
719             for (var index in testList)
720                 console.log(testList[index])
721             return
722         }
723         qtest_testId = TestLogger.log_register_test(name)
724         if (optional)
725             TestLogger.log_optional_test(qtest_testId)
726         qtest_prevWhen = when
727         if (when && !completed && !running)
728             qtest_run()
729     }
730 }