diff options
Diffstat (limited to 'tests')
198 files changed, 5866 insertions, 759 deletions
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 425e88b983..556f5ddc7a 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -2,16 +2,21 @@ TEMPLATE=subdirs SUBDIRS=\ qml \ quick \ - particles \ qmltest \ qmldevtools \ cmake \ installed_cmake \ toolsupport -qtHaveModule(widgets): SUBDIRS += quickwidgets +qtHaveModule(gui):qtConfig(opengl(es1|es2)?) { + SUBDIRS += particles + qtHaveModule(widgets): SUBDIRS += quickwidgets + +} + +# console applications not supported +uikit: SUBDIRS -= qmltest qmldevtools.CONFIG = host_build installed_cmake.depends = cmake - diff --git a/tests/auto/particles/particles.pro b/tests/auto/particles/particles.pro index 265a1eabc7..6ee1290dbb 100644 --- a/tests/auto/particles/particles.pro +++ b/tests/auto/particles/particles.pro @@ -25,6 +25,5 @@ PRIVATETESTS += \ qquickturbulence \ qquickwander -contains(QT_CONFIG, private_tests) { +qtConfig(private_tests): \ SUBDIRS += $$PRIVATETESTS -} diff --git a/tests/auto/particles/qquickage/tst_qquickage.cpp b/tests/auto/particles/qquickage/tst_qquickage.cpp index 04c6fbd9e4..a233b30043 100644 --- a/tests/auto/particles/qquickage/tst_qquickage.cpp +++ b/tests/auto/particles/qquickage/tst_qquickage.cpp @@ -61,7 +61,7 @@ void tst_qquickage::test_kill() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -86,7 +86,7 @@ void tst_qquickage::test_jump() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -112,7 +112,7 @@ void tst_qquickage::test_onceOff() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -138,7 +138,7 @@ void tst_qquickage::test_sustained() //TODO: Ensure some particles have lived to 0.4s point despite unified timer //Can't verify size, because particles never die. It will constantly grow. - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp b/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp index 4ff72f159d..b3fc01caa6 100644 --- a/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp +++ b/tests/auto/particles/qquickangleddirection/tst_qquickangleddirection.cpp @@ -58,7 +58,7 @@ void tst_qquickangleddirection::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp b/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp index 795fcaf42e..360b222367 100644 --- a/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp +++ b/tests/auto/particles/qquickcumulativedirection/tst_qquickcumulativedirection.cpp @@ -57,7 +57,7 @@ void tst_qquickcumulativedirection::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp index fb15af4dd1..ee05fb29c9 100644 --- a/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp +++ b/tests/auto/particles/qquickcustomaffector/tst_qquickcustomaffector.cpp @@ -59,7 +59,7 @@ void tst_qquickcustomaffector::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused //in CI the whole simulation often happens at once, so dead particles end up missing out @@ -92,7 +92,7 @@ void tst_qquickcustomaffector::test_move() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused if (!d->stillAlive(system)) diff --git a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp index a722508a3e..60c6a37899 100644 --- a/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp +++ b/tests/auto/particles/qquickcustomparticle/tst_qquickcustomparticle.cpp @@ -60,7 +60,7 @@ void tst_qquickcustomparticle::test_basic() bool oneNonZero = false; QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp b/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp index ac8e2bac49..a1fe5b225d 100644 --- a/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp +++ b/tests/auto/particles/qquickellipseextruder/tst_qquickellipseextruder.cpp @@ -74,7 +74,7 @@ void tst_qquickellipseextruder::test_basic() //Filled QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -91,7 +91,7 @@ void tst_qquickellipseextruder::test_basic() //Just border QCOMPARE(system->groupData[1]->size(), 500); - foreach (QQuickParticleData *d, system->groupData[1]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp b/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp index 70e0291330..ab682c591e 100644 --- a/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp +++ b/tests/auto/particles/qquickfriction/tst_qquickfriction.cpp @@ -59,7 +59,7 @@ void tst_qquickfriction::test_basic() //Default is just slowed a little QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -76,7 +76,7 @@ void tst_qquickfriction::test_basic() //Nondefault comes to a complete stop within the first half of its life QCOMPARE(system->groupData[1]->size(), 500); - foreach (QQuickParticleData *d, system->groupData[1]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) { if (d->t == -1) continue; //Particle data unused @@ -103,7 +103,7 @@ void tst_qquickfriction::test_threshold() //Velocity capped at 50, but it might take a frame or two to get there QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1.0f) continue; //Particle data unused if (myFuzzyGEQ(d->t, ((qreal)system->timeInt/1000.0) - 0.1)) diff --git a/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp b/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp index 8ef075dc9b..34566b90eb 100644 --- a/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp +++ b/tests/auto/particles/qquickgravity/tst_qquickgravity.cpp @@ -58,7 +58,7 @@ void tst_qquickgravity::test_basic() QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); float mag = 707.10678f; - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1 || !d->stillAlive(system)) continue; //Particle data unused or dead diff --git a/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp b/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp index fc270b991f..1228b4cc68 100644 --- a/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp +++ b/tests/auto/particles/qquickgroupgoal/tst_qquickgroupgoal.cpp @@ -58,7 +58,7 @@ void tst_qquickgroupgoal::test_instantTransition() ensureAnimTime(600, system->m_animation); QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp b/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp index cd684ec59b..7e07878d39 100644 --- a/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp +++ b/tests/auto/particles/qquickimageparticle/tst_qquickimageparticle.cpp @@ -72,7 +72,7 @@ void tst_qquickimageparticle::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -116,7 +116,7 @@ void tst_qquickimageparticle::test_colored() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -160,7 +160,7 @@ void tst_qquickimageparticle::test_colorVariance() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -205,7 +205,7 @@ void tst_qquickimageparticle::test_deformed() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -249,7 +249,7 @@ void tst_qquickimageparticle::test_tabled() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -294,7 +294,7 @@ void tst_qquickimageparticle::test_sprite() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp index 98aac71e93..d9791cdb33 100644 --- a/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp +++ b/tests/auto/particles/qquickitemparticle/tst_qquickitemparticle.cpp @@ -60,7 +60,7 @@ void tst_qquickitemparticle::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp b/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp index 1f36874f0f..6baf8539d3 100644 --- a/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp +++ b/tests/auto/particles/qquicklineextruder/tst_qquicklineextruder.cpp @@ -57,7 +57,7 @@ void tst_qquicklineextruder::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -73,7 +73,7 @@ void tst_qquicklineextruder::test_basic() } QCOMPARE(system->groupData[1]->size(), 500); - foreach (QQuickParticleData *d, system->groupData[1]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp b/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp index a3d0988019..d8481efc47 100644 --- a/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp +++ b/tests/auto/particles/qquickmaskextruder/tst_qquickmaskextruder.cpp @@ -57,7 +57,7 @@ void tst_qquickmaskextruder::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp b/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp index 8b7224623a..8791d19db6 100644 --- a/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp +++ b/tests/auto/particles/qquickparticlegroup/tst_qquickparticlegroup.cpp @@ -58,7 +58,7 @@ void tst_qquickparticlegroup::test_instantTransition() //A frame or two worth of particles will be missed, the transition doesn't take effect on the frame it's spawned (QTBUG-21781) QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp index 4a3c5cdc74..5c82b946e5 100644 --- a/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp +++ b/tests/auto/particles/qquickparticlesystem/tst_qquickparticlesystem.cpp @@ -58,7 +58,7 @@ void tst_qquickparticlesystem::test_basic() QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); int stillAlive = 0; - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp b/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp index 99a8530d3a..c0d7d38512 100644 --- a/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp +++ b/tests/auto/particles/qquickpointattractor/tst_qquickpointattractor.cpp @@ -57,7 +57,7 @@ void tst_qquickpointattractor::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp b/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp index 0d150fb86d..5cc23e0306 100644 --- a/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp +++ b/tests/auto/particles/qquickpointdirection/tst_qquickpointdirection.cpp @@ -57,7 +57,7 @@ void tst_qquickpointdirection::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp b/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp index 24b30bf9ab..414e2d36f7 100644 --- a/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp +++ b/tests/auto/particles/qquickrectangleextruder/tst_qquickrectangleextruder.cpp @@ -57,7 +57,7 @@ void tst_qquickrectangleextruder::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -76,7 +76,7 @@ void tst_qquickrectangleextruder::test_basic() } QCOMPARE(system->groupData[1]->size(), 500); - foreach (QQuickParticleData *d, system->groupData[1]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp b/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp index 8249159e43..ca5d9171f9 100644 --- a/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp +++ b/tests/auto/particles/qquickspritegoal/tst_qquickspritegoal.cpp @@ -57,7 +57,7 @@ void tst_qquickspritegoal::test_instantTransition() ensureAnimTime(600, system->m_animation); QVERIFY(system->groupData[0]->size() <= 500 && system->groupData[0]->size() >= 450); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp b/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp index 8d9556fdac..2f45263c37 100644 --- a/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp +++ b/tests/auto/particles/qquicktargetdirection/tst_qquicktargetdirection.cpp @@ -57,7 +57,7 @@ void tst_qquicktargetdirection::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp index 99ecd7a06a..27d9bf01c9 100644 --- a/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp +++ b/tests/auto/particles/qquicktrailemitter/tst_qquicktrailemitter.cpp @@ -57,7 +57,7 @@ void tst_qquicktrailemitter::test_basic() ensureAnimTime(600, system->m_animation); QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -74,7 +74,7 @@ void tst_qquicktrailemitter::test_basic() } QVERIFY(extremelyFuzzyCompare(system->groupData[1]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[1]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp b/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp index c8024470e4..74fafdc1d2 100644 --- a/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp +++ b/tests/auto/particles/qquickturbulence/tst_qquickturbulence.cpp @@ -59,7 +59,7 @@ void tst_qquickturbulence::test_basic() //Note that the noise image built-in provides the 'randomness', so this test should be stable so long as it and the size //of the Turbulence item remain the same QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 500, 10)); - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/particles/qquickwander/tst_qquickwander.cpp b/tests/auto/particles/qquickwander/tst_qquickwander.cpp index 6e37fc648c..51ef7a272e 100644 --- a/tests/auto/particles/qquickwander/tst_qquickwander.cpp +++ b/tests/auto/particles/qquickwander/tst_qquickwander.cpp @@ -61,7 +61,7 @@ void tst_qquickwander::test_basic() //the 500 was randomly changed from 0.0 in velocity bool vxChanged = false; bool vyChanged = false; - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp b/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp index ab8fa8a9ef..476ad2e955 100644 --- a/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp +++ b/tests/auto/qml/animation/qparallelanimationgroupjob/tst_qparallelanimationgroupjob.cpp @@ -63,8 +63,8 @@ private slots: void tst_QParallelAnimationGroupJob::initTestCase() { qRegisterMetaType<QAbstractAnimationJob::State>("QAbstractAnimationJob::State"); -#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) - // give the mac/wince app start event queue time to clear +#if defined(Q_OS_DARWIN) + // give the Apple application's start event queue time to clear QTest::qWait(1000); #endif } diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro index ccb2d71c53..a50411e18b 100644 --- a/tests/auto/qml/debugger/debugger.pro +++ b/tests/auto/qml/debugger/debugger.pro @@ -20,6 +20,6 @@ PRIVATETESTS += \ SUBDIRS += $$PUBLICTESTS -contains(QT_CONFIG, private_tests) { +qtConfig(private_tests): \ SUBDIRS += $$PRIVATETESTS -} + diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp index b800cc3715..d1150be831 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp @@ -42,11 +42,6 @@ #include <QtCore/qlibraryinfo.h> #include <QtQml/qjsengine.h> -#if defined (Q_OS_WINCE) -#undef IN -#undef OUT -#endif - const char *V8REQUEST = "v8request"; const char *V8MESSAGE = "v8message"; const char *SEQ = "seq"; diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp index 4568d25dc1..40e19d375d 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp @@ -1223,16 +1223,15 @@ void tst_QQmlEngineDebugService::queryObjectTree() int main(int argc, char *argv[]) { int _argc = argc + 1; - char **_argv = new char*[_argc]; + QScopedArrayPointer<char *>_argv(new char*[_argc]); for (int i = 0; i < argc; ++i) _argv[i] = argv[i]; char arg[] = "-qmljsdebugger=port:3768,services:QmlDebugger"; _argv[_argc - 1] = arg; - QGuiApplication app(_argc, _argv); + QGuiApplication app(_argc, _argv.data()); tst_QQmlEngineDebugService tc; - return QTest::qExec(&tc, _argc, _argv); - delete _argv; + return QTest::qExec(&tc, _argc, _argv.data()); } #include "tst_qqmlenginedebugservice.moc" diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml index d1db2af367..dd7cb2055d 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml @@ -26,10 +26,10 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { - Timer { +QtObject { + property var timer: Timer { running: true interval: 1 onTriggered: { @@ -38,7 +38,7 @@ Rectangle { } } - Timer { + property var stopTimer: Timer { id: stopTimer interval: 1000 onTriggered: { @@ -47,7 +47,7 @@ Rectangle { } } - Timer { + property var endTimer: Timer { id: endTimer interval: 1000 onTriggered: Qt.quit(); diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml index b250524caa..4236d70ea3 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml @@ -1,6 +1,6 @@ -import QtQuick 2.0 +import QtQml 2.0 -Item { +QtObject { Timer { running: true interval: 1 diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml index 0555d49652..e25c7524f4 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/javascript.qml @@ -1,6 +1,6 @@ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { +QtObject { function something(i) { if (i > 10) { something(i / 4); @@ -9,8 +9,8 @@ Rectangle { } } - width: 400 - height: 400 + property int width: 400 + property int height: 400 onWidthChanged: something(width); Component.onCompleted: width = 500; diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml index 25e63669c4..0eff9e9030 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/signalSourceLocation.qml @@ -1,8 +1,8 @@ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { - width: 400 - height: 400 +QtObject { + property int width: 400 + property int height: 400 onWidthChanged: console.log(width); Component.onCompleted: width = 500; diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml index 9c36e13c5b..5dd5caf12f 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/test.qml @@ -1,5 +1,5 @@ -import QtQuick 2.0 +import QtQml 2.0 -Item { +QtObject { } diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml index 18b8947172..4af555a27b 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/timer.qml @@ -1,10 +1,10 @@ -import QtQuick 2.0 +import QtQml 2.0 -Rectangle { - width: 100 - height: 62 +QtObject { + property int width: 100 + property int height: 62 - Timer { + property var timer: Timer { running: true repeat: true interval: 50 diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 4f9088d67d..c4b17aa60a 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -64,7 +64,8 @@ class QQmlProfilerTestClient : public QQmlProfilerClient Q_OBJECT public: - QQmlProfilerTestClient(QQmlDebugConnection *connection) : QQmlProfilerClient(connection) {} + QQmlProfilerTestClient(QQmlDebugConnection *connection) : QQmlProfilerClient(connection), + lastTimestamp(-1) {} QVector<QQmlProfilerData> qmlMessages; QVector<QQmlProfilerData> javascriptMessages; @@ -72,6 +73,8 @@ public: QVector<QQmlProfilerData> asynchronousMessages; QVector<QQmlProfilerData> pixmapMessages; + qint64 lastTimestamp; + signals: void recordingFinished(); @@ -114,6 +117,8 @@ void QQmlProfilerTestClient::traceFinished(qint64 time, int engineId) void QQmlProfilerTestClient::rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime) { QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); + QVERIFY(lastTimestamp <= startTime); + lastTimestamp = startTime; QQmlProfilerData data(startTime, QQmlProfilerDefinitions::RangeStart, type); if (type == QQmlProfilerDefinitions::Javascript) javascriptMessages.append(data); @@ -125,6 +130,8 @@ void QQmlProfilerTestClient::rangeData(QQmlProfilerDefinitions::RangeType type, const QString &string) { QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeData, type, string); if (type == QQmlProfilerDefinitions::Javascript) javascriptMessages.append(data); @@ -137,6 +144,8 @@ void QQmlProfilerTestClient::rangeLocation(QQmlProfilerDefinitions::RangeType ty { QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); QVERIFY(location.line >= -2); + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeLocation, type, location.filename); data.line = location.line; data.column = location.column; @@ -149,6 +158,8 @@ void QQmlProfilerTestClient::rangeLocation(QQmlProfilerDefinitions::RangeType ty void QQmlProfilerTestClient::rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime) { QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); + QVERIFY(lastTimestamp <= endTime); + lastTimestamp = endTime; QQmlProfilerData data(endTime, QQmlProfilerDefinitions::RangeEnd, type); if (type == QQmlProfilerDefinitions::Javascript) javascriptMessages.append(data); @@ -161,6 +172,8 @@ void QQmlProfilerTestClient::animationFrame(qint64 time, int frameRate, int anim QVERIFY(threadId >= 0); QVERIFY(frameRate != -1); QVERIFY(animationCount != -1); + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::Event, QQmlProfilerDefinitions::AnimationFrame); data.framerate = frameRate; @@ -178,6 +191,8 @@ void QQmlProfilerTestClient::sceneGraphEvent(QQmlProfilerDefinitions::SceneGraph Q_UNUSED(numericData3); Q_UNUSED(numericData4); Q_UNUSED(numericData5); + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; asynchronousMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::SceneGraphFrame, type)); } @@ -186,6 +201,8 @@ void QQmlProfilerTestClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEve qint64 time, const QString &url, int numericData1, int numericData2) { + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::PixmapCacheEvent, type, url); switch (type) { case QQmlProfilerDefinitions::PixmapSizeKnown: @@ -205,6 +222,8 @@ void QQmlProfilerTestClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEve void QQmlProfilerTestClient::memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time, qint64 amount) { + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; QQmlProfilerData data(time, QQmlProfilerDefinitions::MemoryAllocation, type); data.amount = amount; jsHeapMessages.append(data); @@ -213,6 +232,8 @@ void QQmlProfilerTestClient::memoryAllocation(QQmlProfilerDefinitions::MemoryTyp void QQmlProfilerTestClient::inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, int a, int b) { + QVERIFY(lastTimestamp <= time); + lastTimestamp = time; qmlMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::Event, type, QString::number(a) + QLatin1Char('x') + QString::number(b))); @@ -597,7 +618,7 @@ void tst_QQmlProfilerService::scenegraphData() // if the clocks are acting up. qint64 contextFrameTime = -1; qint64 renderFrameTime = -1; - +#ifndef QT_NO_OPENGL //Software renderer doesn't have context frames foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { if (msg.messageType == QQmlProfilerDefinitions::SceneGraphFrame) { if (msg.detailType == QQmlProfilerDefinitions::SceneGraphContextFrame) { @@ -608,7 +629,7 @@ void tst_QQmlProfilerService::scenegraphData() } QVERIFY(contextFrameTime != -1); - +#endif foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { if (msg.detailType == QQmlProfilerDefinitions::SceneGraphRendererFrame) { QVERIFY(msg.time >= contextFrameTime); @@ -667,11 +688,11 @@ void tst_QQmlProfilerService::signalSourceLocation() QLatin1String("signalSourceLocation.qml")); expected.line = 8; expected.column = 28; - VERIFY(MessageListQML, 13, expected, CheckAll); + VERIFY(MessageListQML, 9, expected, CheckAll); expected.line = 7; expected.column = 21; - VERIFY(MessageListQML, 15, expected, CheckAll); + VERIFY(MessageListQML, 11, expected, CheckAll); } void tst_QQmlProfilerService::javascript() diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index 3f89913f3b..a23b7e37eb 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -326,7 +326,7 @@ private slots: private: QV4Debugger *debugger() const { - return static_cast<QV4Debugger *>(m_v4->debugger); + return static_cast<QV4Debugger *>(m_v4->debugger()); } void evaluateJavaScript(const QString &script, const QString &fileName, int lineNumber = 1) { @@ -444,7 +444,7 @@ void tst_qv4debugger::addBreakPointWhilePaused() static QV4::ReturnedValue someCall(QV4::CallContext *ctx) { - static_cast<QV4Debugger *>(ctx->d()->engine->debugger) + static_cast<QV4Debugger *>(ctx->d()->engine->debugger()) ->removeBreakPoint("removeBreakPointForNextInstruction", 2); return QV4::Encode::undefined(); } diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h index 6fe5d897e0..1ec0a6513d 100644 --- a/tests/auto/qml/debugger/shared/debugutil_p.h +++ b/tests/auto/qml/debugger/shared/debugutil_p.h @@ -135,8 +135,6 @@ public: int lastResponseId; bool lastResult; -public slots: - void recordResponse(int requestId, bool result) { lastResponseId = requestId; diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 13bfa16581..52379a29a4 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -73,6 +73,7 @@ private slots: void newQObject(); void newQObject_ownership(); void newQObject_deletedEngine(); + void newQMetaObject(); void exceptionInSlot(); void globalObjectProperties(); void globalObjectEquals(); @@ -715,6 +716,104 @@ void tst_QJSEngine::newQObject_deletedEngine() QTRY_VERIFY(spy.count()); } +class TestQMetaObject : public QObject { + Q_OBJECT + Q_PROPERTY(int called READ called) +public: + enum Enum1 { + Zero = 0, + One, + Two + }; + enum Enum2 { + A = 0, + B, + C + }; + Q_ENUMS(Enum1 Enum2) + + Q_INVOKABLE TestQMetaObject() + : m_called(1) { + } + Q_INVOKABLE TestQMetaObject(int) + : m_called(2) { + } + Q_INVOKABLE TestQMetaObject(QString) + : m_called(3) { + } + Q_INVOKABLE TestQMetaObject(QString, int) + : m_called(4) { + } + int called() const { + return m_called; + } +private: + int m_called; +}; + +void tst_QJSEngine::newQMetaObject() { + { + QJSEngine engine; + QJSValue metaObject = engine.newQMetaObject(&TestQMetaObject::staticMetaObject); + QCOMPARE(metaObject.isNull(), false); + QCOMPARE(metaObject.isObject(), true); + QCOMPARE(metaObject.isQObject(), false); + QCOMPARE(metaObject.isCallable(), true); + QCOMPARE(metaObject.isQMetaObject(), true); + + QCOMPARE(metaObject.toQMetaObject(), &TestQMetaObject::staticMetaObject); + + QVERIFY(metaObject.strictlyEquals(engine.newQMetaObject<TestQMetaObject>())); + + + { + auto result = metaObject.callAsConstructor(); + if (result.isError()) + qDebug() << result.toString(); + QCOMPARE(result.isError(), false); + QCOMPARE(result.isNull(), false); + QCOMPARE(result.isObject(), true); + QCOMPARE(result.isQObject(), true); + QVERIFY(result.property("constructor").strictlyEquals(metaObject)); + QVERIFY(result.prototype().strictlyEquals(metaObject)); + + + QCOMPARE(result.property("called").toInt(), 1); + + } + + QJSValue integer(42); + QJSValue string("foo"); + + { + auto result = metaObject.callAsConstructor({integer}); + QCOMPARE(result.property("called").toInt(), 2); + } + + { + auto result = metaObject.callAsConstructor({string}); + QCOMPARE(result.property("called").toInt(), 3); + } + + { + auto result = metaObject.callAsConstructor({string, integer}); + QCOMPARE(result.property("called").toInt(), 4); + } + } + + { + QJSEngine engine; + QJSValue metaObject = engine.newQMetaObject(&TestQMetaObject::staticMetaObject); + QCOMPARE(metaObject.property("Zero").toInt(), 0); + QCOMPARE(metaObject.property("One").toInt(), 1); + QCOMPARE(metaObject.property("Two").toInt(), 2); + QCOMPARE(metaObject.property("A").toInt(), 0); + QCOMPARE(metaObject.property("B").toInt(), 1); + QCOMPARE(metaObject.property("C").toInt(), 2); + } + +} + void tst_QJSEngine::exceptionInSlot() { QJSEngine engine; @@ -1028,11 +1127,14 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("Math.pow") << QString("Math.pow") << QString("pow"); QTest::newRow("Math.random") << QString("Math.random") << QString("random"); QTest::newRow("Math.round") << QString("Math.round") << QString("round"); + QTest::newRow("Math.sign") << QString("Math.sign") << QString("sign"); QTest::newRow("Math.sin") << QString("Math.sin") << QString("sin"); QTest::newRow("Math.sqrt") << QString("Math.sqrt") << QString("sqrt"); QTest::newRow("Math.tan") << QString("Math.tan") << QString("tan"); QTest::newRow("Number") << QString("Number") << QString("Number"); + QTest::newRow("Number.isFinite") << QString("Number.isFinite") << QString("isFinite"); + QTest::newRow("Number.isNaN") << QString("Number.isNaN") << QString("isNaN"); QTest::newRow("Number.prototype.toString") << QString("Number.prototype.toString") << QString("toString"); QTest::newRow("Number.prototype.toLocaleString") << QString("Number.prototype.toLocaleString") << QString("toLocaleString"); QTest::newRow("Number.prototype.valueOf") << QString("Number.prototype.valueOf") << QString("valueOf"); @@ -1061,6 +1163,8 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("String.prototype.charAt") << QString("String.prototype.charAt") << QString("charAt"); QTest::newRow("String.prototype.charCodeAt") << QString("String.prototype.charCodeAt") << QString("charCodeAt"); QTest::newRow("String.prototype.concat") << QString("String.prototype.concat") << QString("concat"); + QTest::newRow("String.prototype.endsWith") << QString("String.prototype.endsWith") << QString("endsWith"); + QTest::newRow("String.prototype.includes") << QString("String.prototype.includes") << QString("includes"); QTest::newRow("String.prototype.indexOf") << QString("String.prototype.indexOf") << QString("indexOf"); QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf"); QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare"); @@ -1069,6 +1173,7 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search"); QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice"); QTest::newRow("String.prototype.split") << QString("String.prototype.split") << QString("split"); + QTest::newRow("String.prototype.startsWith") << QString("String.prototype.startsWith") << QString("startsWith"); QTest::newRow("String.prototype.substring") << QString("String.prototype.substring") << QString("substring"); QTest::newRow("String.prototype.toLowerCase") << QString("String.prototype.toLowerCase") << QString("toLowerCase"); QTest::newRow("String.prototype.toLocaleLowerCase") << QString("String.prototype.toLocaleLowerCase") << QString("toLocaleLowerCase"); @@ -1340,6 +1445,7 @@ void tst_QJSEngine::valueConversion_QVariant() QCOMPARE(qjsvalue_cast<QVariant>(QJSValue(123)), QVariant(123)); QVERIFY(eng.toScriptValue(QVariant(QMetaType::VoidStar, 0)).isNull()); + QVERIFY(eng.toScriptValue(QVariant::fromValue(nullptr)).isNull()); { QVariantMap map; @@ -1921,6 +2027,7 @@ void tst_QJSEngine::jsNumberClass() QVERIFY(ctor.property("NaN").isNumber()); QVERIFY(ctor.property("NEGATIVE_INFINITY").isNumber()); QVERIFY(ctor.property("POSITIVE_INFINITY").isNumber()); + QVERIFY(ctor.property("EPSILON").isNumber()); } QCOMPARE(proto.toNumber(), qreal(0)); QVERIFY(proto.property("constructor").strictlyEquals(ctor)); @@ -1959,6 +2066,50 @@ void tst_QJSEngine::jsNumberClass() QCOMPARE(ret.toNumber(), qreal(456)); } + QVERIFY(ctor.property("isFinite").isCallable()); + { + QJSValue ret = eng.evaluate("Number.isFinite()"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(NaN)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(Infinity)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(-Infinity)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isFinite(123)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), true); + } + + QVERIFY(ctor.property("isNaN").isCallable()); + { + QJSValue ret = eng.evaluate("Number.isNaN()"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + { + QJSValue ret = eng.evaluate("Number.isNaN(NaN)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), true); + } + { + QJSValue ret = eng.evaluate("Number.isNaN(123)"); + QVERIFY(ret.isBool()); + QCOMPARE(ret.toBool(), false); + } + QVERIFY(proto.property("toString").isCallable()); { QJSValue ret = eng.evaluate("new Number(123).toString()"); diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index 859caf72c7..d28bbc1ffa 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -431,6 +431,12 @@ void tst_QJSValue::toString() QVERIFY(!o.engine()); QCOMPARE(o.toString(), QStringLiteral("1,2,3")); } + + { + QByteArray hello = QByteArrayLiteral("Hello World"); + QJSValue jsValue = eng.toScriptValue(hello); + QCOMPARE(jsValue.toString(), QString::fromUtf8(hello)); + } } void tst_QJSValue::toNumber() @@ -978,8 +984,8 @@ void tst_QJSValue::toVariant() QCOMPARE(qjsvalue_cast<QVariant>(undefined), QVariant()); QJSValue null = eng.evaluate("null"); - QCOMPARE(null.toVariant(), QVariant(QMetaType::VoidStar, 0)); - QCOMPARE(qjsvalue_cast<QVariant>(null), QVariant(QMetaType::VoidStar, 0)); + QCOMPARE(null.toVariant(), QVariant::fromValue(nullptr)); + QCOMPARE(qjsvalue_cast<QVariant>(null), QVariant::fromValue(nullptr)); { QJSValue number = eng.toScriptValue(123.0); @@ -1055,8 +1061,8 @@ void tst_QJSValue::toVariant() QCOMPARE(qjsvalue_cast<QVariant>(undef), QVariant()); QJSValue nil = QJSValue(QJSValue::NullValue); - QCOMPARE(nil.toVariant(), QVariant(QMetaType::VoidStar, 0)); - QCOMPARE(qjsvalue_cast<QVariant>(nil), QVariant(QMetaType::VoidStar, 0)); + QCOMPARE(nil.toVariant(), QVariant::fromValue(nullptr)); + QCOMPARE(qjsvalue_cast<QVariant>(nil), QVariant::fromValue(nullptr)); } // array diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index 28f04be5d7..68a2eace19 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -8,7 +8,6 @@ PUBLICTESTS += \ qjsvalueiterator \ qjsonbinding \ qmlmin \ - qmlplugindump \ qqmlcomponent \ qqmlconsole \ qqmlengine \ @@ -61,7 +60,9 @@ PRIVATETESTS += \ v4misc \ qqmltranslation \ qqmlimport \ - qqmlobjectmodel + qqmlobjectmodel \ + qmldiskcache \ + qv4mm qtHaveModule(widgets) { PUBLICTESTS += \ @@ -72,14 +73,13 @@ qtHaveModule(widgets) { SUBDIRS += $$PUBLICTESTS \ qqmlextensionplugin SUBDIRS += $$METATYPETESTS -!winrt { # no QProcess on winrt +!uikit:!winrt { # no QProcess on uikit/winrt !contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger - SUBDIRS += qmllint + SUBDIRS += qmllint qmlplugindump } -contains(QT_CONFIG, private_tests) { +qtConfig(private_tests): \ SUBDIRS += $$PRIVATETESTS -} qtNomakeTools( \ qmlplugindump \ diff --git a/tests/auto/qml/qmldiskcache/qmldiskcache.pro b/tests/auto/qml/qmldiskcache/qmldiskcache.pro new file mode 100644 index 0000000000..f98a157b6a --- /dev/null +++ b/tests/auto/qml/qmldiskcache/qmldiskcache.pro @@ -0,0 +1,9 @@ +CONFIG += testcase +TARGET = tst_qmldiskcache +osx:CONFIG -= app_bundle + +SOURCES += tst_qmldiskcache.cpp + +RESOURCES += test.qml + +QT += core-private qml-private testlib diff --git a/tests/auto/qml/qmldiskcache/test.qml b/tests/auto/qml/qmldiskcache/test.qml new file mode 100644 index 0000000000..d632422616 --- /dev/null +++ b/tests/auto/qml/qmldiskcache/test.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property int value: 20 +} diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp new file mode 100644 index 0000000000..8ccf4714ba --- /dev/null +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -0,0 +1,562 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> + +#include <private/qv4compileddata_p.h> +#include <private/qv4compiler_p.h> +#include <private/qv4jsir_p.h> +#include <private/qv4isel_p.h> +#include <private/qv8engine_p.h> +#include <private/qv4engine_p.h> +#include <QQmlComponent> +#include <QQmlEngine> +#include <QQmlFileSelector> +#include <QThread> +#include <QCryptographicHash> +#include <QStandardPaths> +#include <QDirIterator> + +class tst_qmldiskcache: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void regenerateAfterChange(); + void registerImportForImplicitComponent(); + void basicVersionChecks(); + void recompileAfterChange(); + void fileSelectors(); + void localAliases(); + void cacheResources(); +}; + +// A wrapper around QQmlComponent to ensure the temporary reference counts +// on the type data as a result of the main thread <> loader thread communication +// are dropped. Regular Synchronous loading will leave us with an event posted +// to the gui thread and an extra refcount that will only be dropped after the +// event delivery. A plain sendPostedEvents() however is insufficient because +// we can't be sure that the event is posted after the constructor finished. +class CleanlyLoadingComponent : public QQmlComponent +{ +public: + CleanlyLoadingComponent(QQmlEngine *engine, const QUrl &url) + : QQmlComponent(engine, url, QQmlComponent::Asynchronous) + { waitForLoad(); } + CleanlyLoadingComponent(QQmlEngine *engine, const QString &fileName) + : QQmlComponent(engine, fileName, QQmlComponent::Asynchronous) + { waitForLoad(); } + + void waitForLoad() + { + QTRY_VERIFY(status() == QQmlComponent::Ready || status() == QQmlComponent::Error); + } +}; + +static void waitForFileSystem() +{ + // On macOS with HFS+ the precision of file times is measured in seconds, so to ensure that + // the newly written file has a modification date newer than an existing cache file, we must + // wait. + // Similar effects of lacking precision have been observed on some Linux systems. + QThread::sleep(1); +} + +struct TestCompiler +{ + TestCompiler(QQmlEngine *engine) + : engine(engine) + , tempDir() + , testFilePath(tempDir.path() + QStringLiteral("/test.qml")) + , cacheFilePath(tempDir.path() + QStringLiteral("/test.qmlc")) + , mappedFile(cacheFilePath) + , currentMapping(nullptr) + { + } + + bool compile(const QByteArray &contents) + { + closeMapping(); + engine->clearComponentCache(); + + waitForFileSystem(); + + { + QFile f(testFilePath); + if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + lastErrorString = f.errorString(); + return false; + } + if (f.write(contents) != contents.size()) { + lastErrorString = f.errorString(); + return false; + } + } + + CleanlyLoadingComponent component(engine, testFilePath); + if (!component.isReady()) { + lastErrorString = component.errorString(); + return false; + } + + return true; + } + + const QV4::CompiledData::Unit *mapUnit() + { + if (!mappedFile.open(QIODevice::ReadOnly)) { + lastErrorString = mappedFile.errorString(); + return nullptr; + } + + currentMapping = mappedFile.map(/*offset*/0, mappedFile.size()); + if (!currentMapping) { + lastErrorString = mappedFile.errorString(); + return nullptr; + } + QV4::CompiledData::Unit *unitPtr; + memcpy(&unitPtr, ¤tMapping, sizeof(unitPtr)); + return unitPtr; + } + + typedef void (*HeaderTweakFunction)(QV4::CompiledData::Unit *header); + bool tweakHeader(HeaderTweakFunction function) + { + closeMapping(); + + QFile f(cacheFilePath); + if (!f.open(QIODevice::ReadWrite)) + return false; + QV4::CompiledData::Unit header; + if (f.read(reinterpret_cast<char *>(&header), sizeof(header)) != sizeof(header)) + return false; + function(&header); + f.seek(0); + return f.write(reinterpret_cast<const char *>(&header), sizeof(header)) == sizeof(header); + } + + bool verify() + { + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading(); + return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), v4->iselFactory.data(), &lastErrorString); + } + + void closeMapping() + { + if (currentMapping) { + mappedFile.unmap(currentMapping); + currentMapping = nullptr; + } + mappedFile.close(); + } + + void clearCache() + { + closeMapping(); + QFile::remove(cacheFilePath); + } + + QQmlEngine *engine; + const QTemporaryDir tempDir; + const QString testFilePath; + const QString cacheFilePath; + QString lastErrorString; + QFile mappedFile; + uchar *currentMapping; +}; + +void tst_qmldiskcache::initTestCase() +{ + qputenv("QML_FORCE_DISK_CACHE", "1"); +} + +void tst_qmldiskcache::regenerateAfterChange() +{ + QQmlEngine engine; + TestCompiler testCompiler(&engine); + + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n" + "QtObject {\n" + " property string blah: Qt.platform;\n" + "}"); + + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + { + const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit(); + QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString)); + + QCOMPARE(quint32(testUnit->nObjects), quint32(1)); + + const QV4::CompiledData::Object *obj = testUnit->objectAt(0); + QCOMPARE(quint32(obj->nBindings), quint32(1)); + QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Script)); + QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(1)); + + QCOMPARE(quint32(testUnit->functionTableSize), quint32(2)); + + const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1); + QVERIFY(bindingFunction->codeOffset > testUnit->unitSize); + } + + { + const QByteArray newContents = QByteArrayLiteral("import QtQml 2.0\n" + "QtObject {\n" + " property string blah: Qt.platform;\n" + " property int secondProperty: 42;\n" + "}"); + + QVERIFY2(testCompiler.compile(newContents), qPrintable(testCompiler.lastErrorString)); + const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit(); + QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString)); + + QCOMPARE(quint32(testUnit->nObjects), quint32(1)); + + const QV4::CompiledData::Object *obj = testUnit->objectAt(0); + QCOMPARE(quint32(obj->nBindings), quint32(2)); + QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Number)); + QCOMPARE(obj->bindingTable()->valueAsNumber(), double(42)); + + QCOMPARE(quint32(testUnit->functionTableSize), quint32(2)); + + const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1); + QVERIFY(bindingFunction->codeOffset > testUnit->unitSize); + } +} + +void tst_qmldiskcache::registerImportForImplicitComponent() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import QtQuick 2.0\n" + "Loader {\n" + " sourceComponent: Item {}\n" + "}"); + + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + { + const QV4::CompiledData::Unit *testUnit = testCompiler.mapUnit(); + QVERIFY2(testUnit, qPrintable(testCompiler.lastErrorString)); + + QCOMPARE(quint32(testUnit->nImports), quint32(2)); + QCOMPARE(testUnit->stringAt(testUnit->importAt(0)->uriIndex), QStringLiteral("QtQuick")); + + QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject); + + QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->uriIndex), QString(componentType->module())); + QCOMPARE(testUnit->stringAt(testUnit->importAt(1)->qualifierIndex), QStringLiteral("QmlInternals")); + + QCOMPARE(quint32(testUnit->nObjects), quint32(3)); + + const QV4::CompiledData::Object *obj = testUnit->objectAt(0); + QCOMPARE(quint32(obj->nBindings), quint32(1)); + QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Object)); + + const QV4::CompiledData::Object *implicitComponent = testUnit->objectAt(obj->bindingTable()->value.objectIndex); + QCOMPARE(testUnit->stringAt(implicitComponent->inheritedTypeNameIndex), QStringLiteral("QmlInternals.") + componentType->elementName()); + } +} + +void tst_qmldiskcache::basicVersionChecks() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n" + "QtObject {\n" + " property string blah: Qt.platform;\n" + "}"); + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString)); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->qtVersion = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Qt version mismatch. Found 0 expected %1").arg(QT_VERSION, 0, 16)); + testCompiler.clearCache(); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->version = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("V4 data structure version mismatch. Found 0 expected %1").arg(QV4_DATA_STRUCTURE_VERSION, 0, 16)); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->architectureIndex = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Architecture mismatch. Found expected %1").arg(QSysInfo::buildAbi())); + } + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + + testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { + header->codeGeneratorIndex = 0; + }); + + QVERIFY(!testCompiler.verify()); + QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Code generator mismatch. Found code generated by but expected %1").arg(QV8Engine::getV4(&engine)->iselFactory->codeGeneratorName)); + } +} + +class TypeVersion1 : public QObject +{ + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged); +public: + + + int m_value = 0; + int value() const { return m_value; } + void setValue(int v) { m_value = v; emit valueChanged(); } + +signals: + void valueChanged(); +}; + +// Same as TypeVersion1 except the property type changed! +class TypeVersion2 : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged); +public: + + + QString m_value; + QString value() const { return m_value; } + void setValue(QString v) { m_value = v; emit valueChanged(); } + +signals: + void valueChanged(); +}; + +void tst_qmldiskcache::recompileAfterChange() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import TypeTest 1.0\n" + "TypeThatWillChange {\n" + "}"); + + qmlRegisterType<TypeVersion1>("TypeTest", 1, 0, "TypeThatWillChange"); + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString)); + } + + QDateTime initialCacheTimeStamp = QFileInfo(testCompiler.cacheFilePath).lastModified(); + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<TypeVersion1> obj(qobject_cast<TypeVersion1*>(component.create())); + QVERIFY(!obj.isNull()); + QCOMPARE(QFileInfo(testCompiler.cacheFilePath).lastModified(), initialCacheTimeStamp); + } + + engine.clearComponentCache(); + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<TypeVersion1> obj(qobject_cast<TypeVersion1*>(component.create())); + QVERIFY(!obj.isNull()); + QCOMPARE(QFileInfo(testCompiler.cacheFilePath).lastModified(), initialCacheTimeStamp); + } + + engine.clearComponentCache(); + qmlClearTypeRegistrations(); + qmlRegisterType<TypeVersion2>("TypeTest", 1, 0, "TypeThatWillChange"); + + waitForFileSystem(); + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<TypeVersion2> obj(qobject_cast<TypeVersion2*>(component.create())); + QVERIFY(!obj.isNull()); + QVERIFY(QFileInfo(testCompiler.cacheFilePath).lastModified() > initialCacheTimeStamp); + } +} + +void tst_qmldiskcache::fileSelectors() +{ + QQmlEngine engine; + + QTemporaryDir tempDir; + QVERIFY(tempDir.isValid()); + + const QString testFilePath = tempDir.path() + "/test.qml"; + { + QFile f(testFilePath); + QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); + f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject { property int value: 42 }")); + } + + const QString selector = QStringLiteral("testSelector"); + const QString selectorPath = tempDir.path() + "/+" + selector; + const QString selectedTestFilePath = selectorPath + "/test.qml"; + { + QVERIFY(QDir::root().mkpath(selectorPath)); + QFile f(selectorPath + "/test.qml"); + QVERIFY2(f.open(QIODevice::WriteOnly), qPrintable(f.errorString())); + f.write(QByteArrayLiteral("import QtQml 2.0\nQtObject { property int value: 100 }")); + } + + { + QQmlComponent component(&engine, testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 42); + + QFile cacheFile(testFilePath + "c"); + QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName())); + } + + QQmlFileSelector qmlSelector(&engine); + qmlSelector.setExtraSelectors(QStringList() << selector); + + engine.clearComponentCache(); + + { + QQmlComponent component(&engine, testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 100); + + QFile cacheFile(selectedTestFilePath + "c"); + QVERIFY2(cacheFile.exists(), qPrintable(cacheFile.fileName())); + } +} + +void tst_qmldiskcache::localAliases() +{ + QQmlEngine engine; + + TestCompiler testCompiler(&engine); + QVERIFY(testCompiler.tempDir.isValid()); + + const QByteArray contents = QByteArrayLiteral("import QtQml 2.0\n" + "QtObject {\n" + " id: root\n" + " property int prop: 100\n" + " property alias dummy1: root.prop\n" + " property alias dummy2: root.prop\n" + " property alias dummy3: root.prop\n" + " property alias dummy4: root.prop\n" + " property alias dummy5: root.prop\n" + " property alias foo: root.prop\n" + " property alias bar: root.foo\n" + "}"); + + { + testCompiler.clearCache(); + QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); + QVERIFY2(testCompiler.verify(), qPrintable(testCompiler.lastErrorString)); + } + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("bar").toInt(), 100); + } + + engine.clearComponentCache(); + + { + CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("bar").toInt(), 100); + } +} + +void tst_qmldiskcache::cacheResources() +{ + const QString cacheDirectory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); + QVERIFY(QDir::root().mkpath(cacheDirectory)); + + const QString qmlCacheDirectory = cacheDirectory + QLatin1String("/qmlcache/"); + QVERIFY(QDir(qmlCacheDirectory).removeRecursively()); + QVERIFY(QDir::root().mkpath(qmlCacheDirectory)); + QVERIFY(QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot).isEmpty()); + + + QQmlEngine engine; + + { + CleanlyLoadingComponent component(&engine, QUrl("qrc:/test.qml")); + qDebug() << component.errorString(); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QCOMPARE(obj->property("value").toInt(), 20); + } + + QCOMPARE(QDir(qmlCacheDirectory).entryList(QDir::NoDotAndDotDot | QDir::Files).count(), 1); +} + +QTEST_MAIN(tst_qmldiskcache) + +#include "tst_qmldiskcache.moc" diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp index ee417bb480..838966e2a0 100644 --- a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp +++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp @@ -108,6 +108,7 @@ void tst_qmlplugindump::singleton() dumper.waitForFinished(); const QString &result = dumper.readAllStandardOutput(); + qDebug() << "result: " << result; QVERIFY(result.contains(QLatin1String("exports: [\"Singleton 1.0\"]"))); QVERIFY(result.contains(QLatin1String("exportMetaObjectRevisions: [0]"))); } diff --git a/tests/auto/qml/qqmlbinding/data/delayed.qml b/tests/auto/qml/qqmlbinding/data/delayed.qml new file mode 100644 index 0000000000..6f8281cc33 --- /dev/null +++ b/tests/auto/qml/qqmlbinding/data/delayed.qml @@ -0,0 +1,26 @@ +import QtQuick 2.8 + +Item { + width: 400 + height: 400 + + property int changeCount: 0 + + property string text1 + property string text2 + + function updateText() { + text1 = "Hello" + text2 = "World" + } + + Text { + anchors.centerIn: parent + Binding on text { + value: text1 + " " + text2 + delayed: true + } + onTextChanged: ++changeCount + } +} + diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp index 3e8dfbdb12..6f1d82eca5 100644 --- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp +++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp @@ -49,6 +49,7 @@ private slots: void warningOnReadOnlyProperty(); void disabledOnUnknownProperty(); void disabledOnReadonlyProperty(); + void delayed(); private: QQmlEngine engine; @@ -281,6 +282,27 @@ void tst_qqmlbinding::disabledOnReadonlyProperty() QCOMPARE(messageHandler.messages().count(), 0); } +void tst_qqmlbinding::delayed() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("delayed.qml")); + QQuickItem *item = qobject_cast<QQuickItem*>(c.create()); + + QVERIFY(item != 0); + // update on creation + QCOMPARE(item->property("changeCount").toInt(), 1); + + QMetaObject::invokeMethod(item, "updateText"); + // doesn't update immediately + QCOMPARE(item->property("changeCount").toInt(), 1); + + QCoreApplication::processEvents(); + // only updates once (non-delayed would update twice) + QCOMPARE(item->property("changeCount").toInt(), 2); + + delete item; +} + QTEST_MAIN(tst_qqmlbinding) #include "tst_qqmlbinding.moc" diff --git a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml new file mode 100644 index 0000000000..d19b6ecc41 --- /dev/null +++ b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 + +Item { + id:root + + LoggingCategory { + id: testCategory + name: "qt.test" + } + + LoggingCategory { + id: emptyCategory + } + + Component.onCompleted: { + console.debug(testCategory, "console.debug"); + console.log(testCategory, "console.log"); + console.info(testCategory, "console.info"); + console.warn(testCategory, "console.warn"); + console.error(testCategory, "console.error"); + + testCategory.name = "qt.test2"; + + console.error(emptyCategory, "console.error"); + } +} diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp index f12656c5fe..f832143935 100644 --- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp +++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp @@ -40,6 +40,7 @@ public: private slots: void logging(); + void categorized_logging(); void tracing(); void profiling(); void testAssert(); @@ -87,6 +88,41 @@ void tst_qqmlconsole::logging() delete object; } +void tst_qqmlconsole::categorized_logging() +{ + QUrl testUrl = testFileUrl("categorized_logging.qml"); + QQmlTestMessageHandler messageHandler; + messageHandler.setIncludeCategoriesEnabled(true); + + QLoggingCategory testCategory("qt.test"); + testCategory.setEnabled(QtDebugMsg, true); + QVERIFY(testCategory.isDebugEnabled()); + QVERIFY(testCategory.isWarningEnabled()); + QVERIFY(testCategory.isCriticalEnabled()); + + QQmlComponent component(&engine, testUrl); + QObject *object = component.create(); + QVERIFY2(object != 0, component.errorString().toUtf8()); + + QVERIFY(messageHandler.messages().contains("qt.test: console.info")); + QVERIFY(messageHandler.messages().contains("qt.test: console.warn")); + QVERIFY(messageHandler.messages().contains("qt.test: console.error")); + + QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) + + "QML LoggingCategory: Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"; + QVERIFY(messageHandler.messages().contains(emptyCategory)); + + QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + + "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the Item is created"; + QVERIFY(messageHandler.messages().contains(changedCategory)); + + QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(63) + + "Error: A QmlLoggingCatgory was provided without a valid name"; + QVERIFY(messageHandler.messages().contains(useEmptyCategory)); + + delete object; +} + void tst_qqmlconsole::tracing() { QUrl testUrl = testFileUrl("tracing.qml"); diff --git a/tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml b/tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml new file mode 100644 index 0000000000..4006a2a782 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/NullObjectInitializerBase.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 +QtObject { + property Component factory: Component { QtObject {} } + property QtObject testProperty: factory.createObject() +} diff --git a/tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml b/tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml new file mode 100644 index 0000000000..57d3ae2f14 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/dependenciesWithFunctions.qml @@ -0,0 +1,12 @@ +import QtQml 2.0 +QtObject { + property int value: 100 + property bool success: { + unrelatedFunction(); + return value == 42; + } + property int unrelatedValue: 100 + function unrelatedFunction() { + return unrelatedValue; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml new file mode 100644 index 0000000000..d59f8f99f9 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.2.qml @@ -0,0 +1,8 @@ +import QtQml 2.0 +NullObjectInitializerBase { + testProperty: null + property bool success: false + Component.onCompleted: { + success = testProperty === null; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml new file mode 100644 index 0000000000..32bc62c9f2 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/nullObjectInitializer.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property QtObject testProperty: null +} diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index d4d051443f..47fb2a56e7 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -790,7 +790,8 @@ public: Q_INVOKABLE void method_QObject(QObject *a) { invoke(13); m_actuals << qVariantFromValue(a); } Q_INVOKABLE void method_QScriptValue(QJSValue a) { invoke(14); m_actuals << qVariantFromValue(a); } Q_INVOKABLE void method_intQScriptValue(int a, QJSValue b) { invoke(15); m_actuals << a << qVariantFromValue(b); } - Q_INVOKABLE QJSValue method_intQJSValue(int a, QJSValue b) { invoke(29); m_actuals << a << qVariantFromValue(b); return b.call(); } + Q_INVOKABLE void method_QByteArray(QByteArray value) { invoke(29); m_actuals << value; } + Q_INVOKABLE QJSValue method_intQJSValue(int a, QJSValue b) { invoke(30); m_actuals << a << qVariantFromValue(b); return b.call(); } Q_INVOKABLE QJSValue method_intQJSValue(int a, int b) { m_actuals << a << b; return QJSValue();} // Should never be called. Q_INVOKABLE void method_overload(int a) { invoke(16); m_actuals << a; } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 26a15d730c..be04ec2bf3 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -84,6 +84,7 @@ private slots: void arrayExpressions(); void contextPropertiesTriggerReeval(); void objectPropertiesTriggerReeval(); + void dependenciesWithFunctions(); void deferredProperties(); void deferredPropertiesErrors(); void deferredPropertiesInComponents(); @@ -210,6 +211,7 @@ private slots: void dynamicCreationOwnership(); void regExpBug(); void nullObjectBinding(); + void nullObjectInitializer(); void deletedEngine(); void libraryScriptAssert(); void variantsAssignedUndefined(); @@ -881,6 +883,18 @@ void tst_qqmlecmascript::objectPropertiesTriggerReeval() } } +void tst_qqmlecmascript::dependenciesWithFunctions() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("dependenciesWithFunctions.qml")); + + QScopedPointer<QObject> object(component.create()); + QVERIFY2(object, qPrintable(component.errorString())); + QVERIFY(!object->property("success").toBool()); + object->setProperty("value", 42); + QVERIFY(object->property("success").toBool()); +} + void tst_qqmlecmascript::deferredProperties() { QQmlComponent component(&engine, testFileUrl("deferredProperties.qml")); @@ -2318,7 +2332,7 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const QV4::ScopedCallData d(scope, 1); d->args[0] = o; d->thisObject = engine->global(); - function->call(d); + function->call(scope, d); if (scope.engine->hasException) { scope.engine->catchException(); return true; @@ -2344,16 +2358,15 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, if (!function) return false; - QV4::ScopedValue value(scope); QV4::ScopedCallData d(scope, 1); d->args[0] = o; d->thisObject = engine->global(); - value = function->call(d); + function->call(scope, d); if (scope.engine->hasException) { scope.engine->catchException(); return false; } - return QV4::Runtime::strictEqual(value, result); + return QV4::Runtime::method_strictEqual(scope.result, result); } static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o, @@ -2377,12 +2390,12 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o QV4::ScopedCallData d(scope, 1); d->args[0] = o; d->thisObject = engine->global(); - QV4::ScopedValue result(scope, function->call(d)); + function->call(scope, d); if (scope.engine->hasException) { scope.engine->catchException(); return QV4::Encode::undefined(); } - return result->asReturnedValue(); + return scope.result.asReturnedValue(); } #define EVALUATE_ERROR(source) evaluate_error(engine, object, source) @@ -2946,9 +2959,16 @@ void tst_qqmlecmascript::callQtInvokables() QCOMPARE(o->actuals().count(), 0); o->reset(); - QV4::ScopedValue ret(scope, EVALUATE("object.method_intQJSValue(123, function() { return \"Hello world!\";})")); + QVERIFY(EVALUATE_VALUE("object.method_QByteArray(\"Hello\")", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); QCOMPARE(o->invoked(), 29); + QCOMPARE(o->actuals().count(), 1); + QCOMPARE(qvariant_cast<QByteArray>(o->actuals().at(0)), QByteArray("Hello")); + + o->reset(); + QV4::ScopedValue ret(scope, EVALUATE("object.method_intQJSValue(123, function() { return \"Hello world!\";})")); + QCOMPARE(o->error(), false); + QCOMPARE(o->invoked(), 30); QVERIFY(ret->isString()); QCOMPARE(ret->toQStringNoThrow(), QString("Hello world!")); QCOMPARE(o->actuals().count(), 2); @@ -5707,6 +5727,49 @@ void tst_qqmlecmascript::nullObjectBinding() delete object; } +void tst_qqmlecmascript::nullObjectInitializer() +{ + { + QQmlComponent component(&engine, testFileUrl("nullObjectInitializer.qml")); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + + QQmlData *ddata = QQmlData::get(obj.data(), /*create*/false); + QVERIFY(ddata); + + { + const int propertyIndex = obj->metaObject()->indexOfProperty("testProperty"); + QVERIFY(propertyIndex > 0); + QVERIFY(!ddata->hasBindingBit(propertyIndex)); + } + + QVariant value = obj->property("testProperty"); + QVERIFY(value.userType() == qMetaTypeId<QObject*>()); + QVERIFY(!value.value<QObject*>()); + } + + { + QQmlComponent component(&engine, testFileUrl("nullObjectInitializer.2.qml")); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + + QQmlData *ddata = QQmlData::get(obj.data(), /*create*/false); + QVERIFY(ddata); + + { + const int propertyIndex = obj->metaObject()->indexOfProperty("testProperty"); + QVERIFY(propertyIndex > 0); + QVERIFY(ddata->hasBindingBit(propertyIndex)); + } + + QVERIFY(obj->property("success").toBool()); + + QVariant value = obj->property("testProperty"); + QVERIFY(value.userType() == qMetaTypeId<QObject*>()); + QVERIFY(!value.value<QObject*>()); + } +} + // Test that bindings don't evaluate once the engine has been destroyed void tst_qqmlecmascript::deletedEngine() { @@ -5768,7 +5831,7 @@ void tst_qqmlecmascript::variants() QVERIFY(object != 0); QCOMPARE(object->property("undefinedVariant").type(), QVariant::Invalid); - QCOMPARE(int(object->property("nullVariant").type()), int(QMetaType::VoidStar)); + QCOMPARE(int(object->property("nullVariant").type()), int(QMetaType::Nullptr)); QCOMPARE(object->property("intVariant").type(), QVariant::Int); QCOMPARE(object->property("doubleVariant").type(), QVariant::Double); @@ -7196,14 +7259,16 @@ namespace QV4 { namespace Heap { struct WeakReferenceSentinel : public Object { - WeakReferenceSentinel(WeakValue *weakRef, bool *resultPtr) - : weakRef(weakRef) - , resultPtr(resultPtr) { - + void init(WeakValue *weakRef, bool *resultPtr) + { + Object::init(); + this->weakRef = weakRef; + this->resultPtr = resultPtr; } - ~WeakReferenceSentinel() { + void destroy() { *resultPtr = weakRef->isNullOrUndefined(); + Object::destroy(); } WeakValue *weakRef; diff --git a/tests/auto/qml/qqmlengine/data/qtqmlModule.4.qml b/tests/auto/qml/qqmlengine/data/qtqmlModule.4.qml index 9b9b7922da..94ee46ddf0 100644 --- a/tests/auto/qml/qqmlengine/data/qtqmlModule.4.qml +++ b/tests/auto/qml/qqmlengine/data/qtqmlModule.4.qml @@ -1,4 +1,4 @@ -import QtQml 2.5 +import QtQml 2.50 QtObject { } diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index 3208745c5c..9c155eda5b 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -275,6 +275,12 @@ void tst_qqmlengine::clearComponentCache() // Modify qml file { + // On macOS with HFS+ the precision of file times is measured in seconds, so to ensure that + // the newly written file has a modification date newer than an existing cache file, we must + // wait. + // Similar effects of lacking precision have been observed on some Linux systems. + QThread::sleep(1); + QFile file("temp.qml"); QVERIFY(file.open(QIODevice::WriteOnly)); file.write("import QtQuick 2.0\nQtObject {\nproperty int test: 11\n}\n"); @@ -317,6 +323,11 @@ public: QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); QCoreApplication::processEvents(); + // There might be JS function objects around that hold a last ref to the compilation unit that's + // keeping the type compilation data (CompilationUnit) around. Let's collect them as well so that + // trim works well. + engine->collectGarbage(); + engine->trimComponentCache(); } @@ -615,9 +626,9 @@ void tst_qqmlengine::qtqmlModule_data() << QString(testFileUrl("qtqmlModule.3.qml").toString() + QLatin1String(":1 module \"QtQml\" version 1.0 is not installed\n")) << QStringList(); - QTest::newRow("import QtQml of incorrect version (2.5)") + QTest::newRow("import QtQml of incorrect version (2.50)") << testFileUrl("qtqmlModule.4.qml") - << QString(testFileUrl("qtqmlModule.4.qml").toString() + QLatin1String(":1 module \"QtQml\" version 2.5 is not installed\n")) + << QString(testFileUrl("qtqmlModule.4.qml").toString() + QLatin1String(":1 module \"QtQml\" version 2.50 is not installed\n")) << QStringList(); QTest::newRow("QtQml 2.0 module provides Component, QtObject, Connections, Binding and Timer") diff --git a/tests/auto/qml/qqmlenginecleanup/data/types.qml b/tests/auto/qml/qqmlenginecleanup/data/types.qml index 3d27900744..7282c7dbfb 100644 --- a/tests/auto/qml/qqmlenginecleanup/data/types.qml +++ b/tests/auto/qml/qqmlenginecleanup/data/types.qml @@ -29,7 +29,7 @@ import QtQml 2.0 import QtQuick 2.0 import QtQuick.Window 2.0 -import QtQuick.Particles 2.0 + import Test 2.0 import "." @@ -37,7 +37,6 @@ QtObject { //Doesn't create items, just checks that the types are accessible property TestType tt property TestTypeCpp ttc - property ParticleSystem ps property Window wi property Item it } diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp index bd44bd7c8b..124a107a37 100644 --- a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp +++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp @@ -109,7 +109,7 @@ void tst_qqmlextensionplugin::iidCheck() QFETCH(QString, filePath); QPluginLoader loader(filePath); - QVERIFY(loader.load()); + QVERIFY2(loader.load(), qPrintable(loader.errorString())); QVERIFY(loader.instance() != Q_NULLPTR); if (qobject_cast<QQmlExtensionPlugin *>(loader.instance())) { diff --git a/tests/auto/qml/qqmllanguage/data/alias.12.qml b/tests/auto/qml/qqmllanguage/data/alias.12.qml new file mode 100644 index 0000000000..cc17318092 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.12.qml @@ -0,0 +1,15 @@ +import QtQml 2.0 + +QtObject { + id: root + property alias topLevelAlias: subObject.targetProperty + + property QtObject referencingSubObject: QtObject { + property alias success: root.topLevelAlias + } + + property QtObject foo: QtObject { + id: subObject + property bool targetProperty: true + } +} diff --git a/tests/auto/qml/qqmllanguage/data/alias.13.qml b/tests/auto/qml/qqmllanguage/data/alias.13.qml new file mode 100644 index 0000000000..cff8a72d9a --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.13.qml @@ -0,0 +1,16 @@ +import QtQml 2.0 + +QtObject { + id: root + property bool targetProperty: true + + property QtObject foo: QtObject { + id: otherSubObject + property alias theAlias: root.targetProperty + } + + property QtObject referencingSubObject: QtObject { + property alias success: otherSubObject.theAlias + } + +} diff --git a/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt b/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt new file mode 100644 index 0000000000..90a3ea4317 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.14.errors.txt @@ -0,0 +1 @@ +10:34:References to other aliases within the same object are not supported at the moment diff --git a/tests/auto/qml/qqmllanguage/data/alias.14.qml b/tests/auto/qml/qqmllanguage/data/alias.14.qml new file mode 100644 index 0000000000..ff3c36d990 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.14.qml @@ -0,0 +1,17 @@ +import QtQml 2.0 + +QtObject { + id: root + property bool targetProperty: true + + property QtObject foo: QtObject { + id: otherSubObject + property alias theAliasOrigin: root.targetProperty + property alias theAlias: otherSubObject.theAliasOrigin + } + + property QtObject referencingSubObject: QtObject { + property alias success: otherSubObject.theAlias + } + +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_method_arg.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_arg.qml new file mode 100644 index 0000000000..b64a2e23c0 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_arg.qml @@ -0,0 +1,11 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + Component.onCompleted: { + var data = new Uint8Array([1, 2, 3]); + var sum = byteArrayMethod_Sum(data.buffer); + ok = sum == 6; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_method_overload.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_overload.qml new file mode 100644 index 0000000000..9e1c91810a --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_overload.qml @@ -0,0 +1,7 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + Component.onCompleted: ok = byteArrayMethod_Overloaded(new ArrayBuffer()); +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_method_return.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_return.qml new file mode 100644 index 0000000000..5a4f9fec0b --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_return.qml @@ -0,0 +1,15 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + Component.onCompleted: { + var buf = byteArrayMethod_CountUp(1, 3); + var view = new DataView(buf); + ok = buf instanceof ArrayBuffer + && buf.byteLength == 3 + && view.getUint8(0) == 1 + && view.getUint8(1) == 2 + && view.getUint8(2) == 3; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_property_get.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_get.qml new file mode 100644 index 0000000000..78ebb1abe1 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_get.qml @@ -0,0 +1,5 @@ +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: byteArrayProperty instanceof ArrayBuffer +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_property_set.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_set.qml new file mode 100644 index 0000000000..e8a51273ca --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_set.qml @@ -0,0 +1,11 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + onByteArraySignal: ok = byteArrayProperty instanceof ArrayBuffer + Component.onCompleted: { + byteArrayProperty = new ArrayBuffer(42); + ok = byteArrayProperty instanceof ArrayBuffer && byteArrayProperty.byteLength == 42; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_signal_arg.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_signal_arg.qml new file mode 100644 index 0000000000..d9f436e788 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_signal_arg.qml @@ -0,0 +1,14 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + onByteArraySignal: { + var view = new DataView(arg); + ok = arg instanceof ArrayBuffer + && arg.byteLength == 2 + && view.getUint8(0) == 42 + && view.getUint8(1) == 43; + } + Component.onCompleted: emitByteArraySignal(42, 2) +} diff --git a/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt b/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt index 7a75447a62..acf0d1da84 100644 --- a/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt +++ b/tests/auto/qml/qqmllanguage/data/badCompositeRegistration.1.errors.txt @@ -1,2 +1,2 @@ 3:1:Type RegisteredCompositeType2 unavailable --1:-1:File not found +-1:-1:No such file or directory diff --git a/tests/auto/qml/qqmllanguage/data/cppnamespace.qml b/tests/auto/qml/qqmllanguage/data/cppnamespace.qml index e1daf3b78f..efedf2b14a 100644 --- a/tests/auto/qml/qqmllanguage/data/cppnamespace.qml +++ b/tests/auto/qml/qqmllanguage/data/cppnamespace.qml @@ -1,4 +1,5 @@ import Test 1.0 MyNamespacedType { + myEnum: MyNamespace.Key5 } diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt new file mode 100644 index 0000000000..b79b660c46 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.errors.txt @@ -0,0 +1 @@ +5:5:Circular alias reference detected diff --git a/tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml new file mode 100644 index 0000000000..9b50b48df8 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidAlias.11.qml @@ -0,0 +1,10 @@ +import QtQml 2.0 + +QtObject { + id: root + property alias a: subObject.b + property QtObject foo: QtObject { + id: subObject + property alias b: root.a + } +} diff --git a/tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml b/tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml new file mode 100644 index 0000000000..dd653352d9 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/rootItemIsComponent.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +Component { + QtObject { + id: blah + } +} diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest10.error.txt b/tests/auto/qml/qqmllanguage/data/singletonTest10.error.txt deleted file mode 100644 index 32d2ed857e..0000000000 --- a/tests/auto/qml/qqmllanguage/data/singletonTest10.error.txt +++ /dev/null @@ -1 +0,0 @@ -4:1:Composite Singleton Type SingletonType is not creatable. diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt b/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt index 716cf5709a..b3082d80e6 100644 --- a/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt +++ b/tests/auto/qml/qqmllanguage/data/singletonTest12.error.txt @@ -1,2 +1,2 @@ 5:5:Type RegisteredCompositeType unavailable -2:1:pragma Singleton used with a non composite singleton type CompositeSingletonTest/RegisteredCompositeType +-1:-1:pragma Singleton used with a non composite singleton type CompositeSingletonTest/RegisteredCompositeType diff --git a/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt b/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt index 77c26df310..ebeab6987b 100644 --- a/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt +++ b/tests/auto/qml/qqmllanguage/data/singletonTest4.error.txt @@ -1 +1 @@ -2:1:No matching type found, pragma Singleton files cannot be used by QQmlComponent. +-1:-1:No matching type found, pragma Singleton files cannot be used by QQmlComponent. diff --git a/tests/auto/qml/qqmllanguage/data/uncreatableTypeAsProperty.qml b/tests/auto/qml/qqmllanguage/data/uncreatableTypeAsProperty.qml new file mode 100644 index 0000000000..8369ab1eea --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/uncreatableTypeAsProperty.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +import Test 1.0 + +QtObject { + property MyUncreateableBaseClass someProperty; +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 9593bfc940..3af7645ff7 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -27,8 +27,6 @@ ****************************************************************************/ #include "testtypes.h" -#include <private/qqmlcompiler_p.h> - static QObject *myTypeObjectSingleton(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) @@ -47,6 +45,7 @@ void registerTypes() qmlRegisterType<MyDotPropertyObject>("Test",1,0,"MyDotPropertyObject"); qmlRegisterType<MyNamespace::MyNamespacedType>("Test",1,0,"MyNamespacedType"); qmlRegisterType<MyNamespace::MySecondNamespacedType>("Test",1,0,"MySecondNamespacedType"); + qmlRegisterUncreatableMetaObject(MyNamespace::staticMetaObject, "Test", 1, 0, "MyNamespace", "Access to enums & flags only"); qmlRegisterType<MyParserStatus>("Test",1,0,"MyParserStatus"); qmlRegisterType<MyGroupedObject>(); qmlRegisterType<MyRevisionedClass>("Test",1,0,"MyRevisionedClass"); @@ -98,6 +97,8 @@ void registerTypes() qmlRegisterType<MyCompositeBaseType>("Test", 1, 0, "MyCompositeBaseType"); qmlRegisterSingletonType<MyTypeObjectSingleton>("Test", 1, 0, "MyTypeObjectSingleton", myTypeObjectSingleton); + + qmlRegisterType<MyArrayBufferTestClass>("Test", 1, 0, "MyArrayBufferTestClass"); } QVariant myCustomVariantTypeConverter(const QString &data) @@ -108,11 +109,11 @@ QVariant myCustomVariantTypeConverter(const QString &data) } -void CustomBindingParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) +void CustomBindingParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { CustomBinding *customBinding = qobject_cast<CustomBinding*>(object); Q_ASSERT(customBinding); - customBinding->cdata = cdata; + customBinding->compilationUnit = compilationUnit; customBinding->bindings = bindings; } @@ -121,17 +122,18 @@ void CustomBinding::componentComplete() Q_ASSERT(m_target); foreach (const QV4::CompiledData::Binding *binding, bindings) { - QString name = cdata->compilationUnit->data->stringAt(binding->propertyNameIndex); + QString name = compilationUnit->data->stringAt(binding->propertyNameIndex); int bindingId = binding->value.compiledScriptIndex; QQmlContextData *context = QQmlContextData::get(qmlContext(this)); QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); - QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, cdata->compilationUnit->runtimeFunctions[bindingId])); - QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context); + QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, compilationUnit->runtimeFunctions[bindingId])); QQmlProperty property(m_target, name, qmlContext(this)); + QQmlBinding *qmlBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, + function, m_target, context); qmlBinding->setTarget(property); QQmlPropertyPrivate::setBinding(property, qmlBinding); } @@ -167,7 +169,7 @@ void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::Unit *q } } -void SimpleObjectCustomParser::applyBindings(QObject *object, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &bindings) +void SimpleObjectCustomParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &bindings) { SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object); Q_ASSERT(o); diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 337ba91532..6c62bcf7b9 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -43,7 +43,6 @@ #include <QtQml/qqmlpropertyvaluesource.h> #include <QtQml/qqmlscriptstring.h> #include <QtQml/qqmlproperty.h> -#include <private/qqmlcompiler_p.h> #include <private/qqmlcustomparser_p.h> QVariant myCustomVariantTypeConverter(const QString &data); @@ -731,9 +730,19 @@ private: namespace MyNamespace { + Q_NAMESPACE + enum MyNSEnum { + Key1 = 1, + Key2, + Key5 = 5 + }; + Q_ENUM_NS(MyNSEnum); + class MyNamespacedType : public QObject { Q_OBJECT + Q_PROPERTY(MyNamespace::MyNSEnum myEnum MEMBER m_myEnum) + MyNamespace::MyNSEnum m_myEnum = MyNSEnum::Key1; }; class MySecondNamespacedType : public QObject @@ -757,14 +766,14 @@ class MyCustomParserTypeParser : public QQmlCustomParser { public: virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {} - virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {} }; class EnumSupportingCustomParser : public QQmlCustomParser { public: virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &); - virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {} + virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {} }; class MyParserStatus : public QObject, public QQmlParserStatus @@ -1114,6 +1123,58 @@ public: static QObject *qmlAttachedProperties(QObject *parent) { return new QObject(parent); } }; +class MyArrayBufferTestClass : public QObject +{ + Q_OBJECT + Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty NOTIFY byteArrayPropertyChanged) + +signals: + void byteArrayPropertyChanged(); + void byteArraySignal(QByteArray arg); + +public: + QByteArray byteArrayPropertyValue; + QByteArray byteArrayProperty() const { + return byteArrayPropertyValue; + } + void setByteArrayProperty(const QByteArray &v) { + byteArrayPropertyValue = v; + emit byteArrayPropertyChanged(); + } + Q_INVOKABLE void emitByteArraySignal(char begin, char num) { + byteArraySignal(byteArrayMethod_CountUp(begin, num)); + } + Q_INVOKABLE int byteArrayMethod_Sum(QByteArray arg) { + int sum = 0; + for (int i = 0; i < arg.size(); ++i) { + sum += arg[i]; + } + return sum; + } + Q_INVOKABLE QByteArray byteArrayMethod_CountUp(char begin, int num) { + QByteArray ret; + for (int i = 0; i < num; ++i) { + ret.push_back(begin++); + } + return ret; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QByteArray) { + return true; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(int) { + return false; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QString) { + return false; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QJSValue) { + return false; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QVariant) { + return false; + } +}; + Q_DECLARE_METATYPE(MyEnum2Class::EnumB) Q_DECLARE_METATYPE(MyEnum1Class::EnumA) Q_DECLARE_METATYPE(Qt::TextFormat) @@ -1142,7 +1203,7 @@ public: void setTarget(QObject *newTarget) { m_target = newTarget; } QPointer<QObject> m_target; - QQmlRefPointer<QQmlCompiledData> cdata; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; QList<const QV4::CompiledData::Binding*> bindings; QByteArray m_bindingData; }; @@ -1150,7 +1211,7 @@ public: class CustomBindingParser : public QQmlCustomParser { virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {} - virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &); + virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &); }; class SimpleObjectWithCustomParser : public QObject @@ -1196,7 +1257,7 @@ private: class SimpleObjectCustomParser : public QQmlCustomParser { virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {} - virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &); + virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &); }; class RootObjectInCreationTester : public QObject diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 4e4b939e8b..ad06946b0b 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -108,6 +108,7 @@ private slots: void bindTypeToJSValue(); void customParserTypes(); void rootAsQmlComponent(); + void rootItemIsComponent(); void inlineQmlComponents(); void idProperty(); void autoNotifyConnection(); @@ -188,6 +189,8 @@ private slots: void subclassedUncreateableRevision_data(); void subclassedUncreateableRevision(); + void uncreatableTypesAsProperties(); + void propertyInit(); void remoteLoadCrash(); void signalWithDefaultArg(); @@ -246,10 +249,11 @@ private slots: void earlyIdObjectAccess(); - void dataAlignment(); - void deleteSingletons(); + void arrayBuffer_data(); + void arrayBuffer(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -490,6 +494,7 @@ void tst_qqmllanguage::errors_data() QTest::newRow("invalidAlias.8") << "invalidAlias.8.qml" << "invalidAlias.8.errors.txt" << false; QTest::newRow("invalidAlias.9") << "invalidAlias.9.qml" << "invalidAlias.9.errors.txt" << false; QTest::newRow("invalidAlias.10") << "invalidAlias.10.qml" << "invalidAlias.10.errors.txt" << false; + QTest::newRow("invalidAlias.11") << "invalidAlias.11.qml" << "invalidAlias.11.errors.txt" << false; QTest::newRow("invalidAttachedProperty.1") << "invalidAttachedProperty.1.qml" << "invalidAttachedProperty.1.errors.txt" << false; QTest::newRow("invalidAttachedProperty.2") << "invalidAttachedProperty.2.qml" << "invalidAttachedProperty.2.errors.txt" << false; @@ -1193,6 +1198,19 @@ void tst_qqmllanguage::rootAsQmlComponent() QCOMPARE(object->getChildren()->count(), 2); } +void tst_qqmllanguage::rootItemIsComponent() +{ + QQmlComponent component(&engine, testFileUrl("rootItemIsComponent.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> root(component.create()); + QVERIFY(qobject_cast<QQmlComponent*>(root.data())); + QScopedPointer<QObject> other(qobject_cast<QQmlComponent*>(root.data())->create()); + QVERIFY(!other.isNull()); + QQmlContext *context = qmlContext(other.data()); + QVERIFY(context); + QCOMPARE(context->nameForObject(other.data()), QStringLiteral("blah")); +} + // Tests that components can be specified inline void tst_qqmllanguage::inlineQmlComponents() { @@ -1787,6 +1805,48 @@ void tst_qqmllanguage::aliasProperties() delete object; } + + // Nested aliases with a qml file + { + QQmlComponent component(&engine, testFileUrl("alias.12.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QPointer<QObject> subObject = qvariant_cast<QObject*>(object->property("referencingSubObject")); + QVERIFY(!subObject.isNull()); + + QVERIFY(subObject->property("success").toBool()); + } + + // Nested aliases with a qml file with reverse ordering + { + // This is known to fail at the moment. + QQmlComponent component(&engine, testFileUrl("alias.13.qml")); + VERIFY_ERRORS(0); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QPointer<QObject> subObject = qvariant_cast<QObject*>(object->property("referencingSubObject")); + QVERIFY(!subObject.isNull()); + + QVERIFY(subObject->property("success").toBool()); + } + + // "Nested" aliases within an object that require iterative resolution + { + // This is known to fail at the moment. + QQmlComponent component(&engine, testFileUrl("alias.14.qml")); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QPointer<QObject> subObject = qvariant_cast<QObject*>(object->property("referencingSubObject")); + QVERIFY(!subObject.isNull()); + + QVERIFY(subObject->property("success").toBool()); + } } // QTBUG-13374 Test that alias properties and signals can coexist @@ -2058,8 +2118,13 @@ void tst_qqmllanguage::scriptStringWithoutSourceCode() QQmlTypeData *td = eng->typeLoader.getType(url); Q_ASSERT(td); - QV4::CompiledData::Unit *qmlUnit = td->compiledData()->compilationUnit->data; - Q_ASSERT(qmlUnit); + const QV4::CompiledData::Unit *readOnlyQmlUnit = td->compilationUnit()->data; + Q_ASSERT(readOnlyQmlUnit); + QV4::CompiledData::Unit *qmlUnit = reinterpret_cast<QV4::CompiledData::Unit *>(malloc(readOnlyQmlUnit->unitSize)); + memcpy(qmlUnit, readOnlyQmlUnit, readOnlyQmlUnit->unitSize); + qmlUnit->flags &= ~QV4::CompiledData::Unit::StaticData; + td->compilationUnit()->data = qmlUnit; + const QV4::CompiledData::Object *rootObject = qmlUnit->objectAt(qmlUnit->indexOfRootObject); QCOMPARE(qmlUnit->stringAt(rootObject->inheritedTypeNameIndex), QString("MyTypeObject")); quint32 i; @@ -2536,7 +2601,7 @@ void tst_qqmllanguage::basicRemote_data() QTest::newRow("no need for qmldir") << QUrl(serverdir+"Test.qml") << "" << ""; QTest::newRow("absent qmldir") << QUrl(serverdir+"/noqmldir/Test.qml") << "" << ""; - QTest::newRow("need qmldir") << QUrl(serverdir+"TestLocal.qml") << "" << ""; + QTest::newRow("need qmldir") << QUrl(serverdir+"TestNamed.qml") << "" << ""; } void tst_qqmllanguage::basicRemote() @@ -2576,6 +2641,8 @@ void tst_qqmllanguage::importsRemote_data() << ""; QTest::newRow("remote import with local") << "import \""+serverdir+"\"\nTestLocal {}" << "QQuickImage" << ""; + QTest::newRow("remote import with qualifier") << "import \""+serverdir+"\" as NS\nNS.NamedLocal {}" << "QQuickImage" + << ""; QTest::newRow("wrong remote import with undeclared local") << "import \""+serverdir+"\"\nWrongTestLocal {}" << "" << "WrongTestLocal is not a type"; QTest::newRow("wrong remote import of internal local") << "import \""+serverdir+"\"\nLocalInternal {}" << "" @@ -2882,7 +2949,7 @@ void tst_qqmllanguage::importIncorrectCase() QCOMPARE(errors.count(), 1); const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ? - QStringLiteral("File not found") : + QStringLiteral("No such file or directory") : QStringLiteral("File name case mismatch"); QCOMPARE(errors.at(0).description(), expectedError); @@ -3156,6 +3223,14 @@ void tst_qqmllanguage::subclassedUncreateableRevision() delete obj; } +void tst_qqmllanguage::uncreatableTypesAsProperties() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("uncreatableTypeAsProperty.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); +} + void tst_qqmllanguage::initTestCase() { QQmlDataTest::initTestCase(); @@ -3861,12 +3936,11 @@ void tst_qqmllanguage::compositeSingletonInstantiateError() VERIFY_ERRORS("singletonTest9.error.txt"); } -// Having a composite singleton type as dynamic property type fails -// (like C++ singleton) +// Having a composite singleton type as dynamic property type is allowed void tst_qqmllanguage::compositeSingletonDynamicPropertyError() { QQmlComponent component(&engine, testFile("singletonTest10.qml")); - VERIFY_ERRORS("singletonTest10.error.txt"); + VERIFY_ERRORS(0); } // Having a composite singleton type as dynamic signal parameter succeeds @@ -4054,7 +4128,7 @@ void tst_qqmllanguage::preservePropertyCacheOnGroupObjects() QVERIFY(subCache); QQmlPropertyData *pd = subCache->property(QStringLiteral("newProperty"), /*object*/0, /*context*/0); QVERIFY(pd); - QCOMPARE(pd->propType, qMetaTypeId<int>()); + QCOMPARE(pd->propType(), qMetaTypeId<int>()); } void tst_qqmllanguage::propertyCacheInSync() @@ -4120,14 +4194,6 @@ void tst_qqmllanguage::earlyIdObjectAccess() QVERIFY(o->property("success").toBool()); } -void tst_qqmllanguage::dataAlignment() -{ - QVERIFY(sizeof(QQmlVMEMetaData) % sizeof(int) == 0); - QVERIFY(sizeof(QQmlVMEMetaData::AliasData) % sizeof(int) == 0); - QVERIFY(sizeof(QQmlVMEMetaData::PropertyData) % sizeof(int) == 0); - QVERIFY(sizeof(QQmlVMEMetaData::MethodData) % sizeof(int) == 0); -} - void tst_qqmllanguage::deleteSingletons() { QPointer<QObject> singleton; @@ -4146,6 +4212,27 @@ void tst_qqmllanguage::deleteSingletons() QVERIFY(singleton.data() == 0); } +void tst_qqmllanguage::arrayBuffer_data() +{ + QTest::addColumn<QString>("file"); + QTest::newRow("arraybuffer_property_get") << "arraybuffer_property_get.qml"; + QTest::newRow("arraybuffer_property_set") << "arraybuffer_property_set.qml"; + QTest::newRow("arraybuffer_signal_arg") << "arraybuffer_signal_arg.qml"; + QTest::newRow("arraybuffer_method_arg") << "arraybuffer_method_arg.qml"; + QTest::newRow("arraybuffer_method_return") << "arraybuffer_method_return.qml"; + QTest::newRow("arraybuffer_method_overload") << "arraybuffer_method_overload.qml"; +} + +void tst_qqmllanguage::arrayBuffer() +{ + QFETCH(QString, file); + QQmlComponent component(&engine, testFile(file)); + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("ok").toBool(), true); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp index 53247e7912..515d56a3c4 100644 --- a/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2.1/childplugin/childplugin.cpp @@ -53,7 +53,7 @@ private: class MyChildPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyChildPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp index a59347d3a9..56545cfa3c 100644 --- a/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/plugin.2/childplugin/childplugin.cpp @@ -53,7 +53,7 @@ private: class MyChildPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyChildPlugin() diff --git a/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp index 5f4f96f7e4..28490d3d98 100644 --- a/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/plugin/childplugin/childplugin.cpp @@ -52,7 +52,7 @@ private: class MyChildPlugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: MyChildPlugin() diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 1d01f69d9b..fe73610bcc 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -157,7 +157,7 @@ void tst_qqmlproperty::qmlmetaproperty() QObject *obj = new QObject; - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(nullptr, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(obj, QObjectPrivate::get(obj)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -194,7 +194,8 @@ void tst_qqmlproperty::qmlmetaproperty() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -398,7 +399,7 @@ void tst_qqmlproperty::qmlmetaproperty_object() { QQmlProperty prop(&object); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -437,7 +438,8 @@ void tst_qqmlproperty::qmlmetaproperty_object() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -445,7 +447,7 @@ void tst_qqmlproperty::qmlmetaproperty_object() { QQmlProperty prop(&dobject); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -487,7 +489,8 @@ void tst_qqmlproperty::qmlmetaproperty_object() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -501,7 +504,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&object, QString("defaultProperty")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -540,7 +543,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -548,7 +552,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("defaultProperty")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -590,7 +594,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -598,7 +603,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("onClicked")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -639,7 +644,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QVERIFY(!sigExprWatcher.wasDeleted()); QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -647,7 +653,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() { QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged")); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -688,7 +694,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string() QVERIFY(!sigExprWatcher.wasDeleted()); QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -702,7 +709,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() { QQmlProperty prop(&object, engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -741,7 +748,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -749,7 +757,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() { QQmlProperty prop(&dobject, engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -791,7 +799,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_context() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -805,7 +814,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&object, QString("defaultProperty"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&object, QObjectPrivate::get(&object)->signalIndex("destroyed()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); QQmlJavaScriptExpression::DeleteWatcher sigExprWatcher(sigExpr); @@ -844,7 +853,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), -1); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -852,7 +862,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("defaultProperty"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QObjectPrivate::get(&dobject)->signalIndex("clicked()"), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -894,7 +904,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr); QVERIFY(sigExprWatcher.wasDeleted()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -902,7 +913,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("onClicked"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -943,7 +954,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QVERIFY(!sigExprWatcher.wasDeleted()); QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } @@ -951,7 +963,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() { QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext()); - QQmlAbstractBinding::Ptr binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())); + QQmlAbstractBinding::Ptr binding(QQmlBinding::create(&QQmlPropertyPrivate::get(prop)->core, QLatin1String("null"), 0, engine.rootContext())); static_cast<QQmlBinding *>(binding.data())->setTarget(prop); QVERIFY(binding); QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(&dobject, QQmlPropertyPrivate::get(prop)->signalIndex(), QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), QString(), -1, -1); @@ -992,7 +1004,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context() QVERIFY(!sigExprWatcher.wasDeleted()); QCOMPARE(QQmlPropertyPrivate::signalExpression(prop), sigExpr); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()")); - QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1); + QCOMPARE(QQmlPropertyPrivate::propertyIndex(prop).valueTypeIndex(), -1); + QVERIFY(!QQmlPropertyPrivate::propertyIndex(prop).hasValueTypeIndex()); delete obj; } diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp index 5f15afff85..824fe445c0 100644 --- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp +++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp @@ -30,6 +30,8 @@ #include <private/qqmlpropertycache_p.h> #include <QtQml/qqmlengine.h> #include <private/qv8engine_p.h> +#include <private/qmetaobjectbuilder_p.h> +#include <QCryptographicHash> #include "../../shared/util.h" class tst_qqmlpropertycache : public QObject @@ -45,6 +47,9 @@ private slots: void methodsDerived(); void signalHandlers(); void signalHandlersDerived(); + void metaObjectSize_data(); + void metaObjectSize(); + void metaObjectChecksum(); private: QQmlEngine engine; @@ -105,17 +110,17 @@ void tst_qqmlpropertycache::properties() QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject)); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "propertyA")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA")); + QVERIFY((data = cacheProperty(cache, "propertyA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA")); - QVERIFY(data = cacheProperty(cache, "propertyB")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB")); + QVERIFY((data = cacheProperty(cache, "propertyB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyB")); - QVERIFY(data = cacheProperty(cache, "propertyC")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC")); + QVERIFY((data = cacheProperty(cache, "propertyC"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyC")); - QVERIFY(data = cacheProperty(cache, "propertyD")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD")); + QVERIFY((data = cacheProperty(cache, "propertyD"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD")); } void tst_qqmlpropertycache::propertiesDerived() @@ -129,17 +134,17 @@ void tst_qqmlpropertycache::propertiesDerived() QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject())); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "propertyA")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyA")); + QVERIFY((data = cacheProperty(cache, "propertyA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA")); - QVERIFY(data = cacheProperty(cache, "propertyB")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyB")); + QVERIFY((data = cacheProperty(cache, "propertyB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyB")); - QVERIFY(data = cacheProperty(cache, "propertyC")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyC")); + QVERIFY((data = cacheProperty(cache, "propertyC"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyC")); - QVERIFY(data = cacheProperty(cache, "propertyD")); - QCOMPARE(data->coreIndex, metaObject->indexOfProperty("propertyD")); + QVERIFY((data = cacheProperty(cache, "propertyD"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD")); } void tst_qqmlpropertycache::methods() @@ -152,29 +157,29 @@ void tst_qqmlpropertycache::methods() QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject)); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "slotA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()")); + QVERIFY((data = cacheProperty(cache, "slotA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotA()")); - QVERIFY(data = cacheProperty(cache, "slotB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()")); + QVERIFY((data = cacheProperty(cache, "slotB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotB()")); - QVERIFY(data = cacheProperty(cache, "signalA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); + QVERIFY((data = cacheProperty(cache, "signalA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "signalB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); + QVERIFY((data = cacheProperty(cache, "signalB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "propertyAChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyAChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyBChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyBChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyCChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyCChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyDChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyDChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()")); } void tst_qqmlpropertycache::methodsDerived() @@ -188,29 +193,29 @@ void tst_qqmlpropertycache::methodsDerived() QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject())); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "slotA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotA()")); + QVERIFY((data = cacheProperty(cache, "slotA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotA()")); - QVERIFY(data = cacheProperty(cache, "slotB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("slotB()")); + QVERIFY((data = cacheProperty(cache, "slotB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotB()")); - QVERIFY(data = cacheProperty(cache, "signalA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); + QVERIFY((data = cacheProperty(cache, "signalA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "signalB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); + QVERIFY((data = cacheProperty(cache, "signalB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "propertyAChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyAChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyBChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyBChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyCChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyCChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "propertyDChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); + QVERIFY((data = cacheProperty(cache, "propertyDChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()")); } void tst_qqmlpropertycache::signalHandlers() @@ -223,23 +228,23 @@ void tst_qqmlpropertycache::signalHandlers() QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(v4, metaObject)); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "onSignalA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); + QVERIFY((data = cacheProperty(cache, "onSignalA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "onSignalB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); + QVERIFY((data = cacheProperty(cache, "onSignalB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "onPropertyAChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyAChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyBChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyBChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyCChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyCChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyDChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyDChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()")); } void tst_qqmlpropertycache::signalHandlersDerived() @@ -253,25 +258,145 @@ void tst_qqmlpropertycache::signalHandlersDerived() QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject())); QQmlPropertyData *data; - QVERIFY(data = cacheProperty(cache, "onSignalA")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalA()")); + QVERIFY((data = cacheProperty(cache, "onSignalA"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()")); - QVERIFY(data = cacheProperty(cache, "onSignalB")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("signalB()")); + QVERIFY((data = cacheProperty(cache, "onSignalB"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalB()")); - QVERIFY(data = cacheProperty(cache, "onPropertyAChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyAChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyAChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyAChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyBChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyBChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyBChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyBChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyCChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyCChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyCChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyCChanged()")); - QVERIFY(data = cacheProperty(cache, "onPropertyDChanged")); - QCOMPARE(data->coreIndex, metaObject->indexOfMethod("propertyDChanged()")); + QVERIFY((data = cacheProperty(cache, "onPropertyDChanged"))); + QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("propertyDChanged()")); } -QTEST_MAIN(tst_qqmlpropertycache) +class TestClass : public QObject +{ + Q_OBJECT + Q_PROPERTY(int prop READ prop WRITE setProp NOTIFY propChanged) + int m_prop; + +public: + enum MyEnum { + First, Second + }; + Q_ENUM(MyEnum) + + Q_CLASSINFO("Foo", "Bar") + + TestClass() {} + + int prop() const + { + return m_prop; + } + +public slots: + void setProp(int prop) + { + if (m_prop == prop) + return; + + m_prop = prop; + emit propChanged(prop); + } +signals: + void propChanged(int prop); +}; + +class TestClassWithParameters : public QObject +{ + Q_OBJECT + +public: + Q_INVOKABLE void slotWithArguments(int firstArg) { + Q_UNUSED(firstArg); + } +}; + +class TestClassWithClassInfo : public QObject +{ + Q_OBJECT + Q_CLASSINFO("Key", "Value") +}; #include "tst_qqmlpropertycache.moc" + +#define ARRAY_SIZE(arr) \ + int(sizeof(arr) / sizeof(arr[0])) + +#define TEST_CLASS(Class) \ + QTest::newRow(#Class) << &Class::staticMetaObject << ARRAY_SIZE(qt_meta_data_##Class) << ARRAY_SIZE(qt_meta_stringdata_##Class.data) + +Q_DECLARE_METATYPE(const QMetaObject*); + +void tst_qqmlpropertycache::metaObjectSize_data() +{ + QTest::addColumn<const QMetaObject*>("metaObject"); + QTest::addColumn<int>("expectedFieldCount"); + QTest::addColumn<int>("expectedStringCount"); + + TEST_CLASS(TestClass); + TEST_CLASS(TestClassWithParameters); + TEST_CLASS(TestClassWithClassInfo); +} + +void tst_qqmlpropertycache::metaObjectSize() +{ + QFETCH(const QMetaObject *, metaObject); + QFETCH(int, expectedFieldCount); + QFETCH(int, expectedStringCount); + + int size = 0; + int stringDataSize = 0; + bool valid = QQmlPropertyCache::determineMetaObjectSizes(*metaObject, &size, &stringDataSize); + QVERIFY(valid); + + QCOMPARE(size, expectedFieldCount - 1); // Remove trailing zero field until fixed in moc. + QCOMPARE(stringDataSize, expectedStringCount); +} + +void tst_qqmlpropertycache::metaObjectChecksum() +{ + QMetaObjectBuilder builder; + builder.setClassName("Test"); + builder.addClassInfo("foo", "bar"); + + QCryptographicHash hash(QCryptographicHash::Md5); + + QScopedPointer<QMetaObject, QScopedPointerPodDeleter> mo(builder.toMetaObject()); + QVERIFY(!mo.isNull()); + + QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data())); + QByteArray initialHash = hash.result(); + QVERIFY(!initialHash.isEmpty()); + hash.reset(); + + { + QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data())); + QByteArray nextHash = hash.result(); + QVERIFY(!nextHash.isEmpty()); + hash.reset(); + QCOMPARE(initialHash, nextHash); + } + + builder.addProperty("testProperty", "int", -1); + + mo.reset(builder.toMetaObject()); + { + QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data())); + QByteArray nextHash = hash.result(); + QVERIFY(!nextHash.isEmpty()); + hash.reset(); + QVERIFY(initialHash != nextHash); + } +} + +QTEST_MAIN(tst_qqmlpropertycache) diff --git a/tests/auto/qml/qqmlqt/data/LaterComponent.qml b/tests/auto/qml/qqmlqt/data/LaterComponent.qml new file mode 100644 index 0000000000..7dbd81d93d --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/LaterComponent.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 +import LaterImports 1.0 + +TestElement { + id: deleteme + function testFn() { + gc(); // at this point, obj is deleted. + dangerousFunction(); // calling this function will throw an exeption + // because this object has been deleted and its context is not available + + // which means that we shouldn't get to this line. + row.test10_1 = 1; + } +} diff --git a/tests/auto/qml/qqmlqt/data/LaterComponent2.qml b/tests/auto/qml/qqmlqt/data/LaterComponent2.qml new file mode 100644 index 0000000000..56bcc0235b --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/LaterComponent2.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Item { + id: deleteme2 + function testFn() { + // this function shouldn't be called, + // since the object will have been deleted. + var crashy = Qt.createQmlObject("import QtQuick 2.0; Item { }", deleteme2) // invalid calling context if invoked after gc + row.test11_1 = 2; + } + + Component.onDestruction: row.test11_1 = 1; // success == the object was deleted, but testFn wasn't called. +} diff --git a/tests/auto/qml/qqmlqt/data/LaterComponent3.qml b/tests/auto/qml/qqmlqt/data/LaterComponent3.qml new file mode 100644 index 0000000000..c6f445253a --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/LaterComponent3.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 +import LaterImports 1.0 + +TestElement { + id: deleteme3 + function testFn() { + gc(); // at this point, obj is deleted. + dangerousFunction(); // calling this function will throw an exeption + // because this object has been deleted and its context is not available + + // which means that we shouldn't get to this line. + row.test12_1 = 1; + } +} diff --git a/tests/auto/qml/qqmlqt/data/LaterComponent4.qml b/tests/auto/qml/qqmlqt/data/LaterComponent4.qml new file mode 100644 index 0000000000..0c53bd368b --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/LaterComponent4.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +Item { + id: deleteme4 + function testFn() { + // this function shouldn't be called, + // since the object will have been deleted. + row.test13_1 = 2; + } + + Component.onDestruction: row.test13_1 = 1; // success == the object was deleted, but testFn wasn't called. +} diff --git a/tests/auto/qml/qqmlqt/data/exit.qml b/tests/auto/qml/qqmlqt/data/exit.qml new file mode 100644 index 0000000000..12727d9f04 --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/exit.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +QtObject { + property int returnCode: -1 + Component.onCompleted: Qt.exit(returnCode) +} + diff --git a/tests/auto/qml/qqmlqt/data/later.qml b/tests/auto/qml/qqmlqt/data/later.qml new file mode 100644 index 0000000000..a90f3aba9f --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/later.qml @@ -0,0 +1,124 @@ +import QtQuick 2.0 +import LaterImports 1.0 + +Row { + id: row + Repeater { + id: repeater + model: 5 + delegate: Item { } + } + + property bool test1_1: false + property bool test1_2: row.focus + property bool test2_1: false + property bool test2_2: (firstFunctionCallCounter == 1 && secondFunctionCallCounter == 1 && signalCallCounter == 1) + + property int firstFunctionCallCounter: 0 + property int secondFunctionCallCounter: 0 + property int signalCallCounter: 0 + + signal testSignal + onTestSignal: { + signalCallCounter++; + } + + onChildrenChanged: { + Qt.callLater(row.forceActiveFocus); // built-in function + Qt.callLater(row.firstFunction); // JS function + Qt.callLater(row.testSignal); // signal + } + + function firstFunction() { + firstFunctionCallCounter++; + } + + function secondFunction() { + secondFunctionCallCounter++; + } + + Component.onCompleted: { + test1_1 = !row.focus; + test2_1 = (firstFunctionCallCounter == 0); + + Qt.callLater(secondFunction); + Qt.callLater(firstFunction); + Qt.callLater(secondFunction); + } + + function test2() { + repeater.model = 2; + } + + function test3() { + Qt.callLater(test3_recursive); + } + + property int recursion: 0 + property bool test3_1: (recursion == 1) + property bool test3_2: (recursion == 2) + property bool test3_3: (recursion == 3) + function test3_recursive() { + if (recursion < 3) { + Qt.callLater(test3_recursive); + Qt.callLater(test3_recursive); + } + recursion++; + } + + function test4() { + Qt.callLater(functionThatDoesNotExist); + } + + property bool test5_1: false + function test5() { + Qt.callLater(functionWithArguments, "THESE", "ARGS", "WILL", "BE", "OVERWRITTEN") + Qt.callLater(functionWithArguments, "firstArg", 2, "thirdArg") + } + + function functionWithArguments(firstStr, secondInt, thirdString) { + test5_1 = (firstStr == "firstArg" && secondInt == 2 && thirdString == "thirdArg"); + } + + + property bool test6_1: (callOrder_Later == "TWO THREE ") // not "THREE TWO " + function test6() { + Qt.callLater(test6Function1, "ONE"); + Qt.callLater(test6Function2, "TWO"); + Qt.callLater(test6Function1, "THREE"); + } + + property string callOrder_Later + function test6Function1(arg) { callOrder_Later += arg + " "; } + function test6Function2(arg) { callOrder_Later += arg + " "; } + + property int test9_1: SingletonType.intProp; + function test9() { + SingletonType.resetIntProp(); + Qt.callLater(SingletonType.testFunc) + Qt.callLater(SingletonType.testFunc) + Qt.callLater(SingletonType.testFunc) + Qt.callLater(SingletonType.testFunc) + // should only get called once. + } + + property int test10_1: 0 + function test10() { + var c = Qt.createComponent("LaterComponent.qml"); + var obj = c.createObject(); // QML ownership. + Qt.callLater(obj.testFn); + // note: obj will be cleaned up during next gc(). + } + + property int test11_1: 0 + function test11() { + var c = Qt.createComponent("LaterComponent2.qml"); + var obj = c.createObject(); // QML ownership. + Qt.callLater(obj.testFn); + gc(); // this won't actually collect the obj, we need to trigger gc manually in the test. + } + + function test14() { + Qt.callLater(console.log, "success") + } +} diff --git a/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml new file mode 100644 index 0000000000..9d73640c87 --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/timeRoundtrip.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +QtObject { + Component.onCompleted: { + var t = tp.time; + tp.time = t; + } +} diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp index 2f44c34bc2..0576650d01 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -46,6 +46,15 @@ #include <QFont> #include "../../shared/util.h" +// Copied from tst_qdatetime.cpp +#ifdef Q_OS_WIN +# include <qt_windows.h> +# include <time.h> +# if defined(Q_OS_WINRT) +# define tzset() +# endif +#endif + class tst_qqmlqt : public QQmlDataTest { Q_OBJECT @@ -53,6 +62,7 @@ public: tst_qqmlqt() {} private slots: + void initTestCase(); void enums(); void rgba(); void hsla(); @@ -86,13 +96,74 @@ private slots: void atob(); void fontFamilies(); void quit(); + void exit(); void resolvedUrl(); + void later_data(); + void later(); void qtObjectContents(); + void timeRoundtrip_data(); + void timeRoundtrip(); + private: QQmlEngine engine; }; +// for callLater() +class TestElement : public QQuickItem +{ + Q_OBJECT +public: + TestElement() : m_intptr(new int) {} + ~TestElement() { delete m_intptr; } + + Q_INVOKABLE void dangerousFunction() { + delete m_intptr; + m_intptr = new int; + *m_intptr = 5; + } +private: + int *m_intptr; +}; + +// for callLater() +class TestModuleApi : public QObject +{ + Q_OBJECT + Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged) + +public: + TestModuleApi() : m_int(0) {} + ~TestModuleApi() {} + + int intProp() const { return m_int; } + void setIntProp(int v) { m_int = v; emit intPropChanged(); } + + Q_INVOKABLE void testFunc() { ++m_int; emit intPropChanged(); } + Q_INVOKABLE void resetIntProp() { m_int = 0; emit intPropChanged(); } + +signals: + void intPropChanged(); + +private: + int m_int; +}; + +static QObject *test_module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + TestModuleApi *api = new TestModuleApi; + return api; +} + +void tst_qqmlqt::initTestCase() +{ + QQmlDataTest::initTestCase(); + qmlRegisterSingletonType<TestModuleApi>("LaterImports", 1, 0, "SingletonType", test_module_api_factory); + qmlRegisterType<TestElement>("LaterImports", 1, 0, "TestElement"); +} + void tst_qqmlqt::enums() { QQmlComponent component(&engine, testFileUrl("enums.qml")); @@ -814,8 +885,6 @@ void tst_qqmlqt::dateTimeFormattingVariants_data() QTime time(11, 16, 39, 755); temporary = QDateTime(QDate(1970,1,1), time); - QTest::newRow("formatDate, qtime") << "formatDate" << QVariant::fromValue(time) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy")); - QTest::newRow("formatDateTime, qtime") << "formatDateTime" << QVariant::fromValue(time) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a")); QTest::newRow("formatTime, qtime") << "formatTime" << QVariant::fromValue(time) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz")); QDate date(2011,5,31); @@ -922,6 +991,20 @@ void tst_qqmlqt::quit() delete object; } +void tst_qqmlqt::exit() +{ + QQmlComponent component(&engine, testFileUrl("exit.qml")); + + QSignalSpy spy(&engine, &QQmlEngine::exit); + QObject *object = component.create(); + QVERIFY(object != Q_NULLPTR); + QCOMPARE(spy.count(), 1); + QList<QVariant> arguments = spy.takeFirst(); + QVERIFY(arguments.at(0).toInt() == object->property("returnCode").toInt()); + + delete object; +} + void tst_qqmlqt::resolvedUrl() { QQmlComponent component(&engine, testFileUrl("resolvedUrl.qml")); @@ -935,6 +1018,107 @@ void tst_qqmlqt::resolvedUrl() delete object; } +void tst_qqmlqt::later_data() +{ + QTest::addColumn<QString>("function"); + QTest::addColumn<QStringList>("expectedWarnings"); + QTest::addColumn<QStringList>("propNames"); + QTest::addColumn<QVariantList>("values"); + + QVariant vtrue = QVariant(true); + + QTest::newRow("callLater from onCompleted") + << QString() + << QStringList() + << (QStringList() << "test1_1" << "test2_1" << "processEvents" << "test1_2" << "test2_2") + << (QVariantList() << vtrue << vtrue << QVariant() << vtrue << vtrue); + + QTest::newRow("trigger Qt.callLater() via repeater") + << QString(QLatin1String("test2")) + << QStringList() + << (QStringList() << "processEvents" << "test2_2") + << (QVariantList() << QVariant() << vtrue); + + QTest::newRow("recursive Qt.callLater()") + << QString(QLatin1String("test3")) + << QStringList() + << (QStringList() << "processEvents" << "test3_1" << "processEvents" << "test3_2" << "processEvents" << "test3_3") + << (QVariantList() << QVariant() << vtrue << QVariant() << vtrue << QVariant() << vtrue); + + QTest::newRow("nonexistent function") + << QString(QLatin1String("test4")) + << (QStringList() << QString(testFileUrl("later.qml").toString() + QLatin1String(":70: ReferenceError: functionThatDoesNotExist is not defined"))) + << QStringList() + << QVariantList(); + + QTest::newRow("callLater with different args") + << QString(QLatin1String("test5")) + << QStringList() + << (QStringList() << "processEvents" << "test5_1") + << (QVariantList() << QVariant() << vtrue); + + QTest::newRow("delayed call ordering") + << QString(QLatin1String("test6")) + << QStringList() + << (QStringList() << "processEvents" << "test6_1") + << (QVariantList() << QVariant() << vtrue); + + QTest::newRow("invoke module api invokable") + << QString(QLatin1String("test9")) + << QStringList() + << (QStringList() << "processEvents" << "test9_1" << "processEvents") + << (QVariantList() << QVariant() << QVariant(1) << QVariant()); + + QTest::newRow("invoke function of deleted QObject via callLater() causing deletion") + << QString(QLatin1String("test10")) + << (QStringList() << QString(testFileUrl("LaterComponent.qml").toString() + QLatin1String(":8: ReferenceError: dangerousFunction is not defined (exception occurred during delayed function evaluation)"))) + << (QStringList() << "processEvents" << "test10_1" << "processEvents") + << (QVariantList() << QVariant() << QVariant(0) << QVariant()); + + QTest::newRow("invoke function of deleted QObject via callLater() after deletion") + << QString(QLatin1String("test11")) + << QStringList() + << (QStringList() << "collectGarbage" << "processEvents" << "test11_1" << "processEvents") + << (QVariantList() << QVariant() << QVariant() << QVariant(1) << QVariant()); + + QTest::newRow("invoke function which has no script origin") + << QString(QLatin1String("test14")) + << QStringList() + << (QStringList() << "collectGarbage") + << (QVariantList() << QVariant()); +} + +void tst_qqmlqt::later() +{ + QFETCH(QString, function); + QFETCH(QStringList, expectedWarnings); + QFETCH(QStringList, propNames); + QFETCH(QVariantList, values); + + foreach (const QString &w, expectedWarnings) + QTest::ignoreMessage(QtWarningMsg, qPrintable(w)); + + QQmlComponent component(&engine, testFileUrl("later.qml")); + QObject *root = component.create(); + QVERIFY(root != 0); + + if (!function.isEmpty()) + QMetaObject::invokeMethod(root, qPrintable(function)); + + for (int i = 0; i < propNames.size(); ++i) { + if (propNames.at(i) == QLatin1String("processEvents")) { + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + } else if (propNames.at(i) == QLatin1String("collectGarbage")) { + engine.collectGarbage(); + } else { + QCOMPARE(root->property(qPrintable(propNames.at(i))), values.at(i)); + } + } + + delete root; +} + void tst_qqmlqt::qtObjectContents() { struct StaticQtMetaObject : public QObject @@ -980,6 +1164,104 @@ void tst_qqmlqt::qtObjectContents() delete object; } +class TimeProvider: public QObject +{ + Q_OBJECT + Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged) + +public: + TimeProvider(const QTime &t) + : m_getTime(t) + {} + + QTime time() const { return m_getTime; } + void setTime(const QTime &t) { m_putTime = t; emit timeChanged(); } + +signals: + void timeChanged(); + +public: + QTime m_getTime, m_putTime; +}; + +class TimeZoneSwitch +{ +public: + TimeZoneSwitch(const char *newZone) + : doChangeZone(qstrcmp(newZone, "localtime") == 0) + { + if (!doChangeZone) + return; + + hadOldZone = qEnvironmentVariableIsSet("TZ"); + if (hadOldZone) { + oldZone = qgetenv("TZ"); + } + qputenv("TZ", newZone); + tzset(); + } + + ~TimeZoneSwitch() + { + if (!doChangeZone) + return; + + if (hadOldZone) + qputenv("TZ", oldZone); + else + qunsetenv("TZ"); + tzset(); + } + +private: + bool doChangeZone; + bool hadOldZone; + QByteArray oldZone; +}; + +void tst_qqmlqt::timeRoundtrip_data() +{ + QTest::addColumn<QTime>("time"); + + // Local timezone: + QTest::newRow("localtime") << QTime(0, 0, 0); + + // No DST: + QTest::newRow("UTC") << QTime(0, 0, 0); + QTest::newRow("Europe/Amsterdam") << QTime(1, 0, 0); + QTest::newRow("Asia/Jakarta") << QTime(7, 0, 0); + + // DST: + QTest::newRow("Namibia/Windhoek") << QTime(1, 0, 0); + QTest::newRow("Australia/Adelaide") << QTime(10, 0, 0); + QTest::newRow("Australia/Hobart") << QTime(10, 0, 0); + QTest::newRow("Pacific/Auckland") << QTime(12, 0, 0); + QTest::newRow("Pacific/Samoa") << QTime(13, 0, 0); +} + +void tst_qqmlqt::timeRoundtrip() +{ +#ifdef Q_OS_WIN + QSKIP("On Windows, the DateObject doesn't handle DST transitions correctly when the timezone is not localtime."); // I.e.: for this test. +#endif + + TimeZoneSwitch tzs(QTest::currentDataTag()); + QFETCH(QTime, time); + + TimeProvider tp(time); + + QQmlEngine eng; + eng.rootContext()->setContextProperty(QLatin1String("tp"), &tp); + QQmlComponent component(&eng, testFileUrl("timeRoundtrip.qml")); + QObject *obj = component.create(); + QVERIFY(obj != 0); + + // QML reads m_getTime and saves the result as m_putTime; this should come out the same, without + // any perturbation (e.g. by DST effects) from converting from QTime to V4's Date and back + // again. + QCOMPARE(tp.m_getTime, tp.m_putTime); +} + QTEST_MAIN(tst_qqmlqt) #include "tst_qqmlqt.moc" diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp index bf255ba6a0..1fc803a395 100644 --- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp +++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp @@ -31,7 +31,6 @@ #include <QQmlComponent> #include <QTranslator> #include <QQmlContext> -#include <private/qqmlcompiler_p.h> #include <private/qqmlengine_p.h> #include "../../shared/util.h" @@ -77,15 +76,15 @@ void tst_qqmltranslation::translation() QQmlContext *context = qmlContext(object); QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine()); QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl()); - QQmlCompiledData *cdata = typeData->compiledData(); - QVERIFY(cdata); + QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit(); + QVERIFY(compilationUnit); QSet<QString> compiledTranslations; compiledTranslations << QStringLiteral("basic") << QStringLiteral("disambiguation") << QStringLiteral("singular") << QStringLiteral("plural"); - const QV4::CompiledData::Unit *unit = cdata->compilationUnit->data; + const QV4::CompiledData::Unit *unit = compilationUnit->data; const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject); const QV4::CompiledData::Binding *binding = rootObject->bindingTable(); for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) { @@ -96,7 +95,7 @@ void tst_qqmltranslation::translation() if (expectCompiledTranslation) { if (binding->type != QV4::CompiledData::Binding::Type_Translation) qDebug() << "binding for property" << propertyName << "is not a compiled translation"; - QCOMPARE(binding->type, quint32(QV4::CompiledData::Binding::Type_Translation)); + QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_Translation)); } else { if (binding->type == QV4::CompiledData::Binding::Type_Translation) qDebug() << "binding for property" << propertyName << "is not supposed to be a compiled translation"; @@ -137,10 +136,10 @@ void tst_qqmltranslation::idTranslation() QQmlContext *context = qmlContext(object); QQmlEnginePrivate *engine = QQmlEnginePrivate::get(context->engine()); QQmlTypeData *typeData = engine->typeLoader.getType(context->baseUrl()); - QQmlCompiledData *cdata = typeData->compiledData(); - QVERIFY(cdata); + QV4::CompiledData::CompilationUnit *compilationUnit = typeData->compilationUnit(); + QVERIFY(compilationUnit); - const QV4::CompiledData::Unit *unit = cdata->compilationUnit->data; + const QV4::CompiledData::Unit *unit = compilationUnit->data; const QV4::CompiledData::Object *rootObject = unit->objectAt(unit->indexOfRootObject); const QV4::CompiledData::Binding *binding = rootObject->bindingTable(); for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) { @@ -148,7 +147,7 @@ void tst_qqmltranslation::idTranslation() if (propertyName == "idTranslation") { if (binding->type != QV4::CompiledData::Binding::Type_TranslationById) qDebug() << "binding for property" << propertyName << "is not a compiled translation"; - QCOMPARE(binding->type, quint32(QV4::CompiledData::Binding::Type_TranslationById)); + QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_TranslationById)); } else { QVERIFY(binding->type != QV4::CompiledData::Binding::Type_Translation); } diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index 36350e2d08..3d3a7ff725 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -32,7 +32,6 @@ #include <QtQuick/qquickitem.h> #include <QtQml/private/qqmlengine_p.h> #include <QtQml/private/qqmltypeloader_p.h> -#include <QtQml/private/qqmlcompiler_p.h> #include "../../shared/util.h" class tst_QQMLTypeLoader : public QQmlDataTest @@ -90,7 +89,7 @@ void tst_QQMLTypeLoader::trimCache() if (i % 10 == 0) { // keep ref on data, don't add ref on data->compiledData() } else if (i % 5 == 0) { - data->compiledData()->addref(); + data->compilationUnit()->addref(); data->release(); } else { data->release(); diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_read.qml b/tests/auto/qml/qqmlvaluetypes/data/color_read.qml index bc92b1e5f9..73d2b921a7 100644 --- a/tests/auto/qml/qqmlvaluetypes/data/color_read.qml +++ b/tests/auto/qml/qqmlvaluetypes/data/color_read.qml @@ -5,5 +5,11 @@ MyTypeObject { property real v_g: color.g property real v_b: color.b property real v_a: color.a + property real hsv_h: color.hsvHue + property real hsv_s: color.hsvSaturation + property real hsv_v: color.hsvValue + property real hsl_h: color.hslHue + property real hsl_s: color.hslSaturation + property real hsl_l: color.hslLightness property variant copy: color } diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml new file mode 100644 index 0000000000..0034163bbe --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSL.qml @@ -0,0 +1,8 @@ +import Test 1.0 + +MyTypeObject { + color.hslHue: if (true) 0.43 + color.hslSaturation: if (true) 0.74 + color.hslLightness: if (true) 0.54 + color.a: if (true) 0.7 +} diff --git a/tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml new file mode 100644 index 0000000000..1fc47d460e --- /dev/null +++ b/tests/auto/qml/qqmlvaluetypes/data/color_write_HSV.qml @@ -0,0 +1,8 @@ +import Test 1.0 + +MyTypeObject { + color.hsvHue: if (true) 0.43 + color.hsvSaturation: if (true) 0.77 + color.hsvValue: if (true) 0.88 + color.a: if (true) 0.7 +} diff --git a/tests/auto/qml/qqmlvaluetypes/testtypes.h b/tests/auto/qml/qqmlvaluetypes/testtypes.h index 77d723fbd4..bcfe4028c6 100644 --- a/tests/auto/qml/qqmlvaluetypes/testtypes.h +++ b/tests/auto/qml/qqmlvaluetypes/testtypes.h @@ -194,7 +194,7 @@ class MyOffsetValueInterceptor : public QObject, public QQmlPropertyValueInterce Q_INTERFACES(QQmlPropertyValueInterceptor) public: virtual void setTarget(const QQmlProperty &p) { prop = p; } - virtual void write(const QVariant &value) { QQmlPropertyPrivate::write(prop, value.toInt() + 13, QQmlPropertyPrivate::BypassInterceptor); } + virtual void write(const QVariant &value) { QQmlPropertyPrivate::write(prop, value.toInt() + 13, QQmlPropertyData::BypassInterceptor); } private: QQmlProperty prop; @@ -215,7 +215,7 @@ public: c.getRgb(&r, &g, &b, &a); c.setRgb(a, b, g, r); - QQmlPropertyPrivate::write(prop, c, QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::write(prop, c, QQmlPropertyData::BypassInterceptor); } private: @@ -230,7 +230,7 @@ public: virtual void setTarget(const QQmlProperty &p) { prop = p; } virtual void write(const QVariant &) { - QQmlPropertyPrivate::write(prop, 0.0f, QQmlPropertyPrivate::BypassInterceptor); + QQmlPropertyPrivate::write(prop, 0.0f, QQmlPropertyData::BypassInterceptor); } private: diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index 300f5b90e5..803bad197a 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -30,6 +30,7 @@ #include <QQmlEngine> #include <QQmlComponent> #include <QDebug> +#include <QJSValueIterator> #include <private/qquickvaluetypes_p.h> #include <private/qqmlglobal_p.h> #include "../../shared/util.h" @@ -89,6 +90,7 @@ private slots: void customValueTypeInQml(); void gadgetInheritance(); void toStringConversion(); + void enumerableProperties(); private: QQmlEngine engine; @@ -905,6 +907,15 @@ void tst_qqmlvaluetypes::color() QCOMPARE((float)object->property("v_g").toDouble(), (float)0.88); QCOMPARE((float)object->property("v_b").toDouble(), (float)0.6); QCOMPARE((float)object->property("v_a").toDouble(), (float)0.34); + + QCOMPARE(qRound(object->property("hsv_h").toDouble() * 100), 43); + QCOMPARE(qRound(object->property("hsv_s").toDouble() * 100), 77); + QCOMPARE(qRound(object->property("hsv_v").toDouble() * 100), 88); + + QCOMPARE(qRound(object->property("hsl_h").toDouble() * 100), 43); + QCOMPARE(qRound(object->property("hsl_s").toDouble() * 100), 74); + QCOMPARE(qRound(object->property("hsl_l").toDouble() * 100), 54); + QColor comparison; comparison.setRedF(0.2); comparison.setGreenF(0.88); @@ -931,6 +942,30 @@ void tst_qqmlvaluetypes::color() } { + QQmlComponent component(&engine, testFileUrl("color_write_HSV.qml")); + MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QVERIFY(object != 0); + + QColor newColor; + newColor.setHsvF(0.43, 0.77, 0.88, 0.7); + QCOMPARE(object->color(), newColor); + + delete object; + } + + { + QQmlComponent component(&engine, testFileUrl("color_write_HSL.qml")); + MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); + QVERIFY(object != 0); + + QColor newColor; + newColor.setHslF(0.43, 0.74, 0.54, 0.7); + QCOMPARE(object->color(), newColor); + + delete object; + } + + { QQmlComponent component(&engine, testFileUrl("color_compare.qml")); MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create()); QVERIFY(object != 0); @@ -1649,6 +1684,25 @@ void tst_qqmlvaluetypes::toStringConversion() QCOMPARE(stringConversion.toString(), StringLessGadget_to_QString(g)); } +void tst_qqmlvaluetypes::enumerableProperties() +{ + QJSEngine engine; + DerivedGadget g; + QJSValue value = engine.toScriptValue(g); + QSet<QString> names; + QJSValueIterator it(value); + while (it.hasNext()) { + it.next(); + const QString name = it.name(); + QVERIFY(!names.contains(name)); + names.insert(name); + } + + QCOMPARE(names.count(), 2); + QVERIFY(names.contains(QStringLiteral("baseProperty"))); + QVERIFY(names.contains(QStringLiteral("derivedProperty"))); +} + QTEST_MAIN(tst_qqmlvaluetypes) diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect new file mode 100644 index 0000000000..8c13977462 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect @@ -0,0 +1,17 @@ +PATCH /qqmlxmlhttprequest.cpp HTTP/1.1 +Accept-Language: en-US +If-Match: "ETagNumber" +Content-Type: application/example +Content-Length: 247 +Connection: Keep-Alive +Accept-Encoding: gzip, deflate +User-Agent: Mozilla/5.0 +Host: {{ServerHostUrl}} + +--- a/qqmlxmlhttprequest.cpp ++++ b/qqmlxmlhttprequest.cpp +@@ -1238,11 +1238,13 @@ +- } else if (m_method == QLatin1String("OPTIONS")) { ++ } else if (m_method == QLatin1String("OPTIONS") || ++ (m_method == QLatin1String("PATCH"))) { + diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml new file mode 100644 index 0000000000..2abf1c60a8 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.qml @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Canonical Limited and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +QtObject { + property string url + + property bool dataOK: false + property bool headerOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + x.open("PATCH", url); + x.setRequestHeader("Accept-Language","en-US"); + x.setRequestHeader("If-Match","\"ETagNumber\""); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.HEADERS_RECEIVED) { + headerOK = (x.getResponseHeader("Content-Location") == "/qqmlxmlhttprequest.cpp") && + (x.getResponseHeader("ETag") == "\"ETagNumber\"") && + (x.status == "204"); + } else if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText === ""); + } + } + + var body = "--- a/qqmlxmlhttprequest.cpp\n" + + "+++ b/qqmlxmlhttprequest.cpp\n" + + "@@ -1238,11 +1238,13 @@\n" + + "- } else if (m_method == QLatin1String(\"OPTIONS\")) {\n" + + "+ } else if (m_method == QLatin1String(\"OPTIONS\") ||\n" + + "+ (m_method == QLatin1String(\"PATCH\"))) {\n" + + x.send(body); + } +} diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply new file mode 100644 index 0000000000..cece41ced1 --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.reply @@ -0,0 +1,3 @@ +HTTP/1.1 204 No Content +Content-Location: /qqmlxmlhttprequest.cpp +ETag: "ETagNumber" diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp index 425e12677f..1ce07ecdab 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp +++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp @@ -71,6 +71,7 @@ private slots: void send_withdata_data(); void send_options(); void send_options_data(); + void send_patch(); void abort(); void abort_unsent(); void abort_opened(); @@ -639,6 +640,26 @@ void tst_qqmlxmlhttprequest::send_options_data() QTest::newRow("OPTIONS (with data)") << "testdocument.html" << "send_data.10.expect" << "send_data.9.qml" << "send_data.2.reply"; } +void tst_qqmlxmlhttprequest::send_patch() +{ + TestHTTPServer server; + QVERIFY2(server.listen(), qPrintable(server.errorString())); + QVERIFY(server.wait(testFileUrl("send_patch.expect"), + testFileUrl("send_patch.reply"), + // the content of response file will be ignored due to 204 status code + testFileUrl("testdocument.html"))); + + QQmlComponent component(&engine, testFileUrl("send_patch.qml")); + QScopedPointer<QObject> object(component.beginCreate(engine.rootContext())); + QVERIFY(!object.isNull()); + object->setProperty("url", server.urlString("/qqmlxmlhttprequest.cpp")); + component.completeCreate(); + + QTRY_VERIFY(object->property("dataOK").toBool()); + QTRY_VERIFY(object->property("headerOK").toBool()); +} + + // Test abort() has no effect in unsent state void tst_qqmlxmlhttprequest::abort_unsent() { diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp index f3ba3e8971..f19e82032a 100644 --- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp +++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp @@ -56,6 +56,7 @@ public slots: } private slots: + void initTestCase(); void basicProperties(); void showFiles(); void resetFiltering(); @@ -97,6 +98,15 @@ void tst_qquickfolderlistmodel::checkNoErrors(const QQmlComponent& component) QVERIFY(!component.isError()); } +void tst_qquickfolderlistmodel::initTestCase() +{ + // The tests rely on a fixed number of files in the directory with the qml files + // (the data dir), so disable the disk cache to avoid creating .qmlc files and + // confusing the test. + qputenv("QML_DISABLE_DISK_CACHE", "1"); + QQmlDataTest::initTestCase(); +} + void tst_qquickfolderlistmodel::basicProperties() { QQmlComponent component(&engine, testFileUrl("basic.qml")); diff --git a/tests/auto/qml/qv4mm/qv4mm.pro b/tests/auto/qml/qv4mm/qv4mm.pro new file mode 100644 index 0000000000..d9b749af4a --- /dev/null +++ b/tests/auto/qml/qv4mm/qv4mm.pro @@ -0,0 +1,8 @@ +CONFIG += testcase +TARGET = tst_qv4mm +osx:CONFIG -= app_bundle + +SOURCES += tst_qv4mm.cpp + +QT += qml qml-private testlib + diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp new file mode 100644 index 0000000000..d4ba363d00 --- /dev/null +++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2016 basysKom GmbH. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qtest.h> +#include <QQmlEngine> +#include <private/qv4mm_p.h> + +class tst_qv4mm : public QObject +{ + Q_OBJECT + +private slots: + void gcStats(); + void tweaks(); +}; + +void tst_qv4mm::gcStats() +{ + qputenv(QV4_MM_STATS, "1"); + QQmlEngine engine; + engine.collectGarbage(); +} + +void tst_qv4mm::tweaks() +{ + qputenv(QV4_MM_MAXBLOCK_SHIFT, "5"); + qputenv(QV4_MM_MAX_CHUNK_SIZE, "65536"); + QQmlEngine engine; +} + +QTEST_MAIN(tst_qv4mm) + +#include "tst_qv4mm.moc" diff --git a/tests/auto/qmldevtools/compile/compile.pro b/tests/auto/qmldevtools/compile/compile.pro index 54430eb668..832700698f 100644 --- a/tests/auto/qmldevtools/compile/compile.pro +++ b/tests/auto/qmldevtools/compile/compile.pro @@ -5,7 +5,7 @@ force_bootstrap { !build_pass: CONFIG += release } else { QT = core - !build_pass:contains(QT_CONFIG, debug_and_release): CONFIG += release + !build_pass:qtConfig(debug_and_release): CONFIG += release } QT += qmldevtools-private macx:CONFIG -= app_bundle diff --git a/tests/auto/qmldevtools/qmldevtools.pro b/tests/auto/qmldevtools/qmldevtools.pro index a0ca1bff87..a9352d4df3 100644 --- a/tests/auto/qmldevtools/qmldevtools.pro +++ b/tests/auto/qmldevtools/qmldevtools.pro @@ -1,6 +1,4 @@ TEMPLATE = subdirs -contains(QT_CONFIG, private_tests) { - SUBDIRS += \ - compile -} +qtConfig(private_tests): \ + SUBDIRS += compile diff --git a/tests/auto/qmltest/selftests/tst_tryVerify.qml b/tests/auto/qmltest/selftests/tst_tryVerify.qml new file mode 100644 index 0000000000..6f29d8643d --- /dev/null +++ b/tests/auto/qmltest/selftests/tst_tryVerify.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtTest 1.1 + +TestCase { + name: "tst_tryVerify" + + Item { + id: item + } + + QtObject { + id: itemContainer + property Item i + } + + Timer { + id: timer + interval: 100 + onTriggered: itemContainer.i = item + } + + function resetTimer() { + itemContainer.i = null; + timer.restart(); + } + + function test_tryVerify() { + timer.start(); + tryVerify(function(){ return itemContainer.i; }, 200, "string"); + compare(itemContainer.i, item); + + resetTimer(); + tryVerify(function(){ return itemContainer.i; }, 200); + compare(itemContainer.i, item); + + resetTimer(); + tryVerify(function(){ return itemContainer.i; }); + compare(itemContainer.i, item); + + resetTimer(); + tryVerify(function(){ return !itemContainer.i; }, 0, "string"); + verify(!itemContainer.i); + } +} diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp index 233cb33631..872a71011d 100644 --- a/tests/auto/quick/examples/tst_examples.cpp +++ b/tests/auto/quick/examples/tst_examples.cpp @@ -103,6 +103,18 @@ tst_examples::tst_examples() excludedFiles << "views/visualdatamodel/slideshow.qml"; #endif +#ifdef QT_NO_OPENGL + //No support for Particles + excludedFiles << "examples/qml/dynamicscene/dynamicscene.qml"; + excludedFiles << "examples/quick/animation/basics/color-animation.qml"; + excludedFiles << "examples/quick/particles/affectors/content/age.qml"; + excludedFiles << "examples/quick/touchinteraction/multipointtouch/bearwhack.qml"; + excludedFiles << "examples/quick/touchinteraction/multipointtouch/multiflame.qml"; + excludedDirs << "examples/quick/particles"; + // No Support for ShaderEffect + excludedFiles << "src/quick/doc/snippets/qml/animators.qml"; +#endif + } tst_examples::~tst_examples() diff --git a/tests/auto/quick/geometry/tst_geometry.cpp b/tests/auto/quick/geometry/tst_geometry.cpp index 8755e3a1d7..470ce3bd91 100644 --- a/tests/auto/quick/geometry/tst_geometry.cpp +++ b/tests/auto/quick/geometry/tst_geometry.cpp @@ -126,9 +126,9 @@ void GeometryTest::testCustomGeometry() }; static QSGGeometry::Attribute attributes[] = { - { 0, 2, GL_FLOAT, 0, 0}, - { 1, 4, GL_UNSIGNED_BYTE, 0, 0}, - { 2, 4, GL_FLOAT, 0, 0}, + QSGGeometry::Attribute::create(0, 2, QSGGeometry::TypeFloat, false), + QSGGeometry::Attribute::create(1, 4, QSGGeometry::TypeUnsignedByte, false), + QSGGeometry::Attribute::create(2, 4, QSGGeometry::TypeFloat, false) }; static QSGGeometry::AttributeSet set = { 4, 6 * sizeof(float) + 4 * sizeof(unsigned char), attributes }; diff --git a/tests/auto/quick/nodes/tst_nodestest.cpp b/tests/auto/quick/nodes/tst_nodestest.cpp index 16c1174604..63e0aeb324 100644 --- a/tests/auto/quick/nodes/tst_nodestest.cpp +++ b/tests/auto/quick/nodes/tst_nodestest.cpp @@ -31,7 +31,6 @@ #include <QtGui/QOffscreenSurface> #include <QtGui/QOpenGLContext> - #include <QtQuick/qsgnode.h> #include <QtQuick/private/qsgbatchrenderer_p.h> #include <QtQuick/private/qsgnodeupdater_p.h> @@ -76,7 +75,7 @@ private Q_SLOTS: private: QOffscreenSurface *surface; QOpenGLContext *context; - QSGRenderContext *renderContext; + QSGDefaultRenderContext *renderContext; }; void NodesTest::initTestCase() @@ -91,7 +90,8 @@ void NodesTest::initTestCase() QVERIFY(context->create()); QVERIFY(context->makeCurrent(surface)); - renderContext = renderLoop->createRenderContext(renderLoop->sceneGraphContext()); + auto rc = renderLoop->createRenderContext(renderLoop->sceneGraphContext()); + renderContext = static_cast<QSGDefaultRenderContext *>(rc); QVERIFY(renderContext); renderContext->initialize(context); QVERIFY(renderContext->isValid()); @@ -110,7 +110,7 @@ void NodesTest::cleanupTestCase() class DummyRenderer : public QSGBatchRenderer::Renderer { public: - DummyRenderer(QSGRootNode *root, QSGRenderContext *renderContext) + DummyRenderer(QSGRootNode *root, QSGDefaultRenderContext *renderContext) : QSGBatchRenderer::Renderer(renderContext) , changedNode(0) , changedState(0) diff --git a/tests/auto/quick/nokeywords/tst_nokeywords.cpp b/tests/auto/quick/nokeywords/tst_nokeywords.cpp index ffe76cc210..6c94b484ae 100644 --- a/tests/auto/quick/nokeywords/tst_nokeywords.cpp +++ b/tests/auto/quick/nokeywords/tst_nokeywords.cpp @@ -48,13 +48,15 @@ #include <QtQuick/private/qsgadaptationlayer_p.h> #include <QtQuick/private/qsgcontext_p.h> #include <QtQuick/private/qsgcontextplugin_p.h> +#ifndef QT_NO_OPENGL #include <QtQuick/private/qsgdefaultdistancefieldglyphcache_p.h> #include <QtQuick/private/qsgdefaultglyphnode_p.h> -#include <QtQuick/private/qsgdefaultimagenode_p.h> -#include <QtQuick/private/qsgdefaultrectanglenode_p.h> +#include <QtQuick/private/qsgdefaultinternalimagenode_p.h> +#include <QtQuick/private/qsgdefaultinternalrectanglenode_p.h> #include <QtQuick/private/qsgdepthstencilbuffer_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p.h> #include <QtQuick/private/qsgdistancefieldutil_p.h> +#endif #include <QtQuick/private/qsggeometry_p.h> #include <QtQuick/private/qsgnode_p.h> #include <QtQuick/private/qsgnodeupdater_p.h> diff --git a/tests/auto/quick/qquickaccessible/qquickaccessible.pro b/tests/auto/quick/qquickaccessible/qquickaccessible.pro index 02915e8e22..537aad882f 100644 --- a/tests/auto/quick/qquickaccessible/qquickaccessible.pro +++ b/tests/auto/quick/qquickaccessible/qquickaccessible.pro @@ -15,10 +15,3 @@ OTHER_FILES += data/checkbuttons.qml \ data/pushbutton.qml \ data/statictext.qml \ data/ignored.qml \ - -wince*: { - accessneeded.files = $$QT.widgets.plugins/accessible/*.dll - accessneeded.path = accessible - DEPLOYMENT += accessneeded -} - diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp index b34f58f7c4..34b9fb6b07 100644 --- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp +++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp @@ -179,7 +179,11 @@ void tst_qquickanimatedimage::mirror_running() QImage frame0_expected = frame0.transformed(transform); QImage frame1_expected = frame1.transformed(transform); + if (window.devicePixelRatio() != 1.0 && window.rendererInterface()->graphicsApi() == QSGRendererInterface::Software) + QSKIP("QTBUG-53823"); QCOMPARE(frame0_flipped, frame0_expected); + if (window.devicePixelRatio() != 1.0 && window.rendererInterface()->graphicsApi() == QSGRendererInterface::Software) + QSKIP("QTBUG-53823"); QCOMPARE(frame1_flipped, frame1_expected); delete anim; @@ -212,6 +216,8 @@ void tst_qquickanimatedimage::mirror_notRunning() screenshot = window.grabWindow(); screenshot.save("screen.png"); + if (window.devicePixelRatio() != 1.0 && window.rendererInterface()->graphicsApi() == QSGRendererInterface::Software) + QSKIP("QTBUG-53823"); QCOMPARE(screenshot, expected); // mirroring should not change the current frame or playing status diff --git a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp index 1bd163fc4a..114f906736 100644 --- a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp +++ b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp @@ -47,6 +47,7 @@ private slots: void active(); void state(); void layoutDirection(); + void font(); void inputMethod(); void styleHints(); void cleanup(); @@ -196,6 +197,21 @@ void tst_qquickapplication::layoutDirection() QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::LeftToRight); } +void tst_qquickapplication::font() +{ + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0; Item { property font defaultFont: Qt.application.font }", QUrl::fromLocalFile("")); + QQuickItem *item = qobject_cast<QQuickItem *>(component.create()); + QVERIFY(item); + QQuickView view; + item->setParentItem(view.rootObject()); + + QVariant defaultFontProperty = item->property("defaultFont"); + QVERIFY(defaultFontProperty.isValid()); + QCOMPARE(defaultFontProperty.type(), QVariant::Font); + QCOMPARE(defaultFontProperty.value<QFont>(), qApp->font()); +} + void tst_qquickapplication::inputMethod() { // technically not in QQuickApplication, but testing anyway here diff --git a/tests/auto/quick/qquickborderimage/data/mesh.qml b/tests/auto/quick/qquickborderimage/data/mesh.qml new file mode 100644 index 0000000000..203bf25867 --- /dev/null +++ b/tests/auto/quick/qquickborderimage/data/mesh.qml @@ -0,0 +1,22 @@ +import QtQuick 2.8 + +Item { + width: 300 + height: 300 + Image { + id: image + source: "colors.png" + visible: false + } + ShaderEffect { + anchors.fill: parent + property variant source: image + mesh: BorderImageMesh { + border.left: 30 + border.right: 30 + border.top: 30 + border.bottom: 30 + size: image.sourceSize + } + } +} diff --git a/tests/auto/quick/qquickborderimage/data/nonmesh.qml b/tests/auto/quick/qquickborderimage/data/nonmesh.qml new file mode 100644 index 0000000000..7a1830a942 --- /dev/null +++ b/tests/auto/quick/qquickborderimage/data/nonmesh.qml @@ -0,0 +1,11 @@ +import QtQuick 2.8 + +BorderImage { + width: 300 + height: 300 + source: "colors.png" + border.left: 30 + border.right: 30 + border.top: 30 + border.bottom: 30 +} diff --git a/tests/auto/quick/qquickborderimage/qquickborderimage.pro b/tests/auto/quick/qquickborderimage/qquickborderimage.pro index 3e16063559..ba6c01737a 100644 --- a/tests/auto/quick/qquickborderimage/qquickborderimage.pro +++ b/tests/auto/quick/qquickborderimage/qquickborderimage.pro @@ -7,6 +7,7 @@ SOURCES += tst_qquickborderimage.cpp \ ../../shared/testhttpserver.cpp include (../../shared/util.pri) +include (../shared/util.pri) TESTDATA = data/* diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp index c11ae1e8c9..5d242fab9e 100644 --- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp +++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp @@ -44,6 +44,7 @@ #include "../../shared/testhttpserver.h" #include "../../shared/util.h" +#include "../shared/visualtestutil.h" Q_DECLARE_METATYPE(QQuickImageBase::Status) @@ -75,6 +76,9 @@ private slots: void statusChanges_data(); void sourceSizeChanges(); void progressAndStatusChanges(); +#ifndef QT_NO_OPENGL + void borderImageMesh(); +#endif private: QQmlEngine engine; @@ -242,6 +246,11 @@ void tst_qquickborderimage::mirror() image->setProperty("mirror", true); screenshot = window->grabWindow(); + + window->show(); + QTest::qWaitForWindowExposed(window); + if (window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) + QSKIP("QTBUG-53823"); QCOMPARE(screenshot, srcPixmap); delete window; @@ -574,7 +583,22 @@ void tst_qquickborderimage::progressAndStatusChanges() delete obj; } +#ifndef QT_NO_OPENGL +void tst_qquickborderimage::borderImageMesh() +{ + QQuickView *window = new QQuickView; + window->setSource(testFileUrl("nonmesh.qml")); + window->show(); + QTest::qWaitForWindowExposed(window); + QImage nonmesh = window->grabWindow(); + + window->setSource(testFileUrl("mesh.qml")); + QImage mesh = window->grabWindow(); + + QVERIFY(QQuickVisualTestUtil::compareImages(mesh, nonmesh)); +} +#endif QTEST_MAIN(tst_qquickborderimage) #include "tst_qquickborderimage.moc" diff --git a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml index e49f0ac462..b0fb7fcf8c 100644 --- a/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml +++ b/tests/auto/quick/qquickcanvasitem/data/CanvasTestCase.qml @@ -31,7 +31,9 @@ TestCase { } function createCanvasObject(data) { - return component.createObject(testCase, data.properties); + var canvas = component.createObject(testCase, data.properties); + waitForRendering(canvas); + return canvas; } function comparePixel(ctx,x,y,r,g,b,a, d) diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml index 93f85107a7..565f906fb1 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml @@ -590,6 +590,7 @@ CanvasTestCase { verify(canvas); canvas.width = 100; canvas.height = 100; + waitForRendering(canvas); var ctx = canvas.getContext("2d"); diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_image.qml b/tests/auto/quick/qquickcanvasitem/data/tst_image.qml index 46a038a13c..1f695d7080 100644 --- a/tests/auto/quick/qquickcanvasitem/data/tst_image.qml +++ b/tests/auto/quick/qquickcanvasitem/data/tst_image.qml @@ -667,6 +667,7 @@ CanvasTestCase { var canvas2 = Qt.createQmlObject("import QtQuick 2.0; Canvas{renderTarget:Canvas.Image; renderStrategy:Canvas.Immediate}", canvas); canvas2.width = 100; canvas2.height = 50; + waitForRendering(canvas2); var ctx2 = canvas2.getContext('2d'); ctx2.fillStyle = '#0f0'; ctx2.fillRect(0, 0, 100, 50); diff --git a/tests/auto/quick/qquickflickable/data/contentXY.qml b/tests/auto/quick/qquickflickable/data/contentXY.qml new file mode 100644 index 0000000000..8215976949 --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/contentXY.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +Flickable { + width: 400; height: 400 + contentWidth: 1e11; contentHeight: 1e11 +} diff --git a/tests/auto/quick/qquickflickable/data/keepGrab.qml b/tests/auto/quick/qquickflickable/data/keepGrab.qml new file mode 100644 index 0000000000..32546658d0 --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/keepGrab.qml @@ -0,0 +1,22 @@ +import QtQuick 2.3 + +Flickable { + id: flickable + width: 400 + height: 400 + contentWidth: 800 + contentHeight: 800 + + Rectangle { + x: 200 + y: 200 + width: 400 + height: 400 + color: "green" + MouseArea { + id: ma + objectName: "ma" + anchors.fill: parent + } + } +} diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index d0f015324c..b774481592 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -93,6 +93,8 @@ private slots: void cleanup(); void contentSize(); void ratios_smallContent(); + void contentXYNotTruncatedToInt(); + void keepGrab(); private: void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to); @@ -1223,7 +1225,9 @@ void tst_qquickflickable::flickOnRelease() QTRY_VERIFY(!flickable->isMoving()); #ifdef Q_OS_MAC +# ifndef QT_NO_OPENGL QEXPECT_FAIL("", "QTBUG-26094 stopping on a full pixel doesn't work on OS X", Continue); +# endif #endif // Stop on a full pixel after user interaction QCOMPARE(flickable->contentY(), (qreal)qRound(flickable->contentY())); @@ -1966,6 +1970,72 @@ void tst_qquickflickable::ratios_smallContent() QCOMPARE(obj->property("widthRatioIs").toDouble(), 1.); } +// QTBUG-48018 +void tst_qquickflickable::contentXYNotTruncatedToInt() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("contentXY.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); + QVERIFY(flickable); + + flickable->setContentX(1e10); + flick(window.data(), QPoint(200, 100), QPoint(100, 100), 50); + + // make sure we are not clipped at 2^31 + QVERIFY(flickable->contentX() > qreal(1e10)); +} + +void tst_qquickflickable::keepGrab() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("keepGrab.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject()); + QVERIFY(flickable); + + QQuickMouseArea *ma = flickable->findChild<QQuickMouseArea*>("ma"); + QVERIFY(ma); + ma->setPreventStealing(true); + + QPoint pos(250, 250); + moveAndPress(window.data(), pos); + for (int i = 0; i < 6; ++i) { + pos += QPoint(10, 10); + QTest::mouseMove(window.data(), pos); + QTest::qWait(10); + } + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(310, 310)); + QTest::qWait(10); + + QCOMPARE(flickable->contentX(), 0.0); + QCOMPARE(flickable->contentY(), 0.0); + + ma->setPreventStealing(false); + + pos = QPoint(250, 250); + moveAndPress(window.data(), pos); + for (int i = 0; i < 6; ++i) { + pos += QPoint(10, 10); + QTest::mouseMove(window.data(), pos); + QTest::qWait(10); + } + QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(310, 310)); + QTest::qWait(10); + + QVERIFY(flickable->contentX() != 0.0); + QVERIFY(flickable->contentY() != 0.0); +} QTEST_MAIN(tst_qquickflickable) diff --git a/tests/auto/quick/qquickgraphicsinfo/data/basic.qml b/tests/auto/quick/qquickgraphicsinfo/data/basic.qml new file mode 100644 index 0000000000..6ff3b82cec --- /dev/null +++ b/tests/auto/quick/qquickgraphicsinfo/data/basic.qml @@ -0,0 +1,14 @@ +import QtQuick 2.8 + +Item { + property int api: GraphicsInfo.api + + property int shaderType: GraphicsInfo.shaderType + property int shaderCompilationType: GraphicsInfo.shaderCompilationType + property int shaderSourceType: GraphicsInfo.shaderSourceType + + property int majorVersion: GraphicsInfo.majorVersion + property int minorVersion: GraphicsInfo.minorVersion + property int profile: GraphicsInfo.profile + property int renderableType: GraphicsInfo.renderableType +} diff --git a/tests/auto/quick/qquickgraphicsinfo/qquickgraphicsinfo.pro b/tests/auto/quick/qquickgraphicsinfo/qquickgraphicsinfo.pro new file mode 100644 index 0000000000..a4296ad9a2 --- /dev/null +++ b/tests/auto/quick/qquickgraphicsinfo/qquickgraphicsinfo.pro @@ -0,0 +1,14 @@ +CONFIG += testcase +TARGET = tst_qquickgraphicsinfo +SOURCES += tst_qquickgraphicsinfo.cpp + +TESTDATA = data/* +include(../../shared/util.pri) + +osx:CONFIG -= app_bundle + +QT += quick testlib + +OTHER_FILES += \ + data/basic.qml + diff --git a/tests/auto/quick/qquickgraphicsinfo/tst_qquickgraphicsinfo.cpp b/tests/auto/quick/qquickgraphicsinfo/tst_qquickgraphicsinfo.cpp new file mode 100644 index 0000000000..256fa43d2e --- /dev/null +++ b/tests/auto/quick/qquickgraphicsinfo/tst_qquickgraphicsinfo.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/qtest.h> +#include <QtTest/qsignalspy.h> + +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/qsgrendererinterface.h> + +#include "../../shared/util.h" + +#ifndef QT_NO_OPENGL +#include <QtGui/qopenglcontext.h> +#include <QtGui/qsurfaceformat.h> +#endif + +class tst_QQuickGraphicsInfo : public QQmlDataTest +{ + Q_OBJECT + +private slots: + void testProperties(); +}; + +void tst_QQuickGraphicsInfo::testProperties() +{ + QQuickView view; + view.setSource(QUrl::fromLocalFile("data/basic.qml")); + + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QSignalSpy spy(&view, SIGNAL(sceneGraphInitialized())); + spy.wait(); + + QObject* obj = view.rootObject(); + QVERIFY(obj); + + QSGRendererInterface *rif = view.rendererInterface(); + const int expectedAPI = rif ? rif->graphicsApi() : QSGRendererInterface::Unknown; + + QCOMPARE(obj->property("api").toInt(), expectedAPI); + +#ifndef QT_NO_OPENGL + if (expectedAPI == QSGRendererInterface::OpenGL) { + QCOMPARE(obj->property("shaderType").toInt(), int(QSGRendererInterface::GLSL)); + QVERIFY(view.openglContext()); + QSurfaceFormat format = view.openglContext()->format(); + QCOMPARE(obj->property("majorVersion").toInt(), format.majorVersion()); + QCOMPARE(obj->property("minorVersion").toInt(), format.minorVersion()); + QCOMPARE(obj->property("profile").toInt(), static_cast<int>(format.profile())); + QCOMPARE(obj->property("renderableType").toInt(), static_cast<int>(format.renderableType())); + } +#endif +} + +QTEST_MAIN(tst_QQuickGraphicsInfo) + +#include "tst_qquickgraphicsinfo.moc" diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp index 9274a1ac9e..d345163db5 100644 --- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp +++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp @@ -306,6 +306,7 @@ void tst_qquickimage::mirror() qreal width = 300; qreal height = 250; + qreal devicePixelRatio = 1.0; foreach (QQuickImage::FillMode fillMode, fillModes) { #if defined(Q_OS_BLACKBERRY) @@ -325,13 +326,15 @@ void tst_qquickimage::mirror() QImage screenshot = window->grabWindow(); screenshots[fillMode] = screenshot; + devicePixelRatio = window->devicePixelRatio(); } foreach (QQuickImage::FillMode fillMode, fillModes) { QPixmap srcPixmap; QVERIFY(srcPixmap.load(testFile("pattern.png"))); - QPixmap expected(width, height); + QPixmap expected(width * (int)devicePixelRatio, height * (int)devicePixelRatio); + expected.setDevicePixelRatio(devicePixelRatio); expected.fill(); QPainter p_e(&expected); QTransform transform; diff --git a/tests/auto/quick/qquickitem2/data/layoutmirroring_window.qml b/tests/auto/quick/qquickitem2/data/layoutmirroring_window.qml new file mode 100644 index 0000000000..3bac0716e8 --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/layoutmirroring_window.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 + +Window { + LayoutMirroring.enabled: true + LayoutMirroring.childrenInherit: true +} diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp index a087efd6b8..7130dc4cf2 100644 --- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp @@ -88,6 +88,7 @@ private slots: void keyNavigation_focusReason(); void keyNavigation_loop(); void layoutMirroring(); + void layoutMirroringWindow(); void layoutMirroringIllegalParent(); void smooth(); void antialiasing(); @@ -1776,11 +1777,28 @@ void tst_QQuickItem::layoutMirroring() delete parentItem2; } +void tst_QQuickItem::layoutMirroringWindow() +{ + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("layoutmirroring_window.qml")); + QScopedPointer<QObject> object(component.create()); + QQuickWindow *window = qobject_cast<QQuickWindow *>(object.data()); + QVERIFY(window); + window->show(); + + QQuickItemPrivate *content = QQuickItemPrivate::get(window->contentItem()); + QCOMPARE(content->effectiveLayoutMirror, true); + QCOMPARE(content->inheritedLayoutMirror, true); + QCOMPARE(content->isMirrorImplicit, false); + QCOMPARE(content->inheritMirrorFromParent, true); + QCOMPARE(content->inheritMirrorFromItem, true); +} + void tst_QQuickItem::layoutMirroringIllegalParent() { QQmlComponent component(&engine); component.setData("import QtQuick 2.0; QtObject { LayoutMirroring.enabled: true; LayoutMirroring.childrenInherit: true }", QUrl::fromLocalFile("")); - QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1:21: QML QtObject: LayoutDirection attached property only works with Items"); + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1:21: QML QtObject: LayoutDirection attached property only works with Items and Windows"); QObject *object = component.create(); QVERIFY(object != 0); } @@ -2698,113 +2716,122 @@ void tst_QQuickItem::childrenRectBottomRightCorner() struct TestListener : public QQuickItemChangeListener { - TestListener(bool remove = false) : remove(remove) { reset(); } - - void itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &) override { ++itemGeometryChanges; value = newGeometry; } - void itemSiblingOrderChanged(QQuickItem *) override { ++itemSiblingOrderChanges; } - void itemVisibilityChanged(QQuickItem *) override { ++itemVisibilityChanges; } - void itemOpacityChanged(QQuickItem *) override { ++itemOpacityChanges; } - void itemRotationChanged(QQuickItem *) override { ++itemRotationChanges; } - void itemImplicitWidthChanged(QQuickItem *) override { ++itemImplicitWidthChanges; } - void itemImplicitHeightChanged(QQuickItem *) override { ++itemImplicitHeightChanges; } + TestListener(bool remove = false) : remove(remove) { } + void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &diff) override + { + record(item, QQuickItemPrivate::Geometry, diff); + } + void itemSiblingOrderChanged(QQuickItem *item) override + { + record(item, QQuickItemPrivate::SiblingOrder); + } + void itemVisibilityChanged(QQuickItem *item) override + { + record(item, QQuickItemPrivate::Visibility); + } + void itemOpacityChanged(QQuickItem *item) override + { + record(item, QQuickItemPrivate::Opacity); + } + void itemRotationChanged(QQuickItem *item) override + { + record(item, QQuickItemPrivate::Rotation); + } + void itemImplicitWidthChanged(QQuickItem *item) override + { + record(item, QQuickItemPrivate::ImplicitWidth); + } + void itemImplicitHeightChanged(QQuickItem *item) override + { + record(item, QQuickItemPrivate::ImplicitHeight); + } void itemDestroyed(QQuickItem *item) override { - ++itemDestructions; - // QTBUG-53453 - if (remove) - QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed); + record(item, QQuickItemPrivate::Destroyed); } void itemChildAdded(QQuickItem *item, QQuickItem *child) override { - ++itemChildAdditions; - value = QVariant::fromValue(child); - // QTBUG-53453 - if (remove) - QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Children); + record(item, QQuickItemPrivate::Children, QVariant::fromValue(child)); } void itemChildRemoved(QQuickItem *item, QQuickItem *child) override { - ++itemChildRemovals; - value = QVariant::fromValue(child); - // QTBUG-53453 - if (remove) - QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Children); + record(item, QQuickItemPrivate::Children, QVariant::fromValue(child)); } void itemParentChanged(QQuickItem *item, QQuickItem *parent) override { - ++itemParentChanges; - value = QVariant::fromValue(parent); - // QTBUG-53453 - if (remove) - QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Parent); + record(item, QQuickItemPrivate::Parent, QVariant::fromValue(parent)); } QQuickAnchorsPrivate *anchorPrivate() override { return nullptr; } - void reset() + void record(QQuickItem *item, QQuickItemPrivate::ChangeType change, const QVariant &value = QVariant()) + { + changes += change; + values[change] = value; + // QTBUG-54732 + if (remove) + QQuickItemPrivate::get(item)->removeItemChangeListener(this, change); + } + + int count(QQuickItemPrivate::ChangeType change) const + { + return changes.count(change); + } + + QVariant value(QQuickItemPrivate::ChangeType change) const { - value = QVariant(); - itemGeometryChanges = 0; - itemSiblingOrderChanges = 0; - itemVisibilityChanges = 0; - itemOpacityChanges = 0; - itemDestructions = 0; - itemChildAdditions = 0; - itemChildRemovals = 0; - itemParentChanges = 0; - itemRotationChanges = 0; - itemImplicitWidthChanges = 0; - itemImplicitHeightChanges = 0; + return values.value(change); } bool remove; - QVariant value; - int itemGeometryChanges; - int itemSiblingOrderChanges; - int itemVisibilityChanges; - int itemOpacityChanges; - int itemDestructions; - int itemChildAdditions; - int itemChildRemovals; - int itemParentChanges; - int itemRotationChanges; - int itemImplicitWidthChanges; - int itemImplicitHeightChanges; + QList<QQuickItemPrivate::ChangeType> changes; + QHash<QQuickItemPrivate::ChangeType, QVariant> values; }; void tst_QQuickItem::changeListener() { - QQuickItem item; + QQuickWindow window; + window.show(); + QTest::qWaitForWindowExposed(&window); + + QQuickItem *item = new QQuickItem; TestListener itemListener; - QQuickItemPrivate::get(&item)->addItemChangeListener(&itemListener, QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight | - QQuickItemPrivate::Opacity | QQuickItemPrivate::Rotation); + QQuickItemPrivate::get(item)->addItemChangeListener(&itemListener, QQuickItemPrivate::ChangeTypes(0xffff)); - item.setImplicitWidth(50); - QCOMPARE(itemListener.itemImplicitWidthChanges, 1); - QCOMPARE(itemListener.itemGeometryChanges, 1); - QCOMPARE(itemListener.value, QVariant(QRectF(0,0,50,0))); + item->setImplicitWidth(10); + QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitWidth), 1); + QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 1); + QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,10,0))); - item.setImplicitHeight(50); - QCOMPARE(itemListener.itemImplicitHeightChanges, 1); - QCOMPARE(itemListener.itemGeometryChanges, 2); - QCOMPARE(itemListener.value, QVariant(QRectF(0,0,50,50))); + item->setImplicitHeight(20); + QCOMPARE(itemListener.count(QQuickItemPrivate::ImplicitHeight), 1); + QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 2); + QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,20))); - item.setWidth(100); - QCOMPARE(itemListener.itemGeometryChanges, 3); - QCOMPARE(itemListener.value, QVariant(QRectF(0,0,100,50))); + item->setWidth(item->width() + 30); + QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 3); + QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,30,0))); - item.setHeight(100); - QCOMPARE(itemListener.itemGeometryChanges, 4); - QCOMPARE(itemListener.value, QVariant(QRectF(0,0,100,100))); + item->setHeight(item->height() + 40); + QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 4); + QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,0,40))); - item.setOpacity(0.5); - QCOMPARE(itemListener.itemOpacityChanges, 1); + item->setOpacity(0.5); + QCOMPARE(itemListener.count(QQuickItemPrivate::Opacity), 1); - item.setRotation(90); - QCOMPARE(itemListener.itemRotationChanges, 1); + item->setRotation(90); + QCOMPARE(itemListener.count(QQuickItemPrivate::Rotation), 1); - QQuickItem *parent = new QQuickItem; + item->setParentItem(window.contentItem()); + QCOMPARE(itemListener.count(QQuickItemPrivate::Parent), 1); + + item->setVisible(false); + QCOMPARE(itemListener.count(QQuickItemPrivate::Visibility), 1); + + QQuickItemPrivate::get(item)->removeItemChangeListener(&itemListener, QQuickItemPrivate::ChangeTypes(0xffff)); + + QQuickItem *parent = new QQuickItem(window.contentItem()); TestListener parentListener; QQuickItemPrivate::get(parent)->addItemChangeListener(&parentListener, QQuickItemPrivate::Children); @@ -2816,52 +2843,79 @@ void tst_QQuickItem::changeListener() QQuickItemPrivate::get(child2)->addItemChangeListener(&child2Listener, QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed); child1->setParentItem(parent); - QCOMPARE(parentListener.itemChildAdditions, 1); - QCOMPARE(parentListener.value, QVariant::fromValue(child1)); - QCOMPARE(child1Listener.itemParentChanges, 1); - QCOMPARE(child1Listener.value, QVariant::fromValue(parent)); + QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 1); + QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1)); + QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 1); + QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent)); child2->setParentItem(parent); - QCOMPARE(parentListener.itemChildAdditions, 2); - QCOMPARE(parentListener.value, QVariant::fromValue(child2)); - QCOMPARE(child2Listener.itemParentChanges, 1); - QCOMPARE(child2Listener.value, QVariant::fromValue(parent)); + QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 2); + QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2)); + QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 1); + QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue(parent)); child2->stackBefore(child1); - QCOMPARE(child1Listener.itemSiblingOrderChanges, 1); - QCOMPARE(child2Listener.itemSiblingOrderChanges, 1); + QCOMPARE(child1Listener.count(QQuickItemPrivate::SiblingOrder), 1); + QCOMPARE(child2Listener.count(QQuickItemPrivate::SiblingOrder), 1); child1->setParentItem(nullptr); - QCOMPARE(parentListener.itemChildRemovals, 1); - QCOMPARE(parentListener.value, QVariant::fromValue(child1)); - QCOMPARE(child1Listener.itemParentChanges, 2); - QCOMPARE(child1Listener.value, QVariant::fromValue<QQuickItem *>(nullptr)); + QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 3); + QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child1)); + QCOMPARE(child1Listener.count(QQuickItemPrivate::Parent), 2); + QCOMPARE(child1Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr)); delete child1; - QCOMPARE(child1Listener.itemDestructions, 1); + QCOMPARE(child1Listener.count(QQuickItemPrivate::Destroyed), 1); delete child2; - QCOMPARE(parentListener.itemChildRemovals, 2); - QCOMPARE(parentListener.value, QVariant::fromValue(child2)); - QCOMPARE(child2Listener.itemParentChanges, 2); - QCOMPARE(child2Listener.value, QVariant::fromValue<QQuickItem *>(nullptr)); - QCOMPARE(child2Listener.itemDestructions, 1); + QCOMPARE(parentListener.count(QQuickItemPrivate::Children), 4); + QCOMPARE(parentListener.value(QQuickItemPrivate::Children), QVariant::fromValue(child2)); + QCOMPARE(child2Listener.count(QQuickItemPrivate::Parent), 2); + QCOMPARE(child2Listener.value(QQuickItemPrivate::Parent), QVariant::fromValue<QQuickItem *>(nullptr)); + QCOMPARE(child2Listener.count(QQuickItemPrivate::Destroyed), 1); QQuickItemPrivate::get(parent)->removeItemChangeListener(&parentListener, QQuickItemPrivate::Children); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); - // QTBUG-53453: all listeners should get invoked even if they remove themselves while iterating the listeners + // QTBUG-54732: all listeners should get invoked even if they remove themselves while iterating the listeners QList<TestListener *> listeners; for (int i = 0; i < 5; ++i) listeners << new TestListener(true); + // itemVisibilityChanged x 5 + foreach (TestListener *listener, listeners) + QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Visibility); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); + parent->setVisible(false); + foreach (TestListener *listener, listeners) + QCOMPARE(listener->count(QQuickItemPrivate::Visibility), 1); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); + + // itemRotationChanged x 5 + foreach (TestListener *listener, listeners) + QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Rotation); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); + parent->setRotation(90); + foreach (TestListener *listener, listeners) + QCOMPARE(listener->count(QQuickItemPrivate::Rotation), 1); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); + + // itemOpacityChanged x 5 + foreach (TestListener *listener, listeners) + QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Opacity); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); + parent->setOpacity(0.5); + foreach (TestListener *listener, listeners) + QCOMPARE(listener->count(QQuickItemPrivate::Opacity), 1); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); + // itemChildAdded() x 5 foreach (TestListener *listener, listeners) QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); child1 = new QQuickItem(parent); foreach (TestListener *listener, listeners) - QCOMPARE(listener->itemChildAdditions, 1); + QCOMPARE(listener->count(QQuickItemPrivate::Children), 1); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); // itemParentChanged() x 5 @@ -2870,9 +2924,36 @@ void tst_QQuickItem::changeListener() QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), listeners.count()); child1->setParentItem(nullptr); foreach (TestListener *listener, listeners) - QCOMPARE(listener->itemParentChanges, 1); + QCOMPARE(listener->count(QQuickItemPrivate::Parent), 1); QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), 0); + // itemImplicitWidthChanged() x 5 + foreach (TestListener *listener, listeners) + QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitWidth); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); + parent->setImplicitWidth(parent->implicitWidth() + 1); + foreach (TestListener *listener, listeners) + QCOMPARE(listener->count(QQuickItemPrivate::ImplicitWidth), 1); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); + + // itemImplicitHeightChanged() x 5 + foreach (TestListener *listener, listeners) + QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitHeight); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); + parent->setImplicitHeight(parent->implicitHeight() + 1); + foreach (TestListener *listener, listeners) + QCOMPARE(listener->count(QQuickItemPrivate::ImplicitHeight), 1); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); + + // itemGeometryChanged() x 5 + foreach (TestListener *listener, listeners) + QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Geometry); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); + parent->setWidth(parent->width() + 1); + foreach (TestListener *listener, listeners) + QCOMPARE(listener->count(QQuickItemPrivate::Geometry), 1); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); + // itemChildRemoved() x 5 child1->setParentItem(parent); foreach (TestListener *listener, listeners) @@ -2880,7 +2961,7 @@ void tst_QQuickItem::changeListener() QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); delete child1; foreach (TestListener *listener, listeners) - QCOMPARE(listener->itemChildRemovals, 1); + QCOMPARE(listener->count(QQuickItemPrivate::Children), 2); QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); // itemDestroyed() x 5 @@ -2889,7 +2970,7 @@ void tst_QQuickItem::changeListener() QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); delete parent; foreach (TestListener *listener, listeners) - QCOMPARE(listener->itemDestructions, 1); + QCOMPARE(listener->count(QQuickItemPrivate::Destroyed), 1); } // QTBUG-13893 @@ -3215,7 +3296,7 @@ void tst_QQuickItem::grab() QVERIFY(root); QQuickItem *item = root->findChild<QQuickItem *>("myItem"); QVERIFY(item); - +#ifndef QT_NO_OPENGL { // Default size (item is 100x100) QSharedPointer<QQuickItemGrabResult> result = item->grabToImage(); QSignalSpy spy(result.data(), SIGNAL(ready())); @@ -3236,7 +3317,7 @@ void tst_QQuickItem::grab() QCOMPARE(image.pixel(0, 0), qRgb(255, 0, 0)); QCOMPARE(image.pixel(49, 49), qRgb(0, 0, 255)); } - +#endif } void tst_QQuickItem::isAncestorOf() diff --git a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp index 92b7196919..2576a1b0fc 100644 --- a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp +++ b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp @@ -30,6 +30,7 @@ #include <QtQuick/qquickitem.h> #include <QtQuick/qquickview.h> +#include <QtQuick/qsgrendererinterface.h> #include <QtGui/qopenglcontext.h> #include <QtGui/qopenglfunctions.h> @@ -60,9 +61,10 @@ private slots: void initTestCase() Q_DECL_OVERRIDE; void layerEnabled(); void layerSmooth(); +#ifndef QT_NO_OPENGL void layerMipmap(); void layerEffect(); - +#endif void layerVisibility_data(); void layerVisibility(); @@ -90,17 +92,20 @@ private: bool m_isMesaSoftwareRasterizer; int m_mesaVersion; + bool m_isOpenGLRenderer; }; tst_QQuickItemLayer::tst_QQuickItemLayer() : m_isMesaSoftwareRasterizer(false) , m_mesaVersion(0) + , m_isOpenGLRenderer(true) { } void tst_QQuickItemLayer::initTestCase() { QQmlDataTest::initTestCase(); +#ifndef QT_NO_OPENGL QWindow window; QOpenGLContext context; window.setSurfaceType(QWindow::OpenGLSurface); @@ -129,6 +134,13 @@ void tst_QQuickItemLayer::initTestCase() m_mesaVersion = QT_VERSION_CHECK(major, minor, patch); } } + window.create(); +#endif + QQuickView view; + view.showNormal(); + QTest::qWaitForWindowExposed(&view); + if (view.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) + m_isOpenGLRenderer = false; } // The test draws a red and a blue box next to each other and tests that the @@ -165,8 +177,7 @@ void tst_QQuickItemLayer::layerEnabled() QVERIFY(fb.pixel(0, 0) != fb.pixel(0, fb.height() - 1)); } - - +#ifndef QT_NO_OPENGL // The test draws a one pixel wide line and scales it down by more than a a factor 2 // If mipmpping works, the pixels should be gray, not white or black @@ -192,8 +203,7 @@ void tst_QQuickItemLayer::layerEffect() QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0xff, 0)); } - - +#endif // The test draws a rectangle and verifies that there is padding on each side // as the source rect spans outside the item. The padding is verified using @@ -203,6 +213,9 @@ void tst_QQuickItemLayer::layerSourceRect() if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + if (!m_isOpenGLRenderer) + QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); + QImage fb = runTest("SourceRect.qml"); // Check that the edges are converted to blue @@ -223,6 +236,10 @@ void tst_QQuickItemLayer::layerIsTextureProvider() { if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + + if (!m_isOpenGLRenderer) + QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); + QImage fb = runTest("TextureProvider.qml"); QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0xff, 0)); @@ -256,6 +273,9 @@ void tst_QQuickItemLayer::layerVisibility() if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + if (!m_isOpenGLRenderer) + QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); + QFETCH(bool, visible); QFETCH(bool, effect); QFETCH(qreal, opacity); @@ -304,6 +324,9 @@ void tst_QQuickItemLayer::layerZOrder() if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + if (!m_isOpenGLRenderer) + QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); + QFETCH(bool, effect); QQuickView view; @@ -338,6 +361,9 @@ void tst_QQuickItemLayer::changeZOrder() if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + if (!m_isOpenGLRenderer) + QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); + QFETCH(bool, layered); QFETCH(bool, effect); @@ -405,6 +431,10 @@ void tst_QQuickItemLayer::changeSamplerName() { if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + + if (!m_isOpenGLRenderer) + QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); + QImage fb = runTest("SamplerNameChange.qml"); QCOMPARE(fb.pixel(0, 0), qRgb(0, 0, 0xff)); } @@ -413,6 +443,9 @@ void tst_QQuickItemLayer::itemEffect() { if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly."); + if (!m_isOpenGLRenderer) + QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); + QImage fb = runTest("ItemEffect.qml"); QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); QCOMPARE(fb.pixel(199, 0), qRgb(0xff, 0, 0)); @@ -448,6 +481,9 @@ void tst_QQuickItemLayer::textureMirroring() { QFETCH(int, mirroring); + if (!m_isOpenGLRenderer) + QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects"); + QQuickView view; view.setSource(testFileUrl("TextureMirroring.qml")); diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST index 269696ce8c..d259c11219 100644 --- a/tests/auto/quick/qquicklistview/BLACKLIST +++ b/tests/auto/quick/qquicklistview/BLACKLIST @@ -2,3 +2,6 @@ * [enforceRange_withoutHighlight] osx +#QTBUG-53863 +[populateTransitions] +opensuse-42.1 diff --git a/tests/auto/quick/qquickloader/data/qmldir b/tests/auto/quick/qquickloader/data/qmldir deleted file mode 100644 index bf42b507c0..0000000000 --- a/tests/auto/quick/qquickloader/data/qmldir +++ /dev/null @@ -1 +0,0 @@ -# For tst_QDeclarativeLoader::networkRequestUrl; no types needed though. diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp index fe22a238b2..77af4796b6 100644 --- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp +++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp @@ -213,7 +213,7 @@ void tst_QQuickLoader::sourceOrComponent_data() QTest::newRow("source with encoded subdir binding") << "source" << "source: encodeURIComponent('subdir/Test.qml')\n" << testFileUrl("subdir/Test.qml") << ""; QTest::newRow("sourceComponent") << "component" << "Component { id: comp; Rectangle { width: 100; height: 50 } }\n sourceComponent: comp\n" << QUrl() << ""; QTest::newRow("invalid source") << "source" << "source: 'IDontExist.qml'\n" << testFileUrl("IDontExist.qml") - << QString(testFileUrl("IDontExist.qml").toString() + ": File not found"); + << QString(testFileUrl("IDontExist.qml").toString() + ": No such file or directory"); } void tst_QQuickLoader::clear() @@ -748,7 +748,7 @@ void tst_QQuickLoader::initialPropertyValuesError_data() << (QStringList() << QString(testFileUrl("initialPropertyValues.error.1.qml").toString() + ":6:5: QML Loader: setSource: value is not an object")); QTest::newRow("nonexistent source url") << testFileUrl("initialPropertyValues.error.2.qml") - << (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": File not found")); + << (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": No such file or directory")); QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml") << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error")); @@ -901,7 +901,7 @@ void tst_QQuickLoader::asynchronous_data() << QStringList(); QTest::newRow("Non-existent component") << testFileUrl("IDoNotExist.qml") - << (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": File not found")); + << (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": No such file or directory")); QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml") << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Syntax error")); diff --git a/tests/auto/quick/qquickmousearea/data/qtbug54019.qml b/tests/auto/quick/qquickmousearea/data/qtbug54019.qml new file mode 100644 index 0000000000..75cca2691a --- /dev/null +++ b/tests/auto/quick/qquickmousearea/data/qtbug54019.qml @@ -0,0 +1,21 @@ +import QtQuick 2.7 + +Item { + width: 200 + height: 200 + MouseArea { + id: ma + property string str: "foo!" + width: 150; height: 150 + hoverEnabled: true + + Rectangle { + anchors.fill: parent + color: ma.containsMouse ? "lightsteelblue" : "gray" + } + Text { + text: ma.str + textFormat: Text.PlainText // consequently Text does not care about hover events + } + } +} diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index 5891e67df6..f22528a8a0 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -29,6 +29,7 @@ #include <QtTest/QtTest> #include <QtTest/QSignalSpy> #include <QtQuick/private/qquickdrag_p.h> +#include <QtQuick/private/qquickitem_p.h> #include <QtQuick/private/qquickmousearea_p.h> #include <QtQuick/private/qquickrectangle_p.h> #include <private/qquickflickable_p.h> @@ -107,6 +108,7 @@ private slots: void hoverPropagation(); void hoverVisible(); void hoverAfterPress(); + void subtreeHoverEnabled(); void disableAfterPress(); void onWheel(); void transformedMouseArea_data(); @@ -124,8 +126,12 @@ private slots: void containsPress_data(); void containsPress(); void ignoreBySource(); + void notPressedAfterStolenGrab(); private: + int startDragDistance() const { + return QGuiApplication::styleHints()->startDragDistance(); + } void acceptedButton_data(); void rejectedButton_data(); QTouchDevice *device; @@ -321,7 +327,8 @@ void tst_QQuickMouseArea::dragging() QVERIFY(!drag->active()); - QTest::mousePress(&window, button, 0, QPoint(100,100)); + QPoint p = QPoint(100,100); + QTest::mousePress(&window, button, 0, p); QVERIFY(!drag->active()); QCOMPARE(blackRect->x(), 50.0); @@ -332,18 +339,32 @@ void tst_QQuickMouseArea::dragging() // The item is moved relative to the position of the mouse when the drag // was triggered, this prevents a sudden change in position when the drag // threshold is exceeded. - QTest::mouseMove(&window, QPoint(111,111), 50); - QTest::mouseMove(&window, QPoint(116,116), 50); - QTest::mouseMove(&window, QPoint(122,122), 50); + int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); + + // move the minimum distance to activate drag + p += QPoint(dragThreshold + 1, dragThreshold + 1); + QTest::mouseMove(&window, p); + QVERIFY(!drag->active()); + + // from here on move the item + p += QPoint(1, 1); + QTest::mouseMove(&window, p); + QTRY_VERIFY(drag->active()); + // on macOS the cursor movement is going through a native event which + // means that it can actually take some time to show + QTRY_COMPARE(blackRect->x(), 50.0 + 1); + QCOMPARE(blackRect->y(), 50.0 + 1); + + p += QPoint(10, 10); + QTest::mouseMove(&window, p); QTRY_VERIFY(drag->active()); QTRY_COMPARE(blackRect->x(), 61.0); QCOMPARE(blackRect->y(), 61.0); - QTest::mouseRelease(&window, button, 0, QPoint(122,122)); - + QTest::mouseRelease(&window, button, 0, p); QTRY_VERIFY(!drag->active()); - QCOMPARE(blackRect->x(), 61.0); + QTRY_COMPARE(blackRect->x(), 61.0); QCOMPARE(blackRect->y(), 61.0); } @@ -532,15 +553,18 @@ void tst_QQuickMouseArea::cancelDragging() QVERIFY(!drag->active()); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QPoint p = QPoint(100,100); + QTest::mousePress(&window, Qt::LeftButton, 0, p); QVERIFY(!drag->active()); QCOMPARE(blackRect->x(), 50.0); QCOMPARE(blackRect->y(), 50.0); - QTest::mouseMove(&window, QPoint(111,111), 50); - QTest::mouseMove(&window, QPoint(116,116), 50); - QTest::mouseMove(&window, QPoint(122,122), 50); + p += QPoint(startDragDistance() + 1, 0); + QTest::mouseMove(&window, p); + + p += QPoint(11, 11); + QTest::mouseMove(&window, p); QTRY_VERIFY(drag->active()); QTRY_COMPARE(blackRect->x(), 61.0); @@ -575,7 +599,8 @@ void tst_QQuickMouseArea::setDragOnPressed() QQuickItem *target = mouseArea->findChild<QQuickItem*>("target"); QVERIFY(target); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + QPoint p = QPoint(100, 100); + QTest::mousePress(&window, Qt::LeftButton, 0, p); QQuickDrag *drag = mouseArea->drag(); QVERIFY(drag); @@ -587,19 +612,17 @@ void tst_QQuickMouseArea::setDragOnPressed() // First move event triggers drag, second is acted upon. // This is due to possibility of higher stacked area taking precedence. - QTest::mouseMove(&window, QPoint(111,102)); - QTest::qWait(50); - QTest::mouseMove(&window, QPoint(122,122)); - QTest::qWait(50); + p += QPoint(startDragDistance() + 1, 0); + QTest::mouseMove(&window, p); - QVERIFY(drag->active()); - QCOMPARE(target->x(), 61.0); + p += QPoint(11, 0); + QTest::mouseMove(&window, p); + QTRY_VERIFY(drag->active()); + QTRY_COMPARE(target->x(), 61.0); QCOMPARE(target->y(), 50.0); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(122,122)); - QTest::qWait(50); - - QVERIFY(!drag->active()); + QTest::mouseRelease(&window, Qt::LeftButton, 0, p); + QTRY_VERIFY(!drag->active()); QCOMPARE(target->x(), 61.0); QCOMPARE(target->y(), 50.0); } @@ -748,7 +771,7 @@ void tst_QQuickMouseArea::onMousePressRejected() QVERIFY(!window.rootObject()->property("mr1_canceled").toBool()); QVERIFY(window.rootObject()->property("mr2_pressed").toBool()); QVERIFY(!window.rootObject()->property("mr2_released").toBool()); - QVERIFY(window.rootObject()->property("mr2_canceled").toBool()); + QVERIFY(!window.rootObject()->property("mr2_canceled").toBool()); QTest::qWait(200); @@ -792,14 +815,14 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate() QGuiApplication::sendEvent(&window, &pressEvent); - QVERIFY(window.rootObject()->property("pressed").toBool()); + QTRY_VERIFY(window.rootObject()->property("pressed").toBool()); QVERIFY(!window.rootObject()->property("canceled").toBool()); QCOMPARE(window.rootObject()->property("released").toInt(), expectedRelease); QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks); if (doubleClick) { QGuiApplication::sendEvent(&window, &releaseEvent); - QVERIFY(!window.rootObject()->property("pressed").toBool()); + QTRY_VERIFY(!window.rootObject()->property("pressed").toBool()); QVERIFY(!window.rootObject()->property("canceled").toBool()); QCOMPARE(window.rootObject()->property("released").toInt(), ++expectedRelease); QCOMPARE(window.rootObject()->property("clicked").toInt(), ++expectedClicks); @@ -808,7 +831,7 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate() QMouseEvent pressEvent2(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, 0); QGuiApplication::sendEvent(&window, &pressEvent2); - QVERIFY(window.rootObject()->property("pressed").toBool()); + QTRY_VERIFY(window.rootObject()->property("pressed").toBool()); QVERIFY(!window.rootObject()->property("canceled").toBool()); QCOMPARE(window.rootObject()->property("released").toInt(), expectedRelease); QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks); @@ -820,23 +843,21 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate() secondWindow->setProperty("visible", true); QTest::qWaitForWindowExposed(secondWindow); - QVERIFY(!window.rootObject()->property("pressed").toBool()); + QTRY_VERIFY(!window.rootObject()->property("pressed").toBool()); QVERIFY(window.rootObject()->property("canceled").toBool()); QCOMPARE(window.rootObject()->property("released").toInt(), expectedRelease); QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks); //press again QGuiApplication::sendEvent(&window, &pressEvent); - QVERIFY(window.rootObject()->property("pressed").toBool()); + QTRY_VERIFY(window.rootObject()->property("pressed").toBool()); QVERIFY(!window.rootObject()->property("canceled").toBool()); QCOMPARE(window.rootObject()->property("released").toInt(), expectedRelease); QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks); - QTest::qWait(200); - //release QGuiApplication::sendEvent(&window, &releaseEvent); - QVERIFY(!window.rootObject()->property("pressed").toBool()); + QTRY_VERIFY(!window.rootObject()->property("pressed").toBool()); QVERIFY(!window.rootObject()->property("canceled").toBool()); QCOMPARE(window.rootObject()->property("released").toInt(), ++expectedRelease); QCOMPARE(window.rootObject()->property("clicked").toInt(), ++expectedClicks); @@ -994,48 +1015,60 @@ void tst_QQuickMouseArea::preventStealing() QSignalSpy mousePositionSpy(mouseArea, SIGNAL(positionChanged(QQuickMouseEvent*))); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(80, 80)); + QPoint p = QPoint(80, 80); + QTest::mousePress(&window, Qt::LeftButton, 0, p); // Without preventStealing, mouse movement over MouseArea would // cause the Flickable to steal mouse and trigger content movement. - QTest::mouseMove(&window,QPoint(69,69)); - QTest::mouseMove(&window,QPoint(58,58)); - QTest::mouseMove(&window,QPoint(47,47)); + p += QPoint(-startDragDistance() * 2, -startDragDistance() * 2); + QTest::mouseMove(&window, p); + p += QPoint(-10, -10); + QTest::mouseMove(&window, p); + p += QPoint(-10, -10); + QTest::mouseMove(&window, p); + p += QPoint(-10, -10); + QTest::mouseMove(&window, p); - // We should have received all three move events - QCOMPARE(mousePositionSpy.count(), 3); + // We should have received all four move events + QTRY_COMPARE(mousePositionSpy.count(), 4); + mousePositionSpy.clear(); QVERIFY(mouseArea->pressed()); // Flickable content should not have moved. QCOMPARE(flickable->contentX(), 0.); QCOMPARE(flickable->contentY(), 0.); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(47, 47)); + QTest::mouseRelease(&window, Qt::LeftButton, 0, p); // Now allow stealing and confirm Flickable does its thing. window.rootObject()->setProperty("stealing", false); - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(80, 80)); + p = QPoint(80, 80); + QTest::mousePress(&window, Qt::LeftButton, 0, p); // Without preventStealing, mouse movement over MouseArea would // cause the Flickable to steal mouse and trigger content movement. - QTest::mouseMove(&window,QPoint(69,69)); - QTest::mouseMove(&window,QPoint(58,58)); - QTest::mouseMove(&window,QPoint(47,47)); + p += QPoint(-startDragDistance() * 2, -startDragDistance() * 2); + QTest::mouseMove(&window, p); + p += QPoint(-10, -10); + QTest::mouseMove(&window, p); + p += QPoint(-10, -10); + QTest::mouseMove(&window, p); + p += QPoint(-10, -10); + QTest::mouseMove(&window, p); // We should only have received the first move event - QCOMPARE(mousePositionSpy.count(), 4); + QTRY_COMPARE(mousePositionSpy.count(), 1); // Our press should be taken away QVERIFY(!mouseArea->pressed()); - // Flickable content should have moved. - - QCOMPARE(flickable->contentX(), 11.); - QCOMPARE(flickable->contentY(), 11.); + // Flickable swallows the first move, then moves 2*10 px + QTRY_COMPARE(flickable->contentX(), 20.); + QCOMPARE(flickable->contentY(), 20.); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mouseRelease(&window, Qt::LeftButton, 0, p); } void tst_QQuickMouseArea::clickThrough() @@ -1280,6 +1313,26 @@ void tst_QQuickMouseArea::hoverAfterPress() QCOMPARE(mouseArea->hovered(), false); } +void tst_QQuickMouseArea::subtreeHoverEnabled() +{ + QQuickView window; + QByteArray errorMessage; + QVERIFY2(initView(window, testFileUrl("qtbug54019.qml"), true, &errorMessage), errorMessage.constData()); + QQuickItem *root = window.rootObject(); + QVERIFY(root != 0); + + QQuickMouseArea *mouseArea = root->findChild<QQuickMouseArea*>(); + QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(root); + QVERIFY(mouseArea != 0); + QTest::mouseMove(&window, QPoint(10, 160)); + QCOMPARE(mouseArea->hovered(), false); + QVERIFY(rootPrivate->subtreeHoverEnabled); + QTest::mouseMove(&window, QPoint(10, 10)); + QCOMPARE(mouseArea->hovered(), true); + QTest::mouseMove(&window, QPoint(160, 10)); + QCOMPARE(mouseArea->hovered(), false); +} + void tst_QQuickMouseArea::disableAfterPress() { QQuickView window; @@ -1304,9 +1357,8 @@ void tst_QQuickMouseArea::disableAfterPress() QCOMPARE(blackRect, drag->target()); QVERIFY(!drag->active()); - - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); - + QPoint p = QPoint(100,100); + QTest::mousePress(&window, Qt::LeftButton, 0, p); QTRY_COMPARE(mousePressSpy.count(), 1); QVERIFY(!drag->active()); @@ -1316,22 +1368,24 @@ void tst_QQuickMouseArea::disableAfterPress() // First move event triggers drag, second is acted upon. // This is due to possibility of higher stacked area taking precedence. - QTest::mouseMove(&window, QPoint(111,111)); - QTest::qWait(50); - QTest::mouseMove(&window, QPoint(122,122)); + p += QPoint(startDragDistance() + 1, 0); + QTest::mouseMove(&window, p); + p += QPoint(11, 11); + QTest::mouseMove(&window, p); QTRY_COMPARE(mousePositionSpy.count(), 2); - QVERIFY(drag->active()); - QCOMPARE(blackRect->x(), 61.0); + QTRY_VERIFY(drag->active()); + QTRY_COMPARE(blackRect->x(), 61.0); QCOMPARE(blackRect->y(), 61.0); mouseArea->setEnabled(false); // move should still be acted upon - QTest::mouseMove(&window, QPoint(133,133)); - QTest::qWait(50); - QTest::mouseMove(&window, QPoint(144,144)); + p += QPoint(11, 11); + QTest::mouseMove(&window, p); + p += QPoint(11, 11); + QTest::mouseMove(&window, p); QTRY_COMPARE(mousePositionSpy.count(), 4); @@ -1342,7 +1396,7 @@ void tst_QQuickMouseArea::disableAfterPress() QVERIFY(mouseArea->pressed()); QVERIFY(mouseArea->hovered()); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(144,144)); + QTest::mouseRelease(&window, Qt::LeftButton, 0, p); QTRY_COMPARE(mouseReleaseSpy.count(), 1); @@ -1599,36 +1653,39 @@ void tst_QQuickMouseArea::changeAxis() QVERIFY(!drag->active()); // Start a diagonal drag - QTest::mousePress(&view, Qt::LeftButton, 0, QPoint(100, 100)); + QPoint p = QPoint(100, 100); + QTest::mousePress(&view, Qt::LeftButton, 0, p); QVERIFY(!drag->active()); QCOMPARE(blackRect->x(), 50.0); QCOMPARE(blackRect->y(), 50.0); - QTest::mouseMove(&view, QPoint(111, 111)); - QTest::qWait(50); - QTest::mouseMove(&view, QPoint(122, 122)); - + p += QPoint(startDragDistance() + 1, startDragDistance() + 1); + QTest::mouseMove(&view, p); + p += QPoint(11, 11); + QTest::mouseMove(&view, p); QTRY_VERIFY(drag->active()); - QCOMPARE(blackRect->x(), 61.0); + QTRY_COMPARE(blackRect->x(), 61.0); QCOMPARE(blackRect->y(), 61.0); QCOMPARE(drag->axis(), QQuickDrag::XAndYAxis); /* When blackRect.x becomes bigger than 75, the drag axis is changed to * Drag.YAxis by the QML code. Verify that this happens, and that the drag * movement is effectively constrained to the Y axis. */ - QTest::mouseMove(&view, QPoint(144, 144)); + p += QPoint(22, 22); + QTest::mouseMove(&view, p); QTRY_COMPARE(blackRect->x(), 83.0); QTRY_COMPARE(blackRect->y(), 83.0); QTRY_COMPARE(drag->axis(), QQuickDrag::YAxis); - QTest::mouseMove(&view, QPoint(155, 155)); + p += QPoint(11, 11); + QTest::mouseMove(&view, p); QTRY_COMPARE(blackRect->y(), 94.0); QCOMPARE(blackRect->x(), 83.0); - QTest::mouseRelease(&view, Qt::LeftButton, 0, QPoint(155, 155)); + QTest::mouseRelease(&view, Qt::LeftButton, 0, p); QTRY_VERIFY(!drag->active()); QCOMPARE(blackRect->x(), 83.0); @@ -1678,11 +1735,17 @@ void tst_QQuickMouseArea::moveAndReleaseWithoutPress() QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(100,100)); + // the press was not accepted, make sure there is no move or release event QTest::mouseMove(&window, QPoint(110,110), 50); - QTRY_COMPARE(root->property("hadMove").toBool(), false); + + // use qwait here because we want to make sure an event does NOT happen + // the test fails if the default state changes, while it shouldn't + QTest::qWait(100); + QCOMPARE(root->property("hadMove").toBool(), false); QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(110,110)); - QTRY_COMPARE(root->property("hadRelease").toBool(), false); + QTest::qWait(100); + QCOMPARE(root->property("hadRelease").toBool(), false); } void tst_QQuickMouseArea::nestedStopAtBounds_data() @@ -1926,33 +1989,43 @@ void tst_QQuickMouseArea::ignoreBySource() QVERIFY(flickable); // MouseArea should grab the press because it's interested in non-synthesized mouse events - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(80, 80)); - QVERIFY(window.mouseGrabberItem() == mouseArea); + QPoint p = QPoint(80, 80); + QTest::mousePress(&window, Qt::LeftButton, 0, p); + QCOMPARE(window.mouseGrabberItem(), mouseArea); // That was a real mouse event - QVERIFY(root->property("lastEventSource").toInt() == Qt::MouseEventNotSynthesized); + QCOMPARE(root->property("lastEventSource").toInt(), int(Qt::MouseEventNotSynthesized)); // Flickable content should not move - QTest::mouseMove(&window,QPoint(69,69)); - QTest::mouseMove(&window,QPoint(58,58)); - QTest::mouseMove(&window,QPoint(47,47)); + p -= QPoint(startDragDistance() + 1, startDragDistance() + 1); + QTest::mouseMove(&window, p); + p -= QPoint(11, 11); + QTest::mouseMove(&window, p); + p -= QPoint(11, 11); + QTest::mouseMove(&window, p); QCOMPARE(flickable->contentX(), 0.); QCOMPARE(flickable->contentY(), 0.); - QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(47, 47)); + QTest::mouseRelease(&window, Qt::LeftButton, 0, p); + QCOMPARE(window.mouseGrabberItem(), nullptr); // Now try touch events and confirm that MouseArea ignores them, while Flickable does its thing - - QTest::touchEvent(&window, device).press(0, QPoint(80, 80), &window); + p = QPoint(80, 80); + QTest::touchEvent(&window, device).press(0, p, &window); QQuickTouchUtils::flush(&window); - QVERIFY(window.mouseGrabberItem() != mouseArea); + QCOMPARE(window.mouseGrabberItem(), flickable); + // That was a fake mouse event QCOMPARE(root->property("lastEventSource").toInt(), int(Qt::MouseEventSynthesizedByQt)); - QTest::touchEvent(&window, device).move(0, QPoint(69,69), &window); - QTest::touchEvent(&window, device).move(0, QPoint(69,69), &window); - QTest::touchEvent(&window, device).move(0, QPoint(47,47), &window); + p -= QPoint(startDragDistance() + 1, startDragDistance() + 1); + QTest::touchEvent(&window, device).move(0, p, &window); + p -= QPoint(11, 11); + QTest::touchEvent(&window, device).move(0, p, &window); + p -= QPoint(11, 11); + QTest::touchEvent(&window, device).move(0, p, &window); + QQuickTouchUtils::flush(&window); QCOMPARE(window.mouseGrabberItem(), flickable); - QTest::touchEvent(&window, device).release(0, QPoint(47,47), &window); + QTest::touchEvent(&window, device).release(0, p, &window); QQuickTouchUtils::flush(&window); // Flickable content should have moved @@ -1967,15 +2040,19 @@ void tst_QQuickMouseArea::ignoreBySource() // MouseArea should ignore the press because it's interested in synthesized mouse events - QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(80, 80)); + p = QPoint(80, 80); + QTest::mousePress(&window, Qt::LeftButton, 0, p); QVERIFY(window.mouseGrabberItem() != mouseArea); // That was a real mouse event QVERIFY(root->property("lastEventSource").toInt() == Qt::MouseEventNotSynthesized); // Flickable content should move - QTest::mouseMove(&window,QPoint(69,69)); - QTest::mouseMove(&window,QPoint(58,58)); - QTest::mouseMove(&window,QPoint(47,47)); + p -= QPoint(startDragDistance() + 1, startDragDistance() + 1); + QTest::mouseMove(&window, p); + p -= QPoint(11, 11); + QTest::mouseMove(&window, p); + p -= QPoint(11, 11); + QTest::mouseMove(&window, p); QTRY_VERIFY(flickable->contentX() > 1); QVERIFY(flickable->contentY() > 1); @@ -1984,13 +2061,16 @@ void tst_QQuickMouseArea::ignoreBySource() flickable->setContentY(0); // Now try touch events and confirm that MouseArea gets them, while Flickable doesn't - - QTest::touchEvent(&window, device).press(0, QPoint(80, 80), &window); + p = QPoint(80, 80); + QTest::touchEvent(&window, device).press(0, p, &window); QQuickTouchUtils::flush(&window); QCOMPARE(window.mouseGrabberItem(), mouseArea); - QTest::touchEvent(&window, device).move(0, QPoint(69,69), &window); - QTest::touchEvent(&window, device).move(0, QPoint(69,69), &window); - QTest::touchEvent(&window, device).move(0, QPoint(47,47), &window); + p -= QPoint(startDragDistance() + 1, startDragDistance() + 1); + QTest::touchEvent(&window, device).move(0, p, &window); + p -= QPoint(11, 11); + QTest::touchEvent(&window, device).move(0, p, &window); + p -= QPoint(11, 11); + QTest::touchEvent(&window, device).move(0, p, &window); QQuickTouchUtils::flush(&window); QCOMPARE(window.mouseGrabberItem(), mouseArea); QTest::touchEvent(&window, device).release(0, QPoint(47,47), &window); @@ -2001,6 +2081,23 @@ void tst_QQuickMouseArea::ignoreBySource() QCOMPARE(flickable->contentY(), 0.); } +void tst_QQuickMouseArea::notPressedAfterStolenGrab() +{ + QQuickWindow window; + window.resize(200, 200); + window.show(); + QTest::qWaitForWindowExposed(&window); + + QQuickMouseArea *ma = new QQuickMouseArea(window.contentItem()); + ma->setSize(window.size()); + QObject::connect(ma, + static_cast<void (QQuickMouseArea::*)(QQuickMouseEvent*)>(&QQuickMouseArea::pressed), + [&]() { window.contentItem()->grabMouse(); }); + + QTest::mouseClick(&window, Qt::LeftButton); + QVERIFY(!ma->pressed()); +} + QTEST_MAIN(tst_QQuickMouseArea) #include "tst_qquickmousearea.moc" diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index c3981c466f..2872556a94 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -915,13 +915,13 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint() // Touch both, release one, manipulate other touchpoint with mouse QTest::touchEvent(window.data(), device).press(1, touch1); QQuickTouchUtils::flush(window.data()); - QTest::touchEvent(window.data(), device).press(2, touch2); + QTest::touchEvent(window.data(), device).move(1, touch1).press(2, touch2); QQuickTouchUtils::flush(window.data()); QCOMPARE(touch1rect->property("x").toInt(), touch1.x()); QCOMPARE(touch1rect->property("y").toInt(), touch1.y()); QCOMPARE(touch2rect->property("x").toInt(), touch2.x()); QCOMPARE(touch2rect->property("y").toInt(), touch2.y()); - QTest::touchEvent(window.data(), device).release(1, touch1); + QTest::touchEvent(window.data(), device).release(1, touch1).move(2, touch2); touch1.setY(20); QTest::mousePress(window.data(), Qt::LeftButton, 0, touch1); QQuickTouchUtils::flush(window.data()); diff --git a/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp b/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp index 1a04526f61..44d7b40ed9 100644 --- a/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp +++ b/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp @@ -32,8 +32,11 @@ #include <QtQuick/qquickview.h> #include <private/qquickitem_p.h> +#ifndef QT_NO_OPENGL #include <private/qsgdefaultpainternode_p.h> - +#else +#include <private/qsgsoftwarepainternode_p.h> +#endif class tst_QQuickPaintedItem: public QObject { Q_OBJECT @@ -70,7 +73,7 @@ public: ++paintRequests; clipRect = painter->clipBoundingRect(); } - +#ifndef QT_NO_OPENGL QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) { paintNode = static_cast<QSGDefaultPainterNode *>(QQuickPaintedItem::updatePaintNode(oldNode, data)); @@ -78,6 +81,15 @@ public: } QSGDefaultPainterNode *paintNode; +#else + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) + { + paintNode = static_cast<QSGSoftwarePainterNode *>(QQuickPaintedItem::updatePaintNode(oldNode, data)); + return paintNode; + } + + QSGSoftwarePainterNode *paintNode; +#endif int paintRequests; QRectF clipRect; }; diff --git a/tests/auto/quick/qquickpincharea/data/pinchproperties.qml b/tests/auto/quick/qquickpincharea/data/pinchproperties.qml index 37d706fc8e..c5daf6cbfe 100644 --- a/tests/auto/quick/qquickpincharea/data/pinchproperties.qml +++ b/tests/auto/quick/qquickpincharea/data/pinchproperties.qml @@ -2,7 +2,7 @@ import QtQuick 2.0 Rectangle { id: whiteRect property variant center - property real scale + property real scale: -1.0 property int pointCount: 0 property bool pinchActive: false width: 240; height: 320 diff --git a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp index aee35b4b90..c1a51fd659 100644 --- a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp +++ b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp @@ -286,6 +286,7 @@ void tst_QQuickPinchArea::pan() QPoint p1(80, 80); QPoint p2(100, 100); { + const int dragThreshold = QGuiApplication::styleHints()->startDragDistance(); QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device); pinchSequence.press(0, p1, window).commit(); QQuickTouchUtils::flush(window); @@ -293,23 +294,63 @@ void tst_QQuickPinchArea::pan() // we have to reuse the same pinchSequence object. pinchSequence.stationary(0).press(1, p2, window).commit(); QQuickTouchUtils::flush(window); - p1 += QPoint(10,10); - p2 += QPoint(10,10); - pinchSequence.move(0, p1,window).move(1, p2,window).commit(); + QVERIFY(!root->property("pinchActive").toBool()); + QCOMPARE(root->property("scale").toReal(), -1.0); + + p1 += QPoint(dragThreshold - 1, 0); + p2 += QPoint(dragThreshold - 1, 0); + pinchSequence.move(0, p1, window).move(1, p2, window).commit(); QQuickTouchUtils::flush(window); + // movement < dragThreshold: pinch not yet active + QVERIFY(!root->property("pinchActive").toBool()); + QCOMPARE(root->property("scale").toReal(), -1.0); - QCOMPARE(root->property("scale").toReal(), 1.0); + // exactly the dragThreshold: pinch starts + p1 += QPoint(1, 0); + p2 += QPoint(1, 0); + pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); QVERIFY(root->property("pinchActive").toBool()); + QCOMPARE(root->property("scale").toReal(), 1.0); - p1 += QPoint(10,10); - p2 += QPoint(10,10); - pinchSequence.move(0, p1,window).move(1, p2,window).commit(); + // Calculation of the center point is tricky at first: + // center point of the two touch points in item coordinates: + // scene coordinates: (80, 80) + (dragThreshold, 0), (100, 100) + (dragThreshold, 0) + // = ((180+dT)/2, 180/2) = (90+dT, 90) + // item coordinates: (scene) - (50, 50) = (40+dT, 40) + QCOMPARE(root->property("center").toPointF(), QPointF(40 + dragThreshold, 40)); + // pan started, but no actual movement registered yet: + // blackrect starts at 50,50 + QCOMPARE(blackRect->x(), 50.0); + QCOMPARE(blackRect->y(), 50.0); + + p1 += QPoint(10, 0); + p2 += QPoint(10, 0); + pinchSequence.move(0, p1, window).move(1, p2, window).commit(); QQuickTouchUtils::flush(window); - } + QCOMPARE(root->property("center").toPointF(), QPointF(40 + 10 + dragThreshold, 40)); + QCOMPARE(blackRect->x(), 60.0); + QCOMPARE(blackRect->y(), 50.0); - QCOMPARE(root->property("center").toPointF(), QPointF(60, 60)); // blackrect is at 50,50 - QCOMPARE(blackRect->x(), 60.0); - QCOMPARE(blackRect->y(), 60.0); + p1 += QPoint(0, 10); + p2 += QPoint(0, 10); + pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); + // next big surprise: the center is in item local coordinates and the item was just + // moved 10 to the right... which offsets the center point 10 to the left + QCOMPARE(root->property("center").toPointF(), QPointF(40 + 10 - 10 + dragThreshold, 40 + 10)); + QCOMPARE(blackRect->x(), 60.0); + QCOMPARE(blackRect->y(), 60.0); + + p1 += QPoint(10, 10); + p2 += QPoint(10, 10); + pinchSequence.move(0, p1, window).move(1, p2, window).commit(); + QQuickTouchUtils::flush(window); + // now the item moved again, thus the center point of the touch is moved in total by (10, 10) + QCOMPARE(root->property("center").toPointF(), QPointF(50 + dragThreshold, 50)); + QCOMPARE(blackRect->x(), 70.0); + QCOMPARE(blackRect->y(), 70.0); + } // pan x beyond bound p1 += QPoint(100,100); @@ -318,7 +359,7 @@ void tst_QQuickPinchArea::pan() QQuickTouchUtils::flush(window); QCOMPARE(blackRect->x(), 140.0); - QCOMPARE(blackRect->y(), 160.0); + QCOMPARE(blackRect->y(), 170.0); QTest::touchEvent(window, device).release(0, p1, window).release(1, p2, window); QQuickTouchUtils::flush(window); @@ -470,6 +511,7 @@ void tst_QQuickPinchArea::cancel() QCOMPARE(blackRect->scale(), 1.5); QTouchEvent cancelEvent(QEvent::TouchCancel); + cancelEvent.setDevice(device); QCoreApplication::sendEvent(window, &cancelEvent); QQuickTouchUtils::flush(window); diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp index 483cdf7a41..fe33dbd4d8 100644 --- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp +++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp @@ -30,16 +30,16 @@ #include <QList> #include <QByteArray> -#include <private/qquickshadereffect_p.h> - +#include <private/qquickopenglshadereffect_p.h> +#include <QMatrix4x4> #include <QtQuick/QQuickView> +#include <QtQml/QQmlEngine> #include "../../shared/util.h" - class TestShaderEffect : public QQuickShaderEffect { Q_OBJECT - Q_PROPERTY(QVariant source READ dummyRead NOTIFY dummyChanged) + Q_PROPERTY(QVariant source READ dummyRead NOTIFY sourceChanged) Q_PROPERTY(QVariant _0aA9zZ READ dummyRead NOTIFY dummyChanged) Q_PROPERTY(QVariant x86 READ dummyRead NOTIFY dummyChanged) Q_PROPERTY(QVariant X READ dummyRead NOTIFY dummyChanged) @@ -48,17 +48,18 @@ class TestShaderEffect : public QQuickShaderEffect public: QMatrix4x4 mat4x4Read() const { return QMatrix4x4(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1); } QVariant dummyRead() const { return QVariant(); } - bool isConnected(const QMetaMethod &signal) const { return m_signals.contains(signal); } + + int signalsConnected = 0; protected: - void connectNotify(const QMetaMethod &signal) { m_signals.append(signal); } - void disconnectNotify(const QMetaMethod &signal) { m_signals.removeOne(signal); } + void connectNotify(const QMetaMethod &) { ++signalsConnected; } + void disconnectNotify(const QMetaMethod &) { --signalsConnected; } signals: void dummyChanged(); + void sourceChanged(); private: - QList<QMetaMethod> m_signals; }; class tst_qquickshadereffect : public QQmlDataTest @@ -84,12 +85,13 @@ private: TexCoordPresent = 0x02, MatrixPresent = 0x04, OpacityPresent = 0x08, - PropertyPresent = 0x10 + SourcePresent = 0x10 }; }; tst_qquickshadereffect::tst_qquickshadereffect() { + qmlRegisterType<TestShaderEffect>("ShaderEffectTest", 1, 0, "TestShaderEffect"); } void tst_qquickshadereffect::initTestCase() @@ -122,7 +124,7 @@ void tst_qquickshadereffect::lookThroughShaderCode_data() "void main() { \n" " gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity; \n" "}") - << (VertexPresent | TexCoordPresent | MatrixPresent | OpacityPresent | PropertyPresent); + << (VertexPresent | TexCoordPresent | MatrixPresent | OpacityPresent | SourcePresent); QTest::newRow("empty") << QByteArray(" ") // one space -- if completely empty, default will be used instead. @@ -135,14 +137,14 @@ void tst_qquickshadereffect::lookThroughShaderCode_data() "attribute highp vec4 qt_Vertex;\n" "// attribute highp vec2 qt_MultiTexCoord0;") << QByteArray("uniform int source; // uniform lowp float qt_Opacity;") - << (VertexPresent | PropertyPresent); + << (VertexPresent | SourcePresent); QTest::newRow("inside block comments") << QByteArray("/*uniform highp mat4 qt_Matrix;\n" "*/attribute highp vec4 qt_Vertex;\n" "/*/attribute highp vec2 qt_MultiTexCoord0;//**/") << QByteArray("/**/uniform int source; /* uniform lowp float qt_Opacity; */") - << (VertexPresent | PropertyPresent); + << (VertexPresent | SourcePresent); QTest::newRow("inside preprocessor directive") << QByteArray("#define uniform\nhighp mat4 qt_Matrix;\n" @@ -150,7 +152,7 @@ void tst_qquickshadereffect::lookThroughShaderCode_data() "#if\\\nattribute highp vec2 qt_MultiTexCoord0;") << QByteArray("uniform int source;\n" " # undef uniform lowp float qt_Opacity;") - << (VertexPresent | PropertyPresent); + << (VertexPresent | SourcePresent); QTest::newRow("line comments between") @@ -158,21 +160,21 @@ void tst_qquickshadereffect::lookThroughShaderCode_data() "attribute//\nhighp//\nvec4//\nqt_Vertex;\n" " //*/ uniform \n attribute //\\ \n highp //// \n vec2 //* \n qt_MultiTexCoord0;") << QByteArray("uniform// lowp float qt_Opacity;\nsampler2D source;") - << (VertexPresent | TexCoordPresent | MatrixPresent | PropertyPresent); + << (VertexPresent | TexCoordPresent | MatrixPresent | SourcePresent); QTest::newRow("block comments between") << QByteArray("uniform/*foo*/highp/*/bar/*/mat4/**//**/qt_Matrix;\n" "attribute/**/highp/**/vec4/**/qt_Vertex;\n" " /* * */ attribute /*///*/ highp /****/ vec2 /**/ qt_MultiTexCoord0;") << QByteArray("uniform/*/ uniform//lowp/*float qt_Opacity;*/sampler2D source;") - << (VertexPresent | TexCoordPresent | MatrixPresent | PropertyPresent); + << (VertexPresent | TexCoordPresent | MatrixPresent | SourcePresent); QTest::newRow("preprocessor directive between") << QByteArray("uniform\n#foo\nhighp\n#bar\nmat4\n#baz\\\nblimey\nqt_Matrix;\n" "attribute\n#\nhighp\n#\nvec4\n#\nqt_Vertex;\n" " #uniform \n attribute \n # foo \n highp \n # bar \n vec2 \n#baz \n qt_MultiTexCoord0;") << QByteArray("uniform\n#if lowp float qt_Opacity;\nsampler2D source;") - << (VertexPresent | TexCoordPresent | MatrixPresent | PropertyPresent); + << (VertexPresent | TexCoordPresent | MatrixPresent | SourcePresent); QTest::newRow("newline between") << QByteArray("uniform\nhighp\nmat4\nqt_Matrix\n;\n" @@ -180,7 +182,7 @@ void tst_qquickshadereffect::lookThroughShaderCode_data() " \n attribute \n highp \n vec2 \n qt_Multi\nTexCoord0 \n ;") << QByteArray("uniform\nsampler2D\nsource;" "uniform lowp float qt_Opacity;") - << (VertexPresent | MatrixPresent | OpacityPresent | PropertyPresent); + << (VertexPresent | MatrixPresent | OpacityPresent | SourcePresent); QTest::newRow("extra characters #1") @@ -221,28 +223,28 @@ void tst_qquickshadereffect::lookThroughShaderCode_data() "attribute highp qt_MultiTexCoord0;\n") << QByteArray("uniform lowp float qt_Opacity;\n" "uniform mediump float source;\n") - << (MatrixPresent | OpacityPresent | PropertyPresent); + << (MatrixPresent | OpacityPresent | SourcePresent); QTest::newRow("property name #1") << QByteArray("uniform highp vec3 _0aA9zZ;") << QByteArray(" ") - << int(PropertyPresent); + << int(SourcePresent); QTest::newRow("property name #2") << QByteArray("uniform mediump vec2 x86;") << QByteArray(" ") - << int(PropertyPresent); + << int(SourcePresent); QTest::newRow("property name #3") << QByteArray("uniform lowp float X;") << QByteArray(" ") - << int(PropertyPresent); + << int(SourcePresent); QTest::newRow("property name #4") << QByteArray("uniform highp mat4 mat4x4;") << QByteArray(" ") - << int(PropertyPresent); + << int(SourcePresent); } void tst_qquickshadereffect::lookThroughShaderCode() @@ -251,9 +253,11 @@ void tst_qquickshadereffect::lookThroughShaderCode() QFETCH(QByteArray, fragmentShader); QFETCH(int, presenceFlags); - TestShaderEffect item; - QMetaMethod dummyChangedSignal = QMetaMethod::fromSignal(&TestShaderEffect::dummyChanged); - QVERIFY(!item.isConnected(dummyChangedSignal)); // Nothing connected yet. + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nimport ShaderEffectTest 1.0\nTestShaderEffect {}", QUrl()); + QScopedPointer<TestShaderEffect> item(qobject_cast<TestShaderEffect*>(component.create())); + QCOMPARE(item->signalsConnected, 1); QString expected; if ((presenceFlags & VertexPresent) == 0) @@ -265,12 +269,12 @@ void tst_qquickshadereffect::lookThroughShaderCode() if ((presenceFlags & OpacityPresent) == 0) expected += "Warning: Shaders are missing reference to \'qt_Opacity\'.\n"; - item.setVertexShader(vertexShader); - item.setFragmentShader(fragmentShader); - QCOMPARE(item.parseLog(), expected); + item->setVertexShader(vertexShader); + item->setFragmentShader(fragmentShader); + QCOMPARE(item->parseLog(), expected); // If the uniform was successfully parsed, the notify signal has been connected to an update slot. - QCOMPARE(item.isConnected(dummyChangedSignal), (presenceFlags & PropertyPresent) != 0); + QCOMPARE(item->signalsConnected, (presenceFlags & SourcePresent) ? 2 : 1); } void tst_qquickshadereffect::deleteSourceItem() diff --git a/tests/auto/quick/qquicktext/BLACKLIST b/tests/auto/quick/qquicktext/BLACKLIST index 223d8feb67..f400af1d10 100644 --- a/tests/auto/quick/qquicktext/BLACKLIST +++ b/tests/auto/quick/qquicktext/BLACKLIST @@ -4,3 +4,5 @@ * [lineLaidOutRelayout] msvc-2015 +[fontSizeMode] +opensuse-42.1 diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp index f31859ee49..2032f72e26 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -147,8 +147,9 @@ private slots: void padding(); - void zeroWidthAndElidedDoesntRender(); + void hintingPreference(); + void zeroWidthAndElidedDoesntRender(); void hAlignWidthDependsOnImplicitWidth_data(); void hAlignWidthDependsOnImplicitWidth(); @@ -4165,6 +4166,33 @@ void tst_qquicktext::padding() delete root; } +void tst_qquicktext::hintingPreference() +{ + { + QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }"; + QQmlComponent textComponent(&engine); + textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); + + QVERIFY(textObject != 0); + QCOMPARE((int)textObject->font().hintingPreference(), (int)QFont::PreferDefaultHinting); + + delete textObject; + } + { + QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.hintingPreference: Font.PreferNoHinting }"; + QQmlComponent textComponent(&engine); + textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("")); + QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create()); + + QVERIFY(textObject != 0); + QCOMPARE((int)textObject->font().hintingPreference(), (int)QFont::PreferNoHinting); + + delete textObject; + } +} + + void tst_qquicktext::zeroWidthAndElidedDoesntRender() { // Tests QTBUG-34990 diff --git a/tests/auto/quick/qquicktextedit/BLACKLIST b/tests/auto/quick/qquicktextedit/BLACKLIST index 297146195b..492d81531a 100644 --- a/tests/auto/quick/qquicktextedit/BLACKLIST +++ b/tests/auto/quick/qquicktextedit/BLACKLIST @@ -1,6 +1,2 @@ [mouseSelection] * -[undo] -* -[undo_keypressevents] -* diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp index b7bfc357f3..3c899c1e34 100644 --- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp @@ -108,6 +108,7 @@ private slots: void selectionOnFocusOut(); void focusOnPress(); void selection(); + void overwriteMode(); void isRightToLeft_data(); void isRightToLeft(); void keySelection(); @@ -1467,6 +1468,74 @@ void tst_qquicktextedit::selection() QVERIFY(textEditObject->selectedText().isNull()); } +void tst_qquicktextedit::overwriteMode() +{ + QString componentStr = "import QtQuick 2.0\nTextEdit { focus: true; }"; + QQmlComponent textEditComponent(&engine); + textEditComponent.setData(componentStr.toLatin1(), QUrl()); + QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create()); + QVERIFY(textEdit != 0); + + QSignalSpy spy(textEdit, SIGNAL(overwriteModeChanged(bool))); + + QQuickWindow window; + textEdit->setParentItem(window.contentItem()); + window.show(); + window.requestActivate(); + QTest::qWaitForWindowActive(&window); + + QVERIFY(textEdit->hasActiveFocus()); + + textEdit->setOverwriteMode(true); + QCOMPARE(spy.count(), 1); + QCOMPARE(true, textEdit->overwriteMode()); + textEdit->setOverwriteMode(false); + QCOMPARE(spy.count(), 2); + QCOMPARE(false, textEdit->overwriteMode()); + + QVERIFY(!textEdit->overwriteMode()); + QString insertString = "Some first text"; + for (int j = 0; j < insertString.length(); j++) + QTest::keyClick(&window, insertString.at(j).toLatin1()); + + QCOMPARE(textEdit->text(), QString("Some first text")); + + textEdit->setOverwriteMode(true); + QCOMPARE(spy.count(), 3); + textEdit->setCursorPosition(5); + + insertString = "shiny"; + for (int j = 0; j < insertString.length(); j++) + QTest::keyClick(&window, insertString.at(j).toLatin1()); + QCOMPARE(textEdit->text(), QString("Some shiny text")); + + textEdit->setCursorPosition(textEdit->text().length()); + QTest::keyClick(&window, Qt::Key_Enter); + + textEdit->setOverwriteMode(false); + QCOMPARE(spy.count(), 4); + + insertString = "Second paragraph"; + + for (int j = 0; j < insertString.length(); j++) + QTest::keyClick(&window, insertString.at(j).toLatin1()); + QCOMPARE(textEdit->lineCount(), 2); + + textEdit->setCursorPosition(15); + + QCOMPARE(textEdit->cursorPosition(), 15); + + textEdit->setOverwriteMode(true); + QCOMPARE(spy.count(), 5); + + insertString = " blah"; + for (int j = 0; j < insertString.length(); j++) + QTest::keyClick(&window, insertString.at(j).toLatin1()); + QCOMPARE(textEdit->lineCount(), 2); + + QCOMPARE(textEdit->text(), QString("Some shiny text blah\nSecond paragraph")); +} + void tst_qquicktextedit::isRightToLeft_data() { QTest::addColumn<QString>("text"); diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index ea88f9dadb..8dc3053d89 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -105,6 +105,7 @@ private slots: void wrap(); void selection(); void persistentSelection(); + void overwriteMode(); void isRightToLeft_data(); void isRightToLeft(); void moveCursorSelection_data(); @@ -782,6 +783,48 @@ void tst_qquicktextinput::persistentSelection() QCOMPARE(input->property("selected").toString(), QLatin1String("ell")); } +void tst_qquicktextinput::overwriteMode() +{ + QString componentStr = "import QtQuick 2.0\nTextInput { focus: true; }"; + QQmlComponent textInputComponent(&engine); + textInputComponent.setData(componentStr.toLatin1(), QUrl()); + QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create()); + QVERIFY(textInput != 0); + + QSignalSpy spy(textInput, SIGNAL(overwriteModeChanged(bool))); + + QQuickWindow window; + textInput->setParentItem(window.contentItem()); + window.show(); + window.requestActivate(); + QTest::qWaitForWindowActive(&window); + + QVERIFY(textInput->hasActiveFocus()); + + textInput->setOverwriteMode(true); + QCOMPARE(spy.count(), 1); + QCOMPARE(true, textInput->overwriteMode()); + textInput->setOverwriteMode(false); + QCOMPARE(spy.count(), 2); + QCOMPARE(false, textInput->overwriteMode()); + + QVERIFY(!textInput->overwriteMode()); + QString insertString = "Some first text"; + for (int j = 0; j < insertString.length(); j++) + QTest::keyClick(&window, insertString.at(j).toLatin1()); + + QCOMPARE(textInput->text(), QString("Some first text")); + + textInput->setOverwriteMode(true); + QCOMPARE(spy.count(), 3); + textInput->setCursorPosition(5); + + insertString = "shiny"; + for (int j = 0; j < insertString.length(); j++) + QTest::keyClick(&window, insertString.at(j).toLatin1()); + QCOMPARE(textInput->text(), QString("Some shiny text")); +} + void tst_qquicktextinput::isRightToLeft_data() { QTest::addColumn<QString>("text"); diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp index 05922ae20f..fa9192edb4 100644 --- a/tests/auto/quick/qquickview/tst_qquickview.cpp +++ b/tests/auto/quick/qquickview/tst_qquickview.cpp @@ -36,6 +36,30 @@ #include <QtCore/QDebug> #include <QtQml/qqmlengine.h> +class SizeChangesListener : public QObject, public QVector<QSize> +{ + Q_OBJECT +public: + explicit SizeChangesListener(QQuickItem *item); +private slots: + void onSizeChanged(); +private: + QQuickItem *item; + +}; + +SizeChangesListener::SizeChangesListener(QQuickItem *item) : + item(item) +{ + connect(item, &QQuickItem::widthChanged, this, &SizeChangesListener::onSizeChanged); + connect(item, &QQuickItem::heightChanged, this, &SizeChangesListener::onSizeChanged); +} + +void SizeChangesListener::onSizeChanged() +{ + append(QSize(item->width(), item->height())); +} + class tst_QQuickView : public QQmlDataTest { Q_OBJECT @@ -127,7 +151,6 @@ void tst_QQuickView::resizemodeitem() QCOMPARE(item->width(), 80.0); QCOMPARE(item->height(), 100.0); QTRY_COMPARE(view->size(), QSize(80, 100)); - QCOMPARE(view->size(), QSize(80, 100)); QCOMPARE(view->size(), view->sizeHint()); // size update from root object disabled @@ -139,8 +162,16 @@ void tst_QQuickView::resizemodeitem() QCOMPARE(QSize(item->width(), item->height()), view->sizeHint()); // size update from view + QCoreApplication::processEvents(); // make sure the last resize events are gone + SizeChangesListener sizeListener(item); view->resize(QSize(200,300)); QTRY_COMPARE(item->width(), 200.0); + + for (int i = 0; i < sizeListener.count(); ++i) { + // Check that we have the correct geometry on all signals + QCOMPARE(sizeListener.at(i), view->size()); + } + QCOMPARE(item->height(), 300.0); QCOMPARE(view->size(), QSize(200, 300)); QCOMPARE(view->size(), view->sizeHint()); diff --git a/tests/auto/quick/qquickwindow/qquickwindow.pro b/tests/auto/quick/qquickwindow/qquickwindow.pro index f0d287f30f..05093ba8e0 100644 --- a/tests/auto/quick/qquickwindow/qquickwindow.pro +++ b/tests/auto/quick/qquickwindow/qquickwindow.pro @@ -7,7 +7,7 @@ include(../shared/util.pri) macx:CONFIG -= app_bundle -QT += core-private gui-private qml-private quick-private testlib +QT += core-private qml-private quick-private testlib TESTDATA = data/* diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 1365e8b751..acccac8eca 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -40,10 +40,11 @@ #include "../shared/visualtestutil.h" #include "../shared/viewtestutil.h" #include <QSignalSpy> -#include <qpa/qwindowsysteminterface.h> #include <private/qquickwindow_p.h> #include <private/qguiapplication_p.h> #include <QRunnable> +#include <QOpenGLFunctions> +#include <QSGRendererInterface> struct TouchEventData { QEvent::Type type; @@ -156,6 +157,7 @@ public: lastVelocity = lastVelocityFromMouseMove = QVector2D(); lastMousePos = QPointF(); lastMouseCapabilityFlags = 0; + touchEventCount = 0; } static void clearMousePressCounter() @@ -273,25 +275,18 @@ class tst_qquickwindow : public QQmlDataTest Q_OBJECT public: tst_qquickwindow() + : touchDevice(QTest::createTouchDevice()) + , touchDeviceWithVelocity(QTest::createTouchDevice()) { QQuickWindow::setDefaultAlphaBuffer(true); + touchDeviceWithVelocity->setCapabilities(QTouchDevice::Position | QTouchDevice::Velocity); } private slots: - void initTestCase() - { - QQmlDataTest::initTestCase(); - touchDevice = new QTouchDevice; - touchDevice->setType(QTouchDevice::TouchScreen); - QWindowSystemInterface::registerTouchDevice(touchDevice); - touchDeviceWithVelocity = new QTouchDevice; - touchDeviceWithVelocity->setType(QTouchDevice::TouchScreen); - touchDeviceWithVelocity->setCapabilities(QTouchDevice::Position | QTouchDevice::Velocity); - QWindowSystemInterface::registerTouchDevice(touchDeviceWithVelocity); - } void cleanup(); - +#ifndef QT_NO_OPENGL void openglContextCreatedSignal(); +#endif void aboutToStopSignal(); void constantUpdates(); @@ -308,6 +303,9 @@ private slots: void touchEvent_reentrant(); void touchEvent_velocity(); + void mergeTouchPointLists_data(); + void mergeTouchPointLists(); + void mouseFromTouch_basic(); void clearWindow(); @@ -368,18 +366,21 @@ private slots: void testHoverChildMouseEventFilter(); void testHoverTimestamp(); + + void pointerEventTypeAndPointCount(); + private: QTouchDevice *touchDevice; QTouchDevice *touchDeviceWithVelocity; }; - +#ifndef QT_NO_OPENGL Q_DECLARE_METATYPE(QOpenGLContext *); - +#endif void tst_qquickwindow::cleanup() { QVERIFY(QGuiApplication::topLevelWindows().isEmpty()); } - +#ifndef QT_NO_OPENGL void tst_qquickwindow::openglContextCreatedSignal() { qRegisterMetaType<QOpenGLContext *>(); @@ -391,12 +392,15 @@ void tst_qquickwindow::openglContextCreatedSignal() window.show(); QTest::qWaitForWindowExposed(&window); + if (window.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) + QSKIP("Skipping OpenGL context test due to not running with OpenGL"); + QVERIFY(spy.size() > 0); QVariant ctx = spy.at(0).at(0); QCOMPARE(qvariant_cast<QOpenGLContext *>(ctx), window.openglContext()); } - +#endif void tst_qquickwindow::aboutToStopSignal() { QQuickWindow window; @@ -438,8 +442,7 @@ void tst_qquickwindow::constantUpdatesOnWindow_data() window.setGeometry(100, 100, 300, 200); window.show(); QTest::qWaitForWindowExposed(&window); - bool threaded = window.openglContext()->thread() != QGuiApplication::instance()->thread(); - + const bool threaded = QQuickWindowPrivate::get(&window)->context->thread() != QGuiApplication::instance()->thread(); if (threaded) { QTest::newRow("blocked, beforeRender") << true << QByteArray(SIGNAL(beforeRendering())); QTest::newRow("blocked, afterRender") << true << QByteArray(SIGNAL(afterRendering())); @@ -525,9 +528,8 @@ void tst_qquickwindow::touchEvent_basic() // press single point QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window); - QTest::qWait(50); - - QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); + QQuickTouchUtils::flush(window); + QTRY_COMPARE(topItem->lastEvent.touchPoints.count(), 1); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); @@ -535,9 +537,10 @@ void tst_qquickwindow::touchEvent_basic() // would put the decorated window at that position rather than the window itself. COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(topItem, pos))); topItem->reset(); + QTest::touchEvent(window, touchDevice).release(0, topItem->mapToScene(pos).toPoint(), window); // press multiple points - QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),window) + QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window) .press(1, bottomItem->mapToScene(pos).toPoint(), window); QQuickTouchUtils::flush(window); QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); @@ -547,6 +550,7 @@ void tst_qquickwindow::touchEvent_basic() COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos))); topItem->reset(); bottomItem->reset(); + QTest::touchEvent(window, touchDevice).release(0, topItem->mapToScene(pos).toPoint(), window).release(1, bottomItem->mapToScene(pos).toPoint(), window); // touch point on top item moves to bottom item, but top item should still receive the event QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window); @@ -557,6 +561,7 @@ void tst_qquickwindow::touchEvent_basic() COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved, makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos))); topItem->reset(); + QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), window); // touch point on bottom item moves to top item, but bottom item should still receive the event QTest::touchEvent(window, touchDevice).press(0, bottomItem->mapToScene(pos).toPoint(), window); @@ -567,6 +572,7 @@ void tst_qquickwindow::touchEvent_basic() COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, Qt::TouchPointMoved, makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos))); bottomItem->reset(); + QTest::touchEvent(window, touchDevice).release(0, bottomItem->mapToScene(pos).toPoint(), window); // a single stationary press on an item shouldn't cause an event QTest::touchEvent(window, touchDevice).press(0, topItem->mapToScene(pos).toPoint(), window); @@ -671,6 +677,7 @@ void tst_qquickwindow::touchEvent_propagation() QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos)))); + QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window); // touch top and middle items, middle item should get both events QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window) @@ -682,6 +689,8 @@ void tst_qquickwindow::touchEvent_propagation() COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos)) << makeTouchPoint(middleItem, pos) ))); + QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window) + .release(1, pointInMiddleItem, window); middleItem->reset(); // disable middleItem as well @@ -706,6 +715,8 @@ void tst_qquickwindow::touchEvent_propagation() bottomItem->acceptTouchEvents = acceptTouchEvents; bottomItem->setEnabled(enableItem); bottomItem->setVisible(showItem); + QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window) + .release(1, pointInMiddleItem, window); // no events should be received QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window) @@ -715,7 +726,9 @@ void tst_qquickwindow::touchEvent_propagation() QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); - + QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window) + .release(1, pointInMiddleItem, window) + .release(2, pointInBottomItem, window); topItem->reset(); middleItem->reset(); bottomItem->reset(); @@ -741,6 +754,7 @@ void tst_qquickwindow::touchEvent_propagation() COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(topItem, pos))); } + QTest::touchEvent(window, touchDevice).release(0, pointInTopItem, window); delete topItem; delete middleItem; @@ -859,6 +873,8 @@ void tst_qquickwindow::touchEvent_velocity() QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity, points); QGuiApplication::processEvents(); QQuickTouchUtils::flush(window); + QCOMPARE(item->touchEventCount, 1); + points[0].state = Qt::TouchPointMoved; points[0].area.adjust(5, 5, 5, 5); QVector2D velocity(1.5, 2.5); @@ -891,6 +907,67 @@ void tst_qquickwindow::touchEvent_velocity() delete item; } +void tst_qquickwindow::mergeTouchPointLists_data() +{ + QTest::addColumn<QVector<QQuickItem*>>("list1"); + QTest::addColumn<QVector<QQuickItem*>>("list2"); + QTest::addColumn<QVector<QQuickItem*>>("expected"); + QTest::addColumn<bool>("showItem"); + + // FIXME: do not leak all these items + auto item1 = new QQuickItem(); + auto item2 = new QQuickItem(); + auto item3 = new QQuickItem(); + auto item4 = new QQuickItem(); + auto item5 = new QQuickItem(); + + QTest::newRow("empty") << QVector<QQuickItem*>() << QVector<QQuickItem*>() << QVector<QQuickItem*>(); + QTest::newRow("single list left") + << (QVector<QQuickItem*>() << item1 << item2 << item3) + << QVector<QQuickItem*>() + << (QVector<QQuickItem*>() << item1 << item2 << item3); + QTest::newRow("single list right") + << QVector<QQuickItem*>() + << (QVector<QQuickItem*>() << item1 << item2 << item3) + << (QVector<QQuickItem*>() << item1 << item2 << item3); + QTest::newRow("two lists identical") + << (QVector<QQuickItem*>() << item1 << item2 << item3) + << (QVector<QQuickItem*>() << item1 << item2 << item3) + << (QVector<QQuickItem*>() << item1 << item2 << item3); + QTest::newRow("two lists 1") + << (QVector<QQuickItem*>() << item1 << item2 << item5) + << (QVector<QQuickItem*>() << item3 << item4 << item5) + << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4 << item5); + QTest::newRow("two lists 2") + << (QVector<QQuickItem*>() << item1 << item2 << item5) + << (QVector<QQuickItem*>() << item3 << item4 << item5) + << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4 << item5); + QTest::newRow("two lists 3") + << (QVector<QQuickItem*>() << item1 << item2 << item3) + << (QVector<QQuickItem*>() << item1 << item4 << item5) + << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4 << item5); + QTest::newRow("two lists 4") + << (QVector<QQuickItem*>() << item1 << item3 << item4) + << (QVector<QQuickItem*>() << item2 << item3 << item5) + << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4 << item5); + QTest::newRow("two lists 5") + << (QVector<QQuickItem*>() << item1 << item2 << item4) + << (QVector<QQuickItem*>() << item1 << item3 << item4) + << (QVector<QQuickItem*>() << item1 << item2 << item3 << item4); +} + +void tst_qquickwindow::mergeTouchPointLists() +{ + QFETCH(QVector<QQuickItem*>, list1); + QFETCH(QVector<QQuickItem*>, list2); + QFETCH(QVector<QQuickItem*>, expected); + + QQuickWindow win; + auto windowPrivate = QQuickWindowPrivate::get(&win); + auto targetList = windowPrivate->mergePointerTargets(list1, list2); + QCOMPARE(targetList, expected); +} + void tst_qquickwindow::mouseFromTouch_basic() { // Turn off accepting touch events with acceptTouchEvents. This @@ -1229,13 +1306,14 @@ void tst_qquickwindow::headless() QVERIFY(QTest::qWaitForWindowExposed(window)); QVERIFY(window->isVisible()); - bool threaded = window->openglContext()->thread() != QThread::currentThread(); - + const bool threaded = QQuickWindowPrivate::get(window)->context->thread() != QThread::currentThread(); QSignalSpy initialized(window, SIGNAL(sceneGraphInitialized())); QSignalSpy invalidated(window, SIGNAL(sceneGraphInvalidated())); // Verify that the window is alive and kicking - QVERIFY(window->openglContext() != 0); + QVERIFY(window->isSceneGraphInitialized()); + + const bool isGL = window->rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL; // Store the visual result QImage originalContent = window->grabWindow(); @@ -1245,15 +1323,16 @@ void tst_qquickwindow::headless() window->releaseResources(); if (threaded) { - QTRY_COMPARE(invalidated.size(), 1); - QVERIFY(!window->openglContext()); + QTRY_VERIFY(invalidated.size() >= 1); + if (isGL) + QVERIFY(!window->isSceneGraphInitialized()); } - +#ifndef QT_NO_OPENGL if (QGuiApplication::platformName() == QLatin1String("windows") && QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { QSKIP("Crashes on Windows/ANGLE, QTBUG-42967"); } - +#endif // Destroy the native windowing system buffers window->destroy(); QVERIFY(!window->handle()); @@ -1264,7 +1343,8 @@ void tst_qquickwindow::headless() if (threaded) QTRY_COMPARE(initialized.size(), 1); - QVERIFY(window->openglContext() != 0); + + QVERIFY(window->isSceneGraphInitialized()); // Verify that the visual output is the same QImage newContent = window->grabWindow(); @@ -1285,8 +1365,7 @@ void tst_qquickwindow::noUpdateWhenNothingChanges() // the initial expose with a second expose or more. Let these go // through before we let the test continue. QTest::qWait(100); - - if (window.openglContext()->thread() == QGuiApplication::instance()->thread()) { + if (QQuickWindowPrivate::get(&window)->context->thread() == QGuiApplication::instance()->thread()) { QSKIP("Only threaded renderloop implements this feature"); return; } @@ -1593,7 +1672,6 @@ void tst_qquickwindow::hideThenDelete() QSignalSpy *openglDestroyed = 0; QSignalSpy *sgInvalidated = 0; - bool threaded = false; { QQuickWindow window; @@ -1608,9 +1686,13 @@ void tst_qquickwindow::hideThenDelete() window.show(); QTest::qWaitForWindowExposed(&window); - threaded = window.openglContext()->thread() != QThread::currentThread(); + const bool threaded = QQuickWindowPrivate::get(&window)->context->thread() != QGuiApplication::instance()->thread(); + const bool isGL = window.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL; +#ifndef QT_NO_OPENGL + if (isGL) + openglDestroyed = new QSignalSpy(window.openglContext(), SIGNAL(aboutToBeDestroyed())); +#endif - openglDestroyed = new QSignalSpy(window.openglContext(), SIGNAL(aboutToBeDestroyed())); sgInvalidated = new QSignalSpy(&window, SIGNAL(sceneGraphInvalidated())); window.hide(); @@ -1618,6 +1700,9 @@ void tst_qquickwindow::hideThenDelete() QTRY_VERIFY(!window.isExposed()); if (threaded) { + if (!isGL) + QSKIP("Skipping persistency verification due to not running with OpenGL"); + if (!persistentSG) { QVERIFY(sgInvalidated->size() > 0); if (!persistentGL) @@ -1632,7 +1717,10 @@ void tst_qquickwindow::hideThenDelete() } QVERIFY(sgInvalidated->size() > 0); - QVERIFY(openglDestroyed->size() > 0); +#ifndef QT_NO_OPENGL + if (openglDestroyed) + QVERIFY(openglDestroyed->size() > 0); +#endif } void tst_qquickwindow::showHideAnimate() @@ -2029,6 +2117,9 @@ void tst_qquickwindow::defaultSurfaceFormat() window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); + if (window.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) + QSKIP("Skipping OpenGL context test due to not running with OpenGL"); + const QSurfaceFormat reqFmt = window.requestedFormat(); QCOMPARE(format.swapInterval(), reqFmt.swapInterval()); QCOMPARE(format.redBufferSize(), reqFmt.redBufferSize()); @@ -2037,12 +2128,13 @@ void tst_qquickwindow::defaultSurfaceFormat() QCOMPARE(format.profile(), reqFmt.profile()); QCOMPARE(int(format.options()), int(reqFmt.options())); +#ifndef QT_NO_OPENGL // Depth and stencil should be >= what has been requested. For real. But use // the context since the window's surface format is only partially updated // on most platforms. QVERIFY(window.openglContext()->format().depthBufferSize() >= 16); QVERIFY(window.openglContext()->format().stencilBufferSize() >= 8); - +#endif QSurfaceFormat::setDefaultFormat(savedDefaultFormat); } @@ -2091,7 +2183,7 @@ public: } static int deleted; }; - +#ifndef QT_NO_OPENGL class GlRenderJob : public QRunnable { public: @@ -2113,7 +2205,7 @@ public: QMutex *mutex; QWaitCondition *condition; }; - +#endif int RenderJob::deleted = 0; void tst_qquickwindow::testRenderJob() @@ -2162,25 +2254,29 @@ void tst_qquickwindow::testRenderJob() QTRY_COMPARE(RenderJob::deleted, 1); QCOMPARE(completedJobs.size(), 1); - // Do a synchronized GL job. - GLubyte readPixel[4] = {0, 0, 0, 0}; - GlRenderJob *glJob = new GlRenderJob(readPixel); - if (window.openglContext()->thread() != QThread::currentThread()) { - QMutex mutex; - QWaitCondition condition; - glJob->mutex = &mutex; - glJob->condition = &condition; - mutex.lock(); - window.scheduleRenderJob(glJob, QQuickWindow::NoStage); - condition.wait(&mutex); - mutex.unlock(); - } else { - window.scheduleRenderJob(glJob, QQuickWindow::NoStage); +#ifndef QT_NO_OPENGL + if (window.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL) { + // Do a synchronized GL job. + GLubyte readPixel[4] = {0, 0, 0, 0}; + GlRenderJob *glJob = new GlRenderJob(readPixel); + if (window.openglContext()->thread() != QThread::currentThread()) { + QMutex mutex; + QWaitCondition condition; + glJob->mutex = &mutex; + glJob->condition = &condition; + mutex.lock(); + window.scheduleRenderJob(glJob, QQuickWindow::NoStage); + condition.wait(&mutex); + mutex.unlock(); + } else { + window.scheduleRenderJob(glJob, QQuickWindow::NoStage); + } + QCOMPARE(int(readPixel[0]), 255); + QCOMPARE(int(readPixel[1]), 0); + QCOMPARE(int(readPixel[2]), 0); + QCOMPARE(int(readPixel[3]), 255); } - QCOMPARE(int(readPixel[0]), 255); - QCOMPARE(int(readPixel[1]), 0); - QCOMPARE(int(readPixel[2]), 0); - QCOMPARE(int(readPixel[3]), 255); +#endif } // Verify that jobs are deleted when window is not rendered at all @@ -2198,7 +2294,6 @@ void tst_qquickwindow::testRenderJob() class EventCounter : public QQuickRectangle { - Q_OBJECT public: EventCounter(QQuickItem *parent = 0) : QQuickRectangle(parent) @@ -2388,6 +2483,58 @@ void tst_qquickwindow::testHoverTimestamp() QCOMPARE(hoverConsumer->hoverTimestamps.last(), 5UL); } +void tst_qquickwindow::pointerEventTypeAndPointCount() +{ + QPointF localPosition(33, 66); + QPointF scenePosition(133, 166); + QPointF screenPosition(333, 366); + QMouseEvent me(QEvent::MouseButtonPress, localPosition, scenePosition, screenPosition, + Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + QTouchEvent te(QEvent::TouchBegin, touchDevice, Qt::NoModifier, Qt::TouchPointPressed, + QList<QTouchEvent::TouchPoint>() << QTouchEvent::TouchPoint(1)); + + + QQuickPointerMouseEvent pme; + pme.reset(&me); + QVERIFY(pme.isValid()); + QCOMPARE(pme.asMouseEvent(localPosition), &me); + QVERIFY(pme.asPointerMouseEvent()); + QVERIFY(!pme.asPointerTouchEvent()); + QVERIFY(!pme.asPointerTabletEvent()); +// QVERIFY(!pe->asTabletEvent()); // TODO + QCOMPARE(pme.pointCount(), 1); + QCOMPARE(pme.point(0)->scenePos(), scenePosition); + QCOMPARE(pme.asMouseEvent(localPosition)->localPos(), localPosition); + QCOMPARE(pme.asMouseEvent(localPosition)->screenPos(), screenPosition); + + QQuickPointerTouchEvent pte; + pte.reset(&te); + QVERIFY(pte.isValid()); + QCOMPARE(pte.asTouchEvent(), &te); + QVERIFY(!pte.asPointerMouseEvent()); + QVERIFY(pte.asPointerTouchEvent()); + QVERIFY(!pte.asPointerTabletEvent()); + QVERIFY(pte.asTouchEvent()); +// QVERIFY(!pte.asTabletEvent()); // TODO + QCOMPARE(pte.pointCount(), 1); + QCOMPARE(pte.touchPointById(1)->id(), 1); + QVERIFY(!pte.touchPointById(0)); + + te.setTouchPoints(QList<QTouchEvent::TouchPoint>() << QTouchEvent::TouchPoint(1) << QTouchEvent::TouchPoint(2)); + pte.reset(&te); + QCOMPARE(pte.pointCount(), 2); + QCOMPARE(pte.touchPointById(1)->id(), 1); + QCOMPARE(pte.touchPointById(2)->id(), 2); + QVERIFY(!pte.touchPointById(0)); + + te.setTouchPoints(QList<QTouchEvent::TouchPoint>() << QTouchEvent::TouchPoint(2)); + pte.reset(&te); + QCOMPARE(pte.pointCount(), 1); + QCOMPARE(pte.touchPointById(2)->id(), 2); + QVERIFY(!pte.touchPointById(1)); + QVERIFY(!pte.touchPointById(0)); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc" diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 2e43702e7c..c7ba4de86c 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -2,10 +2,20 @@ TEMPLATE = subdirs PUBLICTESTS += \ geometry \ - rendernode \ qquickpixmapcache -qtHaveModule(widgets): PUBLICTESTS += nodes +qtConfig(opengl(es1|es2)?) { + PUBLICTESTS += \ + rendernode + qtHaveModule(widgets): PUBLICTESTS += nodes + + QUICKTESTS += \ + qquickanimatedsprite \ + qquickframebufferobject \ + qquickopenglinfo \ + qquickspritesequence \ + qquickshadereffect +} !cross_compile: PRIVATETESTS += examples @@ -39,7 +49,6 @@ QUICKTESTS = \ qquickaccessible \ qquickanchors \ qquickanimatedimage \ - qquickanimatedsprite \ qquickdynamicpropertyanimation \ qquickborderimage \ qquickwindow \ @@ -48,7 +57,7 @@ QUICKTESTS = \ qquickflickable \ qquickflipable \ qquickfocusscope \ - qquickframebufferobject \ + qquickgraphicsinfo \ qquickgridview \ qquickimage \ qquickitem \ @@ -58,16 +67,13 @@ QUICKTESTS = \ qquickloader \ qquickmousearea \ qquickmultipointtoucharea \ - qquickopenglinfo \ qquickpainteditem \ qquickpathview \ qquickpincharea \ qquickpositioners \ qquickrectangle \ qquickrepeater \ - qquickshadereffect \ qquickshortcut \ - qquickspritesequence \ qquicktext \ qquicktextdocument \ qquicktextedit \ @@ -82,9 +88,9 @@ QUICKTESTS = \ SUBDIRS += $$PUBLICTESTS -!contains(QT_CONFIG, accessibility):QUICKTESTS -= qquickaccessible +!qtConfig(accessibility):QUICKTESTS -= qquickaccessible -contains(QT_CONFIG, private_tests) { +qtConfig(private_tests) { SUBDIRS += $$PRIVATETESTS SUBDIRS += $$QUICKTESTS } diff --git a/tests/auto/quick/rendernode/tst_rendernode.cpp b/tests/auto/quick/rendernode/tst_rendernode.cpp index 782ebf5aee..e15649e62c 100644 --- a/tests/auto/quick/rendernode/tst_rendernode.cpp +++ b/tests/auto/quick/rendernode/tst_rendernode.cpp @@ -66,12 +66,12 @@ private slots: class ClearNode : public QSGRenderNode { public: - virtual StateFlags changedStates() + StateFlags changedStates() const override { return ColorState; } - virtual void render(const RenderState &) + void render(const RenderState *) override { // If clip has been set, scissoring will make sure the right area is cleared. QOpenGLContext::currentContext()->functions()->glClearColor(color.redF(), color.greenF(), color.blueF(), 1.0f); @@ -122,13 +122,13 @@ class MessUpNode : public QSGRenderNode, protected QOpenGLFunctions public: MessUpNode() : initialized(false) { } - virtual StateFlags changedStates() + StateFlags changedStates() const override { return StateFlags(DepthState) | StencilState | ScissorState | ColorState | BlendState - | CullState | ViewportState; + | CullState | ViewportState | RenderTargetState; } - virtual void render(const RenderState &) + void render(const RenderState *) override { if (!initialized) { initializeOpenGLFunctions(); @@ -152,6 +152,9 @@ public: glGetIntegerv(GL_FRONT_FACE, &frontFace); glFrontFace(frontFace == GL_CW ? GL_CCW : GL_CW); glEnable(GL_CULL_FACE); + GLuint fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); } bool initialized; @@ -212,16 +215,18 @@ void tst_rendernode::renderOrder() QSKIP("This test does not work at display depths < 24"); QImage fb = runTest("RenderOrder.qml"); - QCOMPARE(fb.width(), 200); - QCOMPARE(fb.height(), 200); + QQuickView v; + int devicePixelRatio = static_cast<int>(v.devicePixelRatio()); + QCOMPARE(fb.width(), 200 * devicePixelRatio); + QCOMPARE(fb.height(), 200 * devicePixelRatio); - QCOMPARE(fb.pixel(50, 50), qRgb(0xff, 0xff, 0xff)); - QCOMPARE(fb.pixel(50, 150), qRgb(0xff, 0xff, 0xff)); - QCOMPARE(fb.pixel(150, 50), qRgb(0x00, 0x00, 0xff)); + QCOMPARE(fb.pixel(50 * devicePixelRatio, 50 * devicePixelRatio), qRgb(0xff, 0xff, 0xff)); + QCOMPARE(fb.pixel(50 * devicePixelRatio, 150 * devicePixelRatio), qRgb(0xff, 0xff, 0xff)); + QCOMPARE(fb.pixel(150 * devicePixelRatio, 50 * devicePixelRatio), qRgb(0x00, 0x00, 0xff)); QByteArray errorMessage; - QVERIFY2(fuzzyCompareColor(fb.pixel(150, 150), qRgb(0x7f, 0x7f, 0xff), &errorMessage), - msgColorMismatchAt(errorMessage, 150, 150).constData()); + QVERIFY2(fuzzyCompareColor(fb.pixel(150 * devicePixelRatio, 150 * devicePixelRatio), qRgb(0x7f, 0x7f, 0xff), &errorMessage), + msgColorMismatchAt(errorMessage, 150 * devicePixelRatio, 150 * devicePixelRatio).constData()); } /* The test uses a number of nested rectangles with clipping @@ -257,8 +262,8 @@ void tst_rendernode::messUpState() class StateRecordingRenderNode : public QSGRenderNode { public: - StateFlags changedStates() { return StateFlags(-1); } - void render(const RenderState &) { + StateFlags changedStates() const override { return StateFlags(-1); } + void render(const RenderState *) override { matrices[name] = *matrix(); } diff --git a/tests/auto/quick/scenegraph/scenegraph.pro b/tests/auto/quick/scenegraph/scenegraph.pro index 320228bd08..40ff7750cc 100644 --- a/tests/auto/quick/scenegraph/scenegraph.pro +++ b/tests/auto/quick/scenegraph/scenegraph.pro @@ -3,6 +3,7 @@ TARGET = tst_scenegraph SOURCES += tst_scenegraph.cpp include (../../shared/util.pri) +include (../shared/util.pri) macx:CONFIG -= app_bundle diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp index 1e46727526..f6d624d871 100644 --- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp +++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp @@ -28,18 +28,26 @@ #include <qtest.h> +#ifndef QT_NO_OPENGL #include <QOffscreenSurface> #include <QOpenGLContext> #include <QOpenGLFunctions> +#endif #include <QtQuick> #include <QtQml> +#ifndef QT_NO_OPENGL #include <private/qopenglcontext_p.h> +#endif + #include <private/qsgcontext_p.h> #include <private/qsgrenderloop_p.h> #include "../../shared/util.h" +#include "../shared/visualtestutil.h" + +using namespace QQuickVisualTestUtil; class PerPixelRect : public QQuickItem { @@ -97,9 +105,9 @@ private slots: void render_data(); void render(); - +#ifndef QT_NO_OPENGL void hideWithOtherContext(); - +#endif void createTextureFromImage_data(); void createTextureFromImage(); @@ -122,6 +130,7 @@ void tst_SceneGraph::initTestCase() QSGRenderLoop *loop = QSGRenderLoop::instance(); qDebug() << "RenderLoop: " << loop; +#ifndef QT_NO_OPENGL QOpenGLContext context; context.setFormat(loop->sceneGraphContext()->defaultSurfaceFormat()); context.create(); @@ -154,6 +163,7 @@ void tst_SceneGraph::initTestCase() qDebug() << "Broken Mipmap: " << m_brokenMipmapSupport; context.doneCurrent(); +#endif } QQuickView *tst_SceneGraph::createView(const QString &file, QWindow *parent, int x, int y, int w, int h) @@ -169,12 +179,17 @@ QQuickView *tst_SceneGraph::createView(const QString &file, QWindow *parent, int // Assumes the images are opaque white... bool containsSomethingOtherThanWhite(const QImage &image) { - Q_ASSERT(image.format() == QImage::Format_ARGB32_Premultiplied - || image.format() == QImage::Format_RGB32); - int w = image.width(); - int h = image.height(); + QImage img; + if (image.format() != QImage::Format_ARGB32_Premultiplied + || image.format() != QImage::Format_RGB32) + img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + else + img = image; + + int w = img.width(); + int h = img.height(); for (int y=0; y<h; ++y) { - const uint *pixels = (const uint *) image.constScanLine(y); + const uint *pixels = (const uint *) img.constScanLine(y); for (int x=0; x<w; ++x) if (pixels[x] != 0xffffffff) return true; @@ -182,44 +197,6 @@ bool containsSomethingOtherThanWhite(const QImage &image) return false; } -// When running on native Nvidia graphics cards on linux, the -// distance field glyph pixels have a measurable, but not visible -// pixel error. Use a custom compare function to avoid -// -// This was GT-216 with the ubuntu "nvidia-319" driver package. -// llvmpipe does not show the same issue. -// -bool compareImages(const QImage &ia, const QImage &ib) -{ - if (ia.size() != ib.size()) - qDebug() << "images are of different size" << ia.size() << ib.size(); - Q_ASSERT(ia.size() == ib.size()); - Q_ASSERT(ia.format() == ib.format()); - - int w = ia.width(); - int h = ia.height(); - const int tolerance = 5; - for (int y=0; y<h; ++y) { - const uint *as= (const uint *) ia.constScanLine(y); - const uint *bs= (const uint *) ib.constScanLine(y); - for (int x=0; x<w; ++x) { - uint a = as[x]; - uint b = bs[x]; - - // No tolerance for error in the alpha. - if ((a & 0xff000000) != (b & 0xff000000)) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - if (qAbs(qRed(a) - qRed(b)) > tolerance) - return false; - } - } - return true; -} - void tst_SceneGraph::manyWindows_data() { QTest::addColumn<QString>("file"); @@ -245,24 +222,26 @@ void tst_SceneGraph::manyWindows_data() QTest::newRow("rects,subwindow,sharing") << QStringLiteral("manyWindows_rects.qml") << false << true; } +#ifndef QT_NO_OPENGL struct ShareContextResetter { public: ~ShareContextResetter() { qt_gl_set_global_share_context(0); } }; +#endif void tst_SceneGraph::manyWindows() { QFETCH(QString, file); QFETCH(bool, toplevel); QFETCH(bool, shared); - +#ifndef QT_NO_OPENGL QOpenGLContext sharedGLContext; ShareContextResetter cleanup; // To avoid dangling pointer in case of test-failure. if (shared) { QVERIFY(sharedGLContext.create()); qt_gl_set_global_share_context(&sharedGLContext); } - +#endif QScopedPointer<QWindow> parent; if (!toplevel) { parent.reset(new QWindow()); @@ -451,6 +430,13 @@ void tst_SceneGraph::render_data() void tst_SceneGraph::render() { + QQuickView dummy; + dummy.show(); + QTest::qWaitForWindowExposed(&dummy); + if (dummy.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) + QSKIP("Skipping complex rendering tests due to not running with OpenGL"); + dummy.hide(); + QFETCH(QString, file); QFETCH(QList<Sample>, baseStage); QFETCH(QList<Sample>, finalStage); @@ -493,6 +479,7 @@ void tst_SceneGraph::render() } } +#ifndef QT_NO_OPENGL // Testcase for QTBUG-34898. We make another context current on another surface // in the GUI thread and hide the QQuickWindow while the other context is // current on the other window. @@ -513,6 +500,9 @@ void tst_SceneGraph::hideWithOtherContext() view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); + if (view.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) + QSKIP("Skipping OpenGL context test due to not running with OpenGL"); + renderingOnMainThread = view.openglContext()->thread() == QGuiApplication::instance()->thread(); // Make the local context current on the local window... @@ -525,6 +515,7 @@ void tst_SceneGraph::hideWithOtherContext() // GL calls to a new frame (see QOpenGLContext docs). QVERIFY(!renderingOnMainThread || QOpenGLContext::currentContext() != &context); } +#endif void tst_SceneGraph::createTextureFromImage_data() { @@ -550,6 +541,10 @@ void tst_SceneGraph::createTextureFromImage() QFETCH(bool, expectedAlpha); QQuickView view; + view.show(); + QTest::qWaitForWindowExposed(&view); + QTRY_VERIFY(view.isSceneGraphInitialized()); + QScopedPointer<QSGTexture> texture(view.createTextureFromImage(image, (QQuickWindow::CreateTextureOptions) flags)); QCOMPARE(texture->hasAlphaChannel(), expectedAlpha); } diff --git a/tests/auto/quick/shared/visualtestutil.cpp b/tests/auto/quick/shared/visualtestutil.cpp index 3e18c83ee2..eabfe5368b 100644 --- a/tests/auto/quick/shared/visualtestutil.cpp +++ b/tests/auto/quick/shared/visualtestutil.cpp @@ -61,3 +61,38 @@ void QQuickVisualTestUtil::dumpTree(QQuickItem *parent, int depth) } } +// A custom compare function to avoid issues such as: +// When running on native Nvidia graphics cards on linux, the +// distance field glyph pixels have a measurable, but not visible +// pixel error. This was GT-216 with the ubuntu "nvidia-319" driver package. +// llvmpipe does not show the same issue. +bool QQuickVisualTestUtil::compareImages(const QImage &ia, const QImage &ib) +{ + if (ia.size() != ib.size()) + qDebug() << "images are of different size" << ia.size() << ib.size(); + Q_ASSERT(ia.size() == ib.size()); + Q_ASSERT(ia.format() == ib.format()); + + int w = ia.width(); + int h = ia.height(); + const int tolerance = 5; + for (int y=0; y<h; ++y) { + const uint *as= (const uint *) ia.constScanLine(y); + const uint *bs= (const uint *) ib.constScanLine(y); + for (int x=0; x<w; ++x) { + uint a = as[x]; + uint b = bs[x]; + + // No tolerance for error in the alpha. + if ((a & 0xff000000) != (b & 0xff000000)) + return false; + if (qAbs(qRed(a) - qRed(b)) > tolerance) + return false; + if (qAbs(qRed(a) - qRed(b)) > tolerance) + return false; + if (qAbs(qRed(a) - qRed(b)) > tolerance) + return false; + } + } + return true; +} diff --git a/tests/auto/quick/shared/visualtestutil.h b/tests/auto/quick/shared/visualtestutil.h index 2b377a4bab..2daf86cd83 100644 --- a/tests/auto/quick/shared/visualtestutil.h +++ b/tests/auto/quick/shared/visualtestutil.h @@ -96,6 +96,8 @@ namespace QQuickVisualTestUtil items << qobject_cast<QQuickItem*>(findItem<T>(parent, objectName, indexes[i])); return items; } + + bool compareImages(const QImage &ia, const QImage &ib); } #define QQUICK_VERIFY_POLISH(item) \ diff --git a/tests/auto/quick/touchmouse/data/touchpointdeliveryorder.qml b/tests/auto/quick/touchmouse/data/touchpointdeliveryorder.qml new file mode 100644 index 0000000000..9f67c226a0 --- /dev/null +++ b/tests/auto/quick/touchmouse/data/touchpointdeliveryorder.qml @@ -0,0 +1,39 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Rectangle { + id: root + + width: 600 + height: 400 + + EventItem { + objectName: "background" + width: 600 + height: 400 + Rectangle { anchors.fill: parent; color: "lightsteelblue" } + + EventItem { + objectName: "left" + width: 300 + height: 300 + Rectangle { anchors.fill: parent; color: "yellow" } + } + + EventItem { + objectName: "right" + x: 300 + width: 300 + height: 300 + Rectangle { anchors.fill: parent; color: "green" } + } + + EventItem { + objectName: "middle" + x: 150 + width: 300 + height: 300 + Rectangle { anchors.fill: parent; color: "blue" } + } + } +} diff --git a/tests/auto/quick/touchmouse/touchmouse.pro b/tests/auto/quick/touchmouse/touchmouse.pro index 0df9bc53d3..49818bb399 100644 --- a/tests/auto/quick/touchmouse/touchmouse.pro +++ b/tests/auto/quick/touchmouse/touchmouse.pro @@ -1,7 +1,7 @@ CONFIG += testcase TARGET = tst_touchmouse -QT += core-private gui-private qml-private quick-private testlib +QT += core-private qml-private quick-private testlib macx:CONFIG -= app_bundle diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp index 72cc76a855..309c01dcdc 100644 --- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp +++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp @@ -33,13 +33,12 @@ #include <QtQuick/qquickview.h> #include <QtQuick/qquickitem.h> +#include <QtQuick/private/qquickevents_p_p.h> #include <QtQuick/private/qquickmousearea_p.h> #include <QtQuick/private/qquickmultipointtoucharea_p.h> #include <QtQuick/private/qquickpincharea_p.h> #include <QtQuick/private/qquickflickable_p.h> -#include <qpa/qwindowsysteminterface.h> - -#include <private/qquickwindow_p.h> +#include <QtQuick/private/qquickwindow_p.h> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlproperty.h> @@ -66,15 +65,22 @@ struct Event class EventItem : public QQuickItem { Q_OBJECT + +Q_SIGNALS: + void onTouchEvent(QQuickItem *receiver); + public: EventItem(QQuickItem *parent = 0) : QQuickItem(parent), acceptMouse(false), acceptTouch(false), filterTouch(false) - {} + { + setAcceptedMouseButtons(Qt::LeftButton); + } void touchEvent(QTouchEvent *event) { eventList.append(Event(event->type(), event->touchPoints())); event->setAccepted(acceptTouch); + emit onTouchEvent(this); } void mousePressEvent(QMouseEvent *event) { @@ -132,7 +138,7 @@ class tst_TouchMouse : public QQmlDataTest Q_OBJECT public: tst_TouchMouse() - :device(0) + :device(QTest::createTouchDevice()) {} private slots: @@ -145,6 +151,7 @@ private slots: void mouseOverTouch(); void buttonOnFlickable(); + void buttonOnDelayedPressFlickable_data(); void buttonOnDelayedPressFlickable(); void buttonOnTouch(); @@ -155,6 +162,7 @@ private slots: void tapOnDismissiveTopMouseAreaClicksBottomOne(); void touchGrabCausesMouseUngrab(); + void touchPointDeliveryOrder(); void hoverEnabled(); @@ -191,11 +199,6 @@ void tst_TouchMouse::initTestCase() QQmlDataTest::initTestCase(); qmlRegisterType<EventItem>("Qt.test", 1, 0, "EventItem"); - if (!device) { - device = new QTouchDevice; - device->setType(QTouchDevice::TouchScreen); - QWindowSystemInterface::registerTouchDevice(device); - } } void tst_TouchMouse::simpleTouchEvent() @@ -217,15 +220,17 @@ void tst_TouchMouse::simpleTouchEvent() p1 = QPoint(20, 20); QTest::touchEvent(window, device).press(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 1); + // Get a touch and then mouse event offered + QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); p1 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 1); + // Not accepted, no updates + QCOMPARE(eventItem1->eventList.size(), 2); QTest::touchEvent(window, device).release(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 1); + QCOMPARE(eventItem1->eventList.size(), 2); eventItem1->eventList.clear(); // Accept touch @@ -256,8 +261,7 @@ void tst_TouchMouse::simpleTouchEvent() QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); - QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); - QCOMPARE(windowPriv->mouseGrabberItem, eventItem1); + QCOMPARE(window->mouseGrabberItem(), eventItem1); QPoint localPos = eventItem1->mapFromScene(p1).toPoint(); QPoint globalPos = window->mapToGlobal(p1); @@ -292,17 +296,16 @@ void tst_TouchMouse::simpleTouchEvent() p1 = QPoint(20, 20); QTest::touchEvent(window, device).press(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 2); QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin); QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress); - QCOMPARE(eventItem1->eventList.at(2).type, QEvent::UngrabMouse); p1 += QPoint(10, 0); QTest::touchEvent(window, device).move(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 2); QTest::touchEvent(window, device).release(0, p1, window); QQuickTouchUtils::flush(window); - QCOMPARE(eventItem1->eventList.size(), 3); + QCOMPARE(eventItem1->eventList.size(), 2); eventItem1->eventList.clear(); // wait to avoid getting a double click event @@ -579,8 +582,9 @@ void tst_TouchMouse::buttonOnFlickable() QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); QCOMPARE(windowPriv->touchMouseId, 0); - QCOMPARE(windowPriv->itemForTouchPointId[0], eventItem1); - QCOMPARE(windowPriv->mouseGrabberItem, eventItem1); + auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); + QCOMPARE(pointerEvent->point(0)->grabber(), eventItem1); + QCOMPARE(window->mouseGrabberItem(), eventItem1); p1 += QPoint(0, -10); QPoint p2 = p1 + QPoint(0, -10); @@ -598,9 +602,9 @@ void tst_TouchMouse::buttonOnFlickable() QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate); QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove); - QCOMPARE(windowPriv->mouseGrabberItem, flickable); + QCOMPARE(window->mouseGrabberItem(), flickable); QCOMPARE(windowPriv->touchMouseId, 0); - QCOMPARE(windowPriv->itemForTouchPointId[0], flickable); + QCOMPARE(pointerEvent->point(0)->grabber(), flickable); QVERIFY(flickable->isMovingVertically()); QTest::touchEvent(window, device).release(0, p3, window); @@ -608,11 +612,25 @@ void tst_TouchMouse::buttonOnFlickable() delete window; } +void tst_TouchMouse::buttonOnDelayedPressFlickable_data() +{ + QTest::addColumn<bool>("scrollBeforeDelayIsOver"); + + // the item should never see the event, + // due to the pressDelay which never delivers if we start moving + QTest::newRow("scroll before press delay is over") << true; + + // wait until the "button" sees the press but then + // start moving: the button gets a press and cancel event + QTest::newRow("scroll after press delay is over") << false; +} + void tst_TouchMouse::buttonOnDelayedPressFlickable() { // flickable - height 500 / 1000 // - eventItem1 y: 100, height 100 // - eventItem2 y: 300, height 100 + QFETCH(bool, scrollBeforeDelayIsOver); qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true); filteredEventList.clear(); @@ -631,7 +649,8 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() window->installEventFilter(this); - flickable->setPressDelay(60); + // wait 600 ms before letting the child see the press event + flickable->setPressDelay(600); // should a mouse area button be clickable on top of flickable? yes :) EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1"); @@ -647,25 +666,23 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() // wait to avoid getting a double click event QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); + QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); + QCOMPARE(windowPriv->touchMouseId, -1); // no grabber - // check that flickable moves - mouse button - QCOMPARE(eventItem1->eventList.size(), 0); + // touch press QPoint p1 = QPoint(10, 110); QTest::touchEvent(window, device).press(0, p1, window); QQuickTouchUtils::flush(window); - // Flickable initially steals events - QCOMPARE(eventItem1->eventList.size(), 0); - // but we'll get the delayed mouse press after a delay - QTRY_COMPARE(eventItem1->eventList.size(), 1); - QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); - QCOMPARE(filteredEventList.count(), 1); - // eventItem1 should have the mouse grab, and have moved the itemForTouchPointId - // for the touchMouseId to the new grabber. - QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); - QCOMPARE(windowPriv->touchMouseId, 0); - QCOMPARE(windowPriv->itemForTouchPointId[0], eventItem1); - QCOMPARE(windowPriv->mouseGrabberItem, eventItem1); + if (scrollBeforeDelayIsOver) { + // no events, the flickable got scrolled, the button sees nothing + QCOMPARE(eventItem1->eventList.size(), 0); + } else { + // wait until the button sees the press + QTRY_COMPARE(eventItem1->eventList.size(), 1); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); + QCOMPARE(filteredEventList.count(), 1); + } p1 += QPoint(0, -10); QPoint p2 = p1 + QPoint(0, -10); @@ -677,20 +694,35 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() QQuickTouchUtils::flush(window); QTest::touchEvent(window, device).move(0, p3, window); QQuickTouchUtils::flush(window); - QVERIFY(flickable->isMovingVertically()); + QTRY_VERIFY(flickable->isMovingVertically()); + + if (scrollBeforeDelayIsOver) { + QCOMPARE(eventItem1->eventList.size(), 0); + QCOMPARE(filteredEventList.count(), 0); + } else { + // see at least press, move and ungrab + QTRY_VERIFY(eventItem1->eventList.size() > 2); + QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); + QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse); + QCOMPARE(filteredEventList.count(), 1); + } // flickable should have the mouse grab, and have moved the itemForTouchPointId // for the touchMouseId to the new grabber. - QCOMPARE(windowPriv->mouseGrabberItem, flickable); + QCOMPARE(window->mouseGrabberItem(), flickable); QCOMPARE(windowPriv->touchMouseId, 0); - QCOMPARE(windowPriv->itemForTouchPointId[0], flickable); + auto pointerEvent = QQuickPointerDevice::touchDevices().at(0)->pointerEvent(); + QCOMPARE(pointerEvent->point(0)->grabber(), flickable); QTest::touchEvent(window, device).release(0, p3, window); QQuickTouchUtils::flush(window); // We should not have received any synthesised mouse events from Qt gui, // just the delayed press. - QCOMPARE(filteredEventList.count(), 1); + if (scrollBeforeDelayIsOver) + QCOMPARE(filteredEventList.count(), 0); + else + QCOMPARE(filteredEventList.count(), 1); delete window; } @@ -1097,9 +1129,7 @@ void tst_TouchMouse::mouseOnFlickableOnPinch() pinchSequence.move(0, p, window).commit(); QQuickTouchUtils::flush(window); - QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window); - qDebug() << "Mouse Grabber: " << windowPriv->mouseGrabberItem << " itemForTouchPointId: " << windowPriv->itemForTouchPointId; - QCOMPARE(windowPriv->mouseGrabberItem, flickable); + QCOMPARE(window->mouseGrabberItem(), flickable); // Add a second finger, this should lead to stealing p1 = QPoint(40, 100); @@ -1229,6 +1259,105 @@ void tst_TouchMouse::touchGrabCausesMouseUngrab() delete window; } +void tst_TouchMouse::touchPointDeliveryOrder() +{ + // Touch points should be first delivered to the item under the primary finger + QScopedPointer<QQuickView> window(createView()); + + window->setSource(testFileUrl("touchpointdeliveryorder.qml")); + /* + The items are positioned from left to right: + | background | + | left | + | | right | + | middle | + 0 150 300 450 600 + */ + QPoint pLeft = QPoint(100, 100); + QPoint pRight = QPoint(500, 100); + QPoint pLeftMiddle = QPoint(200, 100); + QPoint pRightMiddle = QPoint(350, 100); + + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + + QVector<QQuickItem*> events; + EventItem *background = window->rootObject()->findChild<EventItem*>("background"); + EventItem *left = window->rootObject()->findChild<EventItem*>("left"); + EventItem *middle = window->rootObject()->findChild<EventItem*>("middle"); + EventItem *right = window->rootObject()->findChild<EventItem*>("right"); + QVERIFY(background); + QVERIFY(left); + QVERIFY(middle); + QVERIFY(right); + connect(background, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); + connect(left, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); + connect(middle, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); + connect(right, &EventItem::onTouchEvent, [&events](QQuickItem* receiver){ events.append(receiver); }); + + QTest::touchEvent(window.data(), device).press(0, pLeft, window.data()); + QQuickTouchUtils::flush(window.data()); + + // Touch on left, then background + QCOMPARE(events.size(), 2); + QCOMPARE(events.at(0), left); + QCOMPARE(events.at(1), background); + events.clear(); + + // New press events are deliverd first, the stationary point was not accepted, thus it doesn't get delivered + QTest::touchEvent(window.data(), device).stationary(0).press(1, pRightMiddle, window.data()); + QQuickTouchUtils::flush(window.data()); + QCOMPARE(events.size(), 3); + QCOMPARE(events.at(0), middle); + QCOMPARE(events.at(1), right); + QCOMPARE(events.at(2), background); + events.clear(); + + QTest::touchEvent(window.data(), device).release(0, pLeft, window.data()).release(1, pRightMiddle, window.data()); + QQuickTouchUtils::flush(window.data()); + QCOMPARE(events.size(), 0); // no accepted events + + // Two presses, the first point should come first + QTest::touchEvent(window.data(), device).press(0, pLeft, window.data()).press(1, pRight, window.data()); + QQuickTouchUtils::flush(window.data()); + QCOMPARE(events.size(), 3); + QCOMPARE(events.at(0), left); + QCOMPARE(events.at(1), right); + QCOMPARE(events.at(2), background); + QTest::touchEvent(window.data(), device).release(0, pLeft, window.data()).release(1, pRight, window.data()); + events.clear(); + + // Again, pressing right first + QTest::touchEvent(window.data(), device).press(0, pRight, window.data()).press(1, pLeft, window.data()); + QQuickTouchUtils::flush(window.data()); + QCOMPARE(events.size(), 3); + QCOMPARE(events.at(0), right); + QCOMPARE(events.at(1), left); + QCOMPARE(events.at(2), background); + QTest::touchEvent(window.data(), device).release(0, pRight, window.data()).release(1, pLeft, window.data()); + events.clear(); + + // Two presses, both hitting the middle item on top, then branching left and right, then bottom + // Each target should be offered the events exactly once, middle first, left must come before right (id 0) + QTest::touchEvent(window.data(), device).press(0, pLeftMiddle, window.data()).press(1, pRightMiddle, window.data()); + QCOMPARE(events.size(), 4); + QCOMPARE(events.at(0), middle); + QCOMPARE(events.at(1), left); + QCOMPARE(events.at(2), right); + QCOMPARE(events.at(3), background); + QTest::touchEvent(window.data(), device).release(0, pLeftMiddle, window.data()).release(1, pRightMiddle, window.data()); + events.clear(); + + QTest::touchEvent(window.data(), device).press(0, pRightMiddle, window.data()).press(1, pLeftMiddle, window.data()); + qDebug() << events; + QCOMPARE(events.size(), 4); + QCOMPARE(events.at(0), middle); + QCOMPARE(events.at(1), right); + QCOMPARE(events.at(2), left); + QCOMPARE(events.at(3), background); + QTest::touchEvent(window.data(), device).release(0, pRightMiddle, window.data()).release(1, pLeftMiddle, window.data()); +} + void tst_TouchMouse::hoverEnabled() { // QTouchDevice *device = new QTouchDevice; @@ -1276,8 +1405,8 @@ void tst_TouchMouse::hoverEnabled() // ------------------------- Touch click on mouseArea1 QTest::touchEvent(window, device).press(0, p1, window); - QVERIFY(enterSpy1.count() == 1); - QVERIFY(enterSpy2.count() == 0); + QCOMPARE(enterSpy1.count(), 1); + QCOMPARE(enterSpy2.count(), 0); QVERIFY(mouseArea1->pressed()); QVERIFY(mouseArea1->hovered()); QVERIFY(!mouseArea2->hovered()); @@ -1288,33 +1417,36 @@ void tst_TouchMouse::hoverEnabled() QVERIFY(!mouseArea2->hovered()); // ------------------------- Touch click on mouseArea2 + if (QGuiApplication::platformName().compare(QLatin1String("xcb"), Qt::CaseInsensitive) == 0) + QSKIP("hover can be momentarily inconsistent on X11, depending on timing of flushFrameSynchronousEvents with touch and mouse movements (QTBUG-55350)"); + QTest::touchEvent(window, device).press(0, p2, window); QVERIFY(mouseArea1->hovered()); QVERIFY(mouseArea2->hovered()); QVERIFY(mouseArea2->pressed()); - QVERIFY(enterSpy1.count() == 1); - QVERIFY(enterSpy2.count() == 1); + QCOMPARE(enterSpy1.count(), 1); + QCOMPARE(enterSpy2.count(), 1); QTest::touchEvent(window, device).release(0, p2, window); QVERIFY(clickSpy2.count() == 1); QVERIFY(mouseArea1->hovered()); QVERIFY(!mouseArea2->hovered()); - QVERIFY(exitSpy1.count() == 0); - QVERIFY(exitSpy2.count() == 1); + QCOMPARE(exitSpy1.count(), 0); + QCOMPARE(exitSpy2.count(), 1); // ------------------------- Another touch click on mouseArea1 QTest::touchEvent(window, device).press(0, p1, window); - QVERIFY(enterSpy1.count() == 1); - QVERIFY(enterSpy2.count() == 1); + QCOMPARE(enterSpy1.count(), 1); + QCOMPARE(enterSpy2.count(), 1); QVERIFY(mouseArea1->pressed()); QVERIFY(mouseArea1->hovered()); QVERIFY(!mouseArea2->hovered()); QTest::touchEvent(window, device).release(0, p1, window); - QVERIFY(clickSpy1.count() == 2); + QCOMPARE(clickSpy1.count(), 2); QVERIFY(mouseArea1->hovered()); QVERIFY(!mouseArea1->pressed()); QVERIFY(!mouseArea2->hovered()); diff --git a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp index ab2c41b6bf..5e8f762e23 100644 --- a/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp +++ b/tests/auto/quickwidgets/qquickwidget/tst_qquickwidget.cpp @@ -34,6 +34,7 @@ #include <QtQuick/qquickitem.h> #include "../../shared/util.h" #include <QtGui/QWindow> +#include <QtGui/QImage> #include <QtCore/QDebug> #include <QtQml/qqmlengine.h> @@ -55,6 +56,7 @@ private slots: void readback(); void renderingSignals(); void grabBeforeShow(); + void reparentToNewWindow(); void nullEngine(); }; @@ -302,6 +304,27 @@ void tst_qquickwidget::grabBeforeShow() QVERIFY(!widget.grab().isNull()); } +void tst_qquickwidget::reparentToNewWindow() +{ + QWidget window1; + QWidget window2; + + QQuickWidget *qqw = new QQuickWidget(&window1); + qqw->setSource(testFileUrl("rectangle.qml")); + window1.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window1, 5000)); + window2.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window2, 5000)); + + QSignalSpy afterRenderingSpy(qqw->quickWindow(), &QQuickWindow::afterRendering); + qqw->setParent(&window2); + qqw->show(); + QTRY_VERIFY(afterRenderingSpy.size() > 0); + + QImage img = qqw->grabFramebuffer(); + QCOMPARE(img.pixel(5, 5), qRgb(255, 0, 0)); +} + void tst_qquickwidget::nullEngine() { QQuickWidget widget; diff --git a/tests/auto/shared/util.cpp b/tests/auto/shared/util.cpp index 55041eeb4d..96beb51612 100644 --- a/tests/auto/shared/util.cpp +++ b/tests/auto/shared/util.cpp @@ -101,11 +101,15 @@ Q_GLOBAL_STATIC(QMutex, qQmlTestMessageHandlerMutex) QQmlTestMessageHandler *QQmlTestMessageHandler::m_instance = 0; -void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &, const QString &message) +void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message) { QMutexLocker locker(qQmlTestMessageHandlerMutex()); - if (QQmlTestMessageHandler::m_instance) - QQmlTestMessageHandler::m_instance->m_messages.push_back(message); + if (QQmlTestMessageHandler::m_instance) { + if (QQmlTestMessageHandler::m_instance->m_includeCategories) + QQmlTestMessageHandler::m_instance->m_messages.push_back(QString("%1: %2").arg(context.category, message)); + else + QQmlTestMessageHandler::m_instance->m_messages.push_back(message); + } } QQmlTestMessageHandler::QQmlTestMessageHandler() @@ -114,6 +118,7 @@ QQmlTestMessageHandler::QQmlTestMessageHandler() Q_ASSERT(!QQmlTestMessageHandler::m_instance); QQmlTestMessageHandler::m_instance = this; m_oldHandler = qInstallMessageHandler(messageHandler); + m_includeCategories = false; } QQmlTestMessageHandler::~QQmlTestMessageHandler() diff --git a/tests/auto/shared/util.h b/tests/auto/shared/util.h index 47a4aae231..33d7cbd1d0 100644 --- a/tests/auto/shared/util.h +++ b/tests/auto/shared/util.h @@ -87,12 +87,15 @@ public: void clear() { m_messages.clear(); } + void setIncludeCategoriesEnabled(bool enabled) { m_includeCategories = enabled; } + private: - static void messageHandler(QtMsgType, const QMessageLogContext &, const QString &message); + static void messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message); static QQmlTestMessageHandler *m_instance; QStringList m_messages; QtMessageHandler m_oldHandler; + bool m_includeCategories; }; #endif // QQMLTESTUTILS_H diff --git a/tests/benchmarks/benchmarks.pro b/tests/benchmarks/benchmarks.pro index c7e7c6829a..5e6bc65815 100644 --- a/tests/benchmarks/benchmarks.pro +++ b/tests/benchmarks/benchmarks.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs SUBDIRS = qml script -contains(QT_CONFIG, private_tests) { - SUBDIRS += particles +qtConfig(private_tests) { + qtConfig(opengl(es1|es2)?):SUBDIRS += particles } diff --git a/tests/benchmarks/particles/affectors/tst_affectors.cpp b/tests/benchmarks/particles/affectors/tst_affectors.cpp index 475b8d28ec..99d175564b 100644 --- a/tests/benchmarks/particles/affectors/tst_affectors.cpp +++ b/tests/benchmarks/particles/affectors/tst_affectors.cpp @@ -86,7 +86,7 @@ void tst_affectors::test_basic() int stillAlive = 0; QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 1000, 10));//Small simulation variance is permissible. - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused @@ -126,7 +126,7 @@ void tst_affectors::test_filtered() int stillAlive = 0; QVERIFY(extremelyFuzzyCompare(system->groupData[1]->size(), 1000, 10));//Small simulation variance is permissible. - foreach (QQuickParticleData *d, system->groupData[1]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[1]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/benchmarks/particles/emission/tst_emission.cpp b/tests/benchmarks/particles/emission/tst_emission.cpp index b107120a28..fe08305f68 100644 --- a/tests/benchmarks/particles/emission/tst_emission.cpp +++ b/tests/benchmarks/particles/emission/tst_emission.cpp @@ -79,7 +79,7 @@ void tst_emission::test_basic() int stillAlive = 0; QVERIFY(extremelyFuzzyCompare(system->groupData[0]->size(), 1000, 10));//Small simulation variance is permissible. - foreach (QQuickParticleData *d, system->groupData[0]->data) { + for (QQuickParticleData *d : qAsConst(system->groupData[0]->data)) { if (d->t == -1) continue; //Particle data unused diff --git a/tests/benchmarks/qml/animation/tst_animation.cpp b/tests/benchmarks/qml/animation/tst_animation.cpp index 4f693f9fa8..59f5a57f5c 100644 --- a/tests/benchmarks/qml/animation/tst_animation.cpp +++ b/tests/benchmarks/qml/animation/tst_animation.cpp @@ -107,8 +107,8 @@ void tst_animation::animationelements_data() { QTest::addColumn<QString>("type"); - QSet<QString> types = QQmlMetaType::qmlTypeNames().toSet(); - foreach (const QString &type, types) { + const QSet<QString> types = QQmlMetaType::qmlTypeNames().toSet(); + for (const QString &type : types) { if (type.contains(QLatin1String("Animation"))) QTest::newRow(type.toLatin1()) << type; } diff --git a/tests/benchmarks/qml/compilation/tst_compilation.cpp b/tests/benchmarks/qml/compilation/tst_compilation.cpp index 3f2cb5b94f..690e193b53 100644 --- a/tests/benchmarks/qml/compilation/tst_compilation.cpp +++ b/tests/benchmarks/qml/compilation/tst_compilation.cpp @@ -75,7 +75,9 @@ void tst_compilation::boomblock() QQmlComponent c(&engine); c.setData(data, QUrl()); } - +#ifdef QT_NO_OPENGL + QSKIP("boomblock imports Particles which requires OpenGL Support"); +#endif QBENCHMARK { QQmlComponent c(&engine); c.setData(data, QUrl()); diff --git a/tests/benchmarks/qml/creation/tst_creation.cpp b/tests/benchmarks/qml/creation/tst_creation.cpp index e5ad04b92f..a1c09db158 100644 --- a/tests/benchmarks/qml/creation/tst_creation.cpp +++ b/tests/benchmarks/qml/creation/tst_creation.cpp @@ -62,6 +62,12 @@ private slots: void itemtests_qml_data(); void itemtests_qml(); + void bindings_cpp(); + void bindings_cpp2(); + void bindings_qml(); + + void bindings_parent_qml(); + void anchors_creation(); void anchors_heightChange(); @@ -325,6 +331,89 @@ void tst_creation::itemtests_qml() QBENCHMARK { delete component.create(); } } +void tst_creation::bindings_cpp() +{ + QQuickItem item; + QMetaProperty widthProp = item.metaObject()->property(item.metaObject()->indexOfProperty("width")); + QMetaProperty heightProp = item.metaObject()->property(item.metaObject()->indexOfProperty("height")); + connect(&item, &QQuickItem::heightChanged, [&item, &widthProp, &heightProp](){ + QVariant height = heightProp.read(&item); + widthProp.write(&item, height); + }); + + int height = 0; + QBENCHMARK { + item.setHeight(++height); + } +} + +void tst_creation::bindings_cpp2() +{ + QQuickItem item; + int widthProp = item.metaObject()->indexOfProperty("width"); + int heightProp = item.metaObject()->indexOfProperty("height"); + connect(&item, &QQuickItem::heightChanged, [&item, widthProp, heightProp](){ + + qreal height = -1; + void *args[] = { &height, 0 }; + QMetaObject::metacall(&item, QMetaObject::ReadProperty, heightProp, args); + + int flags = 0; + int status = -1; + void *argv[] = { &height, 0, &status, &flags }; + QMetaObject::metacall(&item, QMetaObject::WriteProperty, widthProp, argv); + }); + + int height = 0; + QBENCHMARK { + item.setHeight(++height); + } +} + +void tst_creation::bindings_qml() +{ + QByteArray data = "import QtQuick 2.0\nItem { width: height }"; + + QQmlComponent component(&engine); + component.setData(data, QUrl()); + if (!component.isReady()) { + qWarning() << "Unable to create component: " << component.errorString(); + return; + } + + QQuickItem *obj = dynamic_cast<QQuickItem *>(component.create()); + QVERIFY(obj != nullptr); + + int height = 0; + QBENCHMARK { + obj->setHeight(++height); + } + + delete obj; +} + +void tst_creation::bindings_parent_qml() +{ + QByteArray data = "import QtQuick 2.0\nItem { Item { width: parent.height }}"; + + QQmlComponent component(&engine); + component.setData(data, QUrl()); + if (!component.isReady()) { + qWarning() << "Unable to create component: " << component.errorString(); + return; + } + + QQuickItem *obj = dynamic_cast<QQuickItem *>(component.create()); + QVERIFY(obj != nullptr); + + int height = 0; + QBENCHMARK { + obj->setHeight(++height); + } + + delete obj; +} + void tst_creation::anchors_creation() { QQmlComponent component(&engine); diff --git a/tests/manual/nodetypes/Animators.qml b/tests/manual/nodetypes/Animators.qml new file mode 100644 index 0000000000..7d8baf1cb8 --- /dev/null +++ b/tests/manual/nodetypes/Animators.qml @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 + +Item { + id: window + + Rectangle { + anchors.fill: parent + gradient: Gradient { + GradientStop { position: 0.0; color: "#14148c" } + GradientStop { position: 0.499; color: "#14aaff" } + GradientStop { position: 0.5; color: "#80c342" } + GradientStop { position: 1.0; color: "#006325" } + } + } + + SequentialAnimation { + id: plainAnim + SequentialAnimation { + ParallelAnimation { + PropertyAnimation { + property: "y" + target: smiley + from: smiley.minHeight + to: smiley.maxHeight + easing.type: Easing.OutExpo + duration: 300 + } + PropertyAnimation { + property: "scale" + target: shadow + from: 1 + to: 0.5 + easing.type: Easing.OutExpo + duration: 300 + } + } + ParallelAnimation { + PropertyAnimation { + property: "y" + target: smiley + from: smiley.maxHeight + to: smiley.minHeight + easing.type: Easing.OutBounce + duration: 1000 + } + PropertyAnimation { + property: "scale" + target: shadow + from: 0.5 + to: 1 + easing.type: Easing.OutBounce + duration: 1000 + } + } + } + running: false + } + + SequentialAnimation { + id: renderThreadAnim + SequentialAnimation { + ParallelAnimation { + YAnimator { + target: smiley + from: smiley.minHeight + to: smiley.maxHeight + easing.type: Easing.OutExpo + duration: 300 + } + ScaleAnimator { + target: shadow + from: 1 + to: 0.5 + easing.type: Easing.OutExpo + duration: 300 + } + } + ParallelAnimation { + YAnimator { + target: smiley + from: smiley.maxHeight + to: smiley.minHeight + easing.type: Easing.OutBounce + duration: 1000 + } + ScaleAnimator { + target: shadow + from: 0.5 + to: 1 + easing.type: Easing.OutBounce + duration: 1000 + } + } + } + running: false + } + + Image { + id: shadow + anchors.horizontalCenter: parent.horizontalCenter + y: smiley.minHeight + smiley.height + source: "qrc:/shadow.png" + } + + Image { + id: smiley + property int maxHeight: window.height / 3 + property int minHeight: 2 * window.height / 3 + + anchors.horizontalCenter: parent.horizontalCenter + y: minHeight + source: "qrc:/face-smile.png" + } + + Text { + text: "click left for plain animation, right for render thread Animators, middle to sleep for 2 sec on the main (gui) thread" + color: "white" + } + + Text { + text: plainAnim.running ? "NORMAL ANIMATION" : (renderThreadAnim.running ? "RENDER THREAD ANIMATION" : "NO ANIMATION") + color: "red" + font.pointSize: 20 + anchors.bottom: parent.bottom + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.AllButtons + onClicked: if (mouse.button === Qt.LeftButton) { + renderThreadAnim.running = false; + plainAnim.running = true; + } else if (mouse.button === Qt.RightButton) { + plainAnim.running = false; + renderThreadAnim.running = true; + } else if (mouse.button === Qt.MiddleButton) { + helper.sleep(2000); + } + } +} diff --git a/tests/manual/nodetypes/Effects.qml b/tests/manual/nodetypes/Effects.qml new file mode 100644 index 0000000000..85e7ab7a15 --- /dev/null +++ b/tests/manual/nodetypes/Effects.qml @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Use QtQuick 2.8 to get GraphicsInfo and the other new properties +import QtQuick 2.8 + +Item { + Rectangle { + color: "gray" + anchors.margins: 10 + anchors.fill: parent + Image { + id: image1 + source: "qrc:/qt.png" + } + ShaderEffectSource { + id: effectSource1 + sourceItem: image1 + hideSource: true + } + ShaderEffect { // wobble + id: eff + width: image1.width + height: image1.height + anchors.centerIn: parent + + property variant source: effectSource1 + property real amplitude: 0.04 * 0.2 + property real frequency: 20 + property real time: 0 + + NumberAnimation on time { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 600 } + + property bool customVertexShader: false // the effect is fine with the default vs, but toggle this to test + property bool useHLSLSourceString: false // toggle to provide HLSL shaders as strings instead of bytecode in files + + property string glslVertexShader: + "uniform highp mat4 qt_Matrix;" + + "attribute highp vec4 qt_Vertex;" + + "attribute highp vec2 qt_MultiTexCoord0;" + + "varying highp vec2 qt_TexCoord0;" + + "void main() {" + + " qt_TexCoord0 = qt_MultiTexCoord0;" + + " gl_Position = qt_Matrix * qt_Vertex;" + + "}" + + property string glslFragmentShader: + "uniform sampler2D source;" + + "uniform highp float amplitude;" + + "uniform highp float frequency;" + + "uniform highp float time;" + + "uniform lowp float qt_Opacity;" + + "varying highp vec2 qt_TexCoord0;" + + "void main() {" + + " highp vec2 p = sin(time + frequency * qt_TexCoord0);" + + " gl_FragColor = texture2D(source, qt_TexCoord0 + amplitude * vec2(p.y, -p.x)) * qt_Opacity;" + + "}" + + property string hlslVertexShader: "cbuffer ConstantBuffer : register(b0) {" + + " float4x4 qt_Matrix;" + + " float qt_Opacity; }" + + "struct PSInput {" + + " float4 position : SV_POSITION;" + + " float2 coord : TEXCOORD0; };" + + "PSInput main(float4 position : POSITION, float2 coord : TEXCOORD0) {" + + " PSInput result;" + + " result.position = mul(qt_Matrix, position);" + + " result.coord = coord;" + + " return result;" + + "}"; + + property string hlslPixelShader:"cbuffer ConstantBuffer : register(b0) {" + + " float4x4 qt_Matrix;" + + " float qt_Opacity;" + + " float amplitude;" + + " float frequency;" + + " float time; }" + + "Texture2D source : register(t0);" + + "SamplerState sourceSampler : register(s0);" + + "float4 main(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET" + + "{" + + " float2 p = sin(time + frequency * coord);" + + " return source.Sample(sourceSampler, coord + amplitude * float2(p.y, -p.x)) * qt_Opacity;" + + "}"; + + property string hlslVertexShaderByteCode: "qrc:/vs_wobble.cso" + property string hlslPixelShaderByteCode: "qrc:/ps_wobble.cso" + + vertexShader: customVertexShader ? (GraphicsInfo.shaderType === GraphicsInfo.HLSL + ? (useHLSLSourceString ? hlslVertexShader : hlslVertexShaderByteCode) + : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? glslVertexShader : "")) : "" + + fragmentShader: GraphicsInfo.shaderType === GraphicsInfo.HLSL + ? (useHLSLSourceString ? hlslPixelShader : hlslPixelShaderByteCode) + : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? glslFragmentShader : "") + } + + Image { + id: image2 + source: "qrc:/face-smile.png" + } + ShaderEffectSource { + id: effectSource2 + sourceItem: image2 + hideSource: true + } + ShaderEffect { // dropshadow + id: eff2 + width: image2.width + height: image2.height + scale: 2 + x: 40 + y: 40 + + property variant source: effectSource2 + + property string glslShaderPass1: " + uniform lowp float qt_Opacity; + uniform sampler2D source; + uniform highp vec2 delta; + varying highp vec2 qt_TexCoord0; + void main() { + gl_FragColor = (0.0538 * texture2D(source, qt_TexCoord0 - 3.182 * delta) + + 0.3229 * texture2D(source, qt_TexCoord0 - 1.364 * delta) + + 0.2466 * texture2D(source, qt_TexCoord0) + + 0.3229 * texture2D(source, qt_TexCoord0 + 1.364 * delta) + + 0.0538 * texture2D(source, qt_TexCoord0 + 3.182 * delta)) * qt_Opacity; + }" + property string glslShaderPass2: " + uniform lowp float qt_Opacity; + uniform highp vec2 offset; + uniform sampler2D source; + uniform sampler2D shadow; + uniform highp float darkness; + uniform highp vec2 delta; + varying highp vec2 qt_TexCoord0; + void main() { + lowp vec4 fg = texture2D(source, qt_TexCoord0); + lowp vec4 bg = texture2D(shadow, qt_TexCoord0 + delta); + gl_FragColor = (fg + vec4(0., 0., 0., darkness * bg.a) * (1. - fg.a)) * qt_Opacity; + }" + + property variant shadow: ShaderEffectSource { + sourceItem: ShaderEffect { + width: eff2.width + height: eff2.height + property variant delta: Qt.size(0.0, 1.0 / height) + property variant source: ShaderEffectSource { + sourceItem: ShaderEffect { + id: innerEff + width: eff2.width + height: eff2.height + property variant delta: Qt.size(1.0 / width, 0.0) + property variant source: effectSource2 + fragmentShader: GraphicsInfo.shaderType === GraphicsInfo.HLSL ? "qrc:/ps_shadow1.cso" : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? eff2.glslShaderPass1 : "") + } + } + fragmentShader: GraphicsInfo.shaderType === GraphicsInfo.HLSL ? "qrc:/ps_shadow1.cso" : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? eff2.glslShaderPass1: "") + } + } + property real angle: 0 + property variant offset: Qt.point(5.0 * Math.cos(angle), 5.0 * Math.sin(angle)) + NumberAnimation on angle { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 6000 } + property variant delta: Qt.size(offset.x / width, offset.y / height) + property real darkness: 0.5 + fragmentShader: GraphicsInfo.shaderType === GraphicsInfo.HLSL ? "qrc:/ps_shadow2.cso" : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? glslShaderPass2 : "") + } + + Column { + anchors.bottom: parent.bottom + Text { + color: "yellow" + font.pointSize: 24 + text: "Shader effect is " + (GraphicsInfo.shaderType === GraphicsInfo.HLSL ? "HLSL" : (GraphicsInfo.shaderType === GraphicsInfo.GLSL ? "GLSL" : "UNKNOWN")) + " based"; + } + Text { + text: GraphicsInfo.shaderType + " " + GraphicsInfo.shaderCompilationType + " " + GraphicsInfo.shaderSourceType + } + Text { + text: eff.status + " " + eff.log + } + } + } +} diff --git a/tests/manual/nodetypes/Images.qml b/tests/manual/nodetypes/Images.qml new file mode 100644 index 0000000000..7c1ba5345b --- /dev/null +++ b/tests/manual/nodetypes/Images.qml @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 + +Item { + Rectangle { + width: 100 + height: 100 + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + + Image { + id: im + source: "qrc:/qt.png" + mipmap: true + + // changing the mipmap property results in the creation of a brand new + // texture resource. enable the following to test. +// Timer { +// interval: 2000 +// onTriggered: im.mipmap = false +// running: true +// } + + SequentialAnimation on scale { + loops: Animation.Infinite + NumberAnimation { + from: 1.0 + to: 4.0 + duration: 2000 + } + NumberAnimation { + from: 4.0 + to: 0.1 + duration: 3000 + } + NumberAnimation { + from: 0.1 + to: 1.0 + duration: 1000 + } + } + + Image { + anchors.centerIn: parent + source: "qrc:/face-smile.png" + } + } + + Image { + source: "qrc:/face-smile.png" + anchors.bottom: parent.bottom + anchors.right: parent.right + antialiasing: true + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } +} diff --git a/tests/manual/nodetypes/Layers.qml b/tests/manual/nodetypes/Layers.qml new file mode 100644 index 0000000000..52c8fa8144 --- /dev/null +++ b/tests/manual/nodetypes/Layers.qml @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + Rectangle { + color: "lightGray" + anchors.fill: parent + anchors.margins: 10 + + Row { + anchors.fill: parent + anchors.margins: 10 + Rectangle { + color: "red" +// ColorAnimation on color { +// from: "black" +// to: "white" +// duration: 2000 +// loops: Animation.Infinite +// } + width: 300 + height: 100 + layer.enabled: true + Text { text: "this is in a layer, going through an offscreen render target" } + clip: true + Rectangle { + color: "lightGreen" + width: 50 + height: 50 + x: 275 + y: 75 + } + } + Rectangle { + color: "white" + width: 300 + height: 100 + Text { text: "this is not a layer" } + } + Rectangle { + color: "green" + width: 300 + height: 100 + layer.enabled: true + Text { text: "this is another layer" } + Rectangle { + border.width: 4 + border.color: "black" + anchors.centerIn: parent + width: 150 + height: 50 + layer.enabled: true + Text { + anchors.centerIn: parent + text: "layer in a layer" + } + } + Image { + source: "qrc:/face-smile.png" + anchors.bottom: parent.bottom + anchors.right: parent.right + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + } + } + } +} diff --git a/tests/manual/nodetypes/LotsOfImages.qml b/tests/manual/nodetypes/LotsOfImages.qml new file mode 100644 index 0000000000..38356a3390 --- /dev/null +++ b/tests/manual/nodetypes/LotsOfImages.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.3 + +Item { + Grid { + columns: 20 + spacing: 4 + anchors.centerIn: parent + + Repeater { + model: 500 + + Image { + source: "qrc:/qt.png" + + // async true, cache false -> there is a separate, new texture for each and every image + // and the pixel data reading is done over and over again on a separate thread. + asynchronous: true + cache: false + + width: 20 + height: 20 + } + } + } + + Rectangle { + width: 100 + height: 100 + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } +} diff --git a/tests/manual/nodetypes/LotsOfRects.qml b/tests/manual/nodetypes/LotsOfRects.qml new file mode 100644 index 0000000000..46a05a2453 --- /dev/null +++ b/tests/manual/nodetypes/LotsOfRects.qml @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + Rectangle { + anchors.margins: 4 + anchors.fill: parent + + // Background + gradient: Gradient { + GradientStop { position: 0; color: "steelblue" } + GradientStop { position: 1; color: "black" } + } + + // Animated gradient stops. + // NB! Causes a full buffer rebuild on every animated change due to the geometry change! + Row { + spacing: 10 + Repeater { + model: 20 + Rectangle { + width: 20 + height: 20 + gradient: Gradient { + GradientStop { position: 0.0; color: "red" } + GradientStop { NumberAnimation on position { from: 0.01; to: 0.99; duration: 5000; loops: Animation.Infinite } color: "yellow" } + GradientStop { position: 1.0; color: "green" } + } + } + } + } + + // Rounded rects with border (smooth material) + Row { + spacing: 10 + Repeater { + model: 5 + Rectangle { + color: "blue" + width: 100 + height: 50 + y: 50 + radius: 16 + border.color: "red" + border.width: 4 + + SequentialAnimation on y { + loops: Animation.Infinite + NumberAnimation { + from: 50 + to: 150 + duration: 7000 + } + NumberAnimation { + from: 150 + to: 50 + duration: 3000 + } + } + } + } + } + + // Clip using scissor + Row { + spacing: 10 + Repeater { + model: 5 + Rectangle { + color: "green" + width: 100 + height: 100 + y: 150 + NumberAnimation on y { + from: 150 + to: 200 + duration: 2000 + loops: Animation.Infinite + } + clip: true + Rectangle { + color: "lightGreen" + width: 50 + height: 50 + x: 75 + y: 75 + } + } + } + } + + // Clip using scissor + Row { + spacing: 10 + Repeater { + model: 5 + Rectangle { + color: "green" + width: 100 + height: 100 + y: 300 + NumberAnimation on y { + from: 300 + to: 400 + duration: 2000 + loops: Animation.Infinite + } + clip: true + Rectangle { + color: "lightGreen" + width: 50 + height: 50 + x: 75 + y: 75 + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + } + } + } + + // Clip using stencil + Row { + spacing: 10 + Repeater { + model: 5 + Rectangle { + color: "green" + width: 100 + height: 100 + y: 450 + NumberAnimation on y { + from: 450 + to: 550 + duration: 2000 + loops: Animation.Infinite + } + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + clip: true + Rectangle { + color: "lightGreen" + width: 50 + height: 50 + x: 75 + y: 75 + } + } + } + } + + // The signature red square with another item with animated opacity blended on top + Rectangle { + width: 100 + height: 100 + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + + Rectangle { + color: "gray" + width: 50 + height: 50 + anchors.centerIn: parent + + SequentialAnimation on opacity { + loops: Animation.Infinite + NumberAnimation { + from: 1.0 + to: 0.0 + duration: 4000 + } + NumberAnimation { + from: 0.0 + to: 1.0 + duration: 4000 + easing.type: Easing.InOutQuad + } + } + } + } + + // Animated size and color. + // NB! Causes a full buffer rebuild on every animated change due to the geometry change! + Rectangle { + anchors.right: parent.right + anchors.bottom: parent.bottom + width: 10 + height: 100 + ColorAnimation on color { + from: "blue" + to: "purple" + duration: 5000 + loops: Animation.Infinite + } + NumberAnimation on width { + from: 10 + to: 300 + duration: 5000 + loops: Animation.Infinite + } + } + + // Semi-transparent rect on top. + Rectangle { + anchors.centerIn: parent + opacity: 0.2 + color: "black" + anchors.fill: parent + anchors.margins: 10 + } + } +} diff --git a/tests/manual/nodetypes/Painter.qml b/tests/manual/nodetypes/Painter.qml new file mode 100644 index 0000000000..a5973379f4 --- /dev/null +++ b/tests/manual/nodetypes/Painter.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import Stuff 1.0 + +Item { + ListModel { + id: balloonModel + ListElement { + balloonWidth: 200 + } + ListElement { + balloonWidth: 120 + } + ListElement { + balloonWidth: 120 + } + ListElement { + balloonWidth: 120 + } + ListElement { + balloonWidth: 120 + } + } + + ListView { + anchors.fill: parent + anchors.margins: 10 + id: balloonView + model: balloonModel + spacing: 5 + delegate: TextBalloon { + anchors.right: index % 2 == 0 ? undefined : parent.right + height: 60 + rightAligned: index % 2 == 0 ? false : true + width: balloonWidth + innerAnim: model.index === 1 + NumberAnimation on width { + from: 200 + to: 300 + duration: 5000 + running: model.index === 0 + } + } + } +} diff --git a/tests/manual/nodetypes/Rects.qml b/tests/manual/nodetypes/Rects.qml new file mode 100644 index 0000000000..0d3a8cd459 --- /dev/null +++ b/tests/manual/nodetypes/Rects.qml @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + Rectangle { + width: 100 + height: 100 + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + + Rectangle { + color: "gray" + width: 50 + height: 50 + anchors.centerIn: parent + + SequentialAnimation on opacity { + loops: Animation.Infinite + NumberAnimation { + from: 1.0 + to: 0.0 + duration: 4000 + } + NumberAnimation { + from: 0.0 + to: 1.0 + duration: 4000 + easing.type: Easing.InOutQuad + } + } + } + } + + Rectangle { + color: "green" + width: 100 + height: 200 + x: 0 + y: 0 + + NumberAnimation on x { + from: 0 + to: 300 + duration: 5000 + } + NumberAnimation on y { + from: 0 + to: 50 + duration: 2000 + } + + clip: true + Rectangle { + color: "lightGreen" + width: 50 + height: 50 + x: 75 + y: 175 + } + } + + Rectangle { + color: "blue" + width: 200 + height: 100 + x: 100 + y: 300 + radius: 16 + border.color: "red" + border.width: 4 + + SequentialAnimation on y { + loops: Animation.Infinite + NumberAnimation { + from: 300 + to: 500 + duration: 7000 + } + NumberAnimation { + from: 500 + to: 300 + duration: 3000 + } + } + } + + Rectangle { + anchors.right: parent.right + width: 100 + height: 100 + gradient: Gradient { + GradientStop { position: 0.0; color: "red" } + GradientStop { position: 0.33; color: "yellow" } + GradientStop { position: 1.0; color: "green" } + } + } +} diff --git a/tests/manual/nodetypes/Text.qml b/tests/manual/nodetypes/Text.qml new file mode 100644 index 0000000000..fb0c92cb10 --- /dev/null +++ b/tests/manual/nodetypes/Text.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + Text { + id: text1 + anchors.top: parent.top + text: "árvíztűrő tükörfúrógép\nÁRVÍZTŰRŐ TÜKÖRFÚRÓGÉP" + } + Text { + anchors.bottom: parent.bottom + text: "the quick brown fox jumps over the lazy dog\nTHE QUICK BROWN FOX JUMPS OVER THE LAZY DOG" + color: "red" + } + Text { + anchors.centerIn: parent + text: "rotate rotate rotate" + font.bold: true + font.pointSize: 20 + color: "green" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + + Row { + anchors.top: text1.bottom + anchors.margins: 10 + Text { font.pointSize: 24; text: "Normal" } + Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" } + Text { font.pointSize: 24; text: "Outline"; style: Text.Outline; styleColor: "red" } + Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" } + } +} diff --git a/tests/manual/nodetypes/face-smile.png b/tests/manual/nodetypes/face-smile.png Binary files differnew file mode 100644 index 0000000000..3d66d72578 --- /dev/null +++ b/tests/manual/nodetypes/face-smile.png diff --git a/tests/manual/nodetypes/hlslcompile.bat b/tests/manual/nodetypes/hlslcompile.bat new file mode 100644 index 0000000000..b24824e324 --- /dev/null +++ b/tests/manual/nodetypes/hlslcompile.bat @@ -0,0 +1,4 @@ +fxc /E VS_Wobble /T vs_5_0 /Fo vs_wobble.cso wobble.hlsl +fxc /E PS_Wobble /T ps_5_0 /Fo ps_wobble.cso wobble.hlsl +fxc /E PS_Shadow1 /T ps_5_0 /Fo ps_shadow1.cso shadow1.hlsl +fxc /E PS_Shadow2 /T ps_5_0 /Fo ps_shadow2.cso shadow2.hlsl diff --git a/tests/manual/nodetypes/main.qml b/tests/manual/nodetypes/main.qml new file mode 100644 index 0000000000..a9fe09972c --- /dev/null +++ b/tests/manual/nodetypes/main.qml @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + focus: true + + Loader { + anchors.fill: parent + id: loader + } + + Keys.onPressed: { + if (event.key === Qt.Key_S) + loader.source = ""; + + if (event.key === Qt.Key_R) + loader.source = "qrc:/Rects.qml"; + if (event.key === Qt.Key_4) + loader.source = "qrc:/LotsOfRects.qml"; + + if (event.key === Qt.Key_I) + loader.source = "qrc:/Images.qml"; + if (event.key === Qt.Key_5) + loader.source = "qrc:/LotsOfImages.qml"; + + if (event.key === Qt.Key_T) + loader.source = "qrc:/Text.qml"; + + if (event.key === Qt.Key_A) + loader.source = "qrc:/Animators.qml"; + + if (event.key === Qt.Key_L) + loader.source = "qrc:/Layers.qml"; + + if (event.key === Qt.Key_E) + loader.source = "qrc:/Effects.qml"; + + if (event.key === Qt.Key_P) + loader.source = "qrc:/Painter.qml"; + + if (event.key === Qt.Key_G) + helper.testGrab() + } +} diff --git a/tests/manual/nodetypes/nodetypes.cpp b/tests/manual/nodetypes/nodetypes.cpp new file mode 100644 index 0000000000..c5382bab4a --- /dev/null +++ b/tests/manual/nodetypes/nodetypes.cpp @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QThread> +#include <QQuickView> +#include <QQmlEngine> +#include <QQmlContext> +#include <QQuickPaintedItem> +#include <QPainter> +#include <QTimer> + +class TextBalloon : public QQuickPaintedItem +{ + Q_OBJECT + Q_PROPERTY(bool rightAligned READ isRightAligned WRITE setRightAligned NOTIFY rightAlignedChanged) + Q_PROPERTY(bool innerAnim READ innerAnimEnabled WRITE setInnerAnimEnabled NOTIFY innerAnimChanged) + +public: + TextBalloon(QQuickItem *parent = nullptr) : QQuickPaintedItem(parent) { + connect(&m_timer, &QTimer::timeout, this, &TextBalloon::onAnim); + m_timer.setInterval(500); + } + void paint(QPainter *painter); + + bool isRightAligned() { return m_rightAligned; } + void setRightAligned(bool rightAligned); + + bool innerAnimEnabled() const { return m_innerAnim; } + void setInnerAnimEnabled(bool b); + +signals: + void rightAlignedChanged(); + void innerAnimChanged(); + +private slots: + void onAnim(); + +private: + bool m_rightAligned = false; + bool m_innerAnim = false; + QTimer m_timer; + QRect m_animRect = QRect(10, 10, 50, 20); + int m_anim = 0; +}; + +void TextBalloon::paint(QPainter *painter) +{ + QBrush brush(QColor("#007430")); + + painter->setBrush(brush); + painter->setPen(Qt::NoPen); + painter->setRenderHint(QPainter::Antialiasing); + + painter->drawRoundedRect(0, 0, boundingRect().width(), boundingRect().height() - 10, 10, 10); + + if (m_rightAligned) { + const QPointF points[3] = { + QPointF(boundingRect().width() - 10.0, boundingRect().height() - 10.0), + QPointF(boundingRect().width() - 20.0, boundingRect().height()), + QPointF(boundingRect().width() - 30.0, boundingRect().height() - 10.0), + }; + painter->drawConvexPolygon(points, 3); + } else { + const QPointF points[3] = { + QPointF(10.0, boundingRect().height() - 10.0), + QPointF(20.0, boundingRect().height()), + QPointF(30.0, boundingRect().height() - 10.0), + }; + painter->drawConvexPolygon(points, 3); + } + + if (m_innerAnim) { + painter->fillRect(m_animRect, Qt::lightGray); + const int x = m_animRect.x() + m_anim; + const int y = m_animRect.y() + m_animRect.height() / 2; + painter->setPen(QPen(QBrush(Qt::SolidLine), 4)); + painter->drawLine(x + 4, y, x + 10, y); + m_anim += 10; + if (m_anim > m_animRect.width()) + m_anim = 0; + } +} + +void TextBalloon::setRightAligned(bool rightAligned) +{ + if (m_rightAligned == rightAligned) + return; + + m_rightAligned = rightAligned; + emit rightAlignedChanged(); +} + +void TextBalloon::setInnerAnimEnabled(bool b) +{ + if (m_innerAnim == b) + return; + + m_innerAnim = b; + if (!b) + m_timer.stop(); + else + m_timer.start(); + emit innerAnimChanged(); +} + +void TextBalloon::onAnim() +{ + update(m_animRect); +} + +class Helper : public QObject +{ + Q_OBJECT + +public: + Helper(QQuickWindow *w) : m_window(w) { } + + Q_INVOKABLE void sleep(int ms) { + QThread::msleep(ms); + } + + Q_INVOKABLE void testGrab() { + QImage img = m_window->grabWindow(); + qDebug() << "Saving image to grab_result.png" << img; + img.save("grab_result.png"); + } + + QQuickWindow *m_window; +}; + +int main(int argc, char **argv) +{ + qputenv("QT_QUICK_BACKEND", "d3d12"); + + QGuiApplication app(argc, argv); + + qDebug("Available tests:"); + qDebug(" [R] - Rectangles"); + qDebug(" [4] - A lot of rectangles"); + qDebug(" [I] - Images"); + qDebug(" [5] - A lot of async images"); + qDebug(" [T] - Text"); + qDebug(" [A] - Render thread Animator"); + qDebug(" [L] - Layers"); + qDebug(" [E] - Effects"); + qDebug(" [P] - QQuickPaintedItem"); + qDebug(" [G] - Grab current window"); + qDebug("\nPress S to stop the currently running test\n"); + + QQuickView view; + Helper helper(&view); + if (app.arguments().contains(QLatin1String("--multisample"))) { + qDebug("Requesting sample count 4"); + QSurfaceFormat fmt; + fmt.setSamples(4); + view.setFormat(fmt); + } + view.engine()->rootContext()->setContextProperty(QLatin1String("helper"), &helper); + qmlRegisterType<TextBalloon>("Stuff", 1, 0, "TextBalloon"); + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.resize(1024, 768); + view.setSource(QUrl("qrc:/main.qml")); + view.show(); + + return app.exec(); +} + +#include "nodetypes.moc" diff --git a/tests/manual/nodetypes/nodetypes.pro b/tests/manual/nodetypes/nodetypes.pro new file mode 100644 index 0000000000..959b43cf18 --- /dev/null +++ b/tests/manual/nodetypes/nodetypes.pro @@ -0,0 +1,9 @@ +QT += qml quick + +SOURCES += nodetypes.cpp + +RESOURCES += nodetypes.qrc + +OTHER_FILES += main.qml Rects.qml LotsOfRects.qml \ + Images.qml LotsOfImages.qml Text.qml Animators.qml Layers.qml Effects.qml Painter.qml \ + wobble.hlsl shadow1.hlsl shadow2.hlsl diff --git a/tests/manual/nodetypes/nodetypes.qrc b/tests/manual/nodetypes/nodetypes.qrc new file mode 100644 index 0000000000..78c0d085a1 --- /dev/null +++ b/tests/manual/nodetypes/nodetypes.qrc @@ -0,0 +1,21 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + <file>Rects.qml</file> + <file>LotsOfRects.qml</file> + <file>Images.qml</file> + <file>LotsOfImages.qml</file> + <file>Text.qml</file> + <file>Animators.qml</file> + <file>Layers.qml</file> + <file>Effects.qml</file> + <file>Painter.qml</file> + <file>qt.png</file> + <file>face-smile.png</file> + <file>shadow.png</file> + <file>vs_wobble.cso</file> + <file>ps_wobble.cso</file> + <file>ps_shadow1.cso</file> + <file>ps_shadow2.cso</file> + </qresource> +</RCC> diff --git a/tests/manual/nodetypes/ps_shadow1.cso b/tests/manual/nodetypes/ps_shadow1.cso Binary files differnew file mode 100644 index 0000000000..b6fbe3f3c2 --- /dev/null +++ b/tests/manual/nodetypes/ps_shadow1.cso diff --git a/tests/manual/nodetypes/ps_shadow2.cso b/tests/manual/nodetypes/ps_shadow2.cso Binary files differnew file mode 100644 index 0000000000..ab8cb63f34 --- /dev/null +++ b/tests/manual/nodetypes/ps_shadow2.cso diff --git a/tests/manual/nodetypes/ps_wobble.cso b/tests/manual/nodetypes/ps_wobble.cso Binary files differnew file mode 100644 index 0000000000..4e5b6a27f4 --- /dev/null +++ b/tests/manual/nodetypes/ps_wobble.cso diff --git a/tests/manual/nodetypes/qt.png b/tests/manual/nodetypes/qt.png Binary files differnew file mode 100644 index 0000000000..f30eec0d4d --- /dev/null +++ b/tests/manual/nodetypes/qt.png diff --git a/tests/manual/nodetypes/shadow.png b/tests/manual/nodetypes/shadow.png Binary files differnew file mode 100644 index 0000000000..8270565e87 --- /dev/null +++ b/tests/manual/nodetypes/shadow.png diff --git a/tests/manual/nodetypes/shadow1.hlsl b/tests/manual/nodetypes/shadow1.hlsl new file mode 100644 index 0000000000..ff3f4b6fd5 --- /dev/null +++ b/tests/manual/nodetypes/shadow1.hlsl @@ -0,0 +1,18 @@ +cbuffer ConstantBuffer : register(b0) +{ + float4x4 qt_Matrix; + float qt_Opacity; + float2 delta; +}; + +Texture2D source : register(t0); +SamplerState sourceSampler : register(s0); + +float4 PS_Shadow1(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET +{ + return (0.0538 * source.Sample(sourceSampler, coord - 3.182 * delta) + + 0.3229 * source.Sample(sourceSampler, coord - 1.364 * delta) + + 0.2466 * source.Sample(sourceSampler, coord) + + 0.3229 * source.Sample(sourceSampler, coord + 1.364 * delta) + + 0.0538 * source.Sample(sourceSampler, coord + 3.182 * delta)) * qt_Opacity; +} diff --git a/tests/manual/nodetypes/shadow2.hlsl b/tests/manual/nodetypes/shadow2.hlsl new file mode 100644 index 0000000000..eaa30cd988 --- /dev/null +++ b/tests/manual/nodetypes/shadow2.hlsl @@ -0,0 +1,22 @@ +cbuffer ConstantBuffer : register(b0) +{ + float4x4 qt_Matrix; + float qt_Opacity; + float2 offset; + float darkness; + float2 delta; +}; + +Texture2D source : register(t0); +Texture2D shadow : register(t1); +SamplerState samp : register(s0); +// Use the same sampler for both textures. In fact the engine will create an extra static sampler +// in any case (to match the number of textures) due to some internals, but that won't hurt, the +// shader works either way. + +float4 PS_Shadow2(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET +{ + float4 fg = source.Sample(samp, coord); + float4 bg = shadow.Sample(samp, coord + delta); + return (fg + float4(0.0, 0.0, 0.0, darkness * bg.a) * (1.0 - fg.a)) * qt_Opacity; +} diff --git a/tests/manual/nodetypes/vs_wobble.cso b/tests/manual/nodetypes/vs_wobble.cso Binary files differnew file mode 100644 index 0000000000..f3a2596457 --- /dev/null +++ b/tests/manual/nodetypes/vs_wobble.cso diff --git a/tests/manual/nodetypes/wobble.hlsl b/tests/manual/nodetypes/wobble.hlsl new file mode 100644 index 0000000000..203dbda7f2 --- /dev/null +++ b/tests/manual/nodetypes/wobble.hlsl @@ -0,0 +1,32 @@ +cbuffer ConstantBuffer : register(b0) +{ + float4x4 qt_Matrix; + float qt_Opacity; + + float amplitude; + float frequency; + float time; +}; + +struct PSInput +{ + float4 position : SV_POSITION; + float2 coord : TEXCOORD0; +}; + +PSInput VS_Wobble(float4 position : POSITION, float2 coord : TEXCOORD0) +{ + PSInput result; + result.position = mul(qt_Matrix, position); + result.coord = coord; + return result; +} + +Texture2D source : register(t0); +SamplerState sourceSampler : register(s0); + +float4 PS_Wobble(PSInput input) : SV_TARGET +{ + float2 p = sin(time + frequency * input.coord); + return source.Sample(sourceSampler, input.coord + amplitude * float2(p.y, -p.x)) * qt_Opacity; +} diff --git a/tests/manual/qmlplugindump/tst_qmlplugindump.cpp b/tests/manual/qmlplugindump/tst_qmlplugindump.cpp index ed00682a83..1bedd4427b 100644 --- a/tests/manual/qmlplugindump/tst_qmlplugindump.cpp +++ b/tests/manual/qmlplugindump/tst_qmlplugindump.cpp @@ -92,7 +92,7 @@ public: { QRegularExpression re; QRegularExpressionMatch m; - Q_FOREACH (const QString &e, m_expected) { + for (const QString &e : m_expected) { re.setPattern(e); m = re.match(QString::fromLatin1(buffer)); if (!m.hasMatch()) { @@ -187,7 +187,8 @@ Test createTest(const QString &id, const QJsonObject &def) return Test(id); } QStringList patterns; - Q_FOREACH (const QJsonValue &x, expected.toArray()) { + const auto expectedArray = expected.toArray(); + for (const QJsonValue &x : expectedArray) { if (!x.isString()) { qWarning() << "Wrong definition for test: " << id << "."; return Test(id); @@ -331,7 +332,7 @@ void tst_qmlplugindump::plugin_data() QTest::addColumn<QString>("version"); QTest::addColumn<QStringList>("expected"); - Q_FOREACH (const Test &t, tests) { + for (const Test &t : qAsConst(tests)) { if (t.isNull()) QSKIP("Errors in test definition."); QTest::newRow(t.id.toLatin1().data()) << t.project << t.version << t.expected; @@ -357,9 +358,9 @@ void tst_qmlplugindump::plugin() void tst_qmlplugindump::cleanupTestCase() { QSet<const QString> projects; - Q_FOREACH (const Test &t, tests) + for (const Test &t : qAsConst(tests)) projects.insert(t.project); - Q_FOREACH (const QString &p, projects) { + for (const QString &p : qAsConst(projects)) { if (!cleanUpSample(p)) qWarning() << "Error in cleaning up project" << p << "."; } diff --git a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp index 5098d51134..886cfc6599 100644 --- a/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp +++ b/tests/manual/scenegraph_lancelot/scenegrabber/main.cpp @@ -183,8 +183,8 @@ int main(int argc, char *argv[]) v.setSource(QUrl::fromLocalFile(ifile)); if (noText) { - QList<QQuickItem*> items = v.rootObject()->findChildren<QQuickItem*>(); - foreach (QQuickItem *item, items) { + const QList<QQuickItem*> items = v.rootObject()->findChildren<QQuickItem*>(); + for (QQuickItem *item : items) { if (QByteArray(item->metaObject()->className()).contains("Text")) item->setVisible(false); } diff --git a/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp b/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp index 426e06ccc2..3f28d90e7b 100644 --- a/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp +++ b/tests/manual/scenegraph_lancelot/scenegraph/tst_scenegraph.cpp @@ -156,7 +156,7 @@ void tst_Scenegraph::setupTestSuite(const QByteArray& filter) } std::sort(itemFiles.begin(), itemFiles.end()); - foreach (const QString &filePath, itemFiles) { + for (const QString &filePath : qAsConst(itemFiles)) { QByteArray itemName = filePath.mid(testSuitePath.length() + 1).toLatin1(); QBaselineTest::newRow(itemName, checksumFileOrDir(filePath)) << filePath; numItems++; @@ -238,7 +238,9 @@ quint16 tst_Scenegraph::checksumFileOrDir(const QString &path) if (fi.isDir()) { static const QStringList nameFilters = QStringList() << "*.qml" << "*.cpp" << "*.png" << "*.jpg"; quint16 cs = 0; - foreach (QString item, QDir(fi.filePath()).entryList(nameFilters, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) + const auto entryList = QDir(fi.filePath()).entryList(nameFilters, + QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + for (const QString &item : entryList) cs ^= checksumFileOrDir(path + QLatin1Char('/') + item); return cs; } |