diff options
Diffstat (limited to 'tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp')
-rw-r--r-- | tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp | 136 |
1 files changed, 119 insertions, 17 deletions
diff --git a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp index c0471890ee..56da58c291 100644 --- a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp +++ b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp @@ -6,6 +6,7 @@ #include <qtest.h> #include <qproperty.h> #include <private/qproperty_p.h> +#include <private/qobject_p.h> #if __has_include(<source_location>) && __cplusplus >= 202002L && !defined(Q_CLANG_QDOC) #include <source_location> @@ -66,6 +67,7 @@ private slots: void quntypedBindableApi(); void readonlyConstQBindable(); void qobjectBindableManualNotify(); + void qobjectBindableReallocatedBindingStorage(); void qobjectBindableSignalTakingNewValue(); void testNewStuff(); @@ -85,6 +87,8 @@ private slots: void noDoubleNotification(); void groupedNotifications(); void groupedNotificationConsistency(); + void bindingGroupMovingBindingData(); + void bindingGroupBindingDeleted(); void uninstalledBindingDoesNotEvaluate(); void notify(); @@ -95,6 +99,8 @@ private slots: void qpropertyAlias(); void scheduleNotify(); + + void notifyAfterAllDepsGone(); }; void tst_QProperty::functorBinding() @@ -387,7 +393,7 @@ void tst_QProperty::changeHandler() } testProperty = 3; - QCOMPARE(recordedValues.count(), 2); + QCOMPARE(recordedValues.size(), 2); QCOMPARE(recordedValues.at(0), 1); QCOMPARE(recordedValues.at(1), 2); } @@ -430,7 +436,7 @@ void tst_QProperty::subscribe() } testProperty = 3; - QCOMPARE(recordedValues.count(), 3); + QCOMPARE(recordedValues.size(), 3); QCOMPARE(recordedValues.at(0), 42); QCOMPARE(recordedValues.at(1), 1); QCOMPARE(recordedValues.at(2), 2); @@ -865,7 +871,7 @@ void tst_QProperty::notifiedProperty() check(); instance.property.setValue(42); - QCOMPARE(instance.recordedValues.count(), 1); + QCOMPARE(instance.recordedValues.size(), 1); QCOMPARE(instance.recordedValues.at(0), 42); instance.recordedValues.clear(); check(); @@ -895,7 +901,7 @@ void tst_QProperty::notifiedProperty() subscribedCount = 0; QCOMPARE(instance.property.value(), 100); - QCOMPARE(instance.recordedValues.count(), 1); + QCOMPARE(instance.recordedValues.size(), 1); QCOMPARE(instance.recordedValues.at(0), 100); instance.recordedValues.clear(); check(); @@ -903,7 +909,7 @@ void tst_QProperty::notifiedProperty() injectedValue = 200; QCOMPARE(instance.property.value(), 200); - QCOMPARE(instance.recordedValues.count(), 1); + QCOMPARE(instance.recordedValues.size(), 1); QCOMPARE(instance.recordedValues.at(0), 200); instance.recordedValues.clear(); check(); @@ -912,7 +918,7 @@ void tst_QProperty::notifiedProperty() injectedValue = 400; QCOMPARE(instance.property.value(), 400); - QCOMPARE(instance.recordedValues.count(), 1); + QCOMPARE(instance.recordedValues.size(), 1); QCOMPARE(instance.recordedValues.at(0), 400); instance.recordedValues.clear(); check(); @@ -1151,12 +1157,12 @@ void tst_QProperty::qobjectBindableManualNotify() object.fooData.setValueBypassingBindings(42); // there is no change. QCOMPARE(fooChangeCount, 0); - QCOMPARE(fooChangedSpy.count(), 0); + QCOMPARE(fooChangedSpy.size(), 0); // Once we notify manually object.fooData.notify(); // observers are notified and the signal arrives. QCOMPARE(fooChangeCount, 1); - QCOMPARE(fooChangedSpy.count(), 1); + QCOMPARE(fooChangedSpy.size(), 1); // If we set a binding int i = 1; @@ -1165,20 +1171,37 @@ void tst_QProperty::qobjectBindableManualNotify() QCOMPARE(object.foo(), 1); // and the change and signal count are incremented. QCOMPARE(fooChangeCount, 2); - QCOMPARE(fooChangedSpy.count(), 2); + QCOMPARE(fooChangedSpy.size(), 2); // Changing a non-property won't trigger any notification. i = 2; QCOMPARE(fooChangeCount, 2); - QCOMPARE(fooChangedSpy.count(), 2); + QCOMPARE(fooChangedSpy.size(), 2); // Manually triggering the notification object.fooData.notify(); // increments the change count QCOMPARE(fooChangeCount, 3); - QCOMPARE(fooChangedSpy.count(), 3); + QCOMPARE(fooChangedSpy.size(), 3); // but doesn't actually cause a binding reevaluation. QCOMPARE(object.foo(), 1); } + +struct ReallocObject : QObject { + ReallocObject() + { v.setBinding([this] { return x.value() + y.value() + z.value(); }); } + Q_OBJECT_BINDABLE_PROPERTY(ReallocObject, int, v) + Q_OBJECT_BINDABLE_PROPERTY(ReallocObject, int, x) + Q_OBJECT_BINDABLE_PROPERTY(ReallocObject, int, y) + Q_OBJECT_BINDABLE_PROPERTY(ReallocObject, int, z) +}; + +void tst_QProperty::qobjectBindableReallocatedBindingStorage() +{ + ReallocObject object; + object.x = 1; + QCOMPARE(object.v.value(), 1); +} + void tst_QProperty::qobjectBindableSignalTakingNewValue() { // Given an object of type MyQObject, @@ -1557,7 +1580,7 @@ void tst_QProperty::compatPropertySignals() tester.setProp2(10); QCOMPARE(prop2Observer.value(), 10); - QCOMPARE(prop2Spy.count(), 1); + QCOMPARE(prop2Spy.size(), 1); QList<QVariant> arguments = prop2Spy.takeFirst(); QCOMPARE(arguments.size(), 1); QCOMPARE(arguments.at(0).metaType().id(), QMetaType::Int); @@ -1573,7 +1596,7 @@ void tst_QProperty::compatPropertySignals() tester.setProp3(5); QCOMPARE(prop3Observer.value(), 5); - QCOMPARE(prop3Spy.count(), 1); + QCOMPARE(prop3Spy.size(), 1); // Compat property with signal, default value, and custom setter. Signal has parameter. QProperty<int> prop4Observer; @@ -1585,7 +1608,7 @@ void tst_QProperty::compatPropertySignals() tester.setProp4(10); QCOMPARE(prop4Observer.value(), 10); - QCOMPARE(prop4Spy.count(), 1); + QCOMPARE(prop4Spy.size(), 1); arguments = prop4Spy.takeFirst(); QCOMPARE(arguments.size(), 1); QCOMPARE(arguments.at(0).metaType().id(), QMetaType::Int); @@ -1594,7 +1617,7 @@ void tst_QProperty::compatPropertySignals() tester.setProp4(42); QCOMPARE(prop4Observer.value(), 42); - QCOMPARE(prop4Spy.count(), 1); + QCOMPARE(prop4Spy.size(), 1); arguments = prop4Spy.takeFirst(); QCOMPARE(arguments.size(), 1); QCOMPARE(arguments.at(0).metaType().id(), QMetaType::Int); @@ -1603,7 +1626,7 @@ void tst_QProperty::compatPropertySignals() tester.setProp4(0); QCOMPARE(prop4Observer.value(), 42); - QCOMPARE(prop4Spy.count(), 1); + QCOMPARE(prop4Spy.size(), 1); arguments = prop4Spy.takeFirst(); QCOMPARE(arguments.size(), 1); QCOMPARE(arguments.at(0).metaType().id(), QMetaType::Int); @@ -1940,6 +1963,63 @@ void tst_QProperty::groupedNotificationConsistency() QVERIFY(areEqual); // value changed runs after everything has been evaluated } +void tst_QProperty::bindingGroupMovingBindingData() +{ + auto tester = std::make_unique<ClassWithNotifiedProperty>(); + auto testerPriv = QObjectPrivate::get(tester.get()); + + auto dummyNotifier = tester->property.addNotifier([](){}); + auto bindingData = testerPriv->bindingStorage.bindingData(&tester->property); + QVERIFY(bindingData); // we have a notifier, so there should be binding data + + Qt::beginPropertyUpdateGroup(); + auto cleanup = qScopeGuard([](){ Qt::endPropertyUpdateGroup(); }); + tester->property = 42; + QCOMPARE(testerPriv->bindingStorage.bindingData(&tester->property), bindingData); + auto proxyData = QPropertyBindingDataPointer::proxyData(bindingData); + // as we've modified the property, we now should have a proxy for the delayed notification + QVERIFY(proxyData); + // trigger binding data reallocation + std::array<QUntypedPropertyData, 10> propertyDataArray; + for (auto&& data: propertyDataArray) + testerPriv->bindingStorage.bindingData(&data, true); + // binding data has moved + QVERIFY(testerPriv->bindingStorage.bindingData(&tester->property) != bindingData); + bindingData = testerPriv->bindingStorage.bindingData(&tester->property); + // the proxy data has been updated + QCOMPARE(proxyData->originalBindingData, bindingData); + + tester.reset(); + // the property data is gone, proxyData should have been informed + QCOMPARE(proxyData->originalBindingData, nullptr); + QVERIFY(proxyData); +} + +void tst_QProperty::bindingGroupBindingDeleted() +{ + auto deleter = std::make_unique<ClassWithNotifiedProperty>(); + auto toBeDeleted = std::make_unique<ClassWithNotifiedProperty>(); + + bool calledHandler = false; + deleter->property.setBinding([&](){ + int newValue = toBeDeleted->property; + if (newValue == 42) + toBeDeleted.reset(); + return newValue; + }); + auto handler = toBeDeleted->property.onValueChanged([&]() { calledHandler = true; } ); + { + Qt::beginPropertyUpdateGroup(); + auto cleanup = qScopeGuard([](){ Qt::endPropertyUpdateGroup(); }); + QVERIFY(toBeDeleted); + toBeDeleted->property = 42; + // ASAN should not complain here + } + QVERIFY(!toBeDeleted); + // the change notification is sent, even if the binding is deleted during evaluation + QVERIFY(calledHandler); +} + void tst_QProperty::uninstalledBindingDoesNotEvaluate() { QProperty<int> i; @@ -1991,7 +2071,7 @@ void tst_QProperty::notify() testProperty = 4; QCOMPARE(value, 3); - QCOMPARE(recordedValues.count(), 2); + QCOMPARE(recordedValues.size(), 2); QCOMPARE(recordedValues.at(0), 1); QCOMPARE(recordedValues.at(1), 2); } @@ -2042,6 +2122,28 @@ void tst_QProperty::scheduleNotify() QCOMPARE(p.value(), 0); } +void tst_QProperty::notifyAfterAllDepsGone() +{ + bool b = true; + QProperty<int> iprop; + QProperty<int> jprop(42); + iprop.setBinding([&](){ + if (b) + return jprop.value(); + return 13; + }); + int changeCounter = 0; + auto keepAlive = iprop.onValueChanged([&](){ changeCounter++; }); + QCOMPARE(iprop.value(), 42); + jprop = 44; + QCOMPARE(iprop.value(), 44); + QCOMPARE(changeCounter, 1); + b = false; + jprop = 43; + QCOMPARE(iprop.value(), 13); + QCOMPARE(changeCounter, 2); +} + QTEST_MAIN(tst_QProperty); #undef QT_SOURCE_LOCATION_NAMESPACE |