TestCase.qml 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2016 The Qt Company Ltd.
  4. ** Contact: https://www.qt.io/licensing/
  5. **
  6. ** This file is part of the test suite of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and The Qt Company. For licensing terms
  14. ** and conditions see https://www.qt.io/terms-conditions. For further
  15. ** information use the contact form at https://www.qt.io/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 3 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL3 included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 3 requirements
  23. ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
  24. **
  25. ** GNU General Public License Usage
  26. ** Alternatively, this file may be used under the terms of the GNU
  27. ** General Public License version 2.0 or (at your option) the GNU General
  28. ** Public license version 3 or any later version approved by the KDE Free
  29. ** Qt Foundation. The licenses are as published by the Free Software
  30. ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
  31. ** included in the packaging of this file. Please review the following
  32. ** information to ensure the GNU General Public License requirements will
  33. ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
  34. ** https://www.gnu.org/licenses/gpl-3.0.html.
  35. **
  36. ** $QT_END_LICENSE$
  37. **
  38. ****************************************************************************/
  39. import QtQuick 2.0
  40. import QtTest 1.1
  41. import "testlogger.js" as TestLogger
  42. import Qt.test.qtestroot 1.0
  43. /*!
  44. \qmltype TestCase
  45. \inqmlmodule QtTest
  46. \brief Represents a unit test case
  47. \since 4.8
  48. \ingroup qtquicktest
  49. \section1 Introduction to QML test cases
  50. Test cases are written as JavaScript functions within a TestCase
  51. type:
  52. \code
  53. import QtQuick 2.0
  54. import QtTest 1.0
  55. TestCase {
  56. name: "MathTests"
  57. function test_math() {
  58. compare(2 + 2, 4, "2 + 2 = 4")
  59. }
  60. function test_fail() {
  61. compare(2 + 2, 5, "2 + 2 = 5")
  62. }
  63. }
  64. \endcode
  65. Functions whose names start with "test_" are treated as test cases
  66. to be executed. The \l name property is used to prefix the functions
  67. in the output:
  68. \code
  69. ********* Start testing of MathTests *********
  70. Config: Using QTest library 4.7.2, Qt 4.7.2
  71. PASS : MathTests::initTestCase()
  72. FAIL! : MathTests::test_fail() 2 + 2 = 5
  73. Actual (): 4
  74. Expected (): 5
  75. Loc: [/home/.../tst_math.qml(12)]
  76. PASS : MathTests::test_math()
  77. PASS : MathTests::cleanupTestCase()
  78. Totals: 3 passed, 1 failed, 0 skipped
  79. ********* Finished testing of MathTests *********
  80. \endcode
  81. Because of the way JavaScript properties work, the order in which the
  82. test functions are found is unpredictable. To assist with predictability,
  83. the test framework will sort the functions on ascending order of name.
  84. This can help when there are two tests that must be run in order.
  85. Multiple TestCase types can be supplied. The test program will exit
  86. once they have all completed. If a test case doesn't need to run
  87. (because a precondition has failed), then \l optional can be set to true.
  88. \section1 Data-driven tests
  89. Table data can be provided to a test using a function name that ends
  90. with "_data". Alternatively, the \c init_data() function can be used
  91. to provide default test data for all test functions in a TestCase type:
  92. \code
  93. import QtQuick 2.0
  94. import QtTest 1.1
  95. TestCase {
  96. name: "DataTests"
  97. function init_data() {
  98. return [
  99. {tag:"init_data_1", a:1, b:2, answer: 3},
  100. {tag:"init_data_2", a:2, b:4, answer: 6}
  101. ];
  102. }
  103. function test_table_data() {
  104. return [
  105. {tag: "2 + 2 = 4", a: 2, b: 2, answer: 4 },
  106. {tag: "2 + 6 = 8", a: 2, b: 6, answer: 8 },
  107. ]
  108. }
  109. function test_table(data) {
  110. //data comes from test_table_data
  111. compare(data.a + data.b, data.answer)
  112. }
  113. function test__default_table(data) {
  114. //data comes from init_data
  115. compare(data.a + data.b, data.answer)
  116. }
  117. }
  118. \endcode
  119. The test framework will iterate over all of the rows in the table
  120. and pass each row to the test function. As shown, the columns can be
  121. extracted for use in the test. The \c tag column is special - it is
  122. printed by the test framework when a row fails, to help the reader
  123. identify which case failed amongst a set of otherwise passing tests.
  124. \section1 Benchmarks
  125. Functions whose names start with "benchmark_" will be run multiple
  126. times with the Qt benchmark framework, with an average timing value
  127. reported for the runs. This is equivalent to using the \c{QBENCHMARK}
  128. macro in the C++ version of QTestLib.
  129. \code
  130. TestCase {
  131. id: top
  132. name: "CreateBenchmark"
  133. function benchmark_create_component() {
  134. var component = Qt.createComponent("item.qml")
  135. var obj = component.createObject(top)
  136. obj.destroy()
  137. component.destroy()
  138. }
  139. }
  140. RESULT : CreateBenchmark::benchmark_create_component:
  141. 0.23 msecs per iteration (total: 60, iterations: 256)
  142. PASS : CreateBenchmark::benchmark_create_component()
  143. \endcode
  144. To get the effect of the \c{QBENCHMARK_ONCE} macro, prefix the test
  145. function name with "benchmark_once_".
  146. \section1 Simulating keyboard and mouse events
  147. The keyPress(), keyRelease(), and keyClick() methods can be used
  148. to simulate keyboard events within unit tests. The events are
  149. delivered to the currently focused QML item. You can pass either
  150. a Qt.Key enum value or a latin1 char (string of length one)
  151. \code
  152. Rectangle {
  153. width: 50; height: 50
  154. focus: true
  155. TestCase {
  156. name: "KeyClick"
  157. when: windowShown
  158. function test_key_click() {
  159. keyClick(Qt.Key_Left)
  160. keyClick("a")
  161. ...
  162. }
  163. }
  164. }
  165. \endcode
  166. The mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence()
  167. and mouseMove() methods can be used to simulate mouse events in a
  168. similar fashion.
  169. \b{Note:} keyboard and mouse events can only be delivered once the
  170. main window has been shown. Attempts to deliver events before then
  171. will fail. Use the \l when and windowShown properties to track
  172. when the main window has been shown.
  173. \sa {QtTest::SignalSpy}{SignalSpy}, {Qt Quick Test Reference Documentation}
  174. */
  175. Item {
  176. id: testCase
  177. visible: false
  178. TestUtil {
  179. id:util
  180. }
  181. /*!
  182. \qmlproperty string TestCase::name
  183. This property defines the name of the test case for result reporting.
  184. The default is the empty string.
  185. \code
  186. TestCase {
  187. name: "ButtonTests"
  188. ...
  189. }
  190. \endcode
  191. */
  192. property string name
  193. /*!
  194. \qmlproperty bool TestCase::when
  195. This property should be set to true when the application wants
  196. the test cases to run. The default value is true. In the following
  197. example, a test is run when the user presses the mouse button:
  198. \code
  199. Rectangle {
  200. id: foo
  201. width: 640; height: 480
  202. color: "cyan"
  203. MouseArea {
  204. id: area
  205. anchors.fill: parent
  206. }
  207. property bool bar: true
  208. TestCase {
  209. name: "ItemTests"
  210. when: area.pressed
  211. id: test1
  212. function test_bar() {
  213. verify(bar)
  214. }
  215. }
  216. }
  217. \endcode
  218. The test application will exit once all \l TestCase types
  219. have been triggered and have run. The \l optional property can
  220. be used to exclude a \l TestCase type.
  221. \sa optional, completed
  222. */
  223. property bool when: true
  224. /*!
  225. \qmlproperty bool TestCase::completed
  226. This property will be set to true once the test case has completed
  227. execution. Test cases are only executed once. The initial value
  228. is false.
  229. \sa running, when
  230. */
  231. property bool completed: false
  232. /*!
  233. \qmlproperty bool TestCase::running
  234. This property will be set to true while the test case is running.
  235. The initial value is false, and the value will become false again
  236. once the test case completes.
  237. \sa completed, when
  238. */
  239. property bool running: false
  240. /*!
  241. \qmlproperty bool TestCase::optional
  242. Multiple \l TestCase types can be supplied in a test application.
  243. The application will exit once they have all completed. If a test case
  244. does not need to run (because a precondition has failed), then this
  245. property can be set to true. The default value is false.
  246. \code
  247. TestCase {
  248. when: false
  249. optional: true
  250. function test_not_run() {
  251. verify(false)
  252. }
  253. }
  254. \endcode
  255. \sa when, completed
  256. */
  257. property bool optional: false
  258. /*!
  259. \qmlproperty bool TestCase::windowShown
  260. This property will be set to true after the QML viewing window has
  261. been displayed. Normally test cases run as soon as the test application
  262. is loaded and before a window is displayed. If the test case involves
  263. visual types and behaviors, then it may need to be delayed until
  264. after the window is shown.
  265. \code
  266. Button {
  267. id: button
  268. onClicked: text = "Clicked"
  269. TestCase {
  270. name: "ClickTest"
  271. when: windowShown
  272. function test_click() {
  273. button.clicked();
  274. compare(button.text, "Clicked");
  275. }
  276. }
  277. }
  278. \endcode
  279. */
  280. property bool windowShown: QTestRootObject.windowShown
  281. // Internal private state. Identifiers prefixed with qtest are reserved.
  282. /*! \internal */
  283. property bool qtest_prevWhen: true
  284. /*! \internal */
  285. property int qtest_testId: -1
  286. /*! \internal */
  287. property bool qtest_componentCompleted : false
  288. /*! \internal */
  289. property var qtest_testCaseResult
  290. /*! \internal */
  291. property var qtest_results: qtest_results_normal
  292. /*! \internal */
  293. TestResult { id: qtest_results_normal }
  294. /*! \internal */
  295. property var qtest_events: qtest_events_normal
  296. TestEvent { id: qtest_events_normal }
  297. /*!
  298. \qmlmethod TestCase::fail(message = "")
  299. Fails the current test case, with the optional \a message.
  300. Similar to \c{QFAIL(message)} in C++.
  301. */
  302. function fail(msg) {
  303. if (msg === undefined)
  304. msg = "";
  305. qtest_results.fail(msg, util.callerFile(), util.callerLine())
  306. throw new Error("QtQuickTest::fail")
  307. }
  308. /*! \internal */
  309. function qtest_fail(msg, frame) {
  310. if (msg === undefined)
  311. msg = "";
  312. qtest_results.fail(msg, util.callerFile(frame), util.callerLine(frame))
  313. throw new Error("QtQuickTest::fail")
  314. }
  315. /*!
  316. \qmlmethod TestCase::verify(condition, message = "")
  317. Fails the current test case if \a condition is false, and
  318. displays the optional \a message. Similar to \c{QVERIFY(condition)}
  319. or \c{QVERIFY2(condition, message)} in C++.
  320. */
  321. function verify(cond, msg) {
  322. if (msg === undefined)
  323. msg = "";
  324. if (!qtest_results.verify(cond, msg, util.callerFile(), util.callerLine()))
  325. throw new Error("QtQuickTest::fail")
  326. }
  327. /*! \internal */
  328. // Determine what is o.
  329. // Discussions and reference: http://philrathe.com/articles/equiv
  330. // Test suites: http://philrathe.com/tests/equiv
  331. // Author: Philippe Rathé <prathe@gmail.com>
  332. function qtest_typeof(o) {
  333. if (typeof o === "undefined") {
  334. return "undefined";
  335. // consider: typeof null === object
  336. } else if (o === null) {
  337. return "null";
  338. } else if (o.constructor === String) {
  339. return "string";
  340. } else if (o.constructor === Boolean) {
  341. return "boolean";
  342. } else if (o.constructor === Number) {
  343. if (isNaN(o)) {
  344. return "nan";
  345. } else {
  346. return "number";
  347. }
  348. // consider: typeof [] === object
  349. } else if (o instanceof Array) {
  350. return "array";
  351. // consider: typeof new Date() === object
  352. } else if (o instanceof Date) {
  353. return "date";
  354. // consider: /./ instanceof Object;
  355. // /./ instanceof RegExp;
  356. // typeof /./ === "function"; // => false in IE and Opera,
  357. // true in FF and Safari
  358. } else if (o instanceof RegExp) {
  359. return "regexp";
  360. } else if (typeof o === "object") {
  361. if ("mapFromItem" in o && "mapToItem" in o) {
  362. return "declarativeitem"; // @todo improve detection of declarative items
  363. } else if ("x" in o && "y" in o && "z" in o) {
  364. return "vector3d"; // Qt 3D vector
  365. }
  366. return "object";
  367. } else if (o instanceof Function) {
  368. return "function";
  369. } else {
  370. return undefined;
  371. }
  372. }
  373. /*! \internal */
  374. // Test for equality
  375. // Large parts contain sources from QUnit or http://philrathe.com
  376. // Discussions and reference: http://philrathe.com/articles/equiv
  377. // Test suites: http://philrathe.com/tests/equiv
  378. // Author: Philippe Rathé <prathe@gmail.com>
  379. function qtest_compareInternal(act, exp) {
  380. var success = false;
  381. if (act === exp) {
  382. success = true; // catch the most you can
  383. } else if (act === null || exp === null || typeof act === "undefined" || typeof exp === "undefined") {
  384. success = false; // don't lose time with error prone cases
  385. } else {
  386. var typeExp = qtest_typeof(exp), typeAct = qtest_typeof(act)
  387. if (typeExp !== typeAct) {
  388. // allow object vs string comparison (e.g. for colors)
  389. // else break on different types
  390. if ((typeExp === "string" && (typeAct === "object") || typeAct == "declarativeitem")
  391. || ((typeExp === "object" || typeExp == "declarativeitem") && typeAct === "string")) {
  392. success = (act == exp)
  393. }
  394. } else if (typeExp === "string" || typeExp === "boolean" ||
  395. typeExp === "null" || typeExp === "undefined") {
  396. if (exp instanceof act.constructor || act instanceof exp.constructor) {
  397. // to catch short annotaion VS 'new' annotation of act declaration
  398. // e.g. var i = 1;
  399. // var j = new Number(1);
  400. success = (act == exp)
  401. } else {
  402. success = (act === exp)
  403. }
  404. } else if (typeExp === "nan") {
  405. success = isNaN(act);
  406. } else if (typeExp === "number") {
  407. // Use act fuzzy compare if the two values are floats
  408. if (Math.abs(act - exp) <= 0.00001) {
  409. success = true
  410. }
  411. } else if (typeExp === "array") {
  412. success = qtest_compareInternalArrays(act, exp)
  413. } else if (typeExp === "object") {
  414. success = qtest_compareInternalObjects(act, exp)
  415. } else if (typeExp === "declarativeitem") {
  416. success = qtest_compareInternalObjects(act, exp) // @todo improve comparison of declarative items
  417. } else if (typeExp === "vector3d") {
  418. success = (Math.abs(act.x - exp.x) <= 0.00001 &&
  419. Math.abs(act.y - exp.y) <= 0.00001 &&
  420. Math.abs(act.z - exp.z) <= 0.00001)
  421. } else if (typeExp === "date") {
  422. success = (act.valueOf() === exp.valueOf())
  423. } else if (typeExp === "regexp") {
  424. success = (act.source === exp.source && // the regex itself
  425. act.global === exp.global && // and its modifers (gmi) ...
  426. act.ignoreCase === exp.ignoreCase &&
  427. act.multiline === exp.multiline)
  428. }
  429. }
  430. return success
  431. }
  432. /*! \internal */
  433. function qtest_compareInternalObjects(act, exp) {
  434. var i;
  435. var eq = true; // unless we can proove it
  436. var aProperties = [], bProperties = []; // collection of strings
  437. // comparing constructors is more strict than using instanceof
  438. if (act.constructor !== exp.constructor) {
  439. return false;
  440. }
  441. for (i in act) { // be strict: don't ensures hasOwnProperty and go deep
  442. aProperties.push(i); // collect act's properties
  443. if (!qtest_compareInternal(act[i], exp[i])) {
  444. eq = false;
  445. break;
  446. }
  447. }
  448. for (i in exp) {
  449. bProperties.push(i); // collect exp's properties
  450. }
  451. // Ensures identical properties name
  452. return eq && qtest_compareInternal(aProperties.sort(), bProperties.sort());
  453. }
  454. /*! \internal */
  455. function qtest_compareInternalArrays(actual, expected) {
  456. if (actual.length != expected.length) {
  457. return false
  458. }
  459. for (var i = 0, len = actual.length; i < len; i++) {
  460. if (!qtest_compareInternal(actual[i], expected[i])) {
  461. return false
  462. }
  463. }
  464. return true
  465. }
  466. /*!
  467. \qmlmethod TestCase::compare(actual, expected, message = "")
  468. Fails the current test case if \a actual is not the same as
  469. \a expected, and displays the optional \a message. Similar
  470. to \c{QCOMPARE(actual, expected)} in C++.
  471. \sa tryCompare(), fuzzyCompare
  472. */
  473. function compare(actual, expected, msg) {
  474. var act = qtest_results.stringify(actual)
  475. var exp = qtest_results.stringify(expected)
  476. var success = qtest_compareInternal(actual, expected)
  477. if (msg === undefined) {
  478. if (success)
  479. msg = "COMPARE()"
  480. else
  481. msg = "Compared values are not the same"
  482. }
  483. if (!qtest_results.compare(success, msg, act, exp, util.callerFile(), util.callerLine())) {
  484. throw new Error("QtQuickTest::fail")
  485. }
  486. }
  487. /*!
  488. \qmlmethod TestCase::fuzzyCompare(actual, expected, delta, message = "")
  489. Fails the current test case if the difference betwen \a actual and \a expected
  490. is greater than \a delta, and displays the optional \a message. Similar
  491. to \c{qFuzzyCompare(actual, expected)} in C++ but with a required \a delta value.
  492. This function can also be used for color comparisons if both the \a actual and
  493. \a expected values can be converted into color values. If any of the differences
  494. for RGBA channel values are greater than \a delta, the test fails.
  495. \sa tryCompare(), compare()
  496. */
  497. function fuzzyCompare(actual, expected, delta, msg) {
  498. if (delta === undefined)
  499. qtest_fail("A delta value is required for fuzzyCompare", 2)
  500. var success = qtest_results.fuzzyCompare(actual, expected, delta)
  501. if (msg === undefined) {
  502. if (success)
  503. msg = "FUZZYCOMPARE()"
  504. else
  505. msg = "Compared values are not the same with delta(" + delta + ")"
  506. }
  507. if (!qtest_results.compare(success, msg, actual, expected, util.callerFile(), util.callerLine())) {
  508. throw new Error("QtQuickTest::fail")
  509. }
  510. }
  511. /*!
  512. \qmlmethod object TestCase::grabImage(item)
  513. Returns a snapshot image object of the given \a item.
  514. The returned image object has the following methods:
  515. \list
  516. \li red(x, y) Returns the red channel value of the pixel at \a x, \a y position
  517. \li green(x, y) Returns the green channel value of the pixel at \a x, \a y position
  518. \li blue(x, y) Returns the blue channel value of the pixel at \a x, \a y position
  519. \li alpha(x, y) Returns the alpha channel value of the pixel at \a x, \a y position
  520. \li pixel(x, y) Returns the color value of the pixel at \a x, \a y position
  521. \li equals(image) Returns \c true if this image is identical to \a image -
  522. see \l QImage::operator== (since 5.6)
  523. For example:
  524. \code
  525. var image = grabImage(rect);
  526. compare(image.red(10, 10), 255);
  527. compare(image.pixel(20, 20), Qt.rgba(255, 0, 0, 255));
  528. rect.width += 10;
  529. var newImage = grabImage(rect);
  530. verify(!newImage.equals(image));
  531. \endcode
  532. \endlist
  533. \sa
  534. */
  535. function grabImage(item) {
  536. return qtest_results.grabImage(item);
  537. }
  538. /*!
  539. \since 5.4
  540. \qmlmethod QtObject TestCase::findChild(parent, objectName)
  541. Returns the first child of \a parent with \a objectName, or \c null if
  542. no such item exists. Both visual and non-visual children are searched
  543. recursively, with visual children being searched first.
  544. \code
  545. compare(findChild(item, "childObject"), expectedChildObject);
  546. \endcode
  547. */
  548. function findChild(parent, objectName) {
  549. // First, search the visual item hierarchy.
  550. var child = qtest_findVisualChild(parent, objectName);
  551. if (child)
  552. return child;
  553. // If it's not a visual child, it might be a QObject child.
  554. return qtest_results.findChild(parent, objectName);
  555. }
  556. /*! \internal */
  557. function qtest_findVisualChild(parent, objectName) {
  558. if (!parent || parent.children === undefined)
  559. return null;
  560. for (var i = 0; i < parent.children.length; ++i) {
  561. // Is this direct child of ours the child we're after?
  562. var child = parent.children[i];
  563. if (child.objectName === objectName)
  564. return child;
  565. }
  566. for (i = 0; i < parent.children.length; ++i) {
  567. // Try the direct child's children.
  568. child = qtest_findVisualChild(parent.children[i], objectName);
  569. if (child)
  570. return child;
  571. }
  572. return null;
  573. }
  574. /*!
  575. \qmlmethod TestCase::tryCompare(obj, property, expected, timeout = 5000, message = "")
  576. Fails the current test case if the specified \a property on \a obj
  577. is not the same as \a expected, and displays the optional \a message.
  578. The test will be retried multiple times until the
  579. \a timeout (in milliseconds) is reached.
  580. This function is intended for testing applications where a property
  581. changes value based on asynchronous events. Use compare() for testing
  582. synchronous property changes.
  583. \code
  584. tryCompare(img, "status", BorderImage.Ready)
  585. compare(img.width, 120)
  586. compare(img.height, 120)
  587. compare(img.horizontalTileMode, BorderImage.Stretch)
  588. compare(img.verticalTileMode, BorderImage.Stretch)
  589. \endcode
  590. SignalSpy::wait() provides an alternative method to wait for a
  591. signal to be emitted.
  592. \sa compare(), SignalSpy::wait()
  593. */
  594. function tryCompare(obj, prop, value, timeout, msg) {
  595. if (arguments.length == 2) {
  596. qtest_results.fail("A value is required for tryCompare",
  597. util.callerFile(), util.callerLine())
  598. throw new Error("QtQuickTest::fail")
  599. }
  600. if (timeout !== undefined && typeof(timeout) != "number") {
  601. qtest_results.fail("timeout should be a number",
  602. util.callerFile(), util.callerLine())
  603. throw new Error("QtQuickTest::fail")
  604. }
  605. if (!timeout)
  606. timeout = 5000
  607. if (msg === undefined)
  608. msg = "property " + prop
  609. if (!qtest_compareInternal(obj[prop], value))
  610. wait(0)
  611. var i = 0
  612. while (i < timeout && !qtest_compareInternal(obj[prop], value)) {
  613. wait(50)
  614. i += 50
  615. }
  616. var actual = obj[prop]
  617. var act = qtest_results.stringify(actual)
  618. var exp = qtest_results.stringify(value)
  619. var success = qtest_compareInternal(actual, value)
  620. if (!qtest_results.compare(success, msg, act, exp, util.callerFile(), util.callerLine()))
  621. throw new Error("QtQuickTest::fail")
  622. }
  623. /*!
  624. \qmlmethod TestCase::skip(message = "")
  625. Skips the current test case and prints the optional \a message.
  626. If this is a data-driven test, then only the current row is skipped.
  627. Similar to \c{QSKIP(message)} in C++.
  628. */
  629. function skip(msg) {
  630. if (msg === undefined)
  631. msg = ""
  632. qtest_results.skip(msg, util.callerFile(), util.callerLine())
  633. throw new Error("QtQuickTest::skip")
  634. }
  635. /*!
  636. \qmlmethod TestCase::expectFail(tag, message)
  637. In a data-driven test, marks the row associated with \a tag as
  638. expected to fail. When the fail occurs, display the \a message,
  639. abort the test, and mark the test as passing. Similar to
  640. \c{QEXPECT_FAIL(tag, message, Abort)} in C++.
  641. If the test is not data-driven, then \a tag must be set to
  642. the empty string.
  643. \sa expectFailContinue()
  644. */
  645. function expectFail(tag, msg) {
  646. if (tag === undefined) {
  647. warn("tag argument missing from expectFail()")
  648. tag = ""
  649. }
  650. if (msg === undefined) {
  651. warn("message argument missing from expectFail()")
  652. msg = ""
  653. }
  654. if (!qtest_results.expectFail(tag, msg, util.callerFile(), util.callerLine()))
  655. throw new Error("QtQuickTest::expectFail")
  656. }
  657. /*!
  658. \qmlmethod TestCase::expectFailContinue(tag, message)
  659. In a data-driven test, marks the row associated with \a tag as
  660. expected to fail. When the fail occurs, display the \a message,
  661. and then continue the test. Similar to
  662. \c{QEXPECT_FAIL(tag, message, Continue)} in C++.
  663. If the test is not data-driven, then \a tag must be set to
  664. the empty string.
  665. \sa expectFail()
  666. */
  667. function expectFailContinue(tag, msg) {
  668. if (tag === undefined) {
  669. warn("tag argument missing from expectFailContinue()")
  670. tag = ""
  671. }
  672. if (msg === undefined) {
  673. warn("message argument missing from expectFailContinue()")
  674. msg = ""
  675. }
  676. if (!qtest_results.expectFailContinue(tag, msg, util.callerFile(), util.callerLine()))
  677. throw new Error("QtQuickTest::expectFail")
  678. }
  679. /*!
  680. \qmlmethod TestCase::warn(message)
  681. Prints \a message as a warning message. Similar to
  682. \c{QWARN(message)} in C++.
  683. \sa ignoreWarning()
  684. */
  685. function warn(msg) {
  686. if (msg === undefined)
  687. msg = ""
  688. qtest_results.warn(msg, util.callerFile(), util.callerLine());
  689. }
  690. /*!
  691. \qmlmethod TestCase::ignoreWarning(message)
  692. Marks \a message as an ignored warning message. When it occurs,
  693. the warning will not be printed and the test passes. If the message
  694. does not occur, then the test will fail. Similar to
  695. \c{QTest::ignoreMessage(QtWarningMsg, message)} in C++.
  696. \sa warn()
  697. */
  698. function ignoreWarning(msg) {
  699. if (msg === undefined)
  700. msg = ""
  701. qtest_results.ignoreWarning(msg)
  702. }
  703. /*!
  704. \qmlmethod TestCase::wait(ms)
  705. Waits for \a ms milliseconds while processing Qt events.
  706. \sa sleep(), waitForRendering()
  707. */
  708. function wait(ms) {
  709. qtest_results.wait(ms)
  710. }
  711. /*!
  712. \qmlmethod TestCase::waitForRendering(item, timeout = 5000)
  713. Waits for \a timeout milliseconds or until the \a item is rendered by the renderer.
  714. Returns true if \c item is rendered in \a timeout milliseconds, otherwise returns false.
  715. The default \a timeout value is 5000.
  716. \sa sleep(), wait()
  717. */
  718. function waitForRendering(item, timeout) {
  719. if (timeout === undefined)
  720. timeout = 5000
  721. if (!item)
  722. qtest_fail("No item given to waitForRendering", 1)
  723. return qtest_results.waitForRendering(item, timeout)
  724. }
  725. /*!
  726. \qmlmethod TestCase::sleep(ms)
  727. Sleeps for \a ms milliseconds without processing Qt events.
  728. \sa wait(), waitForRendering()
  729. */
  730. function sleep(ms) {
  731. qtest_results.sleep(ms)
  732. }
  733. /*!
  734. \qmlmethod TestCase::keyPress(key, modifiers = Qt.NoModifier, delay = -1)
  735. Simulates pressing a \a key with an optional \a modifier on the currently
  736. focused item. If \a delay is larger than 0, the test will wait for
  737. \a delay milliseconds.
  738. The event will be sent to the TestCase window or, in case of multiple windows,
  739. to the current active window. See \l QGuiApplication::focusWindow() for more details.
  740. \b{Note:} At some point you should release the key using keyRelease().
  741. \sa keyRelease(), keyClick()
  742. */
  743. function keyPress(key, modifiers, delay) {
  744. if (modifiers === undefined)
  745. modifiers = Qt.NoModifier
  746. if (delay == undefined)
  747. delay = -1
  748. if (typeof(key) == "string" && key.length == 1) {
  749. if (!qtest_events.keyPressChar(key, modifiers, delay))
  750. qtest_fail("window not shown", 2)
  751. } else {
  752. if (!qtest_events.keyPress(key, modifiers, delay))
  753. qtest_fail("window not shown", 2)
  754. }
  755. }
  756. /*!
  757. \qmlmethod TestCase::keyRelease(key, modifiers = Qt.NoModifier, delay = -1)
  758. Simulates releasing a \a key with an optional \a modifier on the currently
  759. focused item. If \a delay is larger than 0, the test will wait for
  760. \a delay milliseconds.
  761. The event will be sent to the TestCase window or, in case of multiple windows,
  762. to the current active window. See \l QGuiApplication::focusWindow() for more details.
  763. \sa keyPress(), keyClick()
  764. */
  765. function keyRelease(key, modifiers, delay) {
  766. if (modifiers === undefined)
  767. modifiers = Qt.NoModifier
  768. if (delay == undefined)
  769. delay = -1
  770. if (typeof(key) == "string" && key.length == 1) {
  771. if (!qtest_events.keyReleaseChar(key, modifiers, delay))
  772. qtest_fail("window not shown", 2)
  773. } else {
  774. if (!qtest_events.keyRelease(key, modifiers, delay))
  775. qtest_fail("window not shown", 2)
  776. }
  777. }
  778. /*!
  779. \qmlmethod TestCase::keyClick(key, modifiers = Qt.NoModifier, delay = -1)
  780. Simulates clicking of \a key with an optional \a modifier on the currently
  781. focused item. If \a delay is larger than 0, the test will wait for
  782. \a delay milliseconds.
  783. The event will be sent to the TestCase window or, in case of multiple windows,
  784. to the current active window. See \l QGuiApplication::focusWindow() for more details.
  785. \sa keyPress(), keyRelease()
  786. */
  787. function keyClick(key, modifiers, delay) {
  788. if (modifiers === undefined)
  789. modifiers = Qt.NoModifier
  790. if (delay == undefined)
  791. delay = -1
  792. if (typeof(key) == "string" && key.length == 1) {
  793. if (!qtest_events.keyClickChar(key, modifiers, delay))
  794. qtest_fail("window not shown", 2)
  795. } else {
  796. if (!qtest_events.keyClick(key, modifiers, delay))
  797. qtest_fail("window not shown", 2)
  798. }
  799. }
  800. /*!
  801. \qmlmethod TestCase::mousePress(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  802. Simulates pressing a mouse \a button with an optional \a modifier
  803. on an \a item. The position is defined by \a x and \a y.
  804. If \a x or \a y are not defined the position will be the center of \a item.
  805. If \a delay is specified, the test will wait for the specified amount of
  806. milliseconds before the press.
  807. The position given by \a x and \a y is transformed from the co-ordinate
  808. system of \a item into window co-ordinates and then delivered.
  809. If \a item is obscured by another item, or a child of \a item occupies
  810. that position, then the event will be delivered to the other item instead.
  811. \sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
  812. */
  813. function mousePress(item, x, y, button, modifiers, delay) {
  814. if (!item)
  815. qtest_fail("No item given to mousePress", 1)
  816. if (button === undefined)
  817. button = Qt.LeftButton
  818. if (modifiers === undefined)
  819. modifiers = Qt.NoModifier
  820. if (delay == undefined)
  821. delay = -1
  822. if (x === undefined)
  823. x = item.width / 2
  824. if (y === undefined)
  825. y = item.height / 2
  826. if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
  827. qtest_fail("window not shown", 2)
  828. }
  829. /*!
  830. \qmlmethod TestCase::mouseRelease(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  831. Simulates releasing a mouse \a button with an optional \a modifier
  832. on an \a item. The position of the release is defined by \a x and \a y.
  833. If \a x or \a y are not defined the position will be the center of \a item.
  834. If \a delay is specified, the test will wait for the specified amount of
  835. milliseconds before releasing the button.
  836. The position given by \a x and \a y is transformed from the co-ordinate
  837. system of \a item into window co-ordinates and then delivered.
  838. If \a item is obscured by another item, or a child of \a item occupies
  839. that position, then the event will be delivered to the other item instead.
  840. \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
  841. */
  842. function mouseRelease(item, x, y, button, modifiers, delay) {
  843. if (!item)
  844. qtest_fail("No item given to mouseRelease", 1)
  845. if (button === undefined)
  846. button = Qt.LeftButton
  847. if (modifiers === undefined)
  848. modifiers = Qt.NoModifier
  849. if (delay == undefined)
  850. delay = -1
  851. if (x === undefined)
  852. x = item.width / 2
  853. if (y === undefined)
  854. y = item.height / 2
  855. if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
  856. qtest_fail("window not shown", 2)
  857. }
  858. /*!
  859. \qmlmethod TestCase::mouseDrag(item, x, y, dx, dy, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  860. Simulates dragging the mouse on an \a item with \a button pressed and an optional \a modifier.
  861. The initial drag position is defined by \a x and \a y,
  862. and drag distance is defined by \a dx and \a dy. If \a delay is specified,
  863. the test will wait for the specified amount of milliseconds before releasing the button.
  864. The position given by \a x and \a y is transformed from the co-ordinate
  865. system of \a item into window co-ordinates and then delivered.
  866. If \a item is obscured by another item, or a child of \a item occupies
  867. that position, then the event will be delivered to the other item instead.
  868. Note: this method does not imply a drop action, to make a drop, an additional
  869. mouseRelease(item, x + dx, y + dy) is needed.
  870. \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseWheel()
  871. */
  872. function mouseDrag(item, x, y, dx, dy, button, modifiers, delay) {
  873. if (!item)
  874. qtest_fail("No item given to mouseDrag", 1)
  875. if (item.x === undefined || item.y === undefined)
  876. return
  877. if (button === undefined)
  878. button = Qt.LeftButton
  879. if (modifiers === undefined)
  880. modifiers = Qt.NoModifier
  881. if (delay == undefined)
  882. delay = -1
  883. var moveDelay = Math.max(1, delay === -1 ? qtest_events.defaultMouseDelay : delay)
  884. // Divide dx and dy to have intermediate mouseMove while dragging
  885. // Fractions of dx/dy need be superior to the dragThreshold
  886. // to make the drag works though
  887. var ddx = Math.round(dx/3)
  888. if (ddx < (util.dragThreshold + 1))
  889. ddx = 0
  890. var ddy = Math.round(dy/3)
  891. if (ddy < (util.dragThreshold + 1))
  892. ddy = 0
  893. mousePress(item, x, y, button, modifiers, delay)
  894. //trigger dragging
  895. mouseMove(item, x + util.dragThreshold + 1, y + util.dragThreshold + 1, moveDelay, button)
  896. if (ddx > 0 || ddy > 0) {
  897. mouseMove(item, x + ddx, y + ddy, moveDelay, button)
  898. mouseMove(item, x + 2*ddx, y + 2*ddy, moveDelay, button)
  899. }
  900. mouseMove(item, x + dx, y + dy, moveDelay, button)
  901. mouseRelease(item, x + dx, y + dy, button, modifiers, delay)
  902. }
  903. /*!
  904. \qmlmethod TestCase::mouseClick(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  905. Simulates clicking a mouse \a button with an optional \a modifier
  906. on an \a item. The position of the click is defined by \a x and \a y.
  907. If \a x and \a y are not defined the position will be the center of \a item.
  908. If \a delay is specified, the test will wait for the specified amount of
  909. milliseconds before pressing and before releasing the button.
  910. The position given by \a x and \a y is transformed from the co-ordinate
  911. system of \a item into window co-ordinates and then delivered.
  912. If \a item is obscured by another item, or a child of \a item occupies
  913. that position, then the event will be delivered to the other item instead.
  914. \sa mousePress(), mouseRelease(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
  915. */
  916. function mouseClick(item, x, y, button, modifiers, delay) {
  917. if (!item)
  918. qtest_fail("No item given to mouseClick", 1)
  919. if (button === undefined)
  920. button = Qt.LeftButton
  921. if (modifiers === undefined)
  922. modifiers = Qt.NoModifier
  923. if (delay == undefined)
  924. delay = -1
  925. if (x === undefined)
  926. x = item.width / 2
  927. if (y === undefined)
  928. y = item.height / 2
  929. if (!qtest_events.mouseClick(item, x, y, button, modifiers, delay))
  930. qtest_fail("window not shown", 2)
  931. }
  932. /*!
  933. \qmlmethod TestCase::mouseDoubleClick(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  934. Simulates double-clicking a mouse \a button with an optional \a modifier
  935. on an \a item. The position of the click is defined by \a x and \a y.
  936. If \a x and \a y are not defined the position will be the center of \a item.
  937. If \a delay is specified, the test will wait for the specified amount of
  938. milliseconds before pressing and before releasing the button.
  939. The position given by \a x and \a y is transformed from the co-ordinate
  940. system of \a item into window co-ordinates and then delivered.
  941. If \a item is obscured by another item, or a child of \a item occupies
  942. that position, then the event will be delivered to the other item instead.
  943. \sa mouseDoubleClickSequence(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel()
  944. */
  945. function mouseDoubleClick(item, x, y, button, modifiers, delay) {
  946. if (!item)
  947. qtest_fail("No item given to mouseDoubleClick", 1)
  948. if (button === undefined)
  949. button = Qt.LeftButton
  950. if (modifiers === undefined)
  951. modifiers = Qt.NoModifier
  952. if (delay == undefined)
  953. delay = -1
  954. if (x === undefined)
  955. x = item.width / 2
  956. if (y === undefined)
  957. y = item.height / 2
  958. if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
  959. qtest_fail("window not shown", 2)
  960. }
  961. /*!
  962. \qmlmethod TestCase::mouseDoubleClickSequence(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  963. Simulates the full sequence of events generated by double-clicking a mouse
  964. \a button with an optional \a modifier on an \a item.
  965. This method reproduces the sequence of mouse events generated when a user makes
  966. a double click: Press-Release-Press-DoubleClick-Release.
  967. The position of the click is defined by \a x and \a y.
  968. If \a x and \a y are not defined the position will be the center of \a item.
  969. If \a delay is specified, the test will wait for the specified amount of
  970. milliseconds before pressing and before releasing the button.
  971. The position given by \a x and \a y is transformed from the co-ordinate
  972. system of \a item into window co-ordinates and then delivered.
  973. If \a item is obscured by another item, or a child of \a item occupies
  974. that position, then the event will be delivered to the other item instead.
  975. This QML method was introduced in Qt 5.5.
  976. \sa mouseDoubleClick(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel()
  977. */
  978. function mouseDoubleClickSequence(item, x, y, button, modifiers, delay) {
  979. if (!item)
  980. qtest_fail("No item given to mouseDoubleClickSequence", 1)
  981. if (button === undefined)
  982. button = Qt.LeftButton
  983. if (modifiers === undefined)
  984. modifiers = Qt.NoModifier
  985. if (delay == undefined)
  986. delay = -1
  987. if (x === undefined)
  988. x = item.width / 2
  989. if (y === undefined)
  990. y = item.height / 2
  991. if (!qtest_events.mouseDoubleClickSequence(item, x, y, button, modifiers, delay))
  992. qtest_fail("window not shown", 2)
  993. }
  994. /*!
  995. \qmlmethod TestCase::mouseMove(item, x, y, delay = -1)
  996. Moves the mouse pointer to the position given by \a x and \a y within
  997. \a item. If a \a delay (in milliseconds) is given, the test will wait
  998. before moving the mouse pointer.
  999. The position given by \a x and \a y is transformed from the co-ordinate
  1000. system of \a item into window co-ordinates and then delivered.
  1001. If \a item is obscured by another item, or a child of \a item occupies
  1002. that position, then the event will be delivered to the other item instead.
  1003. \sa mousePress(), mouseRelease(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseDrag(), mouseWheel()
  1004. */
  1005. function mouseMove(item, x, y, delay, buttons) {
  1006. if (!item)
  1007. qtest_fail("No item given to mouseMove", 1)
  1008. if (delay == undefined)
  1009. delay = -1
  1010. if (buttons == undefined)
  1011. buttons = Qt.NoButton
  1012. if (!qtest_events.mouseMove(item, x, y, delay, buttons))
  1013. qtest_fail("window not shown", 2)
  1014. }
  1015. /*!
  1016. \qmlmethod TestCase::mouseWheel(item, x, y, xDelta, yDelta, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  1017. Simulates rotating the mouse wheel on an \a item with \a button pressed and an optional \a modifier.
  1018. The position of the wheel event is defined by \a x and \a y.
  1019. If \a delay is specified, the test will wait for the specified amount of milliseconds before releasing the button.
  1020. The position given by \a x and \a y is transformed from the co-ordinate
  1021. system of \a item into window co-ordinates and then delivered.
  1022. If \a item is obscured by another item, or a child of \a item occupies
  1023. that position, then the event will be delivered to the other item instead.
  1024. The \a xDelta and \a yDelta contain the wheel rotation distance in eighths of a degree. see \l QWheelEvent::angleDelta() for more details.
  1025. \sa mousePress(), mouseClick(), mouseDoubleClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseDrag(), QWheelEvent::angleDelta()
  1026. */
  1027. function mouseWheel(item, x, y, xDelta, yDelta, buttons, modifiers, delay) {
  1028. if (!item)
  1029. qtest_fail("No item given to mouseWheel", 1)
  1030. if (delay == undefined)
  1031. delay = -1
  1032. if (buttons == undefined)
  1033. buttons = Qt.NoButton
  1034. if (modifiers === undefined)
  1035. modifiers = Qt.NoModifier
  1036. if (xDelta == undefined)
  1037. xDelta = 0
  1038. if (yDelta == undefined)
  1039. yDelta = 0
  1040. if (!qtest_events.mouseWheel(item, x, y, buttons, modifiers, xDelta, yDelta, delay))
  1041. qtest_fail("window not shown", 2)
  1042. }
  1043. // Functions that can be overridden in subclasses for init/cleanup duties.
  1044. /*!
  1045. \qmlmethod TestCase::initTestCase()
  1046. This function is called before any other test functions in the
  1047. \l TestCase type. The default implementation does nothing.
  1048. The application can provide its own implementation to perform
  1049. test case initialization.
  1050. \sa cleanupTestCase(), init()
  1051. */
  1052. function initTestCase() {}
  1053. /*!
  1054. \qmlmethod TestCase::cleanupTestCase()
  1055. This function is called after all other test functions in the
  1056. \l TestCase type have completed. The default implementation
  1057. does nothing. The application can provide its own implementation
  1058. to perform test case cleanup.
  1059. \sa initTestCase(), cleanup()
  1060. */
  1061. function cleanupTestCase() {}
  1062. /*!
  1063. \qmlmethod TestCase::init()
  1064. This function is called before each test function that is
  1065. executed in the \l TestCase type. The default implementation
  1066. does nothing. The application can provide its own implementation
  1067. to perform initialization before each test function.
  1068. \sa cleanup(), initTestCase()
  1069. */
  1070. function init() {}
  1071. /*!
  1072. \qmlmethod TestCase::cleanup()
  1073. This function is called after each test function that is
  1074. executed in the \l TestCase type. The default implementation
  1075. does nothing. The application can provide its own implementation
  1076. to perform cleanup after each test function.
  1077. \sa init(), cleanupTestCase()
  1078. */
  1079. function cleanup() {}
  1080. /*! \internal */
  1081. function qtest_runInternal(prop, arg) {
  1082. try {
  1083. qtest_testCaseResult = testCase[prop](arg)
  1084. } catch (e) {
  1085. qtest_testCaseResult = []
  1086. if (e.message.indexOf("QtQuickTest::") != 0) {
  1087. // Test threw an unrecognized exception - fail.
  1088. qtest_results.fail("Uncaught exception: " + e.message,
  1089. e.fileName, e.lineNumber)
  1090. }
  1091. }
  1092. return !qtest_results.failed
  1093. }
  1094. /*! \internal */
  1095. function qtest_runFunction(prop, arg) {
  1096. qtest_runInternal("init")
  1097. if (!qtest_results.skipped) {
  1098. qtest_runInternal(prop, arg)
  1099. qtest_results.finishTestData()
  1100. qtest_runInternal("cleanup")
  1101. qtest_results.finishTestDataCleanup()
  1102. // wait(0) will call processEvents() so objects marked for deletion
  1103. // in the test function will be deleted.
  1104. wait(0)
  1105. }
  1106. }
  1107. /*! \internal */
  1108. function qtest_runBenchmarkFunction(prop, arg) {
  1109. qtest_results.startMeasurement()
  1110. do {
  1111. qtest_results.beginDataRun()
  1112. do {
  1113. // Run the initialization function.
  1114. qtest_runInternal("init")
  1115. if (qtest_results.skipped)
  1116. break
  1117. // Execute the benchmark function.
  1118. if (prop.indexOf("benchmark_once_") != 0)
  1119. qtest_results.startBenchmark(TestResult.RepeatUntilValidMeasurement, qtest_results.dataTag)
  1120. else
  1121. qtest_results.startBenchmark(TestResult.RunOnce, qtest_results.dataTag)
  1122. while (!qtest_results.isBenchmarkDone()) {
  1123. var success = qtest_runInternal(prop, arg)
  1124. qtest_results.finishTestData()
  1125. if (!success)
  1126. break
  1127. qtest_results.nextBenchmark()
  1128. }
  1129. qtest_results.stopBenchmark()
  1130. // Run the cleanup function.
  1131. qtest_runInternal("cleanup")
  1132. qtest_results.finishTestDataCleanup()
  1133. // wait(0) will call processEvents() so objects marked for deletion
  1134. // in the test function will be deleted.
  1135. wait(0)
  1136. } while (!qtest_results.measurementAccepted())
  1137. qtest_results.endDataRun()
  1138. } while (qtest_results.needsMoreMeasurements())
  1139. }
  1140. /*! \internal */
  1141. function qtest_run() {
  1142. if (util.printAvailableFunctions) {
  1143. completed = true
  1144. return
  1145. }
  1146. if (TestLogger.log_start_test()) {
  1147. qtest_results.reset()
  1148. qtest_results.testCaseName = name
  1149. qtest_results.startLogging()
  1150. } else {
  1151. qtest_results.testCaseName = name
  1152. }
  1153. running = true
  1154. // Check the run list to see if this class is mentioned.
  1155. var functionsToRun = qtest_results.functionsToRun
  1156. if (functionsToRun.length > 0) {
  1157. var found = false
  1158. var list = []
  1159. if (name.length > 0) {
  1160. var prefix = name + "::"
  1161. for (var index in functionsToRun) {
  1162. if (functionsToRun[index].indexOf(prefix) == 0) {
  1163. list.push(functionsToRun[index])
  1164. found = true
  1165. }
  1166. }
  1167. }
  1168. if (!found) {
  1169. completed = true
  1170. if (!TestLogger.log_complete_test(qtest_testId)) {
  1171. qtest_results.stopLogging()
  1172. Qt.quit()
  1173. }
  1174. qtest_results.testCaseName = ""
  1175. return
  1176. }
  1177. functionsToRun = list
  1178. }
  1179. // Run the initTestCase function.
  1180. qtest_results.functionName = "initTestCase"
  1181. var runTests = true
  1182. if (!qtest_runInternal("initTestCase"))
  1183. runTests = false
  1184. qtest_results.finishTestData()
  1185. qtest_results.finishTestDataCleanup()
  1186. qtest_results.finishTestFunction()
  1187. // Run the test methods.
  1188. var testList = []
  1189. if (runTests) {
  1190. for (var prop in testCase) {
  1191. if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0)
  1192. continue
  1193. var tail = prop.lastIndexOf("_data");
  1194. if (tail != -1 && tail == (prop.length - 5))
  1195. continue
  1196. testList.push(prop)
  1197. }
  1198. testList.sort()
  1199. }
  1200. var checkNames = (functionsToRun.length > 0)
  1201. for (var index in testList) {
  1202. var prop = testList[index]
  1203. var datafunc = prop + "_data"
  1204. var isBenchmark = (prop.indexOf("benchmark_") == 0)
  1205. if (checkNames) {
  1206. var index = functionsToRun.indexOf(name + "::" + prop)
  1207. if (index < 0)
  1208. continue
  1209. functionsToRun.splice(index, 1)
  1210. }
  1211. qtest_results.functionName = prop
  1212. if (!(datafunc in testCase))
  1213. datafunc = "init_data";
  1214. if (datafunc in testCase) {
  1215. if (qtest_runInternal(datafunc)) {
  1216. var table = qtest_testCaseResult
  1217. var haveData = false
  1218. qtest_results.initTestTable()
  1219. for (var index in table) {
  1220. haveData = true
  1221. var row = table[index]
  1222. if (!row.tag)
  1223. row.tag = "row " + index // Must have something
  1224. qtest_results.dataTag = row.tag
  1225. if (isBenchmark)
  1226. qtest_runBenchmarkFunction(prop, row)
  1227. else
  1228. qtest_runFunction(prop, row)
  1229. qtest_results.dataTag = ""
  1230. }
  1231. if (!haveData) {
  1232. if (datafunc === "init_data")
  1233. qtest_runFunction(prop, null, isBenchmark)
  1234. else
  1235. qtest_results.warn("no data supplied for " + prop + "() by " + datafunc + "()"
  1236. , util.callerFile(), util.callerLine());
  1237. }
  1238. qtest_results.clearTestTable()
  1239. }
  1240. } else if (isBenchmark) {
  1241. qtest_runBenchmarkFunction(prop, null, isBenchmark)
  1242. } else {
  1243. qtest_runFunction(prop, null, isBenchmark)
  1244. }
  1245. qtest_results.finishTestFunction()
  1246. qtest_results.skipped = false
  1247. }
  1248. // Run the cleanupTestCase function.
  1249. qtest_results.skipped = false
  1250. qtest_results.functionName = "cleanupTestCase"
  1251. qtest_runInternal("cleanupTestCase")
  1252. // Complain about missing functions that we were supposed to run.
  1253. if (functionsToRun.length > 0)
  1254. qtest_results.fail("Could not find functions: " + functionsToRun, "", 0)
  1255. // Clean up and exit.
  1256. running = false
  1257. completed = true
  1258. qtest_results.finishTestData()
  1259. qtest_results.finishTestDataCleanup()
  1260. qtest_results.finishTestFunction()
  1261. qtest_results.functionName = ""
  1262. // Stop if there are no more tests to be run.
  1263. if (!TestLogger.log_complete_test(qtest_testId)) {
  1264. qtest_results.stopLogging()
  1265. Qt.quit()
  1266. }
  1267. qtest_results.testCaseName = ""
  1268. }
  1269. onWhenChanged: {
  1270. if (when != qtest_prevWhen) {
  1271. qtest_prevWhen = when
  1272. if (when && !completed && !running && qtest_componentCompleted)
  1273. qtest_run()
  1274. }
  1275. }
  1276. onOptionalChanged: {
  1277. if (!completed) {
  1278. if (optional)
  1279. TestLogger.log_optional_test(qtest_testId)
  1280. else
  1281. TestLogger.log_mandatory_test(qtest_testId)
  1282. }
  1283. }
  1284. Component.onCompleted: {
  1285. QTestRootObject.hasTestCase = true;
  1286. qtest_componentCompleted = true;
  1287. if (util.printAvailableFunctions) {
  1288. var testList = []
  1289. for (var prop in testCase) {
  1290. if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0)
  1291. continue
  1292. var tail = prop.lastIndexOf("_data");
  1293. if (tail != -1 && tail == (prop.length - 5))
  1294. continue
  1295. // Note: cannot run functions in TestCase elements
  1296. // that lack a name.
  1297. if (name.length > 0)
  1298. testList.push(name + "::" + prop + "()")
  1299. }
  1300. testList.sort()
  1301. for (var index in testList)
  1302. console.log(testList[index])
  1303. return
  1304. }
  1305. qtest_testId = TestLogger.log_register_test(name)
  1306. if (optional)
  1307. TestLogger.log_optional_test(qtest_testId)
  1308. qtest_prevWhen = when
  1309. if (when && !completed && !running)
  1310. qtest_run()
  1311. }
  1312. }