aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquickshape/tst_qquickshape.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quick/qquickshape/tst_qquickshape.cpp')
-rw-r--r--tests/auto/quick/qquickshape/tst_qquickshape.cpp402
1 files changed, 399 insertions, 3 deletions
diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
index 61fb260612..851475e2cd 100644
--- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp
+++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
@@ -1,6 +1,6 @@
-/****************************************************************************
+/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -34,6 +34,7 @@
#include <QtQml/qqmlexpression.h>
#include <QtQml/qqmlincubator.h>
#include <QtQuickShapes/private/qquickshape_p.h>
+#include <QStandardPaths>
#include "../../shared/util.h"
#include "../shared/viewtestutil.h"
@@ -42,6 +43,28 @@
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
+class PolygonProvider : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QVector<QPolygonF> paths READ paths WRITE setPaths NOTIFY pathsChanged)
+
+public:
+ QVector<QPolygonF> paths() const { return m_paths; }
+ void setPaths(QVector<QPolygonF> paths)
+ {
+ if (m_paths == paths)
+ return;
+ m_paths = paths;
+ emit pathsChanged();
+ }
+
+signals:
+ void pathsChanged();
+
+private:
+ QVector<QPolygonF> m_paths;
+};
+
class tst_QQuickShape : public QQmlDataTest
{
Q_OBJECT
@@ -57,6 +80,16 @@ private slots:
void renderWithMultipleSp();
void radialGrad();
void conicalGrad();
+ void renderPolyline();
+ void renderMultiline();
+ void polylineDataTypes_data();
+ void polylineDataTypes();
+ void multilineDataTypes_data();
+ void multilineDataTypes();
+ void multilineStronglyTyped();
+
+private:
+ QVector<QPolygonF> m_lowPolyLogo;
};
tst_QQuickShape::tst_QQuickShape()
@@ -66,11 +99,36 @@ tst_QQuickShape::tst_QQuickShape()
const char *uri = "tst_qquickpathitem";
qmlRegisterType<QQuickShape>(uri, 1, 0, "Shape");
- qmlRegisterType<QQuickShapePath>(uri, 1, 0, "ShapePath");
+ qmlRegisterType<QQuickShapePath, 14>(uri, 1, 0, "ShapePath");
qmlRegisterUncreatableType<QQuickShapeGradient>(uri, 1, 0, "ShapeGradient", QQuickShapeGradient::tr("ShapeGradient is an abstract base class"));
qmlRegisterType<QQuickShapeLinearGradient>(uri, 1, 0, "LinearGradient");
qmlRegisterType<QQuickShapeRadialGradient>(uri, 1, 0, "RadialGradient");
qmlRegisterType<QQuickShapeConicalGradient>(uri, 1, 0, "ConicalGradient");
+ qmlRegisterType<QQuickPathPolyline>(uri, 1, 0, "PathPolyline");
+ qmlRegisterType<PolygonProvider>("Qt.test", 1, 0, "PolygonProvider");
+
+ m_lowPolyLogo << (QPolygonF() <<
+ QPointF(20, 0) <<
+ QPointF(140, 0) <<
+ QPointF(140, 80) <<
+ QPointF(120, 100) <<
+ QPointF(0, 100) <<
+ QPointF(0, 20) <<
+ QPointF(20, 0) )
+ << (QPolygonF() << QPointF(20, 80) <<
+ QPointF(60, 80) <<
+ QPointF(80, 60) <<
+ QPointF(80, 20) <<
+ QPointF(40, 20) <<
+ QPointF(20, 40) <<
+ QPointF(20, 80) )
+ << (QPolygonF() << QPointF(80, 80) <<
+ QPointF(70, 70) )
+ << (QPolygonF() << QPointF(120, 80) <<
+ QPointF(100, 60) <<
+ QPointF(100, 20) )
+ << (QPolygonF() << QPointF(100, 40) <<
+ QPointF(120, 40) );
}
void tst_QQuickShape::initValues()
@@ -311,6 +369,344 @@ void tst_QQuickShape::conicalGrad()
qPrintable(errorMessage));
}
+void tst_QQuickShape::renderPolyline()
+{
+ QScopedPointer<QQuickView> window(createView());
+
+ window->setSource(testFileUrl("pathitem7.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("pathitem3.png").toLocalFile()); // It's a recreation of pathitem3 using PathPolyline
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/pathitem7.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+}
+
+void tst_QQuickShape::renderMultiline()
+{
+ QScopedPointer<QQuickView> window(createView());
+
+ window->setSource(testFileUrl("pathitem8.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("pathitem8.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/pathitem8.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+}
+
+void tst_QQuickShape::polylineDataTypes_data()
+{
+ QTest::addColumn<QVariant>("path");
+
+ QTest::newRow("polygon") << QVariant::fromValue(m_lowPolyLogo.first());
+ {
+ QVector<QPointF> points;
+ points << m_lowPolyLogo.first();
+ QTest::newRow("vector of points") << QVariant::fromValue(points);
+ }
+ {
+ QList<QPointF> points;
+ for (const auto &point : m_lowPolyLogo.first())
+ points << point;
+ QTest::newRow("list of points") << QVariant::fromValue(points);
+ }
+ {
+ QVariantList points;
+ for (const auto &point : m_lowPolyLogo.first())
+ points << point;
+ QTest::newRow("QVariantList of points") << QVariant::fromValue(points);
+ }
+ {
+ QVector<QPoint> points;
+ for (const auto &point : m_lowPolyLogo.first())
+ points << point.toPoint();
+ QTest::newRow("vector of QPoint (integer points)") << QVariant::fromValue(points);
+ }
+ // Oddly, QPolygon is not supported, even though it's really QVector<QPoint>.
+ // We don't want to have a special case for it in QQuickPathPolyline::setPath(),
+ // but it could potentially be supported by fixing one of the QVariant conversions.
+}
+
+void tst_QQuickShape::polylineDataTypes()
+{
+ QFETCH(QVariant, path);
+
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("polyline.qml"));
+ QQuickShape *shape = qobject_cast<QQuickShape *>(window->rootObject());
+ QVERIFY(shape);
+ shape->setProperty("path", path);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("polyline.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/polyline.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+
+ QCOMPARE(shape->property("path").value<QVector<QPointF>>(), m_lowPolyLogo.first());
+ // Verify that QML sees it as an array of points
+ int i = 0;
+ for (QPointF p : m_lowPolyLogo.first()) {
+ QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue<int>(i++)));
+ QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p);
+ }
+}
+
+void tst_QQuickShape::multilineDataTypes_data()
+{
+ QTest::addColumn<QVariant>("paths");
+
+ QTest::newRow("vector of polygons") << QVariant::fromValue(m_lowPolyLogo);
+ {
+ QVector<QVector<QPointF>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPointF> points;
+ points << poly;
+ paths << points;
+ }
+ QTest::newRow("vector of point vectors") << QVariant::fromValue(paths);
+ }
+ {
+ QList<QVector<QPointF>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPointF> points;
+ points << poly;
+ paths << points;
+ }
+ QTest::newRow("list of point vectors") << QVariant::fromValue(paths);
+ }
+ {
+ QList<QList<QPointF>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPointF> points;
+ for (const auto &point : poly)
+ points << point;
+ paths << points;
+ }
+ QTest::newRow("list of point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QVariantList paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPointF> points;
+ points << poly;
+ paths << QVariant::fromValue(points);
+ }
+ QTest::newRow("QVariantList of point vectors") << QVariant::fromValue(paths);
+ }
+ {
+ QVariantList paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPointF> points;
+ for (const auto &point : poly)
+ points << point;
+ paths << QVariant::fromValue(points);
+ }
+ QTest::newRow("QVariantList of point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QVariantList paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVariantList points;
+ for (const auto &point : poly)
+ points << point;
+ paths << QVariant::fromValue(points);
+ }
+ QTest::newRow("QVariantList of QVariantLists") << QVariant::fromValue(paths);
+ }
+ /* These could be supported if QVariant knew how to convert lists and vectors of QPolygon to QPolygonF.
+ But they are omitted for now because we don't want to have special cases for them
+ in QQuickPathMultiline::setPaths(). Floating point is preferred for geometry in Qt Quick.
+ {
+ QList<QPolygon> paths;
+ for (const auto &poly : m_lowPolyLogo)
+ paths << poly.toPolygon();
+ QTest::newRow("list of QPolygon (integer points)") << QVariant::fromValue(paths);
+ }
+ {
+ QVector<QPolygon> paths;
+ for (const auto &poly : m_lowPolyLogo)
+ paths << poly.toPolygon();
+ QTest::newRow("vector of QPolygon (integer points)") << QVariant::fromValue(paths);
+ }
+ */
+ {
+ QList<QList<QPoint>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPoint> points;
+ for (const auto &point : poly)
+ points << point.toPoint();
+ paths << points;
+ }
+ QTest::newRow("list of integer point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QVector<QList<QPoint>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QList<QPoint> points;
+ for (const auto &point : poly)
+ points << point.toPoint();
+ paths << points;
+ }
+ QTest::newRow("vector of integer point lists") << QVariant::fromValue(paths);
+ }
+ {
+ QList<QVector<QPoint>> paths;
+ for (const auto &poly : m_lowPolyLogo) {
+ QVector<QPoint> points;
+ for (const auto &point : poly)
+ points << point.toPoint();
+ paths << points;
+ }
+ QTest::newRow("list of integer point vectors") << QVariant::fromValue(paths);
+ }
+}
+
+void tst_QQuickShape::multilineDataTypes()
+{
+ QFETCH(QVariant, paths);
+
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("multiline.qml"));
+ QQuickShape *shape = qobject_cast<QQuickShape *>(window->rootObject());
+ QVERIFY(shape);
+ shape->setProperty("paths", paths);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("multiline.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/multiline.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+
+ QVector<QVector<QPointF>> pointVectors;
+ for (auto v : m_lowPolyLogo)
+ pointVectors << v;
+ QCOMPARE(shape->property("paths").value<QVector<QVector<QPointF>>>(), pointVectors);
+ // Verify that QML sees it as an array of arrays of points
+ int i = 0;
+ for (auto pv : m_lowPolyLogo) {
+ int j = 0;
+ for (QPointF p : pv) {
+ QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue<int>(i)), Q_ARG(QVariant, QVariant::fromValue<int>(j++)));
+ QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p);
+ }
+ ++i;
+ }
+}
+
+void tst_QQuickShape::multilineStronglyTyped()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("multilineStronglyTyped.qml"));
+ QQuickShape *shape = qobject_cast<QQuickShape *>(window->rootObject());
+ QVERIFY(shape);
+ PolygonProvider *provider = shape->findChild<PolygonProvider*>("provider");
+ QVERIFY(provider);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+ provider->setPaths(m_lowPolyLogo);
+
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimimal platforms", Abort);
+
+ QImage img = window->grabWindow();
+ QVERIFY(!img.isNull());
+
+ QImage refImg(testFileUrl("multiline.png").toLocalFile());
+ QVERIFY(!refImg.isNull());
+
+ QString errorMessage;
+ const QImage actualImg = img.convertToFormat(refImg.format());
+ const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ if (!res) { // For visual inspection purposes.
+ QTest::qWait(5000);
+ const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
+ actualImg.save(tempLocation + QLatin1String("/multilineStronglyTyped.png"));
+ }
+ QVERIFY2(res, qPrintable(errorMessage));
+
+ QVector<QVector<QPointF>> pointVectors;
+ for (auto v : m_lowPolyLogo)
+ pointVectors << v;
+ QCOMPARE(shape->property("paths").value<QVector<QVector<QPointF>>>(), pointVectors);
+ // Verify that QML sees it as an array of arrays of points
+ int i = 0;
+ for (auto pv : m_lowPolyLogo) {
+ int j = 0;
+ for (QPointF p : pv) {
+ QMetaObject::invokeMethod(shape, "checkVertexAt", Q_ARG(QVariant, QVariant::fromValue<int>(i)), Q_ARG(QVariant, QVariant::fromValue<int>(j++)));
+ QCOMPARE(shape->property("vertexBeingChecked").toPointF(), p);
+ }
+ ++i;
+ }
+}
+
QTEST_MAIN(tst_QQuickShape)
#include "tst_qquickshape.moc"