// Copyright (C) 2025 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include #include #include using namespace std::chrono_literals; template class GrpcCommonOptionsTest { public: void hasSpecialMemberFunctions() const { T o1; QVERIFY(!o1.deadlineTimeout()); QVERIFY(o1.metadata(QtGrpc::MultiValue).empty()); o1.setDeadlineTimeout(100ms); T o2(o1); QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout()); T o3 = o1; QCOMPARE_EQ(o1.deadlineTimeout(), o3.deadlineTimeout()); T o4(std::move(o1)); QCOMPARE_EQ(o4.deadlineTimeout(), o2.deadlineTimeout()); o1 = std::move(o4); QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout()); } void hasImplicitQVariant() const { T o1; o1.setDeadlineTimeout(250ms); o1.setMetadata({ { "keyA", "valA" }, { "keyB", "valB" }, }); QVariant v = o1; QCOMPARE_EQ(v.metaType(), QMetaType::fromType()); const auto o2 = v.value(); QCOMPARE_EQ(o1.metadata(QtGrpc::MultiValue), o2.metadata(QtGrpc::MultiValue)); QCOMPARE_EQ(o1.deadlineTimeout(), o2.deadlineTimeout()); } void hasMemberSwap() const { constexpr std::chrono::milliseconds Dur = 50ms; T o1; o1.setDeadlineTimeout(Dur); T o2; QCOMPARE_EQ(o1.deadlineTimeout(), Dur); QVERIFY(!o2.deadlineTimeout()); o2.swap(o1); QCOMPARE_EQ(o2.deadlineTimeout(), Dur); QVERIFY(!o1.deadlineTimeout()); swap(o2, o1); QCOMPARE_EQ(o1.deadlineTimeout(), Dur); QVERIFY(!o2.deadlineTimeout()); } #if QT_DEPRECATED_SINCE(6, 13) QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED void deprecatedPropertyMetadata() const { QHash data = { { "keyA", "valA" }, { "keyB", "valB" }, }; // cref setter T o1; auto o1Detach = o1; o1.setMetadata(data); QCOMPARE_EQ(o1.metadata(), data); QCOMPARE_NE(o1.metadata(), o1Detach.metadata()); // rvalue setter T o2; auto o2Detach = o2; auto dataMoved = data; o2.setMetadata(std::move(dataMoved)); QCOMPARE_EQ(o2.metadata(), data); QCOMPARE_NE(o2.metadata(), o2Detach.metadata()); // rvalue-this getter T o3; o3.setMetadata(data); auto movedMd = std::move(o3).metadata(); QCOMPARE_EQ(movedMd, data); } void propertyMetadataCompat() const { auto toMulti = [](const QHash &m) { return QMultiHash(m); }; QMultiHash multiMd = { { "keyA", "valA1" }, { "keyA", "valA2" }, { "keyB", "valB1" }, { "keyB", "valB2" }, { "keyC", "valC" }, }; QHash md = { { "keyA", "valA2" }, { "keyB", "valB2" }, { "keyC", "valC" }, }; T o1; o1.setMetadata(md); const auto &mdRef = o1.metadata(); const auto &multiMdRef = o1.metadata(QtGrpc::MultiValue); QCOMPARE_EQ(mdRef, md); QCOMPARE_EQ(multiMdRef, toMulti(mdRef)); QCOMPARE_NE(typeid(mdRef), typeid(multiMdRef)); // Check that the handed out reference gets updates for QMultiHash setter o1.setMetadata(multiMd); QCOMPARE_EQ(multiMdRef, multiMd); QCOMPARE_EQ(mdRef, md); multiMd.insert("keyD", "valD"); o1.setMetadata(multiMd); QCOMPARE_EQ(multiMdRef, multiMd); QCOMPARE_NE(mdRef, md); md.insert("keyD", "valD"); QCOMPARE_EQ(mdRef, md); // Check that the handed out reference gets updates for QHash setter o1.setMetadata(md); QCOMPARE_EQ(multiMdRef, toMulti(md)); QCOMPARE_EQ(mdRef, md); // Check shared state mutation due to lazy evaluation in metadata() auto mdCopy = md; T o2; o2.setMetadata(mdCopy); auto o2Detach = o2; const auto &o2Md = o2.metadata(); const auto &o2DetachMd = o2Detach.metadata(); QCOMPARE_EQ(o2Md, mdCopy); QCOMPARE_EQ(o2Md, o2DetachMd); mdCopy.insert("keyX", "valX"); o2.setMetadata(mdCopy); // trigger new merge const auto &o2MdAfter = o2.metadata(); const auto &o2DetachMdAfter = o2Detach.metadata(); QCOMPARE_NE(o2MdAfter, o2DetachMdAfter); T o3A; T o3B = o3A; const auto &o3aMd = o3A.metadata(); o3B.setMetadata(QHash{ {"keyA","valA"}, {"keyB","valB"} }); // o3aMd is not affected by the update since o3B deprecatedQHashRef is used QCOMPARE_NE(o3aMd, o3B.metadata()); o3A.setMetadata(QHash{ {"keyA","valA"}, {"keyB","valB"}, {"keyC","valC"}, }); // o3aMd is updated accoringly though QCOMPARE_EQ(o3aMd, o3A.metadata()); QCOMPARE_NE(o3B.metadata(), o3A.metadata()); } QT_WARNING_POP #endif void propertyMetadata() const { std::initializer_list> list = { { "keyA", "valA1" }, { "keyA", "valA2" }, { "keyB", "valB" }, }; QMultiHash data(list); // cref setter T o1; auto o1Detach = o1; o1.setMetadata(data); QCOMPARE_EQ(o1.metadata(QtGrpc::MultiValue), data); QCOMPARE_NE(o1.metadata(QtGrpc::MultiValue), o1Detach.metadata(QtGrpc::MultiValue)); // rvalue setter T o2; auto o2Detach = o2; auto dataMoved = data; o2.setMetadata(std::move(dataMoved)); QCOMPARE_EQ(o2.metadata(QtGrpc::MultiValue), data); QCOMPARE_NE(o2.metadata(QtGrpc::MultiValue), o2Detach.metadata(QtGrpc::MultiValue)); // rvalue-this getter T o3; o3.setMetadata(data); auto movedMd = std::move(o3).metadata(QtGrpc::MultiValue); QCOMPARE_EQ(movedMd, data); // std::initializer_list setter T o4; o4.setMetadata(list); QCOMPARE_EQ(o4.metadata(QtGrpc::MultiValue), data); } void propertyDeadline() const { constexpr std::chrono::milliseconds Dur = 50ms; T o1; auto o1Detach = o1; o1.setDeadlineTimeout(Dur); QCOMPARE_EQ(o1.deadlineTimeout(), Dur); QCOMPARE_NE(o1.deadlineTimeout(), o1Detach.deadlineTimeout()); } void streamsToDebug() const { T o; QString storage; QDebug dbg(&storage); dbg.noquote().nospace(); dbg << o; QVERIFY(!storage.isEmpty()); std::unique_ptr ustr(QTest::toString(o)); QCOMPARE_EQ(storage, QString::fromUtf8(ustr.get())); } };