diff --git a/src/testlib/qpropertytesthelper_p.h b/src/testlib/qpropertytesthelper_p.h index 06d503f8756..23fc0477f50 100644 --- a/src/testlib/qpropertytesthelper_p.h +++ b/src/testlib/qpropertytesthelper_p.h @@ -88,7 +88,9 @@ namespace QTestPrivate { \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. (NOTE: The parameter is currently unused!) + 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 @@ -108,12 +110,7 @@ void testReadWritePropertyBasics( std::function represent = [](const PropertyType &val) { return QTest::toString(val); }, std::function(void)> helperConstructor = - []() { - if constexpr (std::is_default_constructible_v) - return std::make_unique(); - else - return std::unique_ptr(); - }) + []() { return std::make_unique(); }) { // get the property const QMetaObject *metaObject = instance.metaObject(); @@ -203,7 +200,23 @@ void testReadWritePropertyBasics( if (spy) QCOMPARE(spy->size(), 4); - Q_UNUSED(helperConstructor); + // test binding loop + if (std::unique_ptr helperObj = std::move(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 binding([&]() { + QObject *obj = static_cast(helperObj.get()); + obj->setProperty(propertyName, QVariant::fromValue(changed)); + return obj->property(propertyName).template value(); + }, {}); + bindable.setBinding(binding); + QPROPERTY_TEST_COMPARISON_HELPER( + testedObj.property(propertyName).template value(), changed, + comparator, represent); + QVERIFY2(!binding.error().hasError(), qPrintable(binding.error().description())); + } } /*! @@ -264,7 +277,9 @@ void testReadWritePropertyBasics( \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. (NOTE: The parameter is currently unused!) + 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 @@ -286,15 +301,8 @@ void testWriteOncePropertyBasics( std::function represent = [](const PropertyType &val) { return QTest::toString(val); }, std::function(void)> helperConstructor = - []() { - if constexpr (std::is_default_constructible_v) - return std::make_unique(); - else - return std::unique_ptr(); - }) + []() { return std::make_unique(); }) { - Q_UNUSED(helperConstructor); - // get the property const QMetaObject *metaObject = instance.metaObject(); QMetaProperty metaProperty = metaObject->property(metaObject->indexOfProperty(propertyName)); @@ -327,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 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 helperObj(std::move(helperConstructor())); + QProperty propSetter(changed); // if the helperConstructor() returns nullptr + const QPropertyBinding binding = helperObj + ? Qt::makePropertyBinding([&]() { + QObject *obj = static_cast(helperObj.get()); + obj->setProperty(propertyName, QVariant::fromValue(changed)); + return obj->property(propertyName).template value(); + }) + : Qt::makePropertyBinding(propSetter); + bindable.setBinding(binding); QVERIFY(bindable.hasBinding()); QPROPERTY_TEST_COMPARISON_HELPER( diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index a4f761d6b99..31345cc3333 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -8197,16 +8197,6 @@ void tst_QObject::objectNameBinding() QObject obj; QTestPrivate::testReadWritePropertyBasics(obj, "test1", "test2", "objectName"); - - const QPropertyBinding binding([]() { - QObject obj2; - obj2.setObjectName(QLatin1String("no loop")); - return obj2.objectName(); - }, {}); - obj.bindableObjectName().setBinding(binding); - - QCOMPARE(obj.objectName(), QLatin1String("no loop")); - QVERIFY2(!binding.error().hasError(), qPrintable(binding.error().description())); } namespace EmitToDestroyedClass {