131 TestedClass &instance,
const PropertyType &initial,
const PropertyType &changed,
132 const char *propertyName,
133 std::function<
bool(
const PropertyType &,
const PropertyType &)> comparator =
134 [](
const PropertyType &lhs,
const PropertyType &rhs) {
return lhs == rhs; },
135 std::function<
char *(
const PropertyType &)> represent =
136 [](
const PropertyType &val) {
return QTest::toString(val); },
137 std::function<std::unique_ptr<TestedClass>(
void)> helperConstructor =
138 []() {
return std::make_unique<TestedClass>(); })
141 const QMetaObject *metaObject = instance.metaObject();
142 QMetaProperty metaProperty = metaObject->property(metaObject->indexOfProperty(propertyName));
143 QVERIFY2(metaProperty.metaType() == QMetaType::fromType<PropertyType>(),
144 QByteArray{QByteArray(
"Preconditions not met for ") + propertyName +
"\n"
145 "The type of initial and changed value does not match the type of the property.\n"
146 "Please ensure that the types match exactly (convertability is not enough).\n"
147 "You can provide the template types to the "
148 "function explicitly to force a certain type.\n"
149 "Expected was a " + metaProperty.metaType().name()
150 +
" but " + QMetaType::fromType<PropertyType>().name() +
" was provided."}.constData());
153 QObject &testedObj =
static_cast<QObject &>(instance);
155 QVERIFY2(metaProperty.isBindable() && metaProperty.isWritable(),
156 QByteArray{QByteArray(
"Preconditions not met for ") + propertyName}.constData());
158 QTestPrivate::OptionalWrapper<QSignalSpy> spy =
std::nullopt;
159 if (metaProperty.hasNotifySignal())
160 spy.emplace(&instance, metaProperty.notifySignal());
162 testedObj.setProperty(propertyName, QVariant::fromValue(initial));
164 testedObj.property(propertyName).
template value<PropertyType>(), initial, comparator,
167 QCOMPARE(spy->size(), 1);
169 QUntypedBindable bindable = metaProperty.bindable(&instance);
173 QProperty<PropertyType> propObserver(changed);
174 propObserver.setBinding(bindable.makeBinding());
177 QProperty<PropertyType> propObserverLambda(changed);
178 propObserverLambda.setBinding(
179 [&]() {
return testedObj.property(propertyName).
template value<PropertyType>(); });
182 testedObj.setProperty(propertyName, QVariant::fromValue(changed));
186 QCOMPARE(spy->size(), 2);
189 QProperty<PropertyType> propSetter(initial);
190 QVERIFY(!bindable.hasBinding());
191 bindable.setBinding(Qt::makePropertyBinding(propSetter));
193 QVERIFY(bindable.hasBinding());
195 testedObj.property(propertyName).
template value<PropertyType>(), initial, comparator,
200 QCOMPARE(spy->size(), 3);
204 auto handler = bindable.onValueChanged([&updateCount]() { ++updateCount; });
207 propSetter.setValue(changed);
209 testedObj.property(propertyName).
template value<PropertyType>(), changed, comparator,
213 QCOMPARE(updateCount, 1);
215 QCOMPARE(spy->size(), 4);
219 testedObj.setProperty(propertyName, QVariant::fromValue(changed));
220 QVERIFY(!bindable.hasBinding());
222 QCOMPARE(updateCount, 1);
226 QCOMPARE(spy->size(), 4);
229 if (std::unique_ptr<TestedClass> helperObj = helperConstructor()) {
233 testedObj.setProperty(propertyName, QVariant::fromValue(initial));
234 const QPropertyBinding<PropertyType> binding([&]() {
235 QObject *obj =
static_cast<QObject *>(helperObj.get());
236 obj->setProperty(propertyName, QVariant::fromValue(changed));
237 return obj->property(propertyName).
template value<PropertyType>();
239 bindable.setBinding(binding);
241 testedObj.property(propertyName).
template value<PropertyType>(), changed,
242 comparator, represent);
243 QVERIFY2(!binding.error().hasError(), qPrintable(binding.error().description()));
321 TestedClass &instance,
const PropertyType &prior,
const PropertyType &changed,
322 const char *propertyName,
323 bool bindingPreservedOnWrite =
true,
324 std::function<
bool(
const PropertyType &,
const PropertyType &)> comparator =
325 [](
const PropertyType &lhs,
const PropertyType &rhs) {
return lhs == rhs; },
326 std::function<
char *(
const PropertyType &)> represent =
327 [](
const PropertyType &val) {
return QTest::toString(val); },
328 std::function<std::unique_ptr<TestedClass>(
void)> helperConstructor =
329 []() {
return std::make_unique<TestedClass>(); })
332 const QMetaObject *metaObject = instance.metaObject();
333 QMetaProperty metaProperty = metaObject->property(metaObject->indexOfProperty(propertyName));
336 QObject &testedObj =
static_cast<QObject &>(instance);
338 QVERIFY2(metaProperty.metaType() == QMetaType::fromType<PropertyType>(),
339 QByteArray{QByteArray(
"Preconditions not met for ") + propertyName +
"\n"
340 "The type of prior and changed value does not match the type of the property.\n"
341 "Please ensure that the types match exactly (convertability is not enough).\n"
342 "You can provide the template types to the "
343 "function explicitly to force a certain type.\n"
344 "Property is " + metaProperty.metaType().name()
345 +
" but parameters are " + QMetaType::fromType<PropertyType>().name() +
".\n"}.constData());
347 QVERIFY2(metaProperty.isBindable(),
348 QByteArray{
"Preconditions not met for " + QByteArray(propertyName)}.constData());
350 QUntypedBindable bindable = metaProperty.bindable(&instance);
352 QTestPrivate::OptionalWrapper<QSignalSpy> spy =
std::nullopt;
353 if (metaProperty.hasNotifySignal())
354 spy.emplace(&instance, metaProperty.notifySignal());
357 testedObj.property(propertyName).
template value<PropertyType>(), prior, comparator,
360 QProperty<PropertyType> propObserver;
361 propObserver.setBinding(bindable.makeBinding());
366 QVERIFY(!bindable.hasBinding());
367 std::unique_ptr<TestedClass> helperObj = helperConstructor();
368 QProperty<PropertyType> propSetter(changed);
369 const QPropertyBinding<PropertyType> binding = helperObj
370 ? Qt::makePropertyBinding([&]() {
371 QObject *obj =
static_cast<QObject *>(helperObj.get());
372 obj->setProperty(propertyName, QVariant::fromValue(changed));
373 return obj->property(propertyName).
template value<PropertyType>();
375 : Qt::makePropertyBinding(propSetter);
376 bindable.setBinding(binding);
377 QVERIFY(bindable.hasBinding());
380 testedObj.property(propertyName).
template value<PropertyType>(), changed, comparator,
384 QCOMPARE(spy->size(), 1);
387 testedObj.setProperty(propertyName, QVariant::fromValue(prior));
389 testedObj.property(propertyName).
template value<PropertyType>(), changed, comparator,
393 QCOMPARE(spy->size(), 1);
394 if (bindingPreservedOnWrite)
395 QVERIFY(bindable.hasBinding());
397 QVERIFY(!bindable.hasBinding());
458 TestedClass &instance,
const PropertyType &initial,
const PropertyType &changed,
459 const char *propertyName,
460 std::function<
void()> mutator = []() { QFAIL(
"Data modifier function must be provided"); },
461 std::function<
bool(
const PropertyType &,
const PropertyType &)> comparator =
462 [](
const PropertyType &lhs,
const PropertyType &rhs) {
return lhs == rhs; },
463 std::function<
char *(
const PropertyType &)> represent =
464 [](
const PropertyType &val) {
return QTest::toString(val); })
467 const QMetaObject *metaObject = instance.metaObject();
468 QMetaProperty metaProperty = metaObject->property(metaObject->indexOfProperty(propertyName));
471 QObject &testedObj =
static_cast<QObject &>(instance);
473 QVERIFY2(metaProperty.metaType() == QMetaType::fromType<PropertyType>(),
474 QByteArray{QByteArray(
"Preconditions not met for ") + propertyName +
"\n"
475 "The type of initial and changed value does not match the type of the property.\n"
476 "Please ensure that the types match exactly (convertability is not enough).\n"
477 "You can provide the template types to the "
478 "function explicitly to force a certain type.\n"
479 "Expected was a " + metaProperty.metaType().name()
480 +
" but " + QMetaType::fromType<PropertyType>().name() +
" was provided."}.constData());
482 QVERIFY2(metaProperty.isBindable(),
483 QByteArray{
"Preconditions not met for " + QByteArray(propertyName)}.constData());
485 QUntypedBindable bindable = metaProperty.bindable(&instance);
487 QTestPrivate::OptionalWrapper<QSignalSpy> spy =
std::nullopt;
488 if (metaProperty.hasNotifySignal())
489 spy.emplace(&instance, metaProperty.notifySignal());
492 testedObj.property(propertyName).
template value<PropertyType>(), initial, comparator,
496 QProperty<PropertyType> propSetter(initial);
497 QVERIFY(!bindable.hasBinding());
498 bindable.setBinding(Qt::makePropertyBinding(propSetter));
499 QVERIFY(!bindable.hasBinding());
500 propSetter.setValue(changed);
502 testedObj.property(propertyName).
template value<PropertyType>(), initial, comparator,
505 QCOMPARE(spy->size(), 0);
507 QProperty<PropertyType> propObserver;
508 propObserver.setBinding(bindable.makeBinding());
516 testedObj.property(propertyName).
template value<PropertyType>(), changed, comparator,
521 QCOMPARE(spy->size(), 1);