From 70199a43a978649d87c5b2815808c4a04902c6e0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 16 Nov 2018 18:52:56 +0100 Subject: Fix for SpinBox crash in Qt Quick Designer The crash was not 100% reliable and depends on the order in the hash(). Something in beginDeferred() has a side effect on deferData->bindings and an element gets deleted. This causes a crash while iterating (++it). Therefore we do a copy of the hash. I added a regression test. The test did only crash for SpinBox and it did only crash roughly half the time. Task-number: QTBUG-71942 Change-Id: I339e0a4382f97db44f6ff2e9f07f2be7278d1e24 Reviewed-by: Mitch Curtis --- tests/auto/designer/tst_designer.cpp | 161 +++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 tests/auto/designer/tst_designer.cpp (limited to 'tests/auto/designer/tst_designer.cpp') diff --git a/tests/auto/designer/tst_designer.cpp b/tests/auto/designer/tst_designer.cpp new file mode 100644 index 00000000..2c67c2c6 --- /dev/null +++ b/tests/auto/designer/tst_designer.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include +#include + +#include + +class tst_Designer : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + void test_controls(); + void test_controls_data(); +}; + + +void tst_Designer::initTestCase() +{ +} + +void doComponentCompleteRecursive(QObject *object) +{ + if (object) { + QQuickItem *item = qobject_cast(object); + + if (item && DesignerSupport::isComponentComplete(item)) + return; + + DesignerSupport::emitComponentCompleteSignalForAttachedProperty(qobject_cast(object)); + + QList childList = object->children(); + + if (item) { + for (QQuickItem *childItem : item->childItems()) { + if (!childList.contains(childItem)) + childList.append(childItem); + } + } + + for (QObject *child : childList) + doComponentCompleteRecursive(child); + + if (item) { + static_cast(item)->componentComplete(); + } else { + QQmlParserStatus *qmlParserStatus = dynamic_cast< QQmlParserStatus*>(object); + if (qmlParserStatus) + qmlParserStatus->componentComplete(); + } + } +} + + +void tst_Designer::test_controls() +{ + QFETCH(QString, type); + + const QByteArray before("import QtQuick 2.10\n" + "import QtQuick.Controls 2.3\n" + "Item {\n"); + + QByteArray source = before; + source.append(type); + + const QByteArray after(" {" + "}\n" + "}\n"); + + source.append(after); + + QQmlEngine engine; + QQmlComponent component(&engine); + + { + ComponentCompleteDisabler disableComponentComplete; + component.setData(source, QUrl::fromLocalFile(QDir::current().absolutePath())); + } + + QObject *root = component.create(); + QVERIFY(root); + doComponentCompleteRecursive(root); +} + +void tst_Designer::test_controls_data() +{ + QTest::addColumn("type"); + + QTest::newRow("type") << "SpinBox"; + QTest::newRow("type") << "Switch"; + QTest::newRow("type") << "ComboBox"; + QTest::newRow("type") << "CheckBox"; + QTest::newRow("type") << "Button"; + QTest::newRow("type") << "DelayButton"; + QTest::newRow("type") << "Dial"; + QTest::newRow("type") << "Frame"; + QTest::newRow("type") << "GroupBox"; + QTest::newRow("type") << "Label"; + QTest::newRow("type") << "Page"; + QTest::newRow("type") << "Pane"; + QTest::newRow("type") << "ProgressBar"; + QTest::newRow("type") << "RadioButton"; + QTest::newRow("type") << "RangeSlider"; + QTest::newRow("type") << "RoundButton"; + QTest::newRow("type") << "ScrollView"; + QTest::newRow("type") << "Slider"; + QTest::newRow("type") << "StackView"; + QTest::newRow("type") << "SwipeView"; + QTest::newRow("type") << "Switch"; + QTest::newRow("type") << "TabBar"; + QTest::newRow("type") << "TabButton"; + QTest::newRow("type") << "TextArea"; + QTest::newRow("type") << "TextField"; + QTest::newRow("type") << "ToolBar"; + QTest::newRow("type") << "ToolButton"; + QTest::newRow("type") << "Tumbler"; +} + +QTEST_MAIN(tst_Designer) + +#include "tst_designer.moc" -- cgit v1.2.3