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(
"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.");
153 QObject &testedObj =
static_cast<QObject &>(instance);
155 QVERIFY2(metaProperty.isBindable() && metaProperty.isWritable(),
156 "Preconditions not met for " + QByteArray(propertyName));
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(
"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");
347 QVERIFY2(metaProperty.isBindable(),
"Preconditions not met for " + QByteArray(propertyName));
349 QUntypedBindable bindable = metaProperty.bindable(&instance);
351 QTestPrivate::OptionalWrapper<QSignalSpy> spy =
std::nullopt;
352 if (metaProperty.hasNotifySignal())
353 spy.emplace(&instance, metaProperty.notifySignal());
356 testedObj.property(propertyName).
template value<PropertyType>(), prior, comparator,
359 QProperty<PropertyType> propObserver;
360 propObserver.setBinding(bindable.makeBinding());
365 QVERIFY(!bindable.hasBinding());
366 std::unique_ptr<TestedClass> helperObj = helperConstructor();
367 QProperty<PropertyType> propSetter(changed);
368 const QPropertyBinding<PropertyType> binding = helperObj
369 ? Qt::makePropertyBinding([&]() {
370 QObject *obj =
static_cast<QObject *>(helperObj.get());
371 obj->setProperty(propertyName, QVariant::fromValue(changed));
372 return obj->property(propertyName).
template value<PropertyType>();
374 : Qt::makePropertyBinding(propSetter);
375 bindable.setBinding(binding);
376 QVERIFY(bindable.hasBinding());
379 testedObj.property(propertyName).
template value<PropertyType>(), changed, comparator,
383 QCOMPARE(spy->size(), 1);
386 testedObj.setProperty(propertyName, QVariant::fromValue(prior));
388 testedObj.property(propertyName).
template value<PropertyType>(), changed, comparator,
392 QCOMPARE(spy->size(), 1);
393 if (bindingPreservedOnWrite)
394 QVERIFY(bindable.hasBinding());
396 QVERIFY(!bindable.hasBinding());
457 TestedClass &instance,
const PropertyType &initial,
const PropertyType &changed,
458 const char *propertyName,
459 std::function<
void()> mutator = []() { QFAIL(
"Data modifier function must be provided"); },
460 std::function<
bool(
const PropertyType &,
const PropertyType &)> comparator =
461 [](
const PropertyType &lhs,
const PropertyType &rhs) {
return lhs == rhs; },
462 std::function<
char *(
const PropertyType &)> represent =
463 [](
const PropertyType &val) {
return QTest::toString(val); })
466 const QMetaObject *metaObject = instance.metaObject();
467 QMetaProperty metaProperty = metaObject->property(metaObject->indexOfProperty(propertyName));
470 QObject &testedObj =
static_cast<QObject &>(instance);
472 QVERIFY2(metaProperty.metaType() == QMetaType::fromType<PropertyType>(),
473 QByteArray(
"Preconditions not met for ") + propertyName +
"\n"
474 "The type of initial and changed value does not match the type of the property.\n"
475 "Please ensure that the types match exactly (convertability is not enough).\n"
476 "You can provide the template types to the "
477 "function explicitly to force a certain type.\n"
478 "Expected was a " + metaProperty.metaType().name()
479 +
" but " + QMetaType::fromType<PropertyType>().name() +
" was provided.");
481 QVERIFY2(metaProperty.isBindable(),
"Preconditions not met for " + QByteArray(propertyName));
483 QUntypedBindable bindable = metaProperty.bindable(&instance);
485 QTestPrivate::OptionalWrapper<QSignalSpy> spy =
std::nullopt;
486 if (metaProperty.hasNotifySignal())
487 spy.emplace(&instance, metaProperty.notifySignal());
490 testedObj.property(propertyName).
template value<PropertyType>(), initial, comparator,
494 QProperty<PropertyType> propSetter(initial);
495 QVERIFY(!bindable.hasBinding());
496 bindable.setBinding(Qt::makePropertyBinding(propSetter));
497 QVERIFY(!bindable.hasBinding());
498 propSetter.setValue(changed);
500 testedObj.property(propertyName).
template value<PropertyType>(), initial, comparator,
503 QCOMPARE(spy->size(), 0);
505 QProperty<PropertyType> propObserver;
506 propObserver.setBinding(bindable.makeBinding());
514 testedObj.property(propertyName).
template value<PropertyType>(), changed, comparator,
519 QCOMPARE(spy->size(), 1);