aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJohn Tapsell <john.tapsell.ext@basyskom.de>2010-07-17 06:39:39 +0900
committerMike FABIAN <mike.fabian@basyskom.de>2010-07-27 11:13:13 +0200
commita5834337f28f112ec7ff0a7a007cec536f2246ab (patch)
tree1213e89fd0eeca776e06ed193b07e1b6ba597872 /tests
parent4b4bc65362c99d062bbd60f34e23435e009d5a3d (diff)
Changes: Add AllWidgets unit test, to check that all widgets paint inside of their bounding box
RevBy: TrustMe Details: * Check that all subitems are inside the geometry of the parent widget unless certain flags are set * Check that we delete the view and model * Check that all subitems are deleted * Check that QObject::parent is not set, and QGraphicsItem::parentItem is correctly set * Check that all painting happens inside the bounding rect * Check that all painting happens within the view's bounding rect * Check all of the above even when the widget is forced to size 1,1 * Check all of the above in right to left mode
Diffstat (limited to 'tests')
-rw-r--r--tests/ut_allwidgets/.gitignore1
-rw-r--r--tests/ut_allwidgets/ut_allwidgets.cpp283
-rw-r--r--tests/ut_allwidgets/ut_allwidgets.css6
-rw-r--r--tests/ut_allwidgets/ut_allwidgets.h64
-rw-r--r--tests/ut_allwidgets/ut_allwidgets.pro15
5 files changed, 369 insertions, 0 deletions
diff --git a/tests/ut_allwidgets/.gitignore b/tests/ut_allwidgets/.gitignore
new file mode 100644
index 00000000..d2915314
--- /dev/null
+++ b/tests/ut_allwidgets/.gitignore
@@ -0,0 +1 @@
+ut_allwidgets
diff --git a/tests/ut_allwidgets/ut_allwidgets.cpp b/tests/ut_allwidgets/ut_allwidgets.cpp
new file mode 100644
index 00000000..3064b59d
--- /dev/null
+++ b/tests/ut_allwidgets/ut_allwidgets.cpp
@@ -0,0 +1,283 @@
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui@nokia.com)
+**
+** This file is part of libmeegotouch.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui@nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+
+#include "ut_allwidgets.h"
+#include <QtGui/QPushButton>
+#include <QtGui/QGraphicsScene>
+#include <QtGui/QLabel>
+#include <QtGui/QWindowsStyle>
+
+//Gain access to the view..
+#define protected public
+#include <mwidgetcontroller.h>
+#undef protected
+
+#include <mapplication.h>
+#include <mlabel.h>
+#include <mbutton.h>
+#include <mtheme.h>
+#include <mwidgetview.h>
+#include <mbubbleitem.h>
+#include <mslider.h>
+
+Q_DECLARE_METATYPE(MWidgetController*)
+MApplication *app;
+
+Ut_AllWidgets::Ut_AllWidgets()
+{
+ static int argc = 1;
+ static char *argv[1] = { (char *) "./ut_allwidgets" };
+ app = new MApplication(argc, argv);
+ m_scene = new QGraphicsScene;
+ MTheme::loadCSS(qApp->applicationDirPath() + "/ut_allwidgets.css");
+ qRegisterMetaType<MWidgetController *>("MWidgetController *");
+}
+
+Ut_AllWidgets::~Ut_AllWidgets()
+{
+}
+
+void Ut_AllWidgets::cleanupTestCase()
+{
+ delete m_scene; // Deletes the items in the scene, too!
+ m_scene = 0;
+ delete app;
+}
+
+void Ut_AllWidgets::init()
+{
+}
+
+void Ut_AllWidgets::cleanup()
+{
+}
+
+void Ut_AllWidgets::debugDisplayImage(const QImage &image, int seconds)
+{
+ debugDisplayPixmap(QPixmap::fromImage(image), seconds);
+}
+void Ut_AllWidgets::debugDisplayPixmap(const QPixmap &pixmap, int seconds)
+{
+ QLabel *label = new QLabel;
+ label->setStyle(new QWindowsStyle);
+ label->setPixmap(pixmap);
+ label->show();
+ QTest::qWait(seconds*1000);
+ delete label;
+}
+
+bool Ut_AllWidgets::paintAndTestWidget(QGraphicsWidget *widget, bool strict)
+{
+ //Because of the async nature, make sure we've got the pixmaps
+ app->processEvents();
+ //Create a pixmap big enough for the widget plus room to check if it paints outside of its bounding box
+ QRectF boundingRect = widget->mapToScene(widget->boundingRect()).boundingRect();
+ if(!(widget->flags() & QGraphicsItem::ItemClipsChildrenToShape))
+ boundingRect |= widget->mapToScene(widget->childrenBoundingRect()).boundingRect();
+ QSize size = boundingRect.size().toSize();
+
+ QImage image(size + QSize(200,200), QImage::Format_ARGB32);
+ image.fill(Qt::transparent);
+
+ QPointF offset = QPointF(100,100) - boundingRect.topLeft();
+ QRectF pixmapBoundingRect = boundingRect.translated(offset);
+ QRectF pixmapGeometry = widget->geometry().translated(offset);
+
+ {
+ QPainter painter(&image);
+ m_scene->render(&painter, QRectF(0,0,image.width(), image.height()), boundingRect.adjusted(-100,-100,100,100));
+ //Draw in the bounding rect and geometry, for showing to the user
+ if(pixmapBoundingRect.adjusted(0,0,-1,-1).isValid()) {
+ painter.setPen(Qt::red);
+ painter.drawRect(pixmapBoundingRect.adjusted(0,0,-1,-1));
+ }
+ if(pixmapGeometry.adjusted(0,0,-1,-1).isValid()) {
+ painter.setPen(Qt::blue);
+ painter.drawRect(pixmapGeometry.adjusted(0,0,-1,-1));
+ }
+ }
+
+ //Now check that we haven't painted outside of the bounding box
+ for(int y = 0; y < image.height(); ++y)
+ for(int x = 0; x < image.width(); ++x) {
+ if(pixmapBoundingRect.contains(x,y)) {
+ if(!pixmapGeometry.contains(x,y) && image.pixel(x,y) != Qt::transparent) {
+ //It's not wrong to paint outside of your geometry but inside the bounding rect, but it is unusual
+ qWarning() << "Pixel at" << x << y << "is not transparent but geometry is" << pixmapGeometry;
+ if(strict) {
+ debugDisplayImage(image, 10);
+ return false;
+ }
+ }
+ } else if(image.pixel(x,y) != Qt::transparent) {
+ qWarning() << "Pixel at" << x << y << "is not transparent (" << QColor(image.pixel(x,y)) << ") but bounding rect is" << pixmapBoundingRect;
+/* {
+ QPainter painter(&image);
+ painter.setPen(Qt::red);
+ painter.drawEllipse(QPoint(x,y),5,5);
+ }*/
+ debugDisplayImage(image, 10);
+ return false;
+ }
+ }
+ // Uncomment to see what the widget looks like:
+ // debugDisplayImage(image, 3);
+ return true;
+}
+bool Ut_AllWidgets::checkChildrenBoundingRect(const QGraphicsWidget *widget) const
+{
+ //Make sure the widget has a chance to relayout if it needs to
+ app->processEvents();
+ // Although it is legal to have children outside the parent's geometry, I think we should
+ // have a policy to not allow it
+ QRectF childrenBoundingRect = widget->childrenBoundingRect();
+ if(!childrenBoundingRect.isEmpty() && !widget->boundingRect().contains(childrenBoundingRect)) {
+ // If this flag has been set, then it's okay to have children outside
+ if(widget->flags() & QGraphicsItem::ItemClipsChildrenToShape)
+ return true;
+ qWarning() << "The widget's children are outside of the parent's bounding rect. Children:" << childrenBoundingRect << "Parent:" << widget->boundingRect();
+ return false;
+ }
+ return true;
+}
+QList< QPointer<QGraphicsObject> > Ut_AllWidgets::getAllLayoutItemObjects(QGraphicsLayoutItem *item)
+{
+ QList< QPointer<QGraphicsObject> > children;
+ if(!item)
+ return children;
+
+ QGraphicsObject* object = dynamic_cast<QGraphicsObject *>(item->graphicsItem());
+ if(object)
+ children << object;
+ if(item->isLayout()) {
+ QGraphicsLayout *layout = static_cast<QGraphicsLayout *>(item);
+ for(int i = 0 ; i < layout->count(); i++)
+ children << getAllLayoutItemObjects(layout->itemAt(i));
+ }
+
+ return children;
+}
+QList< QPointer<QGraphicsObject> > Ut_AllWidgets::getAllSubWidgets(QGraphicsItem *item)
+{
+ QList< QPointer<QGraphicsObject> > children;
+ foreach(QGraphicsItem *child, item->childItems()) {
+ QGraphicsObject *object = child->toGraphicsObject();
+ if(object)
+ children << object;
+ children << getAllSubWidgets(child);
+ }
+
+ if(item->isWidget())
+ children << getAllLayoutItemObjects( static_cast<QGraphicsWidget *>(item)->layout() );
+
+ return children;
+}
+
+bool Ut_AllWidgets::checkSubWidgets(MWidgetController * parentWidget, QList< QPointer<QGraphicsObject> > subwidgets) {
+ foreach(const QPointer<QGraphicsObject> &widget, subwidgets) {
+ if(widget->parent()) {
+ qWarning() << "A subwidget has QObject::parent set - it is better to keep this NULL and let QGraphicsItem::parentItem() delete the object";
+ return false;
+ }
+ QGraphicsItem *parent = widget;
+ while(parent != parentWidget) {
+ if(!parent) {
+ qDebug() << "A subwidget does not have parentItem pointing to the widget.";
+ return false;
+ }
+ parent = parent->parentWidget();
+ };
+ }
+ return true;
+}
+void Ut_AllWidgets::testAllWidgets_data()
+{
+ QTest::addColumn<MWidgetController*>("widget");
+ QTest::addColumn<bool>("strict"); //Make warnings into errors.
+ QTest::addColumn<bool>("leftToRight");
+
+#define TEST_WIDGET(description, widget, strict) \
+ QTest::newRow(description "(LTR)") << static_cast<MWidgetController*>(widget) << (strict) << false; \
+ QTest::newRow(description "(RTL)") << static_cast<MWidgetController*>(widget) << (strict) << true;
+
+ TEST_WIDGET("MLabel - simple", new MLabel("Hello there"), true);
+ TEST_WIDGET("MLabel - simple multiline", new MLabel("Hello there\nHow are you?"), true);
+ TEST_WIDGET("MLabel - rich", new MLabel("<qt><b>Hello</b> there"), true);
+ TEST_WIDGET("MButton - simple", new MButton("Hello there"), true);
+ TEST_WIDGET("MButton - simple multiline", new MButton("Hello there\nHow are you?"), true);
+ TEST_WIDGET("MButton - rich", new MButton("<qt><b>Hello</b> there"), true);
+ TEST_WIDGET("MSlider", new MSlider, true);
+}
+
+
+void Ut_AllWidgets::testAllWidgets()
+{
+ QFETCH(MWidgetController *, widget);
+ QFETCH(bool, strict);
+ QFETCH(bool, leftToRight);
+ widget->setLayoutDirection(leftToRight?Qt::LeftToRight:Qt::RightToLeft);
+
+ m_scene->addItem(widget);
+ widget->style();
+
+ widget->setMinimumSize(0,0);
+ widget->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
+
+ static_cast<MWidget *>(widget)->setGeometry(100,100,100,100);
+
+ QVERIFY(checkChildrenBoundingRect(widget) || !strict);
+ QVERIFY(paintAndTestWidget(widget, strict));
+
+ //Now resize to just 1,1 and make sure it paints at maximum only 1 pixel
+ static_cast<MWidget *>(widget)->setGeometry(100,100,1,1);
+
+ QVERIFY(checkChildrenBoundingRect(widget) || !strict);
+ QVERIFY(paintAndTestWidget(widget, strict));
+
+ //Now resize to 0,0 and make sure it paints nothing at all
+ static_cast<MWidget *>(widget)->setGeometry(100,100,0,0);
+
+ QVERIFY(checkChildrenBoundingRect(widget) || !strict);
+ QVERIFY(paintAndTestWidget(widget, strict));
+
+ // Check that the CSS values override
+ widget->setObjectName("cssWidth");
+ QCOMPARE(widget->minimumSize(), QSizeF(0,0));
+ QCOMPARE(widget->maximumSize(), QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
+ widget->setMinimumSize(-1,-1);
+ widget->setMaximumSize(-1,-1);
+ QCOMPARE(widget->minimumSize().width() - widget->style()->marginLeft() - widget->style()->marginRight(), 9.0); //The values in CSS should now take precedence
+ QCOMPARE(widget->maximumSize().width() - widget->style()->marginLeft() - widget->style()->marginRight(), 11.0);
+
+ // Test for memory leaks by checking that the view, model and all children are deleted
+ QList< QPointer<QGraphicsObject> > subwidgets = getAllSubWidgets(widget);
+ QVERIFY(checkSubWidgets(widget, subwidgets));
+ QPointer<MWidgetView> view = const_cast<MWidgetView*>(widget->view());
+ QPointer<MWidgetModel> model = widget->model();
+ delete widget;
+ foreach(const QPointer<QGraphicsObject> subwidget, subwidgets) {
+ QVERIFY(!subwidget);
+ }
+
+ QVERIFY(!view);
+ QVERIFY(!model);
+}
+
+
+QTEST_APPLESS_MAIN(Ut_AllWidgets)
diff --git a/tests/ut_allwidgets/ut_allwidgets.css b/tests/ut_allwidgets/ut_allwidgets.css
new file mode 100644
index 00000000..3a8f7b0a
--- /dev/null
+++ b/tests/ut_allwidgets/ut_allwidgets.css
@@ -0,0 +1,6 @@
+MWidgetStyle#cssWidth {
+ minimum-size: 9 -1;
+ preferred-size: 10 -1;
+ maximum-size: 11 -1;
+}
+
diff --git a/tests/ut_allwidgets/ut_allwidgets.h b/tests/ut_allwidgets/ut_allwidgets.h
new file mode 100644
index 00000000..6b0cdc7f
--- /dev/null
+++ b/tests/ut_allwidgets/ut_allwidgets.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (directui@nokia.com)
+**
+** This file is part of libmeegotouch.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at directui@nokia.com.
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation
+** and appearing in the file LICENSE.LGPL included in the packaging
+** of this file.
+**
+****************************************************************************/
+
+#ifndef UT_MLAYOUT_H
+#define UT_MLAYOUT_H
+
+#include <QtTest/QtTest>
+#include <QObject>
+#include <QPointer>
+#include <QList>
+
+#include <mlayout.h>
+
+class QGraphicsScene;
+class MWidgetController;
+class QGraphicsProxyWidget;
+class QPushButton;
+
+class Ut_AllWidgets : public QObject
+{
+ Q_OBJECT
+
+public:
+ Ut_AllWidgets();
+ virtual ~Ut_AllWidgets();
+
+private slots:
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+ void testAllWidgets_data();
+ void testAllWidgets();
+
+private:
+ bool checkSubWidgets(MWidgetController * parentWidget, QList< QPointer<QGraphicsObject> > subwidgets);
+ void debugDisplayPixmap(const QPixmap &pixmap, int seconds);
+ void debugDisplayImage(const QImage &image, int seconds);
+ bool paintAndTestWidget(QGraphicsWidget *widget, bool strict);
+ bool checkChildrenBoundingRect(const QGraphicsWidget *widget) const;
+ QList< QPointer<QGraphicsObject> > getAllLayoutItemObjects(QGraphicsLayoutItem *item);
+ QList< QPointer<QGraphicsObject> > getAllSubWidgets(QGraphicsItem *widget);
+ QGraphicsWidget *m_form;
+ QGraphicsScene *m_scene;
+};
+
+#endif // Header guard
+
diff --git a/tests/ut_allwidgets/ut_allwidgets.pro b/tests/ut_allwidgets/ut_allwidgets.pro
new file mode 100644
index 00000000..719bb3af
--- /dev/null
+++ b/tests/ut_allwidgets/ut_allwidgets.pro
@@ -0,0 +1,15 @@
+include(../common_top.pri)
+TARGET = ut_allwidgets
+
+# unit test and unit
+SOURCES += \
+ ut_allwidgets.cpp \
+
+# unit test and unit
+HEADERS += \
+ ut_allwidgets.h
+
+support_files.files += \
+ ut_allwidgets.css
+
+include(../common_bot.pri)