diff options
Diffstat (limited to 'src/testlib/qpropertytesthelper_p.h')
-rw-r--r-- | src/testlib/qpropertytesthelper_p.h | 117 |
1 files changed, 103 insertions, 14 deletions
diff --git a/src/testlib/qpropertytesthelper_p.h b/src/testlib/qpropertytesthelper_p.h index b5bd8d2583..c691802a39 100644 --- a/src/testlib/qpropertytesthelper_p.h +++ b/src/testlib/qpropertytesthelper_p.h @@ -84,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()) @@ -100,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(); @@ -129,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); @@ -148,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); @@ -162,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; @@ -177,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. @@ -188,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); } /*! @@ -224,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()) @@ -242,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(); @@ -276,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( @@ -287,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)); @@ -296,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 @@ -386,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()); @@ -402,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 |