diff options
Diffstat (limited to 'src/testlib/qpropertytesthelper_p.h')
-rw-r--r-- | src/testlib/qpropertytesthelper_p.h | 159 |
1 files changed, 107 insertions, 52 deletions
diff --git a/src/testlib/qpropertytesthelper_p.h b/src/testlib/qpropertytesthelper_p.h index e81b145887..c691802a39 100644 --- a/src/testlib/qpropertytesthelper_p.h +++ b/src/testlib/qpropertytesthelper_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2021 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtTest 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QPROPERTYTESTHELPER_P_H #define QPROPERTYTESTHELPER_P_H @@ -52,8 +16,10 @@ // #include <QtCore/QObject> +#include <QtCore/QProperty> #include <QtTest/QSignalSpy> #include <QTest> +#include <private/qglobal_p.h> QT_BEGIN_NAMESPACE @@ -118,6 +84,14 @@ namespace QTestPrivate { allocate its returned string using \c {new char[]}, so that it can be used in place of \l {QTest::toString()}. + The \a helperConstructor method is used to create another instance of + \c TestedClass. This instance is used to test for binding loops. By default, + the method returns a default-constructed \c TestedClass. A custom + \a helperConstructor should be provided if \c TestedClass is not + default-constructible. Some very specific properties cannot be tested for + binding loops. Pass a lambda that returns an \c {std::nullptr} as + \a helperConstructor in such case. + \note Any test calling this method will need to call \code if (QTest::currentTestFailed()) @@ -134,7 +108,9 @@ void testReadWritePropertyBasics( std::function<bool(const PropertyType &, const PropertyType &)> comparator = [](const PropertyType &lhs, const PropertyType &rhs) { return lhs == rhs; }, std::function<char *(const PropertyType &)> represent = - [](const PropertyType &val) { return QTest::toString(val); }) + [](const PropertyType &val) { return QTest::toString(val); }, + std::function<std::unique_ptr<TestedClass>(void)> helperConstructor = + []() { return std::make_unique<TestedClass>(); }) { // get the property const QMetaObject *metaObject = instance.metaObject(); @@ -163,7 +139,7 @@ void testReadWritePropertyBasics( testedObj.property(propertyName).template value<PropertyType>(), initial, comparator, represent); if (spy) - QCOMPARE(spy->count(), 1); + QCOMPARE(spy->size(), 1); QUntypedBindable bindable = metaProperty.bindable(&instance); @@ -182,7 +158,7 @@ void testReadWritePropertyBasics( QPROPERTY_TEST_COMPARISON_HELPER(propObserver.value(), changed, comparator, represent); QPROPERTY_TEST_COMPARISON_HELPER(propObserverLambda.value(), changed, comparator, represent); if (spy) - QCOMPARE(spy->count(), 2); + QCOMPARE(spy->size(), 2); // Bind object's property to other property QProperty<PropertyType> propSetter(initial); @@ -196,7 +172,7 @@ void testReadWritePropertyBasics( QPROPERTY_TEST_COMPARISON_HELPER(propObserver.value(), initial, comparator, represent); QPROPERTY_TEST_COMPARISON_HELPER(propObserverLambda.value(), initial, comparator, represent); if (spy) - QCOMPARE(spy->count(), 3); + QCOMPARE(spy->size(), 3); // Count notifications triggered; should only happen on actual change. int updateCount = 0; @@ -211,7 +187,7 @@ void testReadWritePropertyBasics( QPROPERTY_TEST_COMPARISON_HELPER(propObserverLambda.value(), changed, comparator, represent); QCOMPARE(updateCount, 1); if (spy) - QCOMPARE(spy->count(), 4); + QCOMPARE(spy->size(), 4); // Test that manually setting the value (even the same one) breaks the // binding. @@ -222,7 +198,46 @@ void testReadWritePropertyBasics( // value didn't change -> the signal should not be emitted if (spy) - QCOMPARE(spy->count(), 4); + QCOMPARE(spy->size(), 4); + + // test binding loop + if (std::unique_ptr<TestedClass> helperObj = helperConstructor()) { + // Reset to 'initial', so that the binding loop test could check the + // 'changed' value, because some tests already rely on the 'instance' to + // have the 'changed' value once this test passes + testedObj.setProperty(propertyName, QVariant::fromValue(initial)); + const QPropertyBinding<PropertyType> binding([&]() { + QObject *obj = static_cast<QObject *>(helperObj.get()); + obj->setProperty(propertyName, QVariant::fromValue(changed)); + return obj->property(propertyName).template value<PropertyType>(); + }, {}); + bindable.setBinding(binding); + QPROPERTY_TEST_COMPARISON_HELPER( + testedObj.property(propertyName).template value<PropertyType>(), changed, + comparator, represent); + QVERIFY2(!binding.error().hasError(), qPrintable(binding.error().description())); + } +} + +/*! + \internal + \overload + + This overload supports the case where the caller only needs to override + the default for \a helperConstructor. It uses the defaults for all the other + parameters. +*/ +template<typename TestedClass, typename PropertyType> +void testReadWritePropertyBasics( + TestedClass &instance, const PropertyType &initial, const PropertyType &changed, + const char *propertyName, + std::function<std::unique_ptr<TestedClass>(void)> helperConstructor) +{ + testReadWritePropertyBasics<TestedClass, PropertyType>( + instance, initial, changed, propertyName, + [](const PropertyType &lhs, const PropertyType &rhs) { return lhs == rhs; }, + [](const PropertyType &val) { return QTest::toString(val); }, + helperConstructor); } /*! @@ -258,6 +273,14 @@ void testReadWritePropertyBasics( allocate its returned string using \c {new char[]}, so that it can be used in place of \l {QTest::toString()}. + The \a helperConstructor method is used to create another instance of + \c TestedClass. This instance is used to test for binding loops. By default, + the method returns a default-constructed \c TestedClass. A custom + \a helperConstructor should be provided if \c TestedClass is not + default-constructible. Some very specific properties cannot be tested for + binding loops. Pass a lambda that returns an \c {std::nullptr} as + \a helperConstructor in such case. + \note Any test calling this method will need to call \code if (QTest::currentTestFailed()) @@ -276,7 +299,9 @@ void testWriteOncePropertyBasics( std::function<bool(const PropertyType &, const PropertyType &)> comparator = [](const PropertyType &lhs, const PropertyType &rhs) { return lhs == rhs; }, std::function<char *(const PropertyType &)> represent = - [](const PropertyType &val) { return QTest::toString(val); }) + [](const PropertyType &val) { return QTest::toString(val); }, + std::function<std::unique_ptr<TestedClass>(void)> helperConstructor = + []() { return std::make_unique<TestedClass>(); }) { // get the property const QMetaObject *metaObject = instance.metaObject(); @@ -310,10 +335,19 @@ void testWriteOncePropertyBasics( propObserver.setBinding(bindable.makeBinding()); QPROPERTY_TEST_COMPARISON_HELPER(propObserver.value(), prior, comparator, represent); - // Create a binding that sets the 'changed' value to the property - QProperty<PropertyType> propSetter(changed); + // Create a binding that sets the 'changed' value to the property. + // This also tests binding loops. QVERIFY(!bindable.hasBinding()); - bindable.setBinding(Qt::makePropertyBinding(propSetter)); + std::unique_ptr<TestedClass> helperObj = helperConstructor(); + QProperty<PropertyType> propSetter(changed); // if the helperConstructor() returns nullptr + const QPropertyBinding<PropertyType> binding = helperObj + ? Qt::makePropertyBinding([&]() { + QObject *obj = static_cast<QObject *>(helperObj.get()); + obj->setProperty(propertyName, QVariant::fromValue(changed)); + return obj->property(propertyName).template value<PropertyType>(); + }) + : Qt::makePropertyBinding(propSetter); + bindable.setBinding(binding); QVERIFY(bindable.hasBinding()); QPROPERTY_TEST_COMPARISON_HELPER( @@ -321,7 +355,7 @@ void testWriteOncePropertyBasics( represent); QPROPERTY_TEST_COMPARISON_HELPER(propObserver.value(), changed, comparator, represent); if (spy) - QCOMPARE(spy->count(), 1); + QCOMPARE(spy->size(), 1); // Attempt to set back the 'prior' value and verify that it has no effect testedObj.setProperty(propertyName, QVariant::fromValue(prior)); @@ -330,13 +364,34 @@ void testWriteOncePropertyBasics( represent); QPROPERTY_TEST_COMPARISON_HELPER(propObserver.value(), changed, comparator, represent); if (spy) - QCOMPARE(spy->count(), 1); + QCOMPARE(spy->size(), 1); if (bindingPreservedOnWrite) QVERIFY(bindable.hasBinding()); else QVERIFY(!bindable.hasBinding()); } +/*! + \internal + \overload + + This overload supports the case where the caller only needs to override + the default for \a helperConstructor. It uses the defaults for all the other + parameters. +*/ +template<typename TestedClass, typename PropertyType> +void testWriteOncePropertyBasics( + TestedClass &instance, const PropertyType &prior, const PropertyType &changed, + const char *propertyName, + bool bindingPreservedOnWrite, + std::function<std::unique_ptr<TestedClass>(void)> helperConstructor) +{ + testWriteOncePropertyBasics<TestedClass, PropertyType>( + instance, prior, changed, propertyName, bindingPreservedOnWrite, + [](const PropertyType &lhs, const PropertyType &rhs) { return lhs == rhs; }, + [](const PropertyType &val) { return QTest::toString(val); }, + helperConstructor); +} /*! \internal @@ -420,7 +475,7 @@ void testReadOnlyPropertyBasics( testedObj.property(propertyName).template value<PropertyType>(), initial, comparator, represent); if (spy) - QCOMPARE(spy->count(), 0); + QCOMPARE(spy->size(), 0); QProperty<PropertyType> propObserver; propObserver.setBinding(bindable.makeBinding()); @@ -436,7 +491,7 @@ void testReadOnlyPropertyBasics( QPROPERTY_TEST_COMPARISON_HELPER(propObserver.value(), changed, comparator, represent); if (spy) - QCOMPARE(spy->count(), 1); + QCOMPARE(spy->size(), 1); } } // namespace QTestPrivate |