diff options
Diffstat (limited to 'tests/auto')
180 files changed, 4843 insertions, 538 deletions
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index b72a43d742..556f5ddc7a 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -8,12 +8,15 @@ SUBDIRS=\ installed_cmake \ toolsupport -qtHaveModule(gui):contains(QT_CONFIG, opengl(es1|es2)?) { +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/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/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/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index c1de5ff594..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))); @@ -588,12 +609,11 @@ void tst_QQmlProfilerService::scenegraphData() checkTraceReceived(); checkJsHeap(); - - // check that at least one frame was rendered - // there should be a SGPolishAndSync + SGRendererFrame + SGRenderLoopFrame sequence - // (though we can't be sure to get the SGRenderLoopFrame in the threaded renderer) + // Check that at least one frame was rendered. + // There should be a SGContextFrame + SGRendererFrame + SGRenderLoopFrame sequence, + // but we can't be sure to get the SGRenderLoopFrame in the threaded renderer. // - // since the rendering happens in a different thread, there could be other unrelated events + // Since the rendering happens in a different thread, there could be other unrelated events // interleaved. Also, events could carry the same time stamps and be sorted in an unexpected way // if the clocks are acting up. qint64 contextFrameTime = -1; @@ -622,8 +642,13 @@ void tst_QQmlProfilerService::scenegraphData() foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { if (msg.detailType == QQmlProfilerDefinitions::SceneGraphRenderLoopFrame) { - QVERIFY(msg.time >= renderFrameTime); - break; + if (msg.time >= contextFrameTime) { + // Make sure SceneGraphRenderLoopFrame is not between SceneGraphContextFrame and + // SceneGraphRendererFrame. A SceneGraphRenderLoopFrame before everything else is + // OK as the scene graph might decide to do an initial rendering. + QVERIFY(msg.time >= renderFrameTime); + break; + } } } } 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 99c18f91a1..f4eb17f1ca 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(); @@ -188,6 +189,8 @@ private slots: void v4FunctionWithoutQML(); + void withNoContext(); + signals: void testSignal(); }; @@ -712,6 +715,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; @@ -1343,6 +1444,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; @@ -2040,18 +2142,42 @@ void tst_QJSEngine::jsNumberClass() QJSValue ret = eng.evaluate("new Number(123).toExponential()"); QVERIFY(ret.isString()); QCOMPARE(ret.toString(), QString::fromLatin1("1.23e+2")); + ret = eng.evaluate("new Number(123).toExponential(1)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("1.2e+2")); + ret = eng.evaluate("new Number(123).toExponential(2)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("1.23e+2")); + ret = eng.evaluate("new Number(123).toExponential(3)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("1.230e+2")); } QVERIFY(proto.property("toFixed").isCallable()); { QJSValue ret = eng.evaluate("new Number(123).toFixed()"); QVERIFY(ret.isString()); QCOMPARE(ret.toString(), QString::fromLatin1("123")); + ret = eng.evaluate("new Number(123).toFixed(1)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("123.0")); + ret = eng.evaluate("new Number(123).toFixed(2)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("123.00")); } QVERIFY(proto.property("toPrecision").isCallable()); { QJSValue ret = eng.evaluate("new Number(123).toPrecision()"); QVERIFY(ret.isString()); QCOMPARE(ret.toString(), QString::fromLatin1("123")); + ret = eng.evaluate("new Number(42).toPrecision(1)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("4e+1")); + ret = eng.evaluate("new Number(42).toPrecision(2)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("42")); + ret = eng.evaluate("new Number(42).toPrecision(3)"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("42.0")); } } @@ -3886,6 +4012,13 @@ void tst_QJSEngine::v4FunctionWithoutQML() QVERIFY(obj.called); } +void tst_QJSEngine::withNoContext() +{ + // Don't crash (QTBUG-53794) + QJSEngine engine; + engine.evaluate("with (noContext) true"); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" 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/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/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index e0cde6c86f..f49fd391ac 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -61,6 +61,7 @@ private slots: void qtbug_22535(); void evalAfterInvalidate(); void qobjectDerived(); + void qtbug_49232(); private: QQmlEngine engine; @@ -200,6 +201,8 @@ class TestObject : public QObject Q_PROPERTY(int a READ a NOTIFY aChanged) Q_PROPERTY(int b READ b NOTIFY bChanged) Q_PROPERTY(int c READ c NOTIFY cChanged) + Q_PROPERTY(char d READ d NOTIFY dChanged) + Q_PROPERTY(uchar e READ e NOTIFY eChanged) public: TestObject() : _a(10), _b(10), _c(10) {} @@ -213,15 +216,25 @@ public: int c() const { return _c; } void setC(int c) { _c = c; emit cChanged(); } + char d() const { return _d; } + void setD(char d) { _d = d; emit dChanged(); } + + uchar e() const { return _e; } + void setE(uchar e) { _e = e; emit eChanged(); } + signals: void aChanged(); void bChanged(); void cChanged(); + void dChanged(); + void eChanged(); private: int _a; int _b; int _c; + char _d; + uchar _e; }; #define TEST_CONTEXT_PROPERTY(ctxt, name, value) \ @@ -694,6 +707,22 @@ void tst_qqmlcontext::qobjectDerived() QCOMPARE(command.count, 2); } +void tst_qqmlcontext::qtbug_49232() +{ + TestObject testObject; + testObject.setD('a'); + testObject.setE(97); + + QQmlEngine engine; + engine.rootContext()->setContextProperty("TestObject", &testObject); + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0; QtObject { property int valueOne: TestObject.d; property int valueTwo: TestObject.e }", QUrl()); + QScopedPointer<QObject> obj(component.create()); + + QCOMPARE(obj->property("valueOne"), QVariant('a')); + QCOMPARE(obj->property("valueTwo"), QVariant(97)); +} + QTEST_MAIN(tst_qqmlcontext) #include "tst_qqmlcontext.moc" diff --git a/tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml b/tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml new file mode 100644 index 0000000000..8bb0a3554e --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/DestructionHelper.qml @@ -0,0 +1,3 @@ +import Test 1.0 +WeakReferenceMutator { +} 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/data/qtbug_54589.qml b/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml new file mode 100644 index 0000000000..8f7d5f2a70 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/qtbug_54589.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +QtObject { + function checkPropertyDeletion() { + var o = { + x: 1, + y: 2 + }; + o.z = 3 + delete o.y; + + return (o.x === 1 && o.y === undefined && o.z === 3) + } + + property bool result: checkPropertyDeletion() +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 2f78df1f11..c734a0a011 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -44,6 +44,8 @@ #include <private/qv4scopedvalue_p.h> #include <private/qv4alloca_p.h> #include <private/qv4runtime_p.h> +#include <private/qv4object_p.h> +#include <private/qqmlcomponentattached_p.h> #ifdef Q_CC_MSVC #define NO_INLINE __declspec(noinline) @@ -82,6 +84,7 @@ private slots: void arrayExpressions(); void contextPropertiesTriggerReeval(); void objectPropertiesTriggerReeval(); + void dependenciesWithFunctions(); void deferredProperties(); void deferredPropertiesErrors(); void deferredPropertiesInComponents(); @@ -208,6 +211,7 @@ private slots: void dynamicCreationOwnership(); void regExpBug(); void nullObjectBinding(); + void nullObjectInitializer(); void deletedEngine(); void libraryScriptAssert(); void variantsAssignedUndefined(); @@ -282,6 +286,7 @@ private slots: void replaceBinding(); void deleteRootObjectInCreation(); void onDestruction(); + void onDestructionViaGC(); void bindingSuppression(); void signalEmitted(); void threadSignal(); @@ -323,6 +328,8 @@ private slots: void switchExpression(); void qtbug_46022(); void qtbug_52340(); + void qtbug_54589(); + void qtbug_54687(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -875,6 +882,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")); @@ -2312,7 +2331,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; @@ -2338,16 +2357,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::method_strictEqual(value, result); + return QV4::Runtime::method_strictEqual(scope.result, result); } static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o, @@ -2371,12 +2389,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) @@ -5708,6 +5726,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() { @@ -5769,7 +5830,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); @@ -7155,6 +7216,105 @@ void tst_qqmlecmascript::onDestruction() } } +class WeakReferenceMutator : public QObject +{ + Q_OBJECT +public: + WeakReferenceMutator() + : resultPtr(Q_NULLPTR) + , weakRef(Q_NULLPTR) + {} + + void init(QV4::ExecutionEngine *v4, QV4::WeakValue *weakRef, bool *resultPtr) + { + QV4::QObjectWrapper::wrap(v4, this); + QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); + + this->resultPtr = resultPtr; + this->weakRef = weakRef; + + QObject::connect(QQmlComponent::qmlAttachedProperties(this), &QQmlComponentAttached::destruction, this, &WeakReferenceMutator::reviveFirstWeakReference); + } + +private slots: + void reviveFirstWeakReference() { + *resultPtr = weakRef->valueRef() && weakRef->isNullOrUndefined(); + if (!*resultPtr) + return; + QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(this)); + weakRef->set(v4, v4->newObject()); + *resultPtr = weakRef->valueRef() && !weakRef->isNullOrUndefined(); + } + +public: + bool *resultPtr; + + QV4::WeakValue *weakRef; +}; + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +namespace Heap { +struct WeakReferenceSentinel : public Object { + WeakReferenceSentinel(WeakValue *weakRef, bool *resultPtr) + : weakRef(weakRef) + , resultPtr(resultPtr) { + + } + + ~WeakReferenceSentinel() { + *resultPtr = weakRef->isNullOrUndefined(); + } + + WeakValue *weakRef; + bool *resultPtr; +}; +} // namespace Heap + +struct WeakReferenceSentinel : public Object { + V4_OBJECT2(WeakReferenceSentinel, Object) + V4_NEEDS_DESTROY +}; + +} // namespace QV4 + +QT_END_NAMESPACE + +DEFINE_OBJECT_VTABLE(QV4::WeakReferenceSentinel); + +void tst_qqmlecmascript::onDestructionViaGC() +{ + qmlRegisterType<WeakReferenceMutator>("Test", 1, 0, "WeakReferenceMutator"); + + QQmlEngine engine; + QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine); + + QQmlComponent component(&engine, testFileUrl("DestructionHelper.qml")); + + QScopedPointer<QV4::WeakValue> weakRef; + + bool mutatorResult = false; + bool sentinelResult = false; + + { + weakRef.reset(new QV4::WeakValue); + weakRef->set(v4, v4->newObject()); + QVERIFY(!weakRef->isNullOrUndefined()); + + QPointer<WeakReferenceMutator> weakReferenceMutator = qobject_cast<WeakReferenceMutator *>(component.create()); + QVERIFY2(!weakReferenceMutator.isNull(), qPrintable(component.errorString())); + weakReferenceMutator->init(v4, weakRef.data(), &mutatorResult); + + v4->memoryManager->allocObject<QV4::WeakReferenceSentinel>(weakRef.data(), &sentinelResult); + } + gc(engine); + + QVERIFY2(mutatorResult, "We failed to re-assign the weak reference a new value during GC"); + QVERIFY2(sentinelResult, "The weak reference was not cleared properly"); +} + struct EventProcessor : public QObject { Q_OBJECT @@ -7425,8 +7585,11 @@ void tst_qqmlecmascript::negativeYear() QVariant q; QMetaObject::invokeMethod(object, "check_negative_tostring", Q_RETURN_ARG(QVariant, q)); - // Strip the timezone. It should be irrelevant as the date was created with the same one. - QCOMPARE(q.toString().left(32), QStringLiteral("result: Sat Jan 1 00:00:00 -2001")); + + // Only check for the year. We hope that every language writes the year in arabic numerals and + // in relation to a specific dude's date of birth. We also hope that no language adds a "-2001" + // junk string somewhere in the middle. + QVERIFY(q.toString().indexOf(QStringLiteral("-2001")) != -1); QMetaObject::invokeMethod(object, "check_negative_toisostring", Q_RETURN_ARG(QVariant, q)); QCOMPARE(q.toString().left(16), QStringLiteral("result: -002000-")); @@ -7922,6 +8085,22 @@ void tst_qqmlecmascript::qtbug_52340() QVERIFY(returnValue.toBool()); } +void tst_qqmlecmascript::qtbug_54589() +{ + QQmlComponent component(&engine, testFileUrl("qtbug_54589.qml")); + + QScopedPointer<QObject> obj(component.create()); + QVERIFY(obj != 0); + QCOMPARE(obj->property("result").toBool(), true); +} + +void tst_qqmlecmascript::qtbug_54687() +{ + QJSEngine e; + // it's simple: this shouldn't crash. + engine.evaluate("12\n----12"); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index 3af1cf46b3..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(); } diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp index ab5e958323..124a107a37 100644 --- a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp +++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp @@ -80,6 +80,10 @@ void tst_qqmlextensionplugin::iidCheck_data() QList<QString> files; for (QDirIterator it(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath), QDirIterator::Subdirectories); it.hasNext(); ) { QString file = it.next(); +#if defined(Q_OS_DARWIN) + if (file.contains(QLatin1String(".dSYM/"))) + continue; +#endif if (file.endsWith(SUFFIX)) { files << file; } @@ -105,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/assignBasicTypes.qml b/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml index c91cf581b3..52027232db 100644 --- a/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml +++ b/tests/auto/qml/qqmllanguage/data/assignBasicTypes.qml @@ -26,7 +26,9 @@ MyTypeObject { boolProperty: true variantProperty: "Hello World!" vectorProperty: "10,1,2.2" + vector2Property: "2, 3" vector4Property: "10,1,2.2,2.3" + quaternionProperty: "4,5,6,7" urlProperty: "main.qml?with%3cencoded%3edata" objectProperty: MyTypeObject { intProperty: 8 } 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/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/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index ccfcfc098e..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"); @@ -131,9 +130,10 @@ void CustomBinding::componentComplete() QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, compilationUnit->runtimeFunctions[bindingId])); - QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context); 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); } diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 788ae42726..6c62bcf7b9 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -33,15 +33,16 @@ #include <QtCore/qdatetime.h> #include <QtGui/qmatrix.h> #include <QtGui/qcolor.h> +#include <QtGui/qvector2d.h> #include <QtGui/qvector3d.h> #include <QtGui/qvector4d.h> +#include <QtGui/qquaternion.h> #include <QtQml/qqml.h> #include <QtQml/qqmlcomponent.h> #include <QtQml/qqmlparserstatus.h> #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); @@ -242,8 +243,10 @@ class MyTypeObject : public QObject Q_PROPERTY(QRectF rectFProperty READ rectFProperty WRITE setRectFProperty NOTIFY rectFPropertyChanged) Q_PROPERTY(bool boolProperty READ boolProperty WRITE setBoolProperty NOTIFY boolPropertyChanged) Q_PROPERTY(QVariant variantProperty READ variantProperty WRITE setVariantProperty NOTIFY variantPropertyChanged) + Q_PROPERTY(QVector2D vector2Property READ vector2Property WRITE setVector2Property NOTIFY vector2PropertyChanged) Q_PROPERTY(QVector3D vectorProperty READ vectorProperty WRITE setVectorProperty NOTIFY vectorPropertyChanged) Q_PROPERTY(QVector4D vector4Property READ vector4Property WRITE setVector4Property NOTIFY vector4PropertyChanged) + Q_PROPERTY(QQuaternion quaternionProperty READ quaternionProperty WRITE setQuaternionProperty NOTIFY quaternionPropertyChanged) Q_PROPERTY(QUrl urlProperty READ urlProperty WRITE setUrlProperty NOTIFY urlPropertyChanged) Q_PROPERTY(QQmlScriptString scriptProperty READ scriptProperty WRITE setScriptProperty) @@ -524,6 +527,15 @@ public: emit vectorPropertyChanged(); } + QVector2D vector2PropertyValue; + QVector2D vector2Property() const { + return vector2PropertyValue; + } + void setVector2Property(const QVector2D &v) { + vector2PropertyValue = v; + emit vector2PropertyChanged(); + } + QVector4D vector4PropertyValue; QVector4D vector4Property() const { return vector4PropertyValue; @@ -533,6 +545,15 @@ public: emit vector4PropertyChanged(); } + QQuaternion quaternionPropertyValue; + QQuaternion quaternionProperty() const { + return quaternionPropertyValue; + } + void setQuaternionProperty(const QQuaternion &v) { + quaternionPropertyValue = v; + emit quaternionPropertyChanged(); + } + QUrl urlPropertyValue; QUrl urlProperty() const { return urlPropertyValue; @@ -586,7 +607,9 @@ signals: void boolPropertyChanged(); void variantPropertyChanged(); void vectorPropertyChanged(); + void vector2PropertyChanged(); void vector4PropertyChanged(); + void quaternionPropertyChanged(); void urlPropertyChanged(); }; @@ -707,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 diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 58a7c39760..ad06946b0b 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -494,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; @@ -681,6 +682,7 @@ void tst_qqmllanguage::assignBasicTypes() QCOMPARE(object->boolProperty(), true); QCOMPARE(object->variantProperty(), QVariant("Hello World!")); QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2f)); + QCOMPARE(object->vector2Property(), QVector2D(2, 3)); QCOMPARE(object->vector4Property(), QVector4D(10, 1, 2.2f, 2.3f)); const QUrl encoded = QUrl::fromEncoded("main.qml?with%3cencoded%3edata", QUrl::TolerantMode); QCOMPARE(object->urlProperty(), component.url().resolved(encoded)); @@ -1803,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 @@ -2074,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; @@ -2552,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() @@ -2592,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 {}" << "" @@ -2898,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); @@ -4077,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() diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index b3d199f80f..cd497cbd79 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -105,6 +105,7 @@ private slots: void get_nested(); void get_nested_data(); void crash_model_with_multiple_roles(); + void crash_model_with_unknown_roles(); void set_model_cache(); void property_changes(); void property_changes_data(); @@ -963,6 +964,21 @@ void tst_qqmllistmodel::crash_model_with_multiple_roles() delete rootItem; } +void tst_qqmllistmodel::crash_model_with_unknown_roles() +{ + QQmlEngine eng; + QQmlComponent component(&eng, testFileUrl("multipleroles.qml")); + QScopedPointer<QObject> rootItem(component.create()); + QVERIFY(component.errorString().isEmpty()); + QVERIFY(rootItem != 0); + QQmlListModel *model = rootItem->findChild<QQmlListModel*>("listModel"); + QVERIFY(model != 0); + + // used to cause a crash in debug builds + model->index(0, 0, QModelIndex()).data(Qt::DisplayRole); + model->index(0, 0, QModelIndex()).data(Qt::UserRole); +} + //QTBUG-15190 void tst_qqmllistmodel::set_model_cache() { diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 5a8f2747a9..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; } @@ -326,11 +327,8 @@ class PropertyObject : public QObject Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject) Q_PROPERTY(MyQObject *qObject READ qObject WRITE setQObject NOTIFY qObjectChanged) Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty) - Q_PROPERTY(char charProperty READ charProperty WRITE setCharProperty) Q_PROPERTY(QChar qcharProperty READ qcharProperty WRITE setQcharProperty) Q_PROPERTY(QChar constQChar READ constQChar STORED false CONSTANT FINAL) - Q_PROPERTY(char constChar READ constChar STORED false CONSTANT FINAL) - Q_PROPERTY(int constInt READ constInt STORED false CONSTANT FINAL) Q_CLASSINFO("DefaultProperty", "defaultProperty") public: @@ -367,15 +365,11 @@ public: } QString stringProperty() const { return m_stringProperty;} - char charProperty() const { return m_charProperty; } QChar qcharProperty() const { return m_qcharProperty; } QChar constQChar() const { return 0x25cf; /* Unicode: black circle */ } - char constChar() const { return 'A'; } - int constInt() const { return 123456; } void setStringProperty(QString arg) { m_stringProperty = arg; } - void setCharProperty(char arg) { m_charProperty = arg; } void setQcharProperty(QChar arg) { m_qcharProperty = arg; } signals: @@ -392,7 +386,6 @@ private: MyQmlObject m_qmlObject; MyQObject *m_qObject; QString m_stringProperty; - char m_charProperty; QChar m_qcharProperty; }; @@ -406,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); @@ -445,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; } @@ -453,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); @@ -495,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; } @@ -509,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); @@ -548,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; } @@ -556,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); @@ -598,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; } @@ -606,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); @@ -647,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; } @@ -655,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); @@ -696,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; } @@ -710,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); @@ -749,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; } @@ -757,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); @@ -799,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; } @@ -813,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); @@ -852,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; } @@ -860,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); @@ -902,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; } @@ -910,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); @@ -951,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; } @@ -959,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); @@ -1000,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; } @@ -1405,23 +1410,14 @@ void tst_qqmlproperty::write() // Char/string-property { PropertyObject o; - QQmlProperty charProperty(&o, "charProperty"); QQmlProperty qcharProperty(&o, "qcharProperty"); QQmlProperty stringProperty(&o, "stringProperty"); const int black_circle = 0x25cf; - QCOMPARE(charProperty.write(QString("foo")), false); - QCOMPARE(charProperty.write('Q'), true); - QCOMPARE(charProperty.read(), QVariant('Q')); - QCOMPARE(charProperty.write(QString("t")), true); - QCOMPARE(charProperty.read(), QVariant('t')); - QCOMPARE(qcharProperty.write(QString("foo")), false); QCOMPARE(qcharProperty.write('Q'), true); QCOMPARE(qcharProperty.read(), QVariant('Q')); - QCOMPARE(qcharProperty.write(QString("t")), true); - QCOMPARE(qcharProperty.read(), QVariant('t')); QCOMPARE(qcharProperty.write(QChar(black_circle)), true); QCOMPARE(qcharProperty.read(), QVariant(QChar(black_circle))); @@ -1430,19 +1426,10 @@ void tst_qqmlproperty::write() QCOMPARE(o.stringProperty(), QString("bar")); QCOMPARE(stringProperty.write(QVariant(1234)), true); QCOMPARE(stringProperty.read().toString(), QString::number(1234)); + QCOMPARE(stringProperty.write('A'), true); + QCOMPARE(stringProperty.read().toString(), QString::number('A')); QCOMPARE(stringProperty.write(QChar(black_circle)), true); - QCOMPARE(stringProperty.read(), QVariant(QString(QChar(black_circle)))); - - { // char -> QString - QQmlComponent component(&engine); - component.setData("import Test 1.0\nPropertyObject { stringProperty: constChar }", QUrl()); - PropertyObject *obj = qobject_cast<PropertyObject*>(component.create()); - QVERIFY(obj != 0); - if (obj) { - QQmlProperty stringProperty(obj, "stringProperty"); - QCOMPARE(stringProperty.read(), QVariant(QString(obj->constChar()))); - } - } + QCOMPARE(stringProperty.read(), QVariant(QChar(black_circle))); { // QChar -> QString QQmlComponent component(&engine); @@ -1455,16 +1442,6 @@ void tst_qqmlproperty::write() } } - { // int -> QString - QQmlComponent component(&engine); - component.setData("import Test 1.0\nPropertyObject { stringProperty: constInt }", QUrl()); - PropertyObject *obj = qobject_cast<PropertyObject*>(component.create()); - QVERIFY(obj != 0); - if (obj) { - QQmlProperty stringProperty(obj, "stringProperty"); - QCOMPARE(stringProperty.read(), QVariant(QString::number(obj->constInt()))); - } - } } // VariantMap-property @@ -2078,15 +2055,15 @@ void tst_qqmlproperty::floatToStringPrecision() QFETCH(QString, qtString); QFETCH(QString, jsString); - const char *name = propertyName.toLatin1().constData(); + QByteArray name = propertyName.toLatin1(); QCOMPARE(obj->property(name).toDouble(), number); QCOMPARE(obj->property(name).toString(), qtString); - const char *name1 = (propertyName + QLatin1Char('1')).toLatin1().constData(); + QByteArray name1 = (propertyName + QLatin1Char('1')).toLatin1(); QCOMPARE(obj->property(name1).toDouble(), number); QCOMPARE(obj->property(name1).toString(), qtString); - const char *name2 = (propertyName + QLatin1Char('2')).toLatin1().constData(); + QByteArray name2 = (propertyName + QLatin1Char('2')).toLatin1(); QCOMPARE(obj->property(name2).toDouble(), number); QCOMPARE(obj->property(name2).toString(), jsString); 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/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp index e0c2324dc6..b8ea98df2b 100644 --- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp +++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp @@ -60,6 +60,7 @@ private slots: void QTBUG_35233(); void disallowExtending(); void QTBUG_35906(); + void QTBUG_48136(); }; class LazyPropertyMap : public QQmlPropertyMap, public QQmlParserStatus @@ -462,6 +463,40 @@ void tst_QQmlPropertyMap::QTBUG_35906() QCOMPARE(value.toInt(), 42); } +void tst_QQmlPropertyMap::QTBUG_48136() +{ + static const char key[] = "mykey"; + QQmlPropertyMap map; + + // + // Test that the notify signal is emitted correctly + // + + const int propIndex = map.metaObject()->indexOfProperty(key); + const QMetaProperty prop = map.metaObject()->property(propIndex); + QSignalSpy notifySpy(&map, QByteArray::number(QSIGNAL_CODE) + prop.notifySignal().methodSignature()); + + map.insert(key, 42); + QCOMPARE(notifySpy.count(), 1); + map.insert(key, 43); + QCOMPARE(notifySpy.count(), 2); + map.insert(key, 43); + QCOMPARE(notifySpy.count(), 2); + map.insert(key, 44); + QCOMPARE(notifySpy.count(), 3); + + // + // Test that the valueChanged signal is emitted correctly + // + QSignalSpy valueChangedSpy(&map, &QQmlPropertyMap::valueChanged); + map.setProperty(key, 44); + QCOMPARE(valueChangedSpy.count(), 0); + map.setProperty(key, 45); + QCOMPARE(valueChangedSpy.count(), 1); + map.setProperty(key, 45); + QCOMPARE(valueChangedSpy.count(), 1); +} + QTEST_MAIN(tst_QQmlPropertyMap) #include "tst_qqmlpropertymap.moc" 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/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 8150241e4a..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 @@ -87,11 +96,15 @@ 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; }; @@ -872,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); @@ -980,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")); @@ -1139,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/qqmlsqldatabase/data/nullvalues.js b/tests/auto/qml/qqmlsqldatabase/data/nullvalues.js new file mode 100644 index 0000000000..322a7aea03 --- /dev/null +++ b/tests/auto/qml/qqmlsqldatabase/data/nullvalues.js @@ -0,0 +1,24 @@ +.import QtQuick.LocalStorage 2.0 as Sql + +function test() { + var db = Sql.LocalStorage.openDatabaseSync("QmlTestDB-nullvalues", "", "Test database from Qt autotests", 1000000); + var r="transaction_not_finished"; + + db.transaction( + function(tx) { + tx.executeSql('CREATE TABLE IF NOT EXISTS NullValues(salutation TEXT, salutee TEXT)'); + tx.executeSql('INSERT INTO NullValues VALUES(?, ?)', [ 'hello', null ]); + var firstRow = tx.executeSql("SELECT * FROM NullValues").rows.item(0); + if (firstRow.salutation !== "hello") + return + if (firstRow.salutee === "") { + r = "wrong_data_type" + return + } + if (firstRow.salutee === null) + r = "passed"; + } + ); + + return r; +} diff --git a/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp b/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp index b1e5cc4e7a..e16bfb08a2 100644 --- a/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp +++ b/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp @@ -122,7 +122,7 @@ void tst_qqmlsqldatabase::checkDatabasePath() QVERIFY(engine->offlineStoragePath().contains("OfflineStorage")); } -static const int total_databases_created_by_tests = 12; +static const int total_databases_created_by_tests = 13; void tst_qqmlsqldatabase::testQml_data() { QTest::addColumn<QString>("jsfile"); // The input file @@ -144,6 +144,7 @@ void tst_qqmlsqldatabase::testQml_data() QTest::newRow("error-outsidetransaction") << "error-outsidetransaction.js"; // reuse above QTest::newRow("reopen1") << "reopen1.js"; QTest::newRow("reopen2") << "reopen2.js"; // re-uses above DB + QTest::newRow("null-values") << "nullvalues.js"; // If you add a test, you should usually use a new database in the // test - in which case increment total_databases_created_by_tests above. 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/data/MyComponent.qml b/tests/auto/qml/qqmltypeloader/data/MyComponent.qml new file mode 100644 index 0000000000..a642518199 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/MyComponent.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 100 + height: 62 + + MyComponent3 {} + + MyComponent2 {} +} + diff --git a/tests/auto/qml/qqmltypeloader/data/MyComponent2.qml b/tests/auto/qml/qqmltypeloader/data/MyComponent2.qml new file mode 100644 index 0000000000..02cf5cb5dd --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/MyComponent2.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Rectangle { + width: 100 + height: 62 +} + diff --git a/tests/auto/qml/qqmltypeloader/data/MyComponent3.qml b/tests/auto/qml/qqmltypeloader/data/MyComponent3.qml new file mode 100644 index 0000000000..ad5d569197 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/MyComponent3.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +Rectangle { + width: 100 + height: 62 + + MyComponent4 {} +} + diff --git a/tests/auto/qml/qqmltypeloader/data/trim_cache2.qml b/tests/auto/qml/qqmltypeloader/data/trim_cache2.qml new file mode 100644 index 0000000000..326a720a87 --- /dev/null +++ b/tests/auto/qml/qqmltypeloader/data/trim_cache2.qml @@ -0,0 +1,13 @@ +import QtQuick 2.0 + +Item { + width: 400 + height: 400 + + Component.onCompleted: { + var component = Qt.createComponent("MyComponent.qml") + if (component.status == Component.Error) + console.log(component.errorString()) + } +} + diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index ef1ea3a897..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 @@ -43,6 +42,7 @@ private slots: void testLoadComplete(); void loadComponentSynchronously(); void trimCache(); + void trimCache2(); }; void tst_QQMLTypeLoader::testLoadComplete() @@ -81,10 +81,19 @@ void tst_QQMLTypeLoader::trimCache() url.setQuery(QString::number(i)); QQmlTypeData *data = loader.getType(url); - if (i % 5 == 0) // keep references to some of them so that they aren't trimmed - data->compiledData()->addref(); + // Run an event loop to receive the callback that release()es. + QTRY_COMPARE(data->count(), 2); - data->release(); + // keep references to some of them so that they aren't trimmed. References to either the + // QQmlTypeData or its compiledData() should prevent the trimming. + if (i % 10 == 0) { + // keep ref on data, don't add ref on data->compiledData() + } else if (i % 5 == 0) { + data->compilationUnit()->addref(); + data->release(); + } else { + data->release(); + } } for (int i = 0; i < 256; ++i) { @@ -98,6 +107,19 @@ void tst_QQMLTypeLoader::trimCache() } } +void tst_QQMLTypeLoader::trimCache2() +{ + QQuickView *window = new QQuickView(); + window->setSource(testFileUrl("trim_cache2.qml")); + QQmlTypeLoader &loader = QQmlEnginePrivate::get(window->engine())->typeLoader; + // in theory if gc has already run this could be false + // QCOMPARE(loader.isTypeLoaded(testFileUrl("MyComponent2.qml")), true); + window->engine()->collectGarbage(); + QTest::qWait(1); // force event loop + window->engine()->trimComponentCache(); + QCOMPARE(loader.isTypeLoaded(testFileUrl("MyComponent2.qml")), false); +} + QTEST_MAIN(tst_QQMLTypeLoader) #include "tst_qqmltypeloader.moc" 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 f506d0f53a..803bad197a 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -907,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); @@ -933,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); 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/animators/Box.qml b/tests/auto/qmltest-blacklist/animators/Box.qml index 88a74e8a54..88a74e8a54 100644 --- a/tests/auto/qmltest/animators/Box.qml +++ b/tests/auto/qmltest-blacklist/animators/Box.qml diff --git a/tests/auto/qmltest/animators/tst_behavior.qml b/tests/auto/qmltest-blacklist/animators/tst_behavior.qml index 1a17c0528e..1a17c0528e 100644 --- a/tests/auto/qmltest/animators/tst_behavior.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_behavior.qml diff --git a/tests/auto/qmltest/animators/tst_mixed.qml b/tests/auto/qmltest-blacklist/animators/tst_mixed.qml index 5ad698254f..5ad698254f 100644 --- a/tests/auto/qmltest/animators/tst_mixed.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_mixed.qml diff --git a/tests/auto/qmltest/animators/tst_mixedparallel.qml b/tests/auto/qmltest-blacklist/animators/tst_mixedparallel.qml index 236f250306..236f250306 100644 --- a/tests/auto/qmltest/animators/tst_mixedparallel.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_mixedparallel.qml diff --git a/tests/auto/qmltest/animators/tst_mixedsequential.qml b/tests/auto/qmltest-blacklist/animators/tst_mixedsequential.qml index 771c5f33ce..771c5f33ce 100644 --- a/tests/auto/qmltest/animators/tst_mixedsequential.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_mixedsequential.qml diff --git a/tests/auto/qmltest/animators/tst_multiwindow.qml b/tests/auto/qmltest-blacklist/animators/tst_multiwindow.qml index 8ea6aab9a7..8ea6aab9a7 100644 --- a/tests/auto/qmltest/animators/tst_multiwindow.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_multiwindow.qml diff --git a/tests/auto/qmltest/animators/tst_nested.qml b/tests/auto/qmltest-blacklist/animators/tst_nested.qml index 7f35118dda..7f35118dda 100644 --- a/tests/auto/qmltest/animators/tst_nested.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_nested.qml diff --git a/tests/auto/qmltest/animators/tst_on.qml b/tests/auto/qmltest-blacklist/animators/tst_on.qml index 5bcbfa2a2e..5bcbfa2a2e 100644 --- a/tests/auto/qmltest/animators/tst_on.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_on.qml diff --git a/tests/auto/qmltest/animators/tst_opacity.qml b/tests/auto/qmltest-blacklist/animators/tst_opacity.qml index 41d09b18c6..41d09b18c6 100644 --- a/tests/auto/qmltest/animators/tst_opacity.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_opacity.qml diff --git a/tests/auto/qmltest/animators/tst_parallel.qml b/tests/auto/qmltest-blacklist/animators/tst_parallel.qml index ac7acf2536..ac7acf2536 100644 --- a/tests/auto/qmltest/animators/tst_parallel.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_parallel.qml diff --git a/tests/auto/qmltest/animators/tst_restart.qml b/tests/auto/qmltest-blacklist/animators/tst_restart.qml index 66f395c938..66f395c938 100644 --- a/tests/auto/qmltest/animators/tst_restart.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_restart.qml diff --git a/tests/auto/qmltest/animators/tst_rotation.qml b/tests/auto/qmltest-blacklist/animators/tst_rotation.qml index b181912299..b181912299 100644 --- a/tests/auto/qmltest/animators/tst_rotation.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_rotation.qml diff --git a/tests/auto/qmltest/animators/tst_scale.qml b/tests/auto/qmltest-blacklist/animators/tst_scale.qml index 0e1abcf729..0e1abcf729 100644 --- a/tests/auto/qmltest/animators/tst_scale.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_scale.qml diff --git a/tests/auto/qmltest/animators/tst_sequential.qml b/tests/auto/qmltest-blacklist/animators/tst_sequential.qml index e8b4e98917..e8b4e98917 100644 --- a/tests/auto/qmltest/animators/tst_sequential.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_sequential.qml diff --git a/tests/auto/qmltest/animators/tst_targetdestroyed.qml b/tests/auto/qmltest-blacklist/animators/tst_targetdestroyed.qml index 588777ce1c..588777ce1c 100644 --- a/tests/auto/qmltest/animators/tst_targetdestroyed.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_targetdestroyed.qml diff --git a/tests/auto/qmltest/animators/tst_transformorigin.qml b/tests/auto/qmltest-blacklist/animators/tst_transformorigin.qml index e9c8a16598..e9c8a16598 100644 --- a/tests/auto/qmltest/animators/tst_transformorigin.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_transformorigin.qml diff --git a/tests/auto/qmltest/animators/tst_transition.qml b/tests/auto/qmltest-blacklist/animators/tst_transition.qml index 1e95ed56c0..1e95ed56c0 100644 --- a/tests/auto/qmltest/animators/tst_transition.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_transition.qml diff --git a/tests/auto/qmltest/animators/tst_x.qml b/tests/auto/qmltest-blacklist/animators/tst_x.qml index 7a89bf564c..7a89bf564c 100644 --- a/tests/auto/qmltest/animators/tst_x.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_x.qml diff --git a/tests/auto/qmltest/animators/tst_y.qml b/tests/auto/qmltest-blacklist/animators/tst_y.qml index abb73db7c1..abb73db7c1 100644 --- a/tests/auto/qmltest/animators/tst_y.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_y.qml diff --git a/tests/auto/qmltest/animators/tst_zeroduration.qml b/tests/auto/qmltest-blacklist/animators/tst_zeroduration.qml index 83ce235f42..83ce235f42 100644 --- a/tests/auto/qmltest/animators/tst_zeroduration.qml +++ b/tests/auto/qmltest-blacklist/animators/tst_zeroduration.qml diff --git a/tests/auto/qmltest/item/tst_layerInPositioner.qml b/tests/auto/qmltest-blacklist/item/tst_layerInPositioner.qml index da081fb5fe..da081fb5fe 100644 --- a/tests/auto/qmltest/item/tst_layerInPositioner.qml +++ b/tests/auto/qmltest-blacklist/item/tst_layerInPositioner.qml diff --git a/tests/auto/qmltest/BLACKLIST b/tests/auto/qmltest/BLACKLIST index cd8b1181e0..c38347b42a 100644 --- a/tests/auto/qmltest/BLACKLIST +++ b/tests/auto/qmltest/BLACKLIST @@ -3,3 +3,9 @@ * [SelfTests::test_blacklistWithData:test2] * +[shadersource-dynamic-sourceobject::test_endresult] +linux +[tst_grabImage::test_equals] +linux +[ListView::test_listInteractiveCurrentIndexEnforce] +linux diff --git a/tests/auto/qmltest/events/tst_events.qml b/tests/auto/qmltest/events/tst_events.qml index e655c26c7d..d9868a316c 100644 --- a/tests/auto/qmltest/events/tst_events.qml +++ b/tests/auto/qmltest/events/tst_events.qml @@ -27,6 +27,7 @@ ****************************************************************************/ import QtQuick 2.0 +import QtQuick.Window 2.0 import QtTest 1.1 Rectangle { @@ -56,6 +57,16 @@ Rectangle { signalName: "doubleClickSignalHelper" } + Window { + id: sub + visible: true + property bool clicked: false + MouseArea { + anchors.fill: parent + onClicked: sub.clicked = true + } + } + MouseArea { anchors.fill: parent onClicked: { @@ -89,6 +100,11 @@ Rectangle { tryCompare(top, "mouseHasBeenClicked", true, 10000) } + function test_mouse_click_subwindow() { + mouseClick(sub) + tryCompare(sub, "clicked", true, 10000) + } + function test_mouse_doubleclick() { doubleClickSpy.clear() mouseDoubleClickSequence(top, 25, 30) diff --git a/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml index 743dad70eb..022e98a202 100644 --- a/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml +++ b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml @@ -102,7 +102,7 @@ Item { property int callCount: 0; property bool ready: false; function handleGrab(result) { - if (!result.saveToFile("image.png")) + if (!result.saveToFile("itemgrabber/image.png")) print("Error: Failed to save image to disk..."); source = "image.png"; ready = true; @@ -116,7 +116,7 @@ Item { y: 0 property bool ready: false; function handleGrab(result) { - if (!result.saveToFile("image_small.png")) + if (!result.saveToFile("itemgrabber/image_small.png")) print("Error: Failed to save image to disk..."); source = "image_small.png"; ready = true; diff --git a/tests/auto/qmltest/listview/tst_listview.qml b/tests/auto/qmltest/listview/tst_listview.qml index 75429c43e1..65f736f305 100644 --- a/tests/auto/qmltest/listview/tst_listview.qml +++ b/tests/auto/qmltest/listview/tst_listview.qml @@ -288,6 +288,7 @@ Item { } function test_asyncLoaderCurrentIndexChange() { + skip("more details in QTBUG-53780") for (var i = 0; i < 500; i++) { asyncLoaderCurrentIndexListView.currentIndex = 0; asyncLoaderCurrentIndexListView.currentIndex = 1; @@ -300,6 +301,7 @@ Item { } function test_asyncListViewLoader() { + skip("more details in QTBUG-53780") for (var i = 0; i < 50; i++) { wait(10); asyncListViewLoaderView.currentIndex = 0; @@ -318,9 +320,13 @@ Item { function test_listInteractiveCurrentIndexEnforce() { mousePress(listInteractiveCurrentIndexEnforce, 10, 50); + wait(1); // because Flickable pays attention to velocity, we need some time between movements mouseMove(listInteractiveCurrentIndexEnforce, 10, 40); + wait(1); mouseMove(listInteractiveCurrentIndexEnforce, 10, 30); + wait(1); mouseMove(listInteractiveCurrentIndexEnforce, 10, 20); + wait(1); mouseMove(listInteractiveCurrentIndexEnforce, 10, 10); compare(listInteractiveCurrentIndexEnforce.interactive, false); mouseRelease(listInteractiveCurrentIndexEnforce, 10, 10); diff --git a/tests/auto/qmltest/qmltest.pro b/tests/auto/qmltest/qmltest.pro index 54db7a78ab..52fd6bf9de 100644 --- a/tests/auto/qmltest/qmltest.pro +++ b/tests/auto/qmltest/qmltest.pro @@ -10,5 +10,5 @@ importFiles.files = borderimage buttonclick createbenchmark events qqmlbindi importFiles.path = . DEPLOYMENT += importFiles -CONFIG+=insignificant_test # QTBUG-33723 - +# Please do not make this test insignificant again, thanks. +# Just skip those unstable ones. See also QTBUG-33723. 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/qmltest/statemachine/tst_signaltransition.qml b/tests/auto/qmltest/statemachine/tst_signaltransition.qml new file mode 100644 index 0000000000..0e35207670 --- /dev/null +++ b/tests/auto/qmltest/statemachine/tst_signaltransition.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Ford Motor Company +** Copyright (C) 2016 The Qt Company +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite module 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 QtTest 1.1 +import QtQml.StateMachine 1.0 + +TestCase { + id: testCase + StateMachine { + id: machine + initialState: startState + State { + id: startState + SignalTransition { + id: signalTrans + signal: testCase.onMysignal + targetState: finalState + } + } + FinalState { + id: finalState + } + } + + SignalSpy { + id: finalStateActive + target: finalState + signalName: "activeChanged" + } + + signal mysignal() + + name: "testSignalTransition" + function test_signalTransition() + { + // Start statemachine, should not have reached finalState yet. + machine.start() + tryCompare(finalStateActive, "count", 0) + tryCompare(machine, "running", true) + + testCase.mysignal() + tryCompare(finalStateActive, "count", 1) + tryCompare(machine, "running", false) + } +} diff --git a/tests/auto/qmltest/text/tst_text.qml b/tests/auto/qmltest/text/tst_text.qml index 691a4838cd..d2899cfb74 100644 --- a/tests/auto/qmltest/text/tst_text.qml +++ b/tests/auto/qmltest/text/tst_text.qml @@ -118,9 +118,10 @@ Item { compare(txtlinecount.lineCount, 2) txtlinecount.text = txtlinecount.third; compare(txtlinecount.lineCount, 3) + console.log(txtlinecount.width) txtlinecount.text = txtlinecount.first; compare(txtlinecount.lineCount, 1) - txtlinecount.width = 50; + txtlinecount.width = 44; compare(txtlinecount.lineCount, 3) } function test_linecounts() { diff --git a/tests/auto/qmltest/textinput/tst_textinput.qml b/tests/auto/qmltest/textinput/tst_textinput.qml index 62659a2188..51868ec8aa 100644 --- a/tests/auto/qmltest/textinput/tst_textinput.qml +++ b/tests/auto/qmltest/textinput/tst_textinput.qml @@ -277,6 +277,7 @@ Item { } function test_doublevalidators(row) { + txtdoublevalidator.validator.locale = "C" compare(txtdoublevalidator.validator.top, 2.0) compare(txtdoublevalidator.validator.bottom, 1.0) txtdoublevalidator.text = row.testnumber; diff --git a/tests/auto/qmltest/window/tst_clickwindow.qml b/tests/auto/qmltest/window/tst_clickwindow.qml index bbe091990c..c3577be4dc 100644 --- a/tests/auto/qmltest/window/tst_clickwindow.qml +++ b/tests/auto/qmltest/window/tst_clickwindow.qml @@ -75,6 +75,8 @@ Item { when: windowShown function test_clickBothWindows() { + if (Qt.platform.os === "linux" || Qt.platform.os === "windows") + skip("more details in QTBUG-53785") mouseClick(ma, 20, 20); verify(ma.everClicked); mouseClick(ma2, 20, 20); diff --git a/tests/auto/quick/drawingmodes/data/DrawingModes.qml b/tests/auto/quick/drawingmodes/data/DrawingModes.qml new file mode 100644 index 0000000000..4211f247f8 --- /dev/null +++ b/tests/auto/quick/drawingmodes/data/DrawingModes.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 +import Test 1.0 + +Rectangle { + id: root + + width: 200 + height: 200 + color: "black" + + DrawingModeItem { + anchors.fill: parent + } +} diff --git a/tests/auto/quick/drawingmodes/drawingmodes.pro b/tests/auto/quick/drawingmodes/drawingmodes.pro new file mode 100644 index 0000000000..ff5383b501 --- /dev/null +++ b/tests/auto/quick/drawingmodes/drawingmodes.pro @@ -0,0 +1,17 @@ +CONFIG += testcase +TARGET = tst_drawingmodes +SOURCES += tst_drawingmodes.cpp + +macos:CONFIG -= app_bundle + +TESTDATA = data/* + +include(../../shared/util.pri) + +CONFIG += parallel_test +QT += gui qml quick testlib + +OTHER_FILES += \ + data/DrawingModes.qml + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp new file mode 100644 index 0000000000..d4065e3d38 --- /dev/null +++ b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** 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 <QtQuick/qquickitem.h> +#include <QtQuick/qquickview.h> +#include <QtQuick/qsgnode.h> +#include <QtQuick/qsggeometry.h> +#include <QtQuick/qsgflatcolormaterial.h> +#include <QtGui/qscreen.h> +#include <QtGui/qopenglcontext.h> + +#include "../../shared/util.h" + +class tst_drawingmodes : public QQmlDataTest +{ + Q_OBJECT +public: + tst_drawingmodes(); + + bool hasPixelAround(const QImage &fb, int centerX, int centerY); + QImage runTest(const QString &fileName) + { + QQuickView view(&outerWindow); + view.setResizeMode(QQuickView::SizeViewToRootObject); + view.setSource(testFileUrl(fileName)); + view.setVisible(true); + QTest::qWaitForWindowExposed(&view); + return view.grabWindow(); + } + + //It is important for platforms that only are able to show fullscreen windows + //to have a container for the window that is painted on. + QQuickWindow outerWindow; + const QRgb black; + const QRgb red; + +private slots: + void points(); + void lines(); + void lineStrip(); + void lineLoop(); + void triangles(); + void triangleStrip(); + void triangleFan(); +}; + +class DrawingModeItem : public QQuickItem +{ + Q_OBJECT +public: + static GLenum drawingMode; + + DrawingModeItem() : first(QSGGeometry::defaultAttributes_Point2D(), 5), + second(QSGGeometry::defaultAttributes_Point2D(), 5) + { + setFlag(ItemHasContents, true); + material.setColor(Qt::red); + } + +protected: + QSGGeometry first; + QSGGeometry second; + QSGFlatColorMaterial material; + + virtual QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) + { + if (!node) { + QRect bounds(0, 0, 200, 200); + first.setDrawingMode(drawingMode); + second.setDrawingMode(drawingMode); + + QSGGeometry::Point2D *v = first.vertexDataAsPoint2D(); + v[0].set(bounds.width() * 2 / 8, bounds.height() / 2); + v[1].set(bounds.width() / 8, bounds.height() / 4); + v[2].set(bounds.width() * 3 / 8, bounds.height() / 4); + v[3].set(bounds.width() * 3 / 8, bounds.height() * 3 / 4); + v[4].set(bounds.width() / 8, bounds.height() * 3 / 4); + + v = second.vertexDataAsPoint2D(); + v[0].set(bounds.width() * 6 / 8, bounds.height() / 2); + v[1].set(bounds.width() * 5 / 8, bounds.height() / 4); + v[2].set(bounds.width() * 7 / 8, bounds.height() / 4); + v[3].set(bounds.width() * 7 / 8, bounds.height() * 3 / 4); + v[4].set(bounds.width() * 5 / 8, bounds.height() * 3 / 4); + + node = new QSGNode; + QSGGeometryNode *child = new QSGGeometryNode; + child->setGeometry(&first); + child->setMaterial(&material); + node->appendChildNode(child); + child = new QSGGeometryNode; + child->setGeometry(&second); + child->setMaterial(&material); + node->appendChildNode(child); + } + return node; + } +}; + +GLenum DrawingModeItem::drawingMode; + +bool tst_drawingmodes::hasPixelAround(const QImage &fb, int centerX, int centerY) { + for (int x = centerX - 2; x <= centerX + 2; ++x) { + for (int y = centerY - 2; y <= centerY + 2; ++y) { + if (fb.pixel(x, y) == red) + return true; + } + } + return false; +} + +tst_drawingmodes::tst_drawingmodes() : black(qRgb(0, 0, 0)), red(qRgb(0xff, 0, 0)) +{ + qmlRegisterType<DrawingModeItem>("Test", 1, 0, "DrawingModeItem"); + outerWindow.showNormal(); + outerWindow.setGeometry(0,0,400,400); +} + +void tst_drawingmodes::points() +{ + DrawingModeItem::drawingMode = GL_POINTS; + if (QGuiApplication::primaryScreen()->depth() < 24) + QSKIP("This test does not work at display depths < 24"); + +#ifdef Q_OS_WIN + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) + QSKIP("ANGLE cannot draw GL_POINTS."); +#endif + + QImage fb = runTest("DrawingModes.qml"); + + QVERIFY(hasPixelAround(fb, 50, 100)); + QVERIFY(hasPixelAround(fb, 25, 50)); + QVERIFY(hasPixelAround(fb, 75, 50)); + QVERIFY(hasPixelAround(fb, 75, 150)); + QVERIFY(hasPixelAround(fb, 25, 150)); + + QVERIFY(hasPixelAround(fb, 150, 100)); + QVERIFY(hasPixelAround(fb, 125, 50)); + QVERIFY(hasPixelAround(fb, 175, 50)); + QVERIFY(hasPixelAround(fb, 175, 150)); + QVERIFY(hasPixelAround(fb, 125, 150)); + + QVERIFY(!hasPixelAround(fb, 135, 70)); + QVERIFY(!hasPixelAround(fb, 175, 100)); + QVERIFY(!hasPixelAround(fb, 110, 140)); + QVERIFY(!hasPixelAround(fb, 50, 50)); + QVERIFY(!hasPixelAround(fb, 50, 150)); + QVERIFY(!hasPixelAround(fb, 25, 100)); + QVERIFY(!hasPixelAround(fb, 75, 100)); + QVERIFY(!hasPixelAround(fb, 125, 100)); + QVERIFY(!hasPixelAround(fb, 150, 50)); + QVERIFY(!hasPixelAround(fb, 150, 150)); + QVERIFY(!hasPixelAround(fb, 135, 130)); + QVERIFY(!hasPixelAround(fb, 35, 130)); +} + +void tst_drawingmodes::lines() +{ + DrawingModeItem::drawingMode = GL_LINES; + if (QGuiApplication::primaryScreen()->depth() < 24) + QSKIP("This test does not work at display depths < 24"); + QImage fb = runTest("DrawingModes.qml"); + + QCOMPARE(fb.width(), 200); + QCOMPARE(fb.height(), 200); + + QVERIFY(hasPixelAround(fb, 135, 70)); + QVERIFY(hasPixelAround(fb, 175, 100)); + QVERIFY(!hasPixelAround(fb, 110, 140)); + QVERIFY(!hasPixelAround(fb, 50, 50)); + QVERIFY(!hasPixelAround(fb, 50, 150)); + + QVERIFY(hasPixelAround(fb, 35, 70)); + QVERIFY(hasPixelAround(fb, 75, 100)); + QVERIFY(!hasPixelAround(fb, 25, 100)); + QVERIFY(!hasPixelAround(fb, 125, 100)); + QVERIFY(!hasPixelAround(fb, 150, 50)); + QVERIFY(!hasPixelAround(fb, 150, 150)); + QVERIFY(!hasPixelAround(fb, 135, 130)); + QVERIFY(!hasPixelAround(fb, 35, 130)); +} + +void tst_drawingmodes::lineStrip() +{ + DrawingModeItem::drawingMode = GL_LINE_STRIP; + if (QGuiApplication::primaryScreen()->depth() < 24) + QSKIP("This test does not work at display depths < 24"); + QImage fb = runTest("DrawingModes.qml"); + + QCOMPARE(fb.width(), 200); + QCOMPARE(fb.height(), 200); + + QVERIFY(hasPixelAround(fb, 135, 70)); + QVERIFY(hasPixelAround(fb, 150, 50)); + QVERIFY(hasPixelAround(fb, 175, 100)); + QVERIFY(hasPixelAround(fb, 150, 150)); + + QVERIFY(hasPixelAround(fb, 35, 70)); + QVERIFY(hasPixelAround(fb, 50, 50)); + QVERIFY(hasPixelAround(fb, 75, 100)); + QVERIFY(hasPixelAround(fb, 50, 150)); + + QVERIFY(!hasPixelAround(fb, 110, 140)); // bad line not there => line strip unbatched + + QVERIFY(!hasPixelAround(fb, 25, 100)); + QVERIFY(!hasPixelAround(fb, 125, 100)); + QVERIFY(!hasPixelAround(fb, 135, 130)); + QVERIFY(!hasPixelAround(fb, 35, 130)); +} + +void tst_drawingmodes::lineLoop() +{ + DrawingModeItem::drawingMode = GL_LINE_LOOP; + if (QGuiApplication::primaryScreen()->depth() < 24) + QSKIP("This test does not work at display depths < 24"); + QImage fb = runTest("DrawingModes.qml"); + + QCOMPARE(fb.width(), 200); + QCOMPARE(fb.height(), 200); + + QVERIFY(hasPixelAround(fb, 135, 70)); + QVERIFY(hasPixelAround(fb, 135, 130)); + QVERIFY(hasPixelAround(fb, 150, 50)); + QVERIFY(hasPixelAround(fb, 175, 100)); + QVERIFY(hasPixelAround(fb, 150, 150)); + + QVERIFY(hasPixelAround(fb, 35, 70)); + QVERIFY(hasPixelAround(fb, 35, 130)); + QVERIFY(hasPixelAround(fb, 50, 50)); + QVERIFY(hasPixelAround(fb, 75, 100)); + QVERIFY(hasPixelAround(fb, 50, 150)); + + QVERIFY(!hasPixelAround(fb, 110, 140)); // bad line not there => line loop unbatched + + QVERIFY(!hasPixelAround(fb, 25, 100)); + QVERIFY(!hasPixelAround(fb, 125, 100)); +} + +void tst_drawingmodes::triangles() +{ + DrawingModeItem::drawingMode = GL_TRIANGLES; + if (QGuiApplication::primaryScreen()->depth() < 24) + QSKIP("This test does not work at display depths < 24"); + QImage fb = runTest("DrawingModes.qml"); + + QCOMPARE(fb.width(), 200); + QCOMPARE(fb.height(), 200); + + QVERIFY(hasPixelAround(fb, 150, 75)); + QVERIFY(!hasPixelAround(fb, 162, 100)); + QVERIFY(!hasPixelAround(fb, 150, 125)); + QVERIFY(!hasPixelAround(fb, 137, 100)); + + QVERIFY(!hasPixelAround(fb, 100, 125)); + + QVERIFY(hasPixelAround(fb, 50, 75)); + QVERIFY(!hasPixelAround(fb, 62, 100)); + QVERIFY(!hasPixelAround(fb, 50, 125)); + QVERIFY(!hasPixelAround(fb, 37, 100)); +} + + +void tst_drawingmodes::triangleStrip() +{ + DrawingModeItem::drawingMode = GL_TRIANGLE_STRIP; + if (QGuiApplication::primaryScreen()->depth() < 24) + QSKIP("This test does not work at display depths < 24"); + QImage fb = runTest("DrawingModes.qml"); + + QCOMPARE(fb.width(), 200); + QCOMPARE(fb.height(), 200); + + QVERIFY(hasPixelAround(fb, 150, 75)); + QVERIFY(hasPixelAround(fb, 162, 100)); + QVERIFY(hasPixelAround(fb, 150, 125)); + QVERIFY(!hasPixelAround(fb, 137, 100)); + + QVERIFY(!hasPixelAround(fb, 100, 125)); // batching avoids extra triangle by duplicating vertices. + + QVERIFY(hasPixelAround(fb, 50, 75)); + QVERIFY(hasPixelAround(fb, 62, 100)); + QVERIFY(hasPixelAround(fb, 50, 125)); + QVERIFY(!hasPixelAround(fb, 37, 100)); +} + +void tst_drawingmodes::triangleFan() +{ + DrawingModeItem::drawingMode = GL_TRIANGLE_FAN; + if (QGuiApplication::primaryScreen()->depth() < 24) + QSKIP("This test does not work at display depths < 24"); + QImage fb = runTest("DrawingModes.qml"); + + QCOMPARE(fb.width(), 200); + QCOMPARE(fb.height(), 200); + + QVERIFY(hasPixelAround(fb, 150, 75)); + QVERIFY(hasPixelAround(fb, 162, 100)); + QVERIFY(hasPixelAround(fb, 150, 125)); + QVERIFY(!hasPixelAround(fb, 137, 100)); + + QVERIFY(!hasPixelAround(fb, 100, 125)); // no extra triangle; triangle fan is not batched + + QVERIFY(hasPixelAround(fb, 50, 75)); + QVERIFY(hasPixelAround(fb, 62, 100)); + QVERIFY(hasPixelAround(fb, 50, 125)); + QVERIFY(!hasPixelAround(fb, 37, 100)); +} + + +QTEST_MAIN(tst_drawingmodes) + +#include "tst_drawingmodes.moc" diff --git a/tests/auto/quick/nokeywords/tst_nokeywords.cpp b/tests/auto/quick/nokeywords/tst_nokeywords.cpp index e25cd9535b..6c94b484ae 100644 --- a/tests/auto/quick/nokeywords/tst_nokeywords.cpp +++ b/tests/auto/quick/nokeywords/tst_nokeywords.cpp @@ -51,8 +51,8 @@ #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> diff --git a/tests/auto/quick/qquickanimatedsprite/data/img100x100.png b/tests/auto/quick/qquickanimatedsprite/data/img100x100.png Binary files differnew file mode 100644 index 0000000000..9dd1990780 --- /dev/null +++ b/tests/auto/quick/qquickanimatedsprite/data/img100x100.png diff --git a/tests/auto/quick/qquickanimatedsprite/data/img50x50.png b/tests/auto/quick/qquickanimatedsprite/data/img50x50.png Binary files differnew file mode 100644 index 0000000000..5cbb47981a --- /dev/null +++ b/tests/auto/quick/qquickanimatedsprite/data/img50x50.png diff --git a/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml b/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml new file mode 100644 index 0000000000..18a8f52661 --- /dev/null +++ b/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** 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.4 + +AnimatedSprite { + id: animatedSprite + source: big ? "img100x100.png" : "img50x50.png" + frameWidth: 100 + frameHeight: 100 + property bool big: true + MouseArea { + anchors.fill: parent + onClicked: animatedSprite.big = !animatedSprite.big + } +} diff --git a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp index 27ce46d163..820c804065 100644 --- a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp +++ b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp @@ -35,6 +35,7 @@ #include <QtGui/qopenglcontext.h> #include <QtGui/qopenglfunctions.h> #include <QtGui/qoffscreensurface.h> +#include <QtQml/qqmlproperty.h> class tst_qquickanimatedsprite : public QQmlDataTest { @@ -50,6 +51,7 @@ private slots: void test_largeAnimation_data(); void test_largeAnimation(); void test_reparenting(); + void test_changeSourceToSmallerImgKeepingBigFrameSize(); }; void tst_qquickanimatedsprite::initTestCase() @@ -286,6 +288,43 @@ void tst_qquickanimatedsprite::test_reparenting() QTRY_COMPARE(QQuickItemPrivate::get(sprite)->polishScheduled, false); } +class KillerThread : public QThread +{ + Q_OBJECT +protected: + void run() Q_DECL_OVERRIDE { + sleep(3); + qFatal("Either the GUI or the render thread is stuck in an infinite loop."); + } +}; + +// Regression test for QTBUG-53937 +void tst_qquickanimatedsprite::test_changeSourceToSmallerImgKeepingBigFrameSize() +{ + QQuickView window; + window.setSource(testFileUrl("sourceSwitch.qml")); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + QVERIFY(window.rootObject()); + QQuickAnimatedSprite* sprite = qobject_cast<QQuickAnimatedSprite*>(window.rootObject()); + QVERIFY(sprite); + + QQmlProperty big(sprite, "big"); + big.write(QVariant::fromValue(false)); + + KillerThread *killer = new KillerThread; + killer->start(); // will kill us in case the GUI or render thread enters an infinite loop + + QTest::qWait(50); // let it draw with the new source. + + // If we reach this point it's because we didn't hit QTBUG-53937 + + killer->terminate(); + killer->wait(); + delete killer; +} + QTEST_MAIN(tst_qquickanimatedsprite) #include "tst_qquickanimatedsprite.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/ratios_smallContent.qml b/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml new file mode 100644 index 0000000000..07bad683ee --- /dev/null +++ b/tests/auto/quick/qquickflickable/data/ratios_smallContent.qml @@ -0,0 +1,19 @@ +import QtQuick 2.0 + +Flickable { + property double heightRatioIs: visibleArea.heightRatio + property double widthRatioIs: visibleArea.widthRatio + + width: 200 + height: 200 + contentWidth: item.width + contentHeight: item.height + topMargin: 20 + leftMargin: 40 + + Item { + id: item + width: 100 + height: 100 + } +} diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 2742f5c1e2..a03e3b8170 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -90,6 +90,8 @@ private slots: void movementFromProgrammaticFlick(); void cleanup(); void contentSize(); + void ratios_smallContent(); + void contentXYNotTruncatedToInt(); private: void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to); @@ -1814,6 +1816,53 @@ void tst_qquickflickable::contentSize() QCOMPARE(chspy.count(), 1); } +// QTBUG-53726 +void tst_qquickflickable::ratios_smallContent() +{ + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("ratios_smallContent.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QQuickItem *root = window->rootObject(); + QVERIFY(root); + QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root); + QVERIFY(obj != 0); + + //doublecheck the item, as specified by contentWidth/Height, fits in the view + //use tryCompare to allow a bit of stabilization in component's properties + QTRY_COMPARE(obj->leftMargin() + obj->contentWidth() + obj->rightMargin() <= obj->width(), true); + QTRY_COMPARE(obj->topMargin() + obj->contentHeight() + obj->bottomMargin() <= obj->height(), true); + + //the whole item fits in the flickable, heightRatio should be 1 + QCOMPARE(obj->property("heightRatioIs").toDouble(), 1.); + 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)); +} + QTEST_MAIN(tst_qquickflickable) #include "tst_qquickflickable.moc" diff --git a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp index ea988bb50d..d4922599be 100644 --- a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp +++ b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp @@ -180,7 +180,7 @@ void tst_QQuickFramebufferObject::testThatStuffWorks() qmlRegisterType<FBOItem>("FBOItem", 1, 0, "FBOItem"); QQuickView view; - view.setSource(QUrl::fromLocalFile("data/testStuff.qml")); + view.setSource(testFileUrl("testStuff.qml")); FBOItem *item = view.rootObject()->findChild<FBOItem *>("fbo"); @@ -224,7 +224,7 @@ void tst_QQuickFramebufferObject::testInvalidate() qmlRegisterType<FBOItem>("FBOItem", 1, 0, "FBOItem"); QQuickView view; - view.setSource(QUrl::fromLocalFile("data/testStuff.qml")); + view.setSource(testFileUrl("testStuff.qml")); FBOItem *item = view.rootObject()->findChild<FBOItem *>("fbo"); item->setTextureFollowsItemSize(false); diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index 4b2c86697e..9fedfb21ab 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -169,6 +169,8 @@ private slots: void childAt(); + void ignoreButtonPressNotInAcceptedMouseButtons(); + private: enum PaintOrderOp { @@ -2009,6 +2011,28 @@ void tst_qquickitem::childAt() QVERIFY(!root->childAt(19,19)); } +void tst_qquickitem::ignoreButtonPressNotInAcceptedMouseButtons() +{ + // Verify the fix for QTBUG-31861 + TestItem item; + QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::NoButton)); + + QQuickWindow window; + item.setSize(QSizeF(200,100)); + item.setParentItem(window.contentItem()); + + item.setAcceptedMouseButtons(Qt::LeftButton); + QCOMPARE(item.acceptedMouseButtons(), Qt::MouseButtons(Qt::LeftButton)); + + QTest::mousePress(&window, Qt::LeftButton, 0, QPoint(50, 50)); + QTest::mousePress(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it's not LeftButton + QTest::mouseRelease(&window, Qt::RightButton, 0, QPoint(50, 50)); // ignored because it didn't grab the RightButton press + QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(50, 50)); + + QCOMPARE(item.pressCount, 1); + QCOMPARE(item.releaseCount, 1); +} + QTEST_MAIN(tst_qquickitem) #include "tst_qquickitem.moc" 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 de61d7aea9..7130dc4cf2 100644 --- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp @@ -35,6 +35,7 @@ #include <QtGui/private/qinputmethod_p.h> #include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquicktextinput_p.h> +#include <QtQuick/private/qquickitemchangelistener_p.h> #include <QtGui/qstylehints.h> #include <private/qquickitem_p.h> #include "../../shared/util.h" @@ -87,6 +88,7 @@ private slots: void keyNavigation_focusReason(); void keyNavigation_loop(); void layoutMirroring(); + void layoutMirroringWindow(); void layoutMirroringIllegalParent(); void smooth(); void antialiasing(); @@ -107,6 +109,7 @@ private slots: void childrenProperty(); void resourcesProperty(); + void changeListener(); void transformCrash(); void implicitSize(); void qtbug_16871(); @@ -1774,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); } @@ -2694,6 +2714,265 @@ void tst_QQuickItem::childrenRectBottomRightCorner() delete window; } +struct TestListener : public QQuickItemChangeListener +{ + 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 + { + record(item, QQuickItemPrivate::Destroyed); + } + void itemChildAdded(QQuickItem *item, QQuickItem *child) override + { + record(item, QQuickItemPrivate::Children, QVariant::fromValue(child)); + } + void itemChildRemoved(QQuickItem *item, QQuickItem *child) override + { + record(item, QQuickItemPrivate::Children, QVariant::fromValue(child)); + } + void itemParentChanged(QQuickItem *item, QQuickItem *parent) override + { + record(item, QQuickItemPrivate::Parent, QVariant::fromValue(parent)); + } + + QQuickAnchorsPrivate *anchorPrivate() override { return nullptr; } + + 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 + { + return values.value(change); + } + + bool remove; + QList<QQuickItemPrivate::ChangeType> changes; + QHash<QQuickItemPrivate::ChangeType, QVariant> values; +}; + +void tst_QQuickItem::changeListener() +{ + QQuickWindow window; + window.show(); + QTest::qWaitForWindowExposed(&window); + + QQuickItem *item = new QQuickItem; + TestListener itemListener; + QQuickItemPrivate::get(item)->addItemChangeListener(&itemListener, QQuickItemPrivate::ChangeTypes(0xffff)); + + 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(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(item->width() + 30); + QCOMPARE(itemListener.count(QQuickItemPrivate::Geometry), 3); + QCOMPARE(itemListener.value(QQuickItemPrivate::Geometry), QVariant(QRectF(0,0,30,0))); + + 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.count(QQuickItemPrivate::Opacity), 1); + + item->setRotation(90); + QCOMPARE(itemListener.count(QQuickItemPrivate::Rotation), 1); + + 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); + + QQuickItem *child1 = new QQuickItem; + QQuickItem *child2 = new QQuickItem; + TestListener child1Listener; + TestListener child2Listener; + QQuickItemPrivate::get(child1)->addItemChangeListener(&child1Listener, QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed); + QQuickItemPrivate::get(child2)->addItemChangeListener(&child2Listener, QQuickItemPrivate::Parent | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Destroyed); + + child1->setParentItem(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.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.count(QQuickItemPrivate::SiblingOrder), 1); + QCOMPARE(child2Listener.count(QQuickItemPrivate::SiblingOrder), 1); + + child1->setParentItem(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.count(QQuickItemPrivate::Destroyed), 1); + + delete child2; + 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-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->count(QQuickItemPrivate::Children), 1); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); + + // itemParentChanged() x 5 + foreach (TestListener *listener, listeners) + QQuickItemPrivate::get(child1)->addItemChangeListener(listener, QQuickItemPrivate::Parent); + QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), listeners.count()); + child1->setParentItem(nullptr); + foreach (TestListener *listener, listeners) + 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) + QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); + delete child1; + foreach (TestListener *listener, listeners) + QCOMPARE(listener->count(QQuickItemPrivate::Children), 2); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0); + + // itemDestroyed() x 5 + foreach (TestListener *listener, listeners) + QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Destroyed); + QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count()); + delete parent; + foreach (TestListener *listener, listeners) + QCOMPARE(listener->count(QQuickItemPrivate::Destroyed), 1); +} + // QTBUG-13893 void tst_QQuickItem::transformCrash() { diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml new file mode 100644 index 0000000000..22205c18f0 --- /dev/null +++ b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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.7 +import QtQuick.Layouts 1.3 + +Item { + objectName: "qtbug51927-window" + visible: true + + default property alias _contents: customContent.data + + RowLayout { + id: customContent + objectName: "qtbug51927-columnLayout" + anchors.fill: parent + } +} diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml new file mode 100644 index 0000000000..ff7ce6221b --- /dev/null +++ b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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.6 +import QtQuick.Window 2.2 + +Container { + visible: true + + Text { + objectName: "qtbug51927-text" + text: qsTr("Hello World") + anchors.centerIn: parent + renderType: Text.QtRendering + } +} diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml index 33b8fd0e4e..2d4e227a9e 100644 --- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml +++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml @@ -926,5 +926,17 @@ Item { waitForRendering(layout) layout.destroy() } + + + function test_defaultPropertyAliasCrash() { + var containerUserComponent = Qt.createComponent("rowlayout/ContainerUser.qml"); + compare(containerUserComponent.status, Component.Ready); + + var containerUser = containerUserComponent.createObject(testCase); + verify(containerUser); + + // Shouldn't crash. + containerUser.destroy(); + } } } 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/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index 658ffa1f57..b0d903908f 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -250,6 +250,7 @@ private slots: void QTBUG_50105(); void keyNavigationEnabled(); void QTBUG_50097_stickyHeader_positionViewAtIndex(); + void itemFiltered(); private: template <class T> void items(const QUrl &source); @@ -629,6 +630,8 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v } listview->setContentY(contentY); + QQuickItemViewPrivate::get(listview)->layout(); + QList<QPair<QString, QString> > newData; for (int i=0; i<insertCount; i++) newData << qMakePair(QString("value %1").arg(i), QString::number(i)); @@ -650,6 +653,14 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v QCOMPARE(item0->y(), itemsOffsetAfterMove); #endif + QList<FxViewItem *> visibleItems = QQuickItemViewPrivate::get(listview)->visibleItems; + for (QList<FxViewItem *>::const_iterator itemIt = visibleItems.begin(); itemIt != visibleItems.end(); ++itemIt) { + FxViewItem *item = *itemIt; + if (item->item->position().y() >= 0 && item->item->position().y() < listview->height()) { + QVERIFY(!QQuickItemPrivate::get(item->item)->culled); + } + } + QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper"); int firstVisibleIndex = -1; for (int i=0; i<items.count(); i++) { @@ -735,7 +746,7 @@ void tst_QQuickListView::inserted_more_data() << 15 << 1 << 0.0; - QTest::newRow("add 1, at end of visible, content at start") + QTest::newRow("add multiple, at end of visible, content at start") << 0.0 << 15 << 3 << 0.0; @@ -756,7 +767,7 @@ void tst_QQuickListView::inserted_more_data() << 16 << 1 << 0.0; - QTest::newRow("add 1, after visible, content at start") + QTest::newRow("add multiple, after visible, content at start") << 0.0 << 16 << 3 << 0.0; @@ -770,6 +781,11 @@ void tst_QQuickListView::inserted_more_data() << 80.0 // show 4-19 << 20 << 3 << 0.0; + + QTest::newRow("add multiple, within visible, content at start") + << 0.0 + << 2 << 50 + << 0.0; } void tst_QQuickListView::insertBeforeVisible() @@ -8328,6 +8344,37 @@ void tst_QQuickListView::QTBUG_50097_stickyHeader_positionViewAtIndex() QTRY_COMPARE(listview->contentY(), -100.0); // back to the same position: header visible, items not under the header. } +void tst_QQuickListView::itemFiltered() +{ + QStringListModel model(QStringList() << "one" << "two" << "three" << "four" << "five" << "six"); + QSortFilterProxyModel proxy1; + proxy1.setSourceModel(&model); + proxy1.setSortRole(Qt::DisplayRole); + proxy1.setDynamicSortFilter(true); + proxy1.sort(0); + + QSortFilterProxyModel proxy2; + proxy2.setSourceModel(&proxy1); + proxy2.setFilterRole(Qt::DisplayRole); + proxy2.setFilterRegExp("^[^ ]*$"); + proxy2.setDynamicSortFilter(true); + + QScopedPointer<QQuickView> window(createView()); + window->engine()->rootContext()->setContextProperty("_model", &proxy2); + QQmlComponent component(window->engine()); + component.setData("import QtQuick 2.4; ListView { " + "anchors.fill: parent; model: _model; delegate: Text { width: parent.width;" + "text: model.display; } }", + QUrl()); + window->setContent(QUrl(), &component, component.create()); + + window->show(); + QTest::qWaitForWindowExposed(window.data()); + + // this should not crash + model.setData(model.index(2), QStringLiteral("modified three"), Qt::DisplayRole); +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" 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 3f78bcf1eb..b69c6eedf8 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> @@ -82,6 +83,7 @@ private slots: void dragging_data() { acceptedButton_data(); } void dragging(); void dragSmoothed(); + void dragThreshold_data(); void dragThreshold(); void invalidDrag_data() { rejectedButton_data(); } void invalidDrag(); @@ -106,6 +108,7 @@ private slots: void hoverPropagation(); void hoverVisible(); void hoverAfterPress(); + void subtreeHoverEnabled(); void disableAfterPress(); void onWheel(); void transformedMouseArea_data(); @@ -122,8 +125,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; @@ -319,7 +326,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); @@ -330,18 +338,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); } @@ -390,8 +412,17 @@ void tst_QQuickMouseArea::dragSmoothed() QTest::mouseRelease(&window, Qt::LeftButton, 0, QPoint(100, 122)); } +void tst_QQuickMouseArea::dragThreshold_data() +{ + QTest::addColumn<bool>("preventStealing"); + QTest::newRow("without preventStealing") << false; + QTest::newRow("with preventStealing") << true; +} + void tst_QQuickMouseArea::dragThreshold() { + QFETCH(bool, preventStealing); + QQuickView window; QByteArray errorMessage; QVERIFY2(initView(window, testFileUrl("dragging.qml"), true, &errorMessage), errorMessage.constData()); @@ -401,6 +432,7 @@ void tst_QQuickMouseArea::dragThreshold() QVERIFY(window.rootObject() != 0); QQuickMouseArea *mouseRegion = window.rootObject()->findChild<QQuickMouseArea*>("mouseregion"); + mouseRegion->setPreventStealing(preventStealing); QQuickDrag *drag = mouseRegion->drag(); drag->setThreshold(5); @@ -520,15 +552,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); @@ -563,7 +598,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); @@ -575,19 +611,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); } @@ -736,7 +770,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); @@ -780,14 +814,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); @@ -796,7 +830,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); @@ -808,23 +842,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); @@ -982,48 +1014,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() @@ -1036,17 +1080,17 @@ void tst_QQuickMouseArea::clickThrough() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(window->rootObject() != 0); + // to avoid generating a double click. + const int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval() + 10; + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTRY_COMPARE(window->rootObject()->property("presses").toInt(), 0); QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 1); - // to avoid generating a double click. - int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval() + 10; - QTest::qWait(doubleClickInterval); - - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QCOMPARE(window->rootObject()->property("doubleClicks").toInt(), 0); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); @@ -1076,9 +1120,7 @@ void tst_QQuickMouseArea::clickThrough() QCOMPARE(window->rootObject()->property("presses").toInt(), 0); QCOMPARE(window->rootObject()->property("clicks").toInt(), 0); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTest::qWait(100); @@ -1097,15 +1139,13 @@ void tst_QQuickMouseArea::clickThrough() window->rootObject()->setProperty("letThrough", QVariant(true)); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QCOMPARE(window->rootObject()->property("presses").toInt(), 0); QTRY_COMPARE(window->rootObject()->property("clicks").toInt(), 1); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTest::qWait(100); @@ -1124,12 +1164,10 @@ void tst_QQuickMouseArea::clickThrough() window->rootObject()->setProperty("noPropagation", QVariant(true)); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::qWait(1000); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QTest::qWait(100); @@ -1150,7 +1188,7 @@ void tst_QQuickMouseArea::clickThrough() QVERIFY(QTest::qWaitForWindowExposed(window.data())); QVERIFY(window->rootObject() != 0); - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 1); @@ -1158,8 +1196,7 @@ void tst_QQuickMouseArea::clickThrough() window->rootObject()->setProperty("disableLower", QVariant(true)); - QTest::qWait(doubleClickInterval); // to avoid generating a double click. - QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100)); + QTest::mousePress(window.data(), Qt::LeftButton, 0, QPoint(100,100), doubleClickInterval); QTest::mouseRelease(window.data(), Qt::LeftButton, 0, QPoint(100,100)); QCOMPARE(window->rootObject()->property("clicksEnabled").toInt(), 2); @@ -1275,6 +1312,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; @@ -1299,9 +1356,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()); @@ -1311,22 +1367,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); @@ -1337,7 +1395,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); @@ -1594,36 +1652,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); @@ -1673,11 +1734,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() @@ -1829,33 +1896,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 @@ -1870,15 +1947,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); @@ -1887,13 +1968,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); @@ -1904,6 +1988,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/data/cancel.qml b/tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml new file mode 100644 index 0000000000..e108003bca --- /dev/null +++ b/tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml @@ -0,0 +1,41 @@ +import QtQuick 2.0 + +MultiPointTouchArea { + width: 240 + height: 320 + + minimumTouchPoints: 1 + maximumTouchPoints: 5 + touchPoints: [ + TouchPoint { objectName: "point1" }, + TouchPoint { objectName: "point2" }, + TouchPoint { objectName: "point3" }, + TouchPoint { objectName: "point4" }, + TouchPoint { objectName: "point5" } + ] + + function clearCounts() { + touchPointPressCount = 0; + touchPointUpdateCount = 0; + touchPointReleaseCount = 0; + touchPointCancelCount = 0; + touchCount = 0; + touchUpdatedHandled = false; + } + + property int touchPointPressCount: 0 + property int touchPointUpdateCount: 0 + property int touchPointReleaseCount: 0 + property int touchPointCancelCount: 0 + property int touchCount: 0 + property bool touchUpdatedHandled: false + + onPressed: { touchPointPressCount = touchPoints.length } + onUpdated: { touchPointUpdateCount = touchPoints.length } + onReleased: { touchPointReleaseCount = touchPoints.length } + onCanceled: { touchPointCancelCount = touchPoints.length } + onTouchUpdated: { + touchCount = touchPoints.length + touchUpdatedHandled = true + } +} diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp index 8320d899f9..2872556a94 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp +++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp @@ -69,6 +69,7 @@ private slots: void transformedTouchArea(); void mouseInteraction(); void mouseInteraction_data(); + void cancel(); private: QQuickView *createAndShowView(const QString &file); @@ -914,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()); @@ -1195,6 +1196,60 @@ void tst_QQuickMultiPointTouchArea::mouseInteraction() QCOMPARE(area->property("touchCount").toInt(), 0); } +void tst_QQuickMultiPointTouchArea::cancel() +{ + QScopedPointer<QQuickView> window(createAndShowView("cancel.qml")); + QVERIFY(window->rootObject() != 0); + + QQuickMultiPointTouchArea *area = qobject_cast<QQuickMultiPointTouchArea *>(window->rootObject()); + QTest::QTouchEventSequence sequence = QTest::touchEvent(window.data(), device); + QQuickTouchPoint *point1 = area->findChild<QQuickTouchPoint*>("point1"); + + QPoint p1(20,100); + sequence.press(0, p1).commit(); + QQuickTouchUtils::flush(window.data()); + QCOMPARE(point1->pressed(), true); + QCOMPARE(area->property("touchPointPressCount").toInt(), 1); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchPointCancelCount").toInt(), 0); + QCOMPARE(area->property("touchCount").toInt(), 1); + QMetaObject::invokeMethod(area, "clearCounts"); + + area->setVisible(false); + // we should get a onCancel signal + QCOMPARE(point1->pressed(), false); + QCOMPARE(area->property("touchPointPressCount").toInt(), 0); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchPointCancelCount").toInt(), 1); + QCOMPARE(area->property("touchCount").toInt(), 0); + QMetaObject::invokeMethod(area, "clearCounts"); + area->setVisible(true); + + + sequence.press(0, p1).commit(); + QQuickTouchUtils::flush(window.data()); + QCOMPARE(point1->pressed(), true); + QCOMPARE(area->property("touchPointPressCount").toInt(), 1); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchPointCancelCount").toInt(), 0); + QCOMPARE(area->property("touchCount").toInt(), 1); + QMetaObject::invokeMethod(area, "clearCounts"); + + area->setEnabled(false); + // we should get a onCancel signal + QCOMPARE(point1->pressed(), false); + QCOMPARE(area->property("touchPointPressCount").toInt(), 0); + QCOMPARE(area->property("touchPointUpdateCount").toInt(), 0); + QCOMPARE(area->property("touchPointReleaseCount").toInt(), 0); + QCOMPARE(area->property("touchPointCancelCount").toInt(), 1); + QCOMPARE(area->property("touchCount").toInt(), 0); + QMetaObject::invokeMethod(area, "clearCounts"); + +} + QTEST_MAIN(tst_QQuickMultiPointTouchArea) diff --git a/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp b/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp index 355301878d..3bf61e8f17 100644 --- a/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp +++ b/tests/auto/quick/qquickopenglinfo/tst_qquickopenglinfo.cpp @@ -48,7 +48,7 @@ private slots: void tst_QQuickOpenGLInfo::testProperties() { QQuickView view; - view.setSource(QUrl::fromLocalFile("data/basic.qml")); + view.setSource(testFileUrl("basic.qml")); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); diff --git a/tests/auto/quick/qquickpathview/data/qtbug37815.qml b/tests/auto/quick/qquickpathview/data/qtbug37815.qml new file mode 100644 index 0000000000..3fd4daca63 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/qtbug37815.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Netris +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 + +Rectangle { + width: 600 + height: 400 + PathView { + objectName: "pathView" + model: 10 + anchors.fill: parent + pathItemCount: 5 + cacheItemCount: 5 + highlightRangeMode: PathView.StrictlyEnforceRange + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + + path: Path { + startX: 0 + startY: 50 + PathLine { + x: 600 + y: 50 + } + } + + delegate: Component { + Text { + width: 50 + height: 50 + text: index + objectName: "delegate" + index + font.pixelSize: 24 + color: PathView.isCurrentItem ? "green" : "black" + } + } + } +} + diff --git a/tests/auto/quick/qquickpathview/data/qtbug53464.qml b/tests/auto/quick/qquickpathview/data/qtbug53464.qml new file mode 100644 index 0000000000..d30d404e68 --- /dev/null +++ b/tests/auto/quick/qquickpathview/data/qtbug53464.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Netris +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 + +Rectangle { + width: 600 + height: 400 + PathView { + objectName: "pathView" + model: 10 + anchors.fill: parent + pathItemCount: 5 + highlightRangeMode: PathView.StrictlyEnforceRange + preferredHighlightBegin: 0.5 + preferredHighlightEnd: 0.5 + currentIndex: 8 + + path: Path { + startX: 0 + startY: 50 + PathLine { + x: 600 + y: 50 + } + } + + delegate: Component { + Text { + width: 50 + height: 50 + text: index + objectName: "delegate" + index + font.pixelSize: 24 + color: PathView.isCurrentItem ? "green" : "black" + } + } + } +} + diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp index 6761313210..d013d190ec 100644 --- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp +++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp @@ -135,7 +135,9 @@ private slots: void nestedinFlickable(); void flickableDelegate(); void jsArrayChange(); + void qtbug37815(); void qtbug42716(); + void qtbug53464(); void addCustomAttribute(); void movementDirection_data(); void movementDirection(); @@ -2330,6 +2332,31 @@ void tst_QQuickPathView::jsArrayChange() QCOMPARE(spy.count(), 1); } +void tst_QQuickPathView::qtbug37815() +{ + QScopedPointer<QQuickView> window(createView()); + + window->setSource(testFileUrl("qtbug37815.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + // cache items will be created async. Let's wait... + QTest::qWait(1000); + + QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView"); + QVERIFY(pathView != Q_NULLPTR); + + const int pathItemCount = pathView->pathItemCount(); + const int cacheItemCount = pathView->cacheItemCount(); + int totalCount = 0; + foreach (QQuickItem *item, pathView->childItems()) { + if (item->objectName().startsWith(QLatin1String("delegate"))) + ++totalCount; + } + QCOMPARE(pathItemCount + cacheItemCount, totalCount); +} + /* This bug was one where if you jump the list such that the sole missing item needed to be * added in the middle of the list, it would instead move an item somewhere else in the list * to the middle (messing it up very badly). @@ -2378,6 +2405,29 @@ void tst_QQuickPathView::qtbug42716() QVERIFY(!itemMiss); } +void tst_QQuickPathView::qtbug53464() +{ + QScopedPointer<QQuickView> window(createView()); + + window->setSource(testFileUrl("qtbug53464.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView"); + QVERIFY(pathView != Q_NULLPTR); + const int currentIndex = pathView->currentIndex(); + QCOMPARE(currentIndex, 8); + + const int pathItemCount = pathView->pathItemCount(); + int totalCount = 0; + foreach (QQuickItem *item, pathView->childItems()) { + if (item->objectName().startsWith(QLatin1String("delegate"))) + ++totalCount; + } + QCOMPARE(pathItemCount, totalCount); +} + void tst_QQuickPathView::addCustomAttribute() { const QScopedPointer<QQuickView> window(createView()); 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/qquickscreen/data/screen.qml b/tests/auto/quick/qquickscreen/data/screen.qml index c246b3cd83..cf60d0ae40 100644 --- a/tests/auto/quick/qquickscreen/data/screen.qml +++ b/tests/auto/quick/qquickscreen/data/screen.qml @@ -1,5 +1,5 @@ import QtQuick 2.0 -import QtQuick.Window 2.0 as Window +import QtQuick.Window 2.3 as Window Item { width: 100 @@ -10,6 +10,18 @@ Item { property int priOrientation: Window.Screen.primaryOrientation property int updateMask: Window.Screen.orientationUpdateMask property real devicePixelRatio: Window.Screen.devicePixelRatio + property int vx: Window.Screen.virtualX + property int vy: Window.Screen.virtualY Window.Screen.orientationUpdateMask: Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation + + property int screenCount: Qt.application.screens.length + + property variant allScreens + Component.onCompleted: { + allScreens = []; + var s = Qt.application.screens; + for (var i = 0; i < s.length; ++i) + allScreens.push(s[i]); + } } diff --git a/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp b/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp index 92afdf6864..26b687a4a6 100644 --- a/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp +++ b/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp @@ -33,13 +33,15 @@ #include <QtQuick/QQuickView> #include <QtGui/QScreen> #include "../../shared/util.h" - +#include <QtQuick/private/qquickscreen_p.h> +#include <QDebug> class tst_qquickscreen : public QQmlDataTest { Q_OBJECT private slots: void basicProperties(); void screenOnStartup(); + void fullScreenList(); }; void tst_qquickscreen::basicProperties() @@ -62,6 +64,10 @@ void tst_qquickscreen::basicProperties() QCOMPARE(int(screen->orientationUpdateMask()), root->property("updateMask").toInt()); QCOMPARE(screen->devicePixelRatio(), root->property("devicePixelRatio").toReal()); QVERIFY(screen->devicePixelRatio() >= 1.0); + QCOMPARE(screen->geometry().x(), root->property("vx").toInt()); + QCOMPARE(screen->geometry().y(), root->property("vy").toInt()); + + QVERIFY(root->property("screenCount").toInt() == QGuiApplication::screens().count()); } void tst_qquickscreen::screenOnStartup() @@ -83,6 +89,38 @@ void tst_qquickscreen::screenOnStartup() QCOMPARE(int(screen->orientationUpdateMask()), root->property("updateMask").toInt()); QCOMPARE(screen->devicePixelRatio(), root->property("devicePixelRatio").toReal()); QVERIFY(screen->devicePixelRatio() >= 1.0); + QCOMPARE(screen->geometry().x(), root->property("vx").toInt()); + QCOMPARE(screen->geometry().y(), root->property("vy").toInt()); +} + +void tst_qquickscreen::fullScreenList() +{ + QQuickView view; + view.setSource(testFileUrl("screen.qml")); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QQuickItem* root = view.rootObject(); + QVERIFY(root); + + QJSValue screensArray = root->property("allScreens").value<QJSValue>(); + QVERIFY(screensArray.isArray()); + int length = screensArray.property("length").toInt(); + const QList<QScreen *> screenList = QGuiApplication::screens(); + QVERIFY(length == screenList.count()); + + for (int i = 0; i < length; ++i) { + QQuickScreenInfo *info = qobject_cast<QQuickScreenInfo *>(screensArray.property(i).toQObject()); + QVERIFY(info != nullptr); + QCOMPARE(screenList[i]->name(), info->name()); + QCOMPARE(screenList[i]->size().width(), info->width()); + QCOMPARE(screenList[i]->size().height(), info->height()); + QCOMPARE(screenList[i]->availableVirtualGeometry().width(), info->desktopAvailableWidth()); + QCOMPARE(screenList[i]->availableVirtualGeometry().height(), info->desktopAvailableHeight()); + QCOMPARE(screenList[i]->devicePixelRatio(), info->devicePixelRatio()); + QCOMPARE(screenList[i]->geometry().x(), info->virtualX()); + QCOMPARE(screenList[i]->geometry().y(), info->virtualY()); + } } QTEST_MAIN(tst_qquickscreen) diff --git a/tests/auto/quick/qquickshadereffect/data/MyIcon.qml b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml new file mode 100644 index 0000000000..b83da321f2 --- /dev/null +++ b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples 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.4 + +Item { + id: root + + property alias source: image.source + property bool shaderActive: false + + implicitWidth: image.width + + Image { + id: image + objectName: "image" + anchors { top: parent.top; bottom: parent.bottom } + sourceSize.height: height + + visible: !shaderActive + } + + ShaderEffect { + id: colorizedImage + + anchors.fill: parent + visible: shaderActive && image.status == Image.Ready + supportsAtlasTextures: true + + property Image source: visible ? image : null + + fragmentShader: " + varying highp vec2 qt_TexCoord0; + uniform sampler2D source; + void main() { + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); + }" + } +} diff --git a/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml new file mode 100644 index 0000000000..d1292f74b8 --- /dev/null +++ b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples 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.4 + +Item { + width: 400 + height: 700 + + MyIcon { + id: icon + + height: 24 + source: "star.png" + shaderActive: true + } + + MyIcon { + anchors.top: icon.bottom + + height: 24 + source: "star.png" + } +} diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp index 171e0800e1..fe33dbd4d8 100644 --- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp +++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp @@ -33,12 +33,13 @@ #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) @@ -47,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 @@ -75,6 +77,7 @@ private slots: void deleteSourceItem(); void deleteShaderEffectSource(); + void twoImagesOneShaderEffect(); private: enum PresenceFlags { @@ -82,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() @@ -120,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. @@ -133,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" @@ -148,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") @@ -156,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" @@ -178,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") @@ -219,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() @@ -249,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) @@ -263,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() @@ -301,6 +307,19 @@ void tst_qquickshadereffect::deleteShaderEffectSource() delete view; } +void tst_qquickshadereffect::twoImagesOneShaderEffect() +{ + // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash + QQuickView *view = new QQuickView(0); + view->setSource(QUrl::fromLocalFile(testFile("twoImagesOneShaderEffect.qml"))); + view->show(); + QVERIFY(QTest::qWaitForWindowExposed(view)); + QVERIFY(view); + QObject *obj = view->rootObject(); + QVERIFY(obj); + delete view; +} + QTEST_MAIN(tst_qquickshadereffect) #include "tst_qquickshadereffect.moc" 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 6c0da40b8e..6f7d494255 100644 --- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp @@ -2771,18 +2771,19 @@ void tst_qquicktext::lineLaidOutRelayout() QVERIFY(!textPrivate->extra.isAllocated()); - qreal maxH = 0; + qreal y = 0.0; for (int i = 0; i < textPrivate->layout.lineCount(); ++i) { QTextLine line = textPrivate->layout.lineAt(i); const QRectF r = line.rect(); - const qreal h = line.height(); if (r.x() == 0) { - QCOMPARE(r.y(), i * h); - maxH = qMax(maxH, r.y() + h); + QCOMPARE(r.y(), y); } else { + if (qFuzzyIsNull(r.y())) + y = 0.0; QCOMPARE(r.x(), myText->width() / 2); - QCOMPARE(r.y(), i * h - maxH); + QCOMPARE(r.y(), y); } + y += line.height(); } } diff --git a/tests/auto/quick/qquicktextinput/data/focusOnlyOneOnPress.qml b/tests/auto/quick/qquicktextinput/data/focusOnlyOneOnPress.qml new file mode 100644 index 0000000000..037b36c8ff --- /dev/null +++ b/tests/auto/quick/qquicktextinput/data/focusOnlyOneOnPress.qml @@ -0,0 +1,32 @@ +import QtQuick 2.2 + +Rectangle { + width: 400 + height: 400 + + Column { + spacing: 5 + TextInput { + objectName: "first" + onEditingFinished: second.focus = true + width: 100 + Rectangle { anchors.fill: parent; color: parent.activeFocus ? "red" : "blue"; opacity: 0.3 } + } + TextInput { + id: second + objectName: "second" + onEditingFinished: third.focus = true + width: 100 + Rectangle { anchors.fill: parent; color: parent.activeFocus ? "red" : "blue"; opacity: 0.3 } + } + TextInput { + objectName: "third" + id: third + width: 100 + Rectangle { anchors.fill: parent; color: parent.activeFocus ? "red" : "blue"; opacity: 0.3 } + } + Component.onCompleted: { + second.focus = true + } + } +} diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp index f505487a14..8dc3053d89 100644 --- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp @@ -154,6 +154,7 @@ private slots: #endif void readOnly(); void focusOnPress(); + void focusOnPressOnlyOneItem(); void openInputPanel(); void setHAlignClearCache(); @@ -200,6 +201,8 @@ private slots: void implicitSize(); void implicitSizeBinding_data(); void implicitSizeBinding(); + void implicitResize_data(); + void implicitResize(); void negativeDimensions(); @@ -3511,6 +3514,46 @@ void tst_qquicktextinput::focusOnPress() QTest::mouseRelease(&window, Qt::LeftButton, noModifiers); } +void tst_qquicktextinput::focusOnPressOnlyOneItem() +{ + QQuickView window(testFileUrl("focusOnlyOneOnPress.qml")); + window.show(); + window.requestActivate(); + QTest::qWaitForWindowActive(&window); + + QQuickTextInput *first = window.rootObject()->findChild<QQuickTextInput*>("first"); + QQuickTextInput *second = window.rootObject()->findChild<QQuickTextInput*>("second"); + QQuickTextInput *third = window.rootObject()->findChild<QQuickTextInput*>("third"); + + // second is focused onComplete + QVERIFY(second->hasActiveFocus()); + + // and first will try focus when we press it + QVERIFY(first->focusOnPress()); + + // write some text to start editing + QTest::keyClick(&window, Qt::Key_A); + + // click the first input. naturally, we are giving focus on press, but + // second's editingFinished also attempts to assign focus. lastly, focus + // should bounce back to second from first's editingFinished signal. + // + // this is a contrived example to be sure, but at the end of this, the + // important thing is that only one thing should have activeFocus. + Qt::KeyboardModifiers noModifiers = 0; + QTest::mousePress(&window, Qt::LeftButton, noModifiers, QPoint(10, 10)); + + // make sure the press is processed. + QGuiApplication::processEvents(); + + QVERIFY(second->hasActiveFocus()); // make sure it's still there + QVERIFY(!third->hasActiveFocus()); // make sure it didn't end up anywhere else + QVERIFY(!first->hasActiveFocus()); // make sure it didn't end up anywhere else + + // reset state + QTest::mouseRelease(&window, Qt::LeftButton, noModifiers, QPoint(10, 10)); +} + void tst_qquicktextinput::openInputPanel() { PlatformInputContext platformInputContext; @@ -5969,6 +6012,39 @@ void tst_qquicktextinput::implicitSizeBinding() QCOMPARE(textObject->height(), textObject->implicitHeight()); } +void tst_qquicktextinput::implicitResize_data() +{ + QTest::addColumn<int>("alignment"); + QTest::newRow("left") << int(Qt::AlignLeft); + QTest::newRow("center") << int(Qt::AlignHCenter); + QTest::newRow("right") << int(Qt::AlignRight); +} + +void tst_qquicktextinput::implicitResize() +{ + QFETCH(int, alignment); + + QQmlComponent component(&engine); + component.setData("import QtQuick 2.0\nTextInput { }", QUrl::fromLocalFile("")); + + QScopedPointer<QQuickTextInput> textInput(qobject_cast<QQuickTextInput *>(component.create())); + QVERIFY(!textInput.isNull()); + + QScopedPointer<QQuickTextInput> textField(qobject_cast<QQuickTextInput *>(component.create())); + QVERIFY(!textField.isNull()); + QQuickTextInputPrivate::get(textField.data())->setImplicitResizeEnabled(false); + + textInput->setWidth(200); + textField->setImplicitWidth(200); + + textInput->setHAlign(QQuickTextInput::HAlignment(alignment)); + textField->setHAlign(QQuickTextInput::HAlignment(alignment)); + + textInput->setText("Qt"); + textField->setText("Qt"); + + QCOMPARE(textField->positionToRectangle(0), textInput->positionToRectangle(0)); +} void tst_qquicktextinput::negativeDimensions() { 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/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp index 17c09805aa..cabfb97914 100644 --- a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp +++ b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp @@ -4094,9 +4094,10 @@ void tst_qquickvisualdatamodel::asynchronousRemove() controller.incubateFor(50); } while (timer.elapsed() < 1000 && controller.incubatingObjectCount() > 0); - QVERIFY(requester.itemInitialized); - QCOMPARE(requester.itemCreated, requester.itemInitialized); - QCOMPARE(requester.itemDestroyed, requester.itemInitialized); + // The item was removed before incubation started. We should not have any item created. + QVERIFY(!requester.itemInitialized); + QVERIFY(!requester.itemCreated); + QVERIFY(!requester.itemDestroyed); } else { item = qobject_cast<QQuickItem*>(visualModel->object(completeIndex, false)); QVERIFY(item); diff --git a/tests/auto/quick/qquickwindow/data/windowWithScreen.qml b/tests/auto/quick/qquickwindow/data/windowWithScreen.qml new file mode 100644 index 0000000000..fdc0be3388 --- /dev/null +++ b/tests/auto/quick/qquickwindow/data/windowWithScreen.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 +import QtQuick.Window 2.3 as Window + +Window.Window { + color: "#00FF00" + targetScreen: Qt.application.screens[0] + Item { + objectName: "item" + } +} 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 0985198d65..bfffa6f7f5 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -40,7 +40,6 @@ #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> @@ -158,6 +157,7 @@ public: lastVelocity = lastVelocityFromMouseMove = QVector2D(); lastMousePos = QPointF(); lastMouseCapabilityFlags = 0; + touchEventCount = 0; } static void clearMousePressCounter() @@ -275,22 +275,14 @@ 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(); @@ -311,11 +303,15 @@ private slots: void touchEvent_reentrant(); void touchEvent_velocity(); + void mergeTouchPointLists_data(); + void mergeTouchPointLists(); + void mouseFromTouch_basic(); void clearWindow(); void qmlCreation(); + void qmlCreationWithScreen(); void clearColor(); void defaultState(); @@ -370,6 +366,10 @@ private slots: void testRenderJob(); void testHoverChildMouseEventFilter(); + void testHoverTimestamp(); + + void pointerEventTypeAndPointCount(); + private: QTouchDevice *touchDevice; QTouchDevice *touchDeviceWithVelocity; @@ -529,9 +529,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()); @@ -539,9 +538,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); @@ -551,6 +551,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); @@ -561,6 +562,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); @@ -571,6 +573,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); @@ -675,6 +678,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) @@ -686,6 +690,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 @@ -710,6 +716,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) @@ -719,7 +727,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(); @@ -745,6 +755,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; @@ -863,6 +874,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); @@ -895,6 +908,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 @@ -1049,6 +1123,24 @@ void tst_qquickwindow::qmlCreation() QCOMPARE(item->window(), window); } +void tst_qquickwindow::qmlCreationWithScreen() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("windowWithScreen.qml")); + QObject *created = component.create(); + QScopedPointer<QObject> cleanup(created); + QVERIFY(created); + + QQuickWindow *window = qobject_cast<QQuickWindow*>(created); + QVERIFY(window); + QCOMPARE(window->color(), QColor(Qt::green)); + + QQuickItem *item = window->findChild<QQuickItem*>("item"); + QVERIFY(item); + QCOMPARE(item->window(), window); +} + void tst_qquickwindow::clearColor() { //::grab examines rendering to make sure it works visually @@ -2326,6 +2418,142 @@ void tst_qquickwindow::testHoverChildMouseEventFilter() QCOMPARE(middleItem->eventCount(QEvent::HoverEnter), 0); } +class HoverTimestampConsumer : public QQuickItem +{ + Q_OBJECT +public: + HoverTimestampConsumer(QQuickItem *parent = 0) + : QQuickItem(parent) + { + setAcceptHoverEvents(true); + } + + void hoverEnterEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + void hoverLeaveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + void hoverMoveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); } + + QList<ulong> hoverTimestamps; +}; + +// Checks that a QHoverEvent carries the timestamp of the QMouseEvent that caused it. +// QTBUG-54600 +void tst_qquickwindow::testHoverTimestamp() +{ + QQuickWindow window; + + window.resize(200, 200); + window.setPosition(100, 100); + window.setTitle(QTest::currentTestFunction()); + window.show(); + QVERIFY(QTest::qWaitForWindowActive(&window)); + + HoverTimestampConsumer *hoverConsumer = new HoverTimestampConsumer(window.contentItem()); + hoverConsumer->setWidth(100); + hoverConsumer->setHeight(100); + hoverConsumer->setX(50); + hoverConsumer->setY(50); + + // First position, outside + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(40, 40), QPointF(40, 40), QPointF(140, 140), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(10); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + + // Enter + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(50, 50), QPointF(50, 50), QPointF(150, 150), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(20); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 1); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 20UL); + + // Move + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(60, 60), QPointF(60, 60), QPointF(160, 160), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(30); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 2); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 30UL); + + // Move + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(100, 100), QPointF(100, 100), QPointF(200, 200), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(40); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 3); + QCOMPARE(hoverConsumer->hoverTimestamps.last(), 40UL); + + // Leave + { + QMouseEvent mouseEvent(QEvent::MouseMove, QPointF(160, 160), QPointF(160, 160), QPointF(260, 260), + Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventNotSynthesized); + mouseEvent.setTimestamp(5); + QVERIFY(QCoreApplication::sendEvent(&window, &mouseEvent)); + } + QCOMPARE(hoverConsumer->hoverTimestamps.size(), 4); + 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 70e5b8ef6a..6e9998c061 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -4,8 +4,9 @@ PUBLICTESTS += \ geometry \ qquickpixmapcache -contains(QT_CONFIG, opengl(es1|es2)?) { +qtConfig(opengl(es1|es2)?) { PUBLICTESTS += \ + drawingmodes \ rendernode qtHaveModule(widgets): PUBLICTESTS += nodes @@ -88,9 +89,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 313e5ac196..e15649e62c 100644 --- a/tests/auto/quick/rendernode/tst_rendernode.cpp +++ b/tests/auto/quick/rendernode/tst_rendernode.cpp @@ -215,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 diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp index c0d1b53e92..f6d624d871 100644 --- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp +++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp @@ -44,6 +44,7 @@ #include <private/qsgcontext_p.h> #include <private/qsgrenderloop_p.h> +#include "../../shared/util.h" #include "../shared/visualtestutil.h" using namespace QQuickVisualTestUtil; @@ -92,7 +93,7 @@ private: QColor m_color; }; -class tst_SceneGraph : public QObject +class tst_SceneGraph : public QQmlDataTest { Q_OBJECT @@ -112,6 +113,7 @@ private slots: private: bool m_brokenMipmapSupport; + QQuickView *createView(const QString &file, QWindow *parent = 0, int x = -1, int y = -1, int w = -1, int h = -1); }; template <typename T> class ScopedList : public QList<T> { @@ -123,6 +125,8 @@ void tst_SceneGraph::initTestCase() { qmlRegisterType<PerPixelRect>("SceneGraphTest", 1, 0, "PerPixelRect"); + QQmlDataTest::initTestCase(); + QSGRenderLoop *loop = QSGRenderLoop::instance(); qDebug() << "RenderLoop: " << loop; @@ -162,26 +166,16 @@ void tst_SceneGraph::initTestCase() #endif } -QQuickView *createView(const QString &file, QWindow *parent = 0, int x = -1, int y = -1, int w = -1, int h = -1) +QQuickView *tst_SceneGraph::createView(const QString &file, QWindow *parent, int x, int y, int w, int h) { QQuickView *view = new QQuickView(parent); - view->setSource(QUrl::fromLocalFile("data/" + file)); + view->setSource(testFileUrl(file)); if (x >= 0 && y >= 0) view->setPosition(x, y); if (w >= 0 && h >= 0) view->resize(w, h); view->show(); return view; } -QImage showAndGrab(const QString &file, int w, int h) -{ - QQuickView view; - view.setSource(QUrl::fromLocalFile(QStringLiteral("data/") + file)); - if (w >= 0 && h >= 0) - view.resize(w, h); - view.create(); - return view.grabWindow(); -} - // Assumes the images are opaque white... bool containsSomethingOtherThanWhite(const QImage &image) { @@ -384,17 +378,17 @@ void tst_SceneGraph::render_data() QTest::addColumn<QList<Sample> >("finalStage"); QList<QString> files; - files << "data/render_DrawSets.qml" - << "data/render_Overlap.qml" - << "data/render_MovingOverlap.qml" - << "data/render_BreakOpacityBatch.qml" - << "data/render_OutOfFloatRange.qml" - << "data/render_StackingOrder.qml" - << "data/render_ImageFiltering.qml" - << "data/render_bug37422.qml" - << "data/render_OpacityThroughBatchRoot.qml"; + files << "render_DrawSets.qml" + << "render_Overlap.qml" + << "render_MovingOverlap.qml" + << "render_BreakOpacityBatch.qml" + << "render_OutOfFloatRange.qml" + << "render_StackingOrder.qml" + << "render_ImageFiltering.qml" + << "render_bug37422.qml" + << "render_OpacityThroughBatchRoot.qml"; if (!m_brokenMipmapSupport) - files << "data/render_Mipmap.qml"; + files << "render_Mipmap.qml"; QRegExp sampleCount("#samples: *(\\d+)"); // X:int Y:int R:float G:float B:float Error:float @@ -402,7 +396,7 @@ void tst_SceneGraph::render_data() QRegExp finalSamples("#final: *(\\d+) *(\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+)"); foreach (QString fileName, files) { - QFile file(fileName); + QFile file(testFile(fileName)); if (!file.open(QFile::ReadOnly)) { qFatal("render_data: QFile::open failed! file=%s, error=%s", qPrintable(fileName), qPrintable(file.errorString())); @@ -452,7 +446,7 @@ void tst_SceneGraph::render() QQuickView view; view.rootContext()->setContextProperty("suite", &suite); - view.setSource(QUrl::fromLocalFile(file)); + view.setSource(testFileUrl(file)); view.setResizeMode(QQuickView::SizeViewToRootObject); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); @@ -501,7 +495,7 @@ void tst_SceneGraph::hideWithOtherContext() { QQuickView view; - view.setSource(QUrl::fromLocalFile("data/simple.qml")); + view.setSource(testFileUrl("simple.qml")); view.setResizeMode(QQuickView::SizeViewToRootObject); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); @@ -549,6 +543,7 @@ void tst_SceneGraph::createTextureFromImage() 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/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 15d7ffd9d9..1594da46bd 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: @@ -155,6 +161,7 @@ private slots: void tapOnDismissiveTopMouseAreaClicksBottomOne(); void touchGrabCausesMouseUngrab(); + void touchPointDeliveryOrder(); void hoverEnabled(); @@ -191,11 +198,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 +219,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 +260,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 +295,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 +581,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 +601,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); @@ -660,12 +663,13 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress); QCOMPARE(filteredEventList.count(), 1); - // eventItem1 should have the mouse grab, and have moved the itemForTouchPointId + // eventItem1 should have the mouse grab, and have moved the grab // 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); + 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); @@ -681,9 +685,9 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable() // 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); + QCOMPARE(pointerEvent->point(0)->grabber(), flickable); QTest::touchEvent(window, device).release(0, p3, window); QQuickTouchUtils::flush(window); @@ -1097,9 +1101,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,14 +1231,117 @@ 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; // device->setType(QTouchDevice::TouchScreen); // QWindowSystemInterface::registerTouchDevice(device); + // Ensure the cursor is away from the window + QCursor::setPos(0, 0); + QQuickView *window = createView(); window->setSource(testFileUrl("hoverMouseAreas.qml")); + window->setPosition(10, 10); window->show(); window->requestActivate(); @@ -1272,8 +1377,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()); @@ -1284,33 +1389,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 09359060f6..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,8 @@ private slots: void readback(); void renderingSignals(); void grabBeforeShow(); + void reparentToNewWindow(); + void nullEngine(); }; @@ -301,6 +304,39 @@ 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; + // Default should have no errors, even with a null qml engine + QVERIFY(widget.errors().isEmpty()); + QCOMPARE(widget.status(), QQuickWidget::Null); + + // A QML engine should be created lazily. + QVERIFY(widget.rootContext()); + QVERIFY(widget.engine()); +} + QTEST_MAIN(tst_qquickwidget) #include "tst_qquickwidget.moc" 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 |