TestCase.qml 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046
  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 QtQuick.Window 2.0 // used for qtest_verifyItem
  41. import QtTest 1.2
  42. import "testlogger.js" as TestLogger
  43. import Qt.test.qtestroot 1.0
  44. /*!
  45. \qmltype TestCase
  46. \inqmlmodule QtTest
  47. \brief Represents a unit test case.
  48. \since 4.8
  49. \ingroup qtquicktest
  50. \section1 Introduction to QML Test Cases
  51. Test cases are written as JavaScript functions within a TestCase
  52. type:
  53. \code
  54. import QtQuick 2.0
  55. import QtTest 1.2
  56. TestCase {
  57. name: "MathTests"
  58. function test_math() {
  59. compare(2 + 2, 4, "2 + 2 = 4")
  60. }
  61. function test_fail() {
  62. compare(2 + 2, 5, "2 + 2 = 5")
  63. }
  64. }
  65. \endcode
  66. Functions whose names start with "test_" are treated as test cases
  67. to be executed. The \l name property is used to prefix the functions
  68. in the output:
  69. \code
  70. ********* Start testing of MathTests *********
  71. Config: Using QTest library 4.7.2, Qt 4.7.2
  72. PASS : MathTests::initTestCase()
  73. FAIL! : MathTests::test_fail() 2 + 2 = 5
  74. Actual (): 4
  75. Expected (): 5
  76. Loc: [/home/.../tst_math.qml(12)]
  77. PASS : MathTests::test_math()
  78. PASS : MathTests::cleanupTestCase()
  79. Totals: 3 passed, 1 failed, 0 skipped
  80. ********* Finished testing of MathTests *********
  81. \endcode
  82. Because of the way JavaScript properties work, the order in which the
  83. test functions are found is unpredictable. To assist with predictability,
  84. the test framework will sort the functions on ascending order of name.
  85. This can help when there are two tests that must be run in order.
  86. Multiple TestCase types can be supplied. The test program will exit
  87. once they have all completed. If a test case doesn't need to run
  88. (because a precondition has failed), then \l optional can be set to true.
  89. \section1 Data-driven Tests
  90. Table data can be provided to a test using a function name that ends
  91. with "_data". Alternatively, the \c init_data() function can be used
  92. to provide default test data for all test functions in a TestCase type:
  93. \code
  94. import QtQuick 2.0
  95. import QtTest 1.2
  96. TestCase {
  97. name: "DataTests"
  98. function init_data() {
  99. return [
  100. {tag:"init_data_1", a:1, b:2, answer: 3},
  101. {tag:"init_data_2", a:2, b:4, answer: 6}
  102. ];
  103. }
  104. function test_table_data() {
  105. return [
  106. {tag: "2 + 2 = 4", a: 2, b: 2, answer: 4 },
  107. {tag: "2 + 6 = 8", a: 2, b: 6, answer: 8 },
  108. ]
  109. }
  110. function test_table(data) {
  111. //data comes from test_table_data
  112. compare(data.a + data.b, data.answer)
  113. }
  114. function test__default_table(data) {
  115. //data comes from init_data
  116. compare(data.a + data.b, data.answer)
  117. }
  118. }
  119. \endcode
  120. The test framework will iterate over all of the rows in the table
  121. and pass each row to the test function. As shown, the columns can be
  122. extracted for use in the test. The \c tag column is special - it is
  123. printed by the test framework when a row fails, to help the reader
  124. identify which case failed amongst a set of otherwise passing tests.
  125. \section1 Benchmarks
  126. Functions whose names start with "benchmark_" will be run multiple
  127. times with the Qt benchmark framework, with an average timing value
  128. reported for the runs. This is equivalent to using the \c{QBENCHMARK}
  129. macro in the C++ version of QTestLib.
  130. \code
  131. TestCase {
  132. id: top
  133. name: "CreateBenchmark"
  134. function benchmark_create_component() {
  135. var component = Qt.createComponent("item.qml")
  136. var obj = component.createObject(top)
  137. obj.destroy()
  138. component.destroy()
  139. }
  140. }
  141. RESULT : CreateBenchmark::benchmark_create_component:
  142. 0.23 msecs per iteration (total: 60, iterations: 256)
  143. PASS : CreateBenchmark::benchmark_create_component()
  144. \endcode
  145. To get the effect of the \c{QBENCHMARK_ONCE} macro, prefix the test
  146. function name with "benchmark_once_".
  147. \section1 Simulating Keyboard and Mouse Events
  148. The keyPress(), keyRelease(), and keyClick() methods can be used
  149. to simulate keyboard events within unit tests. The events are
  150. delivered to the currently focused QML item. You can pass either
  151. a Qt.Key enum value or a latin1 char (string of length one)
  152. \code
  153. Rectangle {
  154. width: 50; height: 50
  155. focus: true
  156. TestCase {
  157. name: "KeyClick"
  158. when: windowShown
  159. function test_key_click() {
  160. keyClick(Qt.Key_Left)
  161. keyClick("a")
  162. ...
  163. }
  164. }
  165. }
  166. \endcode
  167. The mousePress(), mouseRelease(), mouseClick(), mouseDoubleClickSequence()
  168. and mouseMove() methods can be used to simulate mouse events in a
  169. similar fashion.
  170. \b{Note:} keyboard and mouse events can only be delivered once the
  171. main window has been shown. Attempts to deliver events before then
  172. will fail. Use the \l when and windowShown properties to track
  173. when the main window has been shown.
  174. \section1 Managing Dynamically Created Test Objects
  175. A typical pattern with QML tests is to
  176. \l {Dynamic QML Object Creation from JavaScript}{dynamically create}
  177. an item and then destroy it at the end of the test function:
  178. \code
  179. TestCase {
  180. id: testCase
  181. name: "MyTest"
  182. when: windowShown
  183. function test_click() {
  184. var item = Qt.createQmlObject("import QtQuick 2.0; Item {}", testCase);
  185. verify(item);
  186. // Test item...
  187. item.destroy();
  188. }
  189. }
  190. \endcode
  191. The problem with this pattern is that any failures in the test function
  192. will cause the call to \c item.destroy() to be skipped, leaving the item
  193. hanging around in the scene until the test case has finished. This can
  194. result in interference with future tests; for example, by blocking input
  195. events or producing unrelated debug output that makes it difficult to
  196. follow the code's execution.
  197. By calling \l createTemporaryQmlObject() instead, the object is guaranteed
  198. to be destroyed at the end of the test function:
  199. \code
  200. TestCase {
  201. id: testCase
  202. name: "MyTest"
  203. when: windowShown
  204. function test_click() {
  205. var item = createTemporaryQmlObject("import QtQuick 2.0; Item {}", testCase);
  206. verify(item);
  207. // Test item...
  208. // Don't need to worry about destroying "item" here.
  209. }
  210. }
  211. \endcode
  212. For objects that are created via the \l {Component::}{createObject()} function
  213. of \l Component, the \l createTemporaryObject() function can be used.
  214. \sa {QtTest::SignalSpy}{SignalSpy}, {Qt Quick Test}
  215. */
  216. Item {
  217. id: testCase
  218. visible: false
  219. TestUtil {
  220. id:util
  221. }
  222. /*!
  223. \qmlproperty string TestCase::name
  224. This property defines the name of the test case for result reporting.
  225. The default value is an empty string.
  226. \code
  227. TestCase {
  228. name: "ButtonTests"
  229. ...
  230. }
  231. \endcode
  232. */
  233. property string name
  234. /*!
  235. \qmlproperty bool TestCase::when
  236. This property should be set to true when the application wants
  237. the test cases to run. The default value is true. In the following
  238. example, a test is run when the user presses the mouse button:
  239. \code
  240. Rectangle {
  241. id: foo
  242. width: 640; height: 480
  243. color: "cyan"
  244. MouseArea {
  245. id: area
  246. anchors.fill: parent
  247. }
  248. property bool bar: true
  249. TestCase {
  250. name: "ItemTests"
  251. when: area.pressed
  252. id: test1
  253. function test_bar() {
  254. verify(bar)
  255. }
  256. }
  257. }
  258. \endcode
  259. The test application will exit once all \l TestCase types
  260. have been triggered and have run. The \l optional property can
  261. be used to exclude a \l TestCase type.
  262. \sa optional, completed
  263. */
  264. property bool when: true
  265. /*!
  266. \qmlproperty bool TestCase::completed
  267. This property will be set to true once the test case has completed
  268. execution. Test cases are only executed once. The initial value
  269. is false.
  270. \sa running, when
  271. */
  272. property bool completed: false
  273. /*!
  274. \qmlproperty bool TestCase::running
  275. This property will be set to true while the test case is running.
  276. The initial value is false, and the value will become false again
  277. once the test case completes.
  278. \sa completed, when
  279. */
  280. property bool running: false
  281. /*!
  282. \qmlproperty bool TestCase::optional
  283. Multiple \l TestCase types can be supplied in a test application.
  284. The application will exit once they have all completed. If a test case
  285. does not need to run (because a precondition has failed), then this
  286. property can be set to true. The default value is false.
  287. \code
  288. TestCase {
  289. when: false
  290. optional: true
  291. function test_not_run() {
  292. verify(false)
  293. }
  294. }
  295. \endcode
  296. \sa when, completed
  297. */
  298. property bool optional: false
  299. /*!
  300. \qmlproperty bool TestCase::windowShown
  301. This property will be set to true after the QML viewing window has
  302. been displayed. Normally test cases run as soon as the test application
  303. is loaded and before a window is displayed. If the test case involves
  304. visual types and behaviors, then it may need to be delayed until
  305. after the window is shown.
  306. \code
  307. Button {
  308. id: button
  309. onClicked: text = "Clicked"
  310. TestCase {
  311. name: "ClickTest"
  312. when: windowShown
  313. function test_click() {
  314. button.clicked();
  315. compare(button.text, "Clicked");
  316. }
  317. }
  318. }
  319. \endcode
  320. */
  321. property bool windowShown: QTestRootObject.windowShown
  322. // Internal private state. Identifiers prefixed with qtest are reserved.
  323. /*! \internal */
  324. property bool qtest_prevWhen: true
  325. /*! \internal */
  326. property int qtest_testId: -1
  327. /*! \internal */
  328. property bool qtest_componentCompleted : false
  329. /*! \internal */
  330. property var qtest_testCaseResult
  331. /*! \internal */
  332. property var qtest_results: qtest_results_normal
  333. /*! \internal */
  334. TestResult { id: qtest_results_normal }
  335. /*! \internal */
  336. property var qtest_events: qtest_events_normal
  337. TestEvent { id: qtest_events_normal }
  338. /*! \internal */
  339. property var qtest_temporaryObjects: []
  340. /*!
  341. \qmlmethod TestCase::fail(message = "")
  342. Fails the current test case, with the optional \a message.
  343. Similar to \c{QFAIL(message)} in C++.
  344. */
  345. function fail(msg) {
  346. if (msg === undefined)
  347. msg = "";
  348. qtest_results.fail(msg, util.callerFile(), util.callerLine())
  349. throw new Error("QtQuickTest::fail")
  350. }
  351. /*! \internal */
  352. function qtest_fail(msg, frame) {
  353. if (msg === undefined)
  354. msg = "";
  355. qtest_results.fail(msg, util.callerFile(frame), util.callerLine(frame))
  356. throw new Error("QtQuickTest::fail")
  357. }
  358. /*!
  359. \qmlmethod TestCase::verify(condition, message = "")
  360. Fails the current test case if \a condition is false, and
  361. displays the optional \a message. Similar to \c{QVERIFY(condition)}
  362. or \c{QVERIFY2(condition, message)} in C++.
  363. */
  364. function verify(cond, msg) {
  365. if (arguments.length > 2)
  366. qtest_fail("More than two arguments given to verify(). Did you mean tryVerify() or tryCompare()?", 1)
  367. if (msg === undefined)
  368. msg = "";
  369. if (!qtest_results.verify(cond, msg, util.callerFile(), util.callerLine()))
  370. throw new Error("QtQuickTest::fail")
  371. }
  372. /*!
  373. \since 5.8
  374. \qmlmethod TestCase::tryVerify(function, timeout = 5000, message = "")
  375. Fails the current test case if \a function does not evaluate to
  376. \c true before the specified \a timeout (in milliseconds) has elapsed.
  377. The function is evaluated multiple times until the timeout is
  378. reached. An optional \a message is displayed upon failure.
  379. This function is intended for testing applications where a condition
  380. changes based on asynchronous events. Use verify() for testing
  381. synchronous condition changes, and tryCompare() for testing
  382. asynchronous property changes.
  383. For example, in the code below, it's not possible to use tryCompare(),
  384. because the \c currentItem property might be \c null for a short period
  385. of time:
  386. \code
  387. tryCompare(listView.currentItem, "text", "Hello");
  388. \endcode
  389. Instead, we can use tryVerify() to first check that \c currentItem
  390. isn't \c null, and then use a regular compare afterwards:
  391. \code
  392. tryVerify(function(){ return listView.currentItem })
  393. compare(listView.currentItem.text, "Hello")
  394. \endcode
  395. \sa verify(), compare(), tryCompare(), SignalSpy::wait()
  396. */
  397. function tryVerify(expressionFunction, timeout, msg) {
  398. if (!expressionFunction || !(expressionFunction instanceof Function)) {
  399. qtest_results.fail("First argument must be a function", util.callerFile(), util.callerLine())
  400. throw new Error("QtQuickTest::fail")
  401. }
  402. if (timeout && typeof(timeout) !== "number") {
  403. qtest_results.fail("timeout argument must be a number", util.callerFile(), util.callerLine())
  404. throw new Error("QtQuickTest::fail")
  405. }
  406. if (msg && typeof(msg) !== "string") {
  407. qtest_results.fail("message argument must be a string", util.callerFile(), util.callerLine())
  408. throw new Error("QtQuickTest::fail")
  409. }
  410. if (!timeout)
  411. timeout = 5000
  412. if (msg === undefined)
  413. msg = "function returned false"
  414. if (!expressionFunction())
  415. wait(0)
  416. var i = 0
  417. while (i < timeout && !expressionFunction()) {
  418. wait(50)
  419. i += 50
  420. }
  421. if (!qtest_results.verify(expressionFunction(), msg, util.callerFile(), util.callerLine()))
  422. throw new Error("QtQuickTest::fail")
  423. }
  424. /*!
  425. \since 5.13
  426. \qmlmethod bool TestCase::isPolishScheduled(object item)
  427. Returns \c true if \l {QQuickItem::}{updatePolish()} has not been called
  428. on \a item since the last call to \l {QQuickItem::}{polish()},
  429. otherwise returns \c false.
  430. When assigning values to properties in QML, any layouting the item
  431. must do as a result of the assignment might not take effect immediately,
  432. but can instead be postponed until the item is polished. For these cases,
  433. you can use this function to ensure that the item has been polished
  434. before the execution of the test continues. For example:
  435. \code
  436. verify(isPolishScheduled(item))
  437. verify(waitForItemPolished(item))
  438. \endcode
  439. Without the call to \c isPolishScheduled() above, the
  440. call to \c waitForItemPolished() might see that no polish
  441. was scheduled and therefore pass instantly, assuming that
  442. the item had already been polished. This function
  443. makes it obvious why an item wasn't polished and allows tests to
  444. fail early under such circumstances.
  445. \sa waitForItemPolished(), QQuickItem::polish(), QQuickItem::updatePolish()
  446. */
  447. function isPolishScheduled(item) {
  448. if (!item || typeof item !== "object") {
  449. qtest_results.fail("Argument must be a valid Item; actual type is " + typeof item,
  450. util.callerFile(), util.callerLine())
  451. throw new Error("QtQuickTest::fail")
  452. }
  453. return qtest_results.isPolishScheduled(item)
  454. }
  455. /*!
  456. \since 5.13
  457. \qmlmethod bool waitForItemPolished(object item, int timeout = 5000)
  458. Waits for \a timeout milliseconds or until
  459. \l {QQuickItem::}{updatePolish()} has been called on \a item.
  460. Returns \c true if \c updatePolish() was called on \a item within
  461. \a timeout milliseconds, otherwise returns \c false.
  462. \sa isPolishScheduled(), QQuickItem::polish(), QQuickItem::updatePolish()
  463. */
  464. function waitForItemPolished(item, timeout) {
  465. if (!item || typeof item !== "object") {
  466. qtest_results.fail("First argument must be a valid Item; actual type is " + typeof item,
  467. util.callerFile(), util.callerLine())
  468. throw new Error("QtQuickTest::fail")
  469. }
  470. if (timeout !== undefined && typeof(timeout) != "number") {
  471. qtest_results.fail("Second argument must be a number; actual type is " + typeof timeout,
  472. util.callerFile(), util.callerLine())
  473. throw new Error("QtQuickTest::fail")
  474. }
  475. if (!timeout)
  476. timeout = 5000
  477. return qtest_results.waitForItemPolished(item, timeout)
  478. }
  479. /*!
  480. \since 5.9
  481. \qmlmethod object TestCase::createTemporaryQmlObject(string qml, object parent, string filePath)
  482. This function dynamically creates a QML object from the given \a qml
  483. string with the specified \a parent. The returned object will be
  484. destroyed (if it was not already) after \l cleanup() has finished
  485. executing, meaning that objects created with this function are
  486. guaranteed to be destroyed after each test, regardless of whether or
  487. not the tests fail.
  488. If there was an error while creating the object, \c null will be
  489. returned.
  490. If \a filePath is specified, it will be used for error reporting for
  491. the created object.
  492. This function calls
  493. \l {QtQml::Qt::createQmlObject()}{Qt.createQmlObject()} internally.
  494. \sa {Managing Dynamically Created Test Objects}
  495. */
  496. function createTemporaryQmlObject(qml, parent, filePath) {
  497. if (typeof qml !== "string") {
  498. qtest_results.fail("First argument must be a string of QML; actual type is " + typeof qml,
  499. util.callerFile(), util.callerLine());
  500. throw new Error("QtQuickTest::fail");
  501. }
  502. if (!parent || typeof parent !== "object") {
  503. qtest_results.fail("Second argument must be a valid parent object; actual type is " + typeof parent,
  504. util.callerFile(), util.callerLine());
  505. throw new Error("QtQuickTest::fail");
  506. }
  507. if (filePath !== undefined && typeof filePath !== "string") {
  508. qtest_results.fail("Third argument must be a file path string; actual type is " + typeof filePath,
  509. util.callerFile(), util.callerLine());
  510. throw new Error("QtQuickTest::fail");
  511. }
  512. var object = Qt.createQmlObject(qml, parent, filePath);
  513. qtest_temporaryObjects.push(object);
  514. return object;
  515. }
  516. /*!
  517. \since 5.9
  518. \qmlmethod object TestCase::createTemporaryObject(Component component, object parent, object properties)
  519. This function dynamically creates a QML object from the given
  520. \a component with the specified optional \a parent and \a properties.
  521. The returned object will be destroyed (if it was not already) after
  522. \l cleanup() has finished executing, meaning that objects created with
  523. this function are guaranteed to be destroyed after each test,
  524. regardless of whether or not the tests fail.
  525. If there was an error while creating the object, \c null will be
  526. returned.
  527. This function calls
  528. \l {QtQml::Component::createObject()}{component.createObject()}
  529. internally.
  530. \sa {Managing Dynamically Created Test Objects}
  531. */
  532. function createTemporaryObject(component, parent, properties) {
  533. if (typeof component !== "object") {
  534. qtest_results.fail("First argument must be a Component; actual type is " + typeof component,
  535. util.callerFile(), util.callerLine());
  536. throw new Error("QtQuickTest::fail");
  537. }
  538. if (properties && typeof properties !== "object") {
  539. qtest_results.fail("Third argument must be an object; actual type is " + typeof properties,
  540. util.callerFile(), util.callerLine());
  541. throw new Error("QtQuickTest::fail");
  542. }
  543. var object = component.createObject(parent, properties ? properties : ({}));
  544. qtest_temporaryObjects.push(object);
  545. return object;
  546. }
  547. /*!
  548. \internal
  549. Destroys all temporary objects that still exist.
  550. */
  551. function qtest_destroyTemporaryObjects() {
  552. for (var i = 0; i < qtest_temporaryObjects.length; ++i) {
  553. var temporaryObject = qtest_temporaryObjects[i];
  554. // ### the typeof check can be removed when QTBUG-57749 is fixed
  555. if (temporaryObject && typeof temporaryObject.destroy === "function")
  556. temporaryObject.destroy();
  557. }
  558. qtest_temporaryObjects = [];
  559. }
  560. /*! \internal */
  561. // Determine what is o.
  562. // Discussions and reference: http://philrathe.com/articles/equiv
  563. // Test suites: http://philrathe.com/tests/equiv
  564. // Author: Philippe Rathé <prathe@gmail.com>
  565. function qtest_typeof(o) {
  566. if (typeof o === "undefined") {
  567. return "undefined";
  568. // consider: typeof null === object
  569. } else if (o === null) {
  570. return "null";
  571. } else if (o.constructor === String) {
  572. return "string";
  573. } else if (o.constructor === Boolean) {
  574. return "boolean";
  575. } else if (o.constructor === Number) {
  576. if (isNaN(o)) {
  577. return "nan";
  578. } else {
  579. return "number";
  580. }
  581. // consider: typeof [] === object
  582. } else if (o instanceof Array) {
  583. return "array";
  584. // consider: typeof new Date() === object
  585. } else if (o instanceof Date) {
  586. return "date";
  587. // consider: /./ instanceof Object;
  588. // /./ instanceof RegExp;
  589. // typeof /./ === "function"; // => false in IE and Opera,
  590. // true in FF and Safari
  591. } else if (o instanceof RegExp) {
  592. return "regexp";
  593. } else if (typeof o === "object") {
  594. if ("mapFromItem" in o && "mapToItem" in o) {
  595. return "declarativeitem"; // @todo improve detection of declarative items
  596. } else if ("x" in o && "y" in o && "z" in o) {
  597. return "vector3d"; // Qt 3D vector
  598. }
  599. return "object";
  600. } else if (o instanceof Function) {
  601. return "function";
  602. } else {
  603. return undefined;
  604. }
  605. }
  606. /*! \internal */
  607. // Test for equality
  608. // Large parts contain sources from QUnit or http://philrathe.com
  609. // Discussions and reference: http://philrathe.com/articles/equiv
  610. // Test suites: http://philrathe.com/tests/equiv
  611. // Author: Philippe Rathé <prathe@gmail.com>
  612. function qtest_compareInternal(act, exp) {
  613. var success = false;
  614. if (act === exp) {
  615. success = true; // catch the most you can
  616. } else if (act === null || exp === null || typeof act === "undefined" || typeof exp === "undefined") {
  617. success = false; // don't lose time with error prone cases
  618. } else {
  619. var typeExp = qtest_typeof(exp), typeAct = qtest_typeof(act)
  620. if (typeExp !== typeAct) {
  621. // allow object vs string comparison (e.g. for colors)
  622. // else break on different types
  623. if ((typeExp === "string" && (typeAct === "object") || typeAct == "declarativeitem")
  624. || ((typeExp === "object" || typeExp == "declarativeitem") && typeAct === "string")) {
  625. success = (act == exp)
  626. }
  627. } else if (typeExp === "string" || typeExp === "boolean" ||
  628. typeExp === "null" || typeExp === "undefined") {
  629. if (exp instanceof act.constructor || act instanceof exp.constructor) {
  630. // to catch short annotaion VS 'new' annotation of act declaration
  631. // e.g. var i = 1;
  632. // var j = new Number(1);
  633. success = (act == exp)
  634. } else {
  635. success = (act === exp)
  636. }
  637. } else if (typeExp === "nan") {
  638. success = isNaN(act);
  639. } else if (typeExp === "number") {
  640. // Use act fuzzy compare if the two values are floats
  641. if (Math.abs(act - exp) <= 0.00001) {
  642. success = true
  643. }
  644. } else if (typeExp === "array") {
  645. success = qtest_compareInternalArrays(act, exp)
  646. } else if (typeExp === "object") {
  647. success = qtest_compareInternalObjects(act, exp)
  648. } else if (typeExp === "declarativeitem") {
  649. success = qtest_compareInternalObjects(act, exp) // @todo improve comparison of declarative items
  650. } else if (typeExp === "vector3d") {
  651. success = (Math.abs(act.x - exp.x) <= 0.00001 &&
  652. Math.abs(act.y - exp.y) <= 0.00001 &&
  653. Math.abs(act.z - exp.z) <= 0.00001)
  654. } else if (typeExp === "date") {
  655. success = (act.valueOf() === exp.valueOf())
  656. } else if (typeExp === "regexp") {
  657. success = (act.source === exp.source && // the regex itself
  658. act.global === exp.global && // and its modifers (gmi) ...
  659. act.ignoreCase === exp.ignoreCase &&
  660. act.multiline === exp.multiline)
  661. }
  662. }
  663. return success
  664. }
  665. /*! \internal */
  666. function qtest_compareInternalObjects(act, exp) {
  667. var i;
  668. var eq = true; // unless we can proove it
  669. var aProperties = [], bProperties = []; // collection of strings
  670. // comparing constructors is more strict than using instanceof
  671. if (act.constructor !== exp.constructor) {
  672. return false;
  673. }
  674. for (i in act) { // be strict: don't ensures hasOwnProperty and go deep
  675. aProperties.push(i); // collect act's properties
  676. if (!qtest_compareInternal(act[i], exp[i])) {
  677. eq = false;
  678. break;
  679. }
  680. }
  681. for (i in exp) {
  682. bProperties.push(i); // collect exp's properties
  683. }
  684. if (aProperties.length == 0 && bProperties.length == 0) { // at least a special case for QUrl
  685. return eq && (JSON.stringify(act) == JSON.stringify(exp));
  686. }
  687. // Ensures identical properties name
  688. return eq && qtest_compareInternal(aProperties.sort(), bProperties.sort());
  689. }
  690. /*! \internal */
  691. function qtest_compareInternalArrays(actual, expected) {
  692. if (actual.length != expected.length) {
  693. return false
  694. }
  695. for (var i = 0, len = actual.length; i < len; i++) {
  696. if (!qtest_compareInternal(actual[i], expected[i])) {
  697. return false
  698. }
  699. }
  700. return true
  701. }
  702. /*!
  703. \qmlmethod TestCase::compare(actual, expected, message = "")
  704. Fails the current test case if \a actual is not the same as
  705. \a expected, and displays the optional \a message. Similar
  706. to \c{QCOMPARE(actual, expected)} in C++.
  707. \sa tryCompare(), fuzzyCompare
  708. */
  709. function compare(actual, expected, msg) {
  710. var act = qtest_results.stringify(actual)
  711. var exp = qtest_results.stringify(expected)
  712. var success = qtest_compareInternal(actual, expected)
  713. if (msg === undefined) {
  714. if (success)
  715. msg = "COMPARE()"
  716. else
  717. msg = "Compared values are not the same"
  718. }
  719. if (!qtest_results.compare(success, msg, act, exp, util.callerFile(), util.callerLine())) {
  720. throw new Error("QtQuickTest::fail")
  721. }
  722. }
  723. /*!
  724. \qmlmethod TestCase::fuzzyCompare(actual, expected, delta, message = "")
  725. Fails the current test case if the difference betwen \a actual and \a expected
  726. is greater than \a delta, and displays the optional \a message. Similar
  727. to \c{qFuzzyCompare(actual, expected)} in C++ but with a required \a delta value.
  728. This function can also be used for color comparisons if both the \a actual and
  729. \a expected values can be converted into color values. If any of the differences
  730. for RGBA channel values are greater than \a delta, the test fails.
  731. \sa tryCompare(), compare()
  732. */
  733. function fuzzyCompare(actual, expected, delta, msg) {
  734. if (delta === undefined)
  735. qtest_fail("A delta value is required for fuzzyCompare", 2)
  736. var success = qtest_results.fuzzyCompare(actual, expected, delta)
  737. if (msg === undefined) {
  738. if (success)
  739. msg = "FUZZYCOMPARE()"
  740. else
  741. msg = "Compared values are not the same with delta(" + delta + ")"
  742. }
  743. if (!qtest_results.compare(success, msg, actual, expected, util.callerFile(), util.callerLine())) {
  744. throw new Error("QtQuickTest::fail")
  745. }
  746. }
  747. /*!
  748. \qmlmethod object TestCase::grabImage(item)
  749. Returns a snapshot image object of the given \a item.
  750. The returned image object has the following properties:
  751. \list
  752. \li width Returns the width of the underlying image (since 5.10)
  753. \li height Returns the height of the underlying image (since 5.10)
  754. \li size Returns the size of the underlying image (since 5.10)
  755. \endlist
  756. Additionally, the returned image object has the following methods:
  757. \list
  758. \li \c {red(x, y)} Returns the red channel value of the pixel at \e x, \e y position
  759. \li \c {green(x, y)} Returns the green channel value of the pixel at \e x, \e y position
  760. \li \c {blue(x, y)} Returns the blue channel value of the pixel at \e x, \e y position
  761. \li \c {alpha(x, y)} Returns the alpha channel value of the pixel at \e x, \e y position
  762. \li \c {pixel(x, y)} Returns the color value of the pixel at \e x, \e y position
  763. \li \c {equals(image)} Returns \c true if this image is identical to \e image -
  764. see \l QImage::operator== (since 5.6)
  765. For example:
  766. \code
  767. var image = grabImage(rect);
  768. compare(image.red(10, 10), 255);
  769. compare(image.pixel(20, 20), Qt.rgba(255, 0, 0, 255));
  770. rect.width += 10;
  771. var newImage = grabImage(rect);
  772. verify(!newImage.equals(image));
  773. \endcode
  774. \li \c {save(path)} Saves the image to the given \e path. If the image cannot
  775. be saved, an exception will be thrown. (since 5.10)
  776. This can be useful to perform postmortem analysis on failing tests, for
  777. example:
  778. \code
  779. var image = grabImage(rect);
  780. try {
  781. compare(image.width, 100);
  782. } catch (ex) {
  783. image.save("debug.png");
  784. throw ex;
  785. }
  786. \endcode
  787. \endlist
  788. */
  789. function grabImage(item) {
  790. return qtest_results.grabImage(item);
  791. }
  792. /*!
  793. \since 5.4
  794. \qmlmethod QtObject TestCase::findChild(parent, objectName)
  795. Returns the first child of \a parent with \a objectName, or \c null if
  796. no such item exists. Both visual and non-visual children are searched
  797. recursively, with visual children being searched first.
  798. \code
  799. compare(findChild(item, "childObject"), expectedChildObject);
  800. \endcode
  801. */
  802. function findChild(parent, objectName) {
  803. // First, search the visual item hierarchy.
  804. var child = qtest_findVisualChild(parent, objectName);
  805. if (child)
  806. return child;
  807. // If it's not a visual child, it might be a QObject child.
  808. return qtest_results.findChild(parent, objectName);
  809. }
  810. /*! \internal */
  811. function qtest_findVisualChild(parent, objectName) {
  812. if (!parent || parent.children === undefined)
  813. return null;
  814. for (var i = 0; i < parent.children.length; ++i) {
  815. // Is this direct child of ours the child we're after?
  816. var child = parent.children[i];
  817. if (child.objectName === objectName)
  818. return child;
  819. }
  820. for (i = 0; i < parent.children.length; ++i) {
  821. // Try the direct child's children.
  822. child = qtest_findVisualChild(parent.children[i], objectName);
  823. if (child)
  824. return child;
  825. }
  826. return null;
  827. }
  828. /*!
  829. \qmlmethod TestCase::tryCompare(obj, property, expected, timeout = 5000, message = "")
  830. Fails the current test case if the specified \a property on \a obj
  831. is not the same as \a expected, and displays the optional \a message.
  832. The test will be retried multiple times until the
  833. \a timeout (in milliseconds) is reached.
  834. This function is intended for testing applications where a property
  835. changes value based on asynchronous events. Use compare() for testing
  836. synchronous property changes.
  837. \code
  838. tryCompare(img, "status", BorderImage.Ready)
  839. compare(img.width, 120)
  840. compare(img.height, 120)
  841. compare(img.horizontalTileMode, BorderImage.Stretch)
  842. compare(img.verticalTileMode, BorderImage.Stretch)
  843. \endcode
  844. SignalSpy::wait() provides an alternative method to wait for a
  845. signal to be emitted.
  846. \sa compare(), SignalSpy::wait()
  847. */
  848. function tryCompare(obj, prop, value, timeout, msg) {
  849. if (arguments.length == 1 || (typeof(prop) != "string" && typeof(prop) != "number")) {
  850. qtest_results.fail("A property name as string or index is required for tryCompare",
  851. util.callerFile(), util.callerLine())
  852. throw new Error("QtQuickTest::fail")
  853. }
  854. if (arguments.length == 2) {
  855. qtest_results.fail("A value is required for tryCompare",
  856. util.callerFile(), util.callerLine())
  857. throw new Error("QtQuickTest::fail")
  858. }
  859. if (timeout !== undefined && typeof(timeout) != "number") {
  860. qtest_results.fail("timeout should be a number",
  861. util.callerFile(), util.callerLine())
  862. throw new Error("QtQuickTest::fail")
  863. }
  864. if (!timeout)
  865. timeout = 5000
  866. if (msg === undefined)
  867. msg = "property " + prop
  868. if (!qtest_compareInternal(obj[prop], value))
  869. wait(0)
  870. var i = 0
  871. while (i < timeout && !qtest_compareInternal(obj[prop], value)) {
  872. wait(50)
  873. i += 50
  874. }
  875. var actual = obj[prop]
  876. var act = qtest_results.stringify(actual)
  877. var exp = qtest_results.stringify(value)
  878. var success = qtest_compareInternal(actual, value)
  879. if (!qtest_results.compare(success, msg, act, exp, util.callerFile(), util.callerLine()))
  880. throw new Error("QtQuickTest::fail")
  881. }
  882. /*!
  883. \qmlmethod TestCase::skip(message = "")
  884. Skips the current test case and prints the optional \a message.
  885. If this is a data-driven test, then only the current row is skipped.
  886. Similar to \c{QSKIP(message)} in C++.
  887. */
  888. function skip(msg) {
  889. if (msg === undefined)
  890. msg = ""
  891. qtest_results.skip(msg, util.callerFile(), util.callerLine())
  892. throw new Error("QtQuickTest::skip")
  893. }
  894. /*!
  895. \qmlmethod TestCase::expectFail(tag, message)
  896. In a data-driven test, marks the row associated with \a tag as
  897. expected to fail. When the fail occurs, display the \a message,
  898. abort the test, and mark the test as passing. Similar to
  899. \c{QEXPECT_FAIL(tag, message, Abort)} in C++.
  900. If the test is not data-driven, then \a tag must be set to
  901. an empty string.
  902. \sa expectFailContinue()
  903. */
  904. function expectFail(tag, msg) {
  905. if (tag === undefined) {
  906. warn("tag argument missing from expectFail()")
  907. tag = ""
  908. }
  909. if (msg === undefined) {
  910. warn("message argument missing from expectFail()")
  911. msg = ""
  912. }
  913. if (!qtest_results.expectFail(tag, msg, util.callerFile(), util.callerLine()))
  914. throw new Error("QtQuickTest::expectFail")
  915. }
  916. /*!
  917. \qmlmethod TestCase::expectFailContinue(tag, message)
  918. In a data-driven test, marks the row associated with \a tag as
  919. expected to fail. When the fail occurs, display the \a message,
  920. and then continue the test. Similar to
  921. \c{QEXPECT_FAIL(tag, message, Continue)} in C++.
  922. If the test is not data-driven, then \a tag must be set to
  923. an empty string.
  924. \sa expectFail()
  925. */
  926. function expectFailContinue(tag, msg) {
  927. if (tag === undefined) {
  928. warn("tag argument missing from expectFailContinue()")
  929. tag = ""
  930. }
  931. if (msg === undefined) {
  932. warn("message argument missing from expectFailContinue()")
  933. msg = ""
  934. }
  935. if (!qtest_results.expectFailContinue(tag, msg, util.callerFile(), util.callerLine()))
  936. throw new Error("QtQuickTest::expectFail")
  937. }
  938. /*!
  939. \qmlmethod TestCase::warn(message)
  940. Prints \a message as a warning message. Similar to
  941. \c{QWARN(message)} in C++.
  942. \sa ignoreWarning()
  943. */
  944. function warn(msg) {
  945. if (msg === undefined)
  946. msg = ""
  947. qtest_results.warn(msg, util.callerFile(), util.callerLine());
  948. }
  949. /*!
  950. \qmlmethod TestCase::ignoreWarning(message)
  951. Marks \a message as an ignored warning message. When it occurs,
  952. the warning will not be printed and the test passes. If the message
  953. does not occur, then the test will fail. Similar to
  954. \c{QTest::ignoreMessage(QtWarningMsg, message)} in C++.
  955. Since Qt 5.12, \a message can be either a string, or a regular
  956. expression providing a pattern of messages to ignore.
  957. For example, the following snippet will ignore a string warning message:
  958. \qml
  959. ignoreWarning("Something sort of bad happened")
  960. \endqml
  961. And the following snippet will ignore a regular expression matching a
  962. number of possible warning messages:
  963. \qml
  964. ignoreWarning(new RegExp("[0-9]+ bad things happened"))
  965. \endqml
  966. \note Despite being a JavaScript RegExp object, it will not be
  967. interpreted as such; instead, the pattern will be passed to
  968. \l QRegularExpression.
  969. \sa warn()
  970. */
  971. function ignoreWarning(msg) {
  972. if (msg === undefined)
  973. msg = ""
  974. qtest_results.ignoreWarning(msg)
  975. }
  976. /*!
  977. \qmlmethod TestCase::wait(ms)
  978. Waits for \a ms milliseconds while processing Qt events.
  979. \sa sleep(), waitForRendering()
  980. */
  981. function wait(ms) {
  982. qtest_results.wait(ms)
  983. }
  984. /*!
  985. \qmlmethod TestCase::waitForRendering(item, timeout = 5000)
  986. Waits for \a timeout milliseconds or until the \a item is rendered by the renderer.
  987. Returns true if \c item is rendered in \a timeout milliseconds, otherwise returns false.
  988. The default \a timeout value is 5000.
  989. \sa sleep(), wait()
  990. */
  991. function waitForRendering(item, timeout) {
  992. if (timeout === undefined)
  993. timeout = 5000
  994. if (!qtest_verifyItem(item, "waitForRendering"))
  995. return
  996. return qtest_results.waitForRendering(item, timeout)
  997. }
  998. /*!
  999. \qmlmethod TestCase::sleep(ms)
  1000. Sleeps for \a ms milliseconds without processing Qt events.
  1001. \sa wait(), waitForRendering()
  1002. */
  1003. function sleep(ms) {
  1004. qtest_results.sleep(ms)
  1005. }
  1006. /*!
  1007. \qmlmethod TestCase::keyPress(key, modifiers = Qt.NoModifier, delay = -1)
  1008. Simulates pressing a \a key with optional \a modifiers on the currently
  1009. focused item. If \a delay is larger than 0, the test will wait for
  1010. \a delay milliseconds.
  1011. The event will be sent to the TestCase window or, in case of multiple windows,
  1012. to the current active window. See \l QGuiApplication::focusWindow() for more details.
  1013. \b{Note:} At some point you should release the key using keyRelease().
  1014. \sa keyRelease(), keyClick()
  1015. */
  1016. function keyPress(key, modifiers, delay) {
  1017. if (modifiers === undefined)
  1018. modifiers = Qt.NoModifier
  1019. if (delay == undefined)
  1020. delay = -1
  1021. if (typeof(key) == "string" && key.length == 1) {
  1022. if (!qtest_events.keyPressChar(key, modifiers, delay))
  1023. qtest_fail("window not shown", 2)
  1024. } else {
  1025. if (!qtest_events.keyPress(key, modifiers, delay))
  1026. qtest_fail("window not shown", 2)
  1027. }
  1028. }
  1029. /*!
  1030. \qmlmethod TestCase::keyRelease(key, modifiers = Qt.NoModifier, delay = -1)
  1031. Simulates releasing a \a key with optional \a modifiers on the currently
  1032. focused item. If \a delay is larger than 0, the test will wait for
  1033. \a delay milliseconds.
  1034. The event will be sent to the TestCase window or, in case of multiple windows,
  1035. to the current active window. See \l QGuiApplication::focusWindow() for more details.
  1036. \sa keyPress(), keyClick()
  1037. */
  1038. function keyRelease(key, modifiers, delay) {
  1039. if (modifiers === undefined)
  1040. modifiers = Qt.NoModifier
  1041. if (delay == undefined)
  1042. delay = -1
  1043. if (typeof(key) == "string" && key.length == 1) {
  1044. if (!qtest_events.keyReleaseChar(key, modifiers, delay))
  1045. qtest_fail("window not shown", 2)
  1046. } else {
  1047. if (!qtest_events.keyRelease(key, modifiers, delay))
  1048. qtest_fail("window not shown", 2)
  1049. }
  1050. }
  1051. /*!
  1052. \qmlmethod TestCase::keyClick(key, modifiers = Qt.NoModifier, delay = -1)
  1053. Simulates clicking of \a key with optional \a modifiers on the currently
  1054. focused item. If \a delay is larger than 0, the test will wait for
  1055. \a delay milliseconds.
  1056. The event will be sent to the TestCase window or, in case of multiple windows,
  1057. to the current active window. See \l QGuiApplication::focusWindow() for more details.
  1058. \sa keyPress(), keyRelease()
  1059. */
  1060. function keyClick(key, modifiers, delay) {
  1061. if (modifiers === undefined)
  1062. modifiers = Qt.NoModifier
  1063. if (delay == undefined)
  1064. delay = -1
  1065. if (typeof(key) == "string" && key.length == 1) {
  1066. if (!qtest_events.keyClickChar(key, modifiers, delay))
  1067. qtest_fail("window not shown", 2)
  1068. } else {
  1069. if (!qtest_events.keyClick(key, modifiers, delay))
  1070. qtest_fail("window not shown", 2)
  1071. }
  1072. }
  1073. /*!
  1074. \since 5.10
  1075. \qmlmethod TestCase::keySequence(keySequence)
  1076. Simulates typing of \a keySequence. The key sequence can be set
  1077. to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, or
  1078. it can be described with a string containing a sequence of up to four key
  1079. presses.
  1080. Each event shall be sent to the TestCase window or, in case of multiple windows,
  1081. to the current active window. See \l QGuiApplication::focusWindow() for more details.
  1082. \sa keyPress(), keyRelease(), {GNU Emacs Style Key Sequences},
  1083. {QtQuick::Shortcut::sequence}{Shortcut.sequence}
  1084. */
  1085. function keySequence(keySequence) {
  1086. if (!qtest_events.keySequence(keySequence))
  1087. qtest_fail("window not shown", 2)
  1088. }
  1089. /*!
  1090. \qmlmethod TestCase::mousePress(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  1091. Simulates pressing a mouse \a button with optional \a modifiers
  1092. on an \a item. The position is defined by \a x and \a y.
  1093. If \a x or \a y are not defined the position will be the center of \a item.
  1094. If \a delay is specified, the test will wait for the specified amount of
  1095. milliseconds before the press.
  1096. The position given by \a x and \a y is transformed from the co-ordinate
  1097. system of \a item into window co-ordinates and then delivered.
  1098. If \a item is obscured by another item, or a child of \a item occupies
  1099. that position, then the event will be delivered to the other item instead.
  1100. \sa mouseRelease(), mouseClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
  1101. */
  1102. function mousePress(item, x, y, button, modifiers, delay) {
  1103. if (!qtest_verifyItem(item, "mousePress"))
  1104. return
  1105. if (button === undefined)
  1106. button = Qt.LeftButton
  1107. if (modifiers === undefined)
  1108. modifiers = Qt.NoModifier
  1109. if (delay == undefined)
  1110. delay = -1
  1111. if (x === undefined)
  1112. x = item.width / 2
  1113. if (y === undefined)
  1114. y = item.height / 2
  1115. if (!qtest_events.mousePress(item, x, y, button, modifiers, delay))
  1116. qtest_fail("window not shown", 2)
  1117. }
  1118. /*!
  1119. \qmlmethod TestCase::mouseRelease(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  1120. Simulates releasing a mouse \a button with optional \a modifiers
  1121. on an \a item. The position of the release is defined by \a x and \a y.
  1122. If \a x or \a y are not defined the position will be the center of \a item.
  1123. If \a delay is specified, the test will wait for the specified amount of
  1124. milliseconds before releasing the button.
  1125. The position given by \a x and \a y is transformed from the co-ordinate
  1126. system of \a item into window co-ordinates and then delivered.
  1127. If \a item is obscured by another item, or a child of \a item occupies
  1128. that position, then the event will be delivered to the other item instead.
  1129. \sa mousePress(), mouseClick(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
  1130. */
  1131. function mouseRelease(item, x, y, button, modifiers, delay) {
  1132. if (!qtest_verifyItem(item, "mouseRelease"))
  1133. return
  1134. if (button === undefined)
  1135. button = Qt.LeftButton
  1136. if (modifiers === undefined)
  1137. modifiers = Qt.NoModifier
  1138. if (delay == undefined)
  1139. delay = -1
  1140. if (x === undefined)
  1141. x = item.width / 2
  1142. if (y === undefined)
  1143. y = item.height / 2
  1144. if (!qtest_events.mouseRelease(item, x, y, button, modifiers, delay))
  1145. qtest_fail("window not shown", 2)
  1146. }
  1147. /*!
  1148. \qmlmethod TestCase::mouseDrag(item, x, y, dx, dy, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  1149. Simulates dragging the mouse on an \a item with \a button pressed and optional \a modifiers
  1150. The initial drag position is defined by \a x and \a y,
  1151. and drag distance is defined by \a dx and \a dy. If \a delay is specified,
  1152. the test will wait for the specified amount of milliseconds before releasing the button.
  1153. The position given by \a x and \a y is transformed from the co-ordinate
  1154. system of \a item into window co-ordinates and then delivered.
  1155. If \a item is obscured by another item, or a child of \a item occupies
  1156. that position, then the event will be delivered to the other item instead.
  1157. \sa mousePress(), mouseClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseWheel()
  1158. */
  1159. function mouseDrag(item, x, y, dx, dy, button, modifiers, delay) {
  1160. if (!qtest_verifyItem(item, "mouseDrag"))
  1161. return
  1162. if (item.x === undefined || item.y === undefined)
  1163. return
  1164. if (button === undefined)
  1165. button = Qt.LeftButton
  1166. if (modifiers === undefined)
  1167. modifiers = Qt.NoModifier
  1168. if (delay == undefined)
  1169. delay = -1
  1170. var moveDelay = Math.max(1, delay === -1 ? qtest_events.defaultMouseDelay : delay)
  1171. // Divide dx and dy to have intermediate mouseMove while dragging
  1172. // Fractions of dx/dy need be superior to the dragThreshold
  1173. // to make the drag works though
  1174. var intermediateDx = Math.round(dx/3)
  1175. if (Math.abs(intermediateDx) < (util.dragThreshold + 1))
  1176. intermediateDx = 0
  1177. var intermediateDy = Math.round(dy/3)
  1178. if (Math.abs(intermediateDy) < (util.dragThreshold + 1))
  1179. intermediateDy = 0
  1180. mousePress(item, x, y, button, modifiers, delay)
  1181. // Trigger dragging by dragging past the drag threshold, but making sure to only drag
  1182. // along a certain axis if a distance greater than zero was given for that axis.
  1183. var dragTriggerXDistance = dx > 0 ? (util.dragThreshold + 1) : 0
  1184. var dragTriggerYDistance = dy > 0 ? (util.dragThreshold + 1) : 0
  1185. mouseMove(item, x + dragTriggerXDistance, y + dragTriggerYDistance, moveDelay, button)
  1186. if (intermediateDx !== 0 || intermediateDy !== 0) {
  1187. mouseMove(item, x + intermediateDx, y + intermediateDy, moveDelay, button)
  1188. mouseMove(item, x + 2*intermediateDx, y + 2*intermediateDy, moveDelay, button)
  1189. }
  1190. mouseMove(item, x + dx, y + dy, moveDelay, button)
  1191. mouseRelease(item, x + dx, y + dy, button, modifiers, delay)
  1192. }
  1193. /*!
  1194. \qmlmethod TestCase::mouseClick(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  1195. Simulates clicking a mouse \a button with optional \a modifiers
  1196. on an \a item. The position of the click is defined by \a x and \a y.
  1197. If \a x and \a y are not defined the position will be the center of \a item.
  1198. If \a delay is specified, the test will wait for the specified amount of
  1199. milliseconds before pressing and before releasing the button.
  1200. The position given by \a x and \a y is transformed from the co-ordinate
  1201. system of \a item into window co-ordinates and then delivered.
  1202. If \a item is obscured by another item, or a child of \a item occupies
  1203. that position, then the event will be delivered to the other item instead.
  1204. \sa mousePress(), mouseRelease(), mouseDoubleClickSequence(), mouseMove(), mouseDrag(), mouseWheel()
  1205. */
  1206. function mouseClick(item, x, y, button, modifiers, delay) {
  1207. if (!qtest_verifyItem(item, "mouseClick"))
  1208. return
  1209. if (button === undefined)
  1210. button = Qt.LeftButton
  1211. if (modifiers === undefined)
  1212. modifiers = Qt.NoModifier
  1213. if (delay == undefined)
  1214. delay = -1
  1215. if (x === undefined)
  1216. x = item.width / 2
  1217. if (y === undefined)
  1218. y = item.height / 2
  1219. if (!qtest_events.mouseClick(item, x, y, button, modifiers, delay))
  1220. qtest_fail("window not shown", 2)
  1221. }
  1222. /*!
  1223. \qmlmethod TestCase::mouseDoubleClick(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  1224. \deprecated
  1225. Simulates double-clicking a mouse \a button with optional \a modifiers
  1226. on an \a item. The position of the click is defined by \a x and \a y.
  1227. If \a x and \a y are not defined the position will be the center of \a item.
  1228. If \a delay is specified, the test will wait for the specified amount of
  1229. milliseconds before pressing and before releasing the button.
  1230. The position given by \a x and \a y is transformed from the co-ordinate
  1231. system of \a item into window co-ordinates and then delivered.
  1232. If \a item is obscured by another item, or a child of \a item occupies
  1233. that position, then the event will be delivered to the other item instead.
  1234. \sa mouseDoubleClickSequence(), mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel()
  1235. */
  1236. function mouseDoubleClick(item, x, y, button, modifiers, delay) {
  1237. if (!qtest_verifyItem(item, "mouseDoubleClick"))
  1238. return
  1239. if (button === undefined)
  1240. button = Qt.LeftButton
  1241. if (modifiers === undefined)
  1242. modifiers = Qt.NoModifier
  1243. if (delay == undefined)
  1244. delay = -1
  1245. if (x === undefined)
  1246. x = item.width / 2
  1247. if (y === undefined)
  1248. y = item.height / 2
  1249. if (!qtest_events.mouseDoubleClick(item, x, y, button, modifiers, delay))
  1250. qtest_fail("window not shown", 2)
  1251. }
  1252. /*!
  1253. \qmlmethod TestCase::mouseDoubleClickSequence(item, x = item.width / 2, y = item.height / 2, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  1254. Simulates the full sequence of events generated by double-clicking a mouse
  1255. \a button with optional \a modifiers on an \a item.
  1256. This method reproduces the sequence of mouse events generated when a user makes
  1257. a double click: Press-Release-Press-DoubleClick-Release.
  1258. The position of the click is defined by \a x and \a y.
  1259. If \a x and \a y are not defined the position will be the center of \a item.
  1260. If \a delay is specified, the test will wait for the specified amount of
  1261. milliseconds before pressing and before releasing the button.
  1262. The position given by \a x and \a y is transformed from the co-ordinate
  1263. system of \a item into window co-ordinates and then delivered.
  1264. If \a item is obscured by another item, or a child of \a item occupies
  1265. that position, then the event will be delivered to the other item instead.
  1266. This QML method was introduced in Qt 5.5.
  1267. \sa mousePress(), mouseRelease(), mouseClick(), mouseMove(), mouseDrag(), mouseWheel()
  1268. */
  1269. function mouseDoubleClickSequence(item, x, y, button, modifiers, delay) {
  1270. if (!qtest_verifyItem(item, "mouseDoubleClickSequence"))
  1271. return
  1272. if (button === undefined)
  1273. button = Qt.LeftButton
  1274. if (modifiers === undefined)
  1275. modifiers = Qt.NoModifier
  1276. if (delay == undefined)
  1277. delay = -1
  1278. if (x === undefined)
  1279. x = item.width / 2
  1280. if (y === undefined)
  1281. y = item.height / 2
  1282. if (!qtest_events.mouseDoubleClickSequence(item, x, y, button, modifiers, delay))
  1283. qtest_fail("window not shown", 2)
  1284. }
  1285. /*!
  1286. \qmlmethod TestCase::mouseMove(item, x, y, delay = -1)
  1287. Moves the mouse pointer to the position given by \a x and \a y within
  1288. \a item. If a \a delay (in milliseconds) is given, the test will wait
  1289. before moving the mouse pointer.
  1290. The position given by \a x and \a y is transformed from the co-ordinate
  1291. system of \a item into window co-ordinates and then delivered.
  1292. If \a item is obscured by another item, or a child of \a item occupies
  1293. that position, then the event will be delivered to the other item instead.
  1294. \sa mousePress(), mouseRelease(), mouseClick(), mouseDoubleClickSequence(), mouseDrag(), mouseWheel()
  1295. */
  1296. function mouseMove(item, x, y, delay, buttons) {
  1297. if (!qtest_verifyItem(item, "mouseMove"))
  1298. return
  1299. if (delay == undefined)
  1300. delay = -1
  1301. if (buttons == undefined)
  1302. buttons = Qt.NoButton
  1303. if (!qtest_events.mouseMove(item, x, y, delay, buttons))
  1304. qtest_fail("window not shown", 2)
  1305. }
  1306. /*!
  1307. \qmlmethod TestCase::mouseWheel(item, x, y, xDelta, yDelta, button = Qt.LeftButton, modifiers = Qt.NoModifier, delay = -1)
  1308. Simulates rotating the mouse wheel on an \a item with \a button pressed and optional \a modifiers.
  1309. The position of the wheel event is defined by \a x and \a y.
  1310. If \a delay is specified, the test will wait for the specified amount of milliseconds before releasing the button.
  1311. The position given by \a x and \a y is transformed from the co-ordinate
  1312. system of \a item into window co-ordinates and then delivered.
  1313. If \a item is obscured by another item, or a child of \a item occupies
  1314. that position, then the event will be delivered to the other item instead.
  1315. The \a xDelta and \a yDelta contain the wheel rotation distance in eighths of a degree. see \l QWheelEvent::angleDelta() for more details.
  1316. \sa mousePress(), mouseClick(), mouseDoubleClickSequence(), mouseMove(), mouseRelease(), mouseDrag(), QWheelEvent::angleDelta()
  1317. */
  1318. function mouseWheel(item, x, y, xDelta, yDelta, buttons, modifiers, delay) {
  1319. if (!qtest_verifyItem(item, "mouseWheel"))
  1320. return
  1321. if (delay == undefined)
  1322. delay = -1
  1323. if (buttons == undefined)
  1324. buttons = Qt.NoButton
  1325. if (modifiers === undefined)
  1326. modifiers = Qt.NoModifier
  1327. if (xDelta == undefined)
  1328. xDelta = 0
  1329. if (yDelta == undefined)
  1330. yDelta = 0
  1331. if (!qtest_events.mouseWheel(item, x, y, buttons, modifiers, xDelta, yDelta, delay))
  1332. qtest_fail("window not shown", 2)
  1333. }
  1334. /*!
  1335. \qmlmethod TouchEventSequence TestCase::touchEvent(object item)
  1336. \since 5.9
  1337. Begins a sequence of touch events through a simulated QTouchDevice::TouchScreen.
  1338. Events are delivered to the window containing \a item.
  1339. The returned object is used to enumerate events to be delivered through a single
  1340. QTouchEvent. Touches are delivered to the window containing the TestCase unless
  1341. otherwise specified.
  1342. \code
  1343. Rectangle {
  1344. width: 640; height: 480
  1345. MultiPointTouchArea {
  1346. id: area
  1347. anchors.fill: parent
  1348. property bool touched: false
  1349. onPressed: touched = true
  1350. }
  1351. TestCase {
  1352. name: "ItemTests"
  1353. when: windowShown
  1354. id: test1
  1355. function test_touch() {
  1356. var touch = touchEvent(area);
  1357. touch.press(0, area, 10, 10);
  1358. touch.commit();
  1359. verify(area.touched);
  1360. }
  1361. }
  1362. }
  1363. \endcode
  1364. \sa TouchEventSequence::press(), TouchEventSequence::move(), TouchEventSequence::release(), TouchEventSequence::stationary(), TouchEventSequence::commit(), QTouchDevice::TouchScreen
  1365. */
  1366. function touchEvent(item) {
  1367. if (!qtest_verifyItem(item, "touchEvent"))
  1368. return
  1369. return {
  1370. _defaultItem: item,
  1371. _sequence: qtest_events.touchEvent(item),
  1372. press: function (id, target, x, y) {
  1373. if (!target)
  1374. target = this._defaultItem;
  1375. if (id === undefined)
  1376. qtest_fail("No id given to TouchEventSequence::press", 1);
  1377. if (x === undefined)
  1378. x = target.width / 2;
  1379. if (y === undefined)
  1380. y = target.height / 2;
  1381. this._sequence.press(id, target, x, y);
  1382. return this;
  1383. },
  1384. move: function (id, target, x, y) {
  1385. if (!target)
  1386. target = this._defaultItem;
  1387. if (id === undefined)
  1388. qtest_fail("No id given to TouchEventSequence::move", 1);
  1389. if (x === undefined)
  1390. x = target.width / 2;
  1391. if (y === undefined)
  1392. y = target.height / 2;
  1393. this._sequence.move(id, target, x, y);
  1394. return this;
  1395. },
  1396. stationary: function (id) {
  1397. if (id === undefined)
  1398. qtest_fail("No id given to TouchEventSequence::stationary", 1);
  1399. this._sequence.stationary(id);
  1400. return this;
  1401. },
  1402. release: function (id, target, x, y) {
  1403. if (!target)
  1404. target = this._defaultItem;
  1405. if (id === undefined)
  1406. qtest_fail("No id given to TouchEventSequence::release", 1);
  1407. if (x === undefined)
  1408. x = target.width / 2;
  1409. if (y === undefined)
  1410. y = target.height / 2;
  1411. this._sequence.release(id, target, x, y);
  1412. return this;
  1413. },
  1414. commit: function () {
  1415. this._sequence.commit();
  1416. return this;
  1417. }
  1418. };
  1419. }
  1420. // Functions that can be overridden in subclasses for init/cleanup duties.
  1421. /*!
  1422. \qmlmethod TestCase::initTestCase()
  1423. This function is called before any other test functions in the
  1424. \l TestCase type. The default implementation does nothing.
  1425. The application can provide its own implementation to perform
  1426. test case initialization.
  1427. \sa cleanupTestCase(), init()
  1428. */
  1429. function initTestCase() {}
  1430. /*!
  1431. \qmlmethod TestCase::cleanupTestCase()
  1432. This function is called after all other test functions in the
  1433. \l TestCase type have completed. The default implementation
  1434. does nothing. The application can provide its own implementation
  1435. to perform test case cleanup.
  1436. \sa initTestCase(), cleanup()
  1437. */
  1438. function cleanupTestCase() {}
  1439. /*!
  1440. \qmlmethod TestCase::init()
  1441. This function is called before each test function that is
  1442. executed in the \l TestCase type. The default implementation
  1443. does nothing. The application can provide its own implementation
  1444. to perform initialization before each test function.
  1445. \sa cleanup(), initTestCase()
  1446. */
  1447. function init() {}
  1448. /*!
  1449. \qmlmethod TestCase::cleanup()
  1450. This function is called after each test function that is
  1451. executed in the \l TestCase type. The default implementation
  1452. does nothing. The application can provide its own implementation
  1453. to perform cleanup after each test function.
  1454. \sa init(), cleanupTestCase()
  1455. */
  1456. function cleanup() {}
  1457. /*! \internal */
  1458. function qtest_verifyItem(item, method) {
  1459. try {
  1460. if (!(item instanceof Item) &&
  1461. !(item instanceof Window)) {
  1462. // it's a QObject, but not a type
  1463. qtest_fail("TypeError: %1 requires an Item or Window type".arg(method), 2);
  1464. return false;
  1465. }
  1466. } catch (e) { // it's not a QObject
  1467. qtest_fail("TypeError: %1 requires an Item or Window type".arg(method), 3);
  1468. return false;
  1469. }
  1470. return true;
  1471. }
  1472. /*! \internal */
  1473. function qtest_runInternal(prop, arg) {
  1474. try {
  1475. qtest_testCaseResult = testCase[prop](arg)
  1476. } catch (e) {
  1477. qtest_testCaseResult = []
  1478. if (e.message.indexOf("QtQuickTest::") != 0) {
  1479. // Test threw an unrecognized exception - fail.
  1480. qtest_results.fail("Uncaught exception: " + e.message,
  1481. e.fileName, e.lineNumber)
  1482. }
  1483. }
  1484. return !qtest_results.failed
  1485. }
  1486. /*! \internal */
  1487. function qtest_runFunction(prop, arg) {
  1488. qtest_runInternal("init")
  1489. if (!qtest_results.skipped) {
  1490. qtest_runInternal(prop, arg)
  1491. qtest_results.finishTestData()
  1492. qtest_runInternal("cleanup")
  1493. qtest_destroyTemporaryObjects()
  1494. qtest_results.finishTestDataCleanup()
  1495. // wait(0) will call processEvents() so objects marked for deletion
  1496. // in the test function will be deleted.
  1497. wait(0)
  1498. }
  1499. }
  1500. /*! \internal */
  1501. function qtest_runBenchmarkFunction(prop, arg) {
  1502. qtest_results.startMeasurement()
  1503. do {
  1504. qtest_results.beginDataRun()
  1505. do {
  1506. // Run the initialization function.
  1507. qtest_runInternal("init")
  1508. if (qtest_results.skipped)
  1509. break
  1510. // Execute the benchmark function.
  1511. if (prop.indexOf("benchmark_once_") != 0)
  1512. qtest_results.startBenchmark(TestResult.RepeatUntilValidMeasurement, qtest_results.dataTag)
  1513. else
  1514. qtest_results.startBenchmark(TestResult.RunOnce, qtest_results.dataTag)
  1515. while (!qtest_results.isBenchmarkDone()) {
  1516. var success = qtest_runInternal(prop, arg)
  1517. qtest_results.finishTestData()
  1518. if (!success)
  1519. break
  1520. qtest_results.nextBenchmark()
  1521. }
  1522. qtest_results.stopBenchmark()
  1523. // Run the cleanup function.
  1524. qtest_runInternal("cleanup")
  1525. qtest_results.finishTestDataCleanup()
  1526. // wait(0) will call processEvents() so objects marked for deletion
  1527. // in the test function will be deleted.
  1528. wait(0)
  1529. } while (!qtest_results.measurementAccepted())
  1530. qtest_results.endDataRun()
  1531. } while (qtest_results.needsMoreMeasurements())
  1532. }
  1533. /*! \internal */
  1534. function qtest_run() {
  1535. if (TestLogger.log_start_test()) {
  1536. qtest_results.reset()
  1537. qtest_results.testCaseName = name
  1538. qtest_results.startLogging()
  1539. } else {
  1540. qtest_results.testCaseName = name
  1541. }
  1542. running = true
  1543. // Check the run list to see if this class is mentioned.
  1544. let checkNames = false
  1545. let testsToRun = {} // explicitly provided function names to run and their tags for data-driven tests
  1546. if (qtest_results.functionsToRun.length > 0) {
  1547. checkNames = true
  1548. var found = false
  1549. if (name.length > 0) {
  1550. for (var index in qtest_results.functionsToRun) {
  1551. let caseFuncName = qtest_results.functionsToRun[index]
  1552. if (caseFuncName.indexOf(name + "::") != 0)
  1553. continue
  1554. found = true
  1555. let funcName = caseFuncName.substring(name.length + 2)
  1556. if (!(funcName in testsToRun))
  1557. testsToRun[funcName] = []
  1558. let tagName = qtest_results.tagsToRun[index]
  1559. if (tagName.length > 0) // empty tags mean run all rows
  1560. testsToRun[funcName].push(tagName)
  1561. }
  1562. }
  1563. if (!found) {
  1564. completed = true
  1565. if (!TestLogger.log_complete_test(qtest_testId)) {
  1566. qtest_results.stopLogging()
  1567. Qt.quit()
  1568. }
  1569. qtest_results.testCaseName = ""
  1570. return
  1571. }
  1572. }
  1573. // Run the initTestCase function.
  1574. qtest_results.functionName = "initTestCase"
  1575. var runTests = true
  1576. if (!qtest_runInternal("initTestCase"))
  1577. runTests = false
  1578. qtest_results.finishTestData()
  1579. qtest_results.finishTestDataCleanup()
  1580. qtest_results.finishTestFunction()
  1581. // Run the test methods.
  1582. var testList = []
  1583. if (runTests) {
  1584. for (var prop in testCase) {
  1585. if (prop.indexOf("test_") != 0 && prop.indexOf("benchmark_") != 0)
  1586. continue
  1587. var tail = prop.lastIndexOf("_data");
  1588. if (tail != -1 && tail == (prop.length - 5))
  1589. continue
  1590. testList.push(prop)
  1591. }
  1592. testList.sort()
  1593. }
  1594. for (var index in testList) {
  1595. var prop = testList[index]
  1596. if (checkNames && !(prop in testsToRun))
  1597. continue
  1598. var datafunc = prop + "_data"
  1599. var isBenchmark = (prop.indexOf("benchmark_") == 0)
  1600. qtest_results.functionName = prop
  1601. if (!(datafunc in testCase))
  1602. datafunc = "init_data";
  1603. if (datafunc in testCase) {
  1604. if (qtest_runInternal(datafunc)) {
  1605. var table = qtest_testCaseResult
  1606. var haveData = false
  1607. let checkTags = (checkNames && testsToRun[prop].length > 0)
  1608. qtest_results.initTestTable()
  1609. for (var index in table) {
  1610. haveData = true
  1611. var row = table[index]
  1612. if (!row.tag)
  1613. row.tag = "row " + index // Must have something
  1614. if (checkTags) {
  1615. let tags = testsToRun[prop]
  1616. let tagIdx = tags.indexOf(row.tag)
  1617. if (tagIdx < 0)
  1618. continue
  1619. tags.splice(tagIdx, 1)
  1620. }
  1621. qtest_results.dataTag = row.tag
  1622. if (isBenchmark)
  1623. qtest_runBenchmarkFunction(prop, row)
  1624. else
  1625. qtest_runFunction(prop, row)
  1626. qtest_results.dataTag = ""
  1627. qtest_results.skipped = false
  1628. }
  1629. if (!haveData) {
  1630. if (datafunc === "init_data")
  1631. qtest_runFunction(prop, null, isBenchmark)
  1632. else
  1633. qtest_results.warn("no data supplied for " + prop + "() by " + datafunc + "()"
  1634. , util.callerFile(), util.callerLine());
  1635. }
  1636. qtest_results.clearTestTable()
  1637. }
  1638. } else if (isBenchmark) {
  1639. qtest_runBenchmarkFunction(prop, null, isBenchmark)
  1640. } else {
  1641. qtest_runFunction(prop, null, isBenchmark)
  1642. }
  1643. qtest_results.finishTestFunction()
  1644. qtest_results.skipped = false
  1645. if (checkNames && testsToRun[prop].length <= 0)
  1646. delete testsToRun[prop]
  1647. }
  1648. // Run the cleanupTestCase function.
  1649. qtest_results.skipped = false
  1650. qtest_results.functionName = "cleanupTestCase"
  1651. qtest_runInternal("cleanupTestCase")
  1652. // Complain about missing functions that we were supposed to run.
  1653. if (checkNames) {
  1654. let missingTests = []
  1655. for (var func in testsToRun) {
  1656. let caseFuncName = name + '::' + func
  1657. let tags = testsToRun[func]
  1658. if (tags.length <= 0)
  1659. missingTests.push(caseFuncName)
  1660. else
  1661. for (var i in tags)
  1662. missingTests.push(caseFuncName + ':' + tags[i])
  1663. }
  1664. missingTests.sort()
  1665. if (missingTests.length > 0)
  1666. qtest_results.fail("Could not find test functions: " + missingTests, "", 0)
  1667. }
  1668. // Clean up and exit.
  1669. running = false
  1670. completed = true
  1671. qtest_results.finishTestData()
  1672. qtest_results.finishTestDataCleanup()
  1673. qtest_results.finishTestFunction()
  1674. qtest_results.functionName = ""
  1675. // Stop if there are no more tests to be run.
  1676. if (!TestLogger.log_complete_test(qtest_testId)) {
  1677. qtest_results.stopLogging()
  1678. Qt.quit()
  1679. }
  1680. qtest_results.testCaseName = ""
  1681. }
  1682. onWhenChanged: {
  1683. if (when != qtest_prevWhen) {
  1684. qtest_prevWhen = when
  1685. if (when && !completed && !running && qtest_componentCompleted)
  1686. qtest_run()
  1687. }
  1688. }
  1689. onOptionalChanged: {
  1690. if (!completed) {
  1691. if (optional)
  1692. TestLogger.log_optional_test(qtest_testId)
  1693. else
  1694. TestLogger.log_mandatory_test(qtest_testId)
  1695. }
  1696. }
  1697. Component.onCompleted: {
  1698. QTestRootObject.hasTestCase = true;
  1699. qtest_componentCompleted = true;
  1700. qtest_testId = TestLogger.log_register_test(name)
  1701. if (optional)
  1702. TestLogger.log_optional_test(qtest_testId)
  1703. qtest_prevWhen = when
  1704. if (when && !completed && !running)
  1705. qtest_run()
  1706. }
  1707. }