File indexing completed on 2024-11-10 04:40:12
0001 /* 0002 SPDX-FileCopyrightText: 2006 Till Adam <adam@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "itemhydratest.h" 0008 0009 #include "item.h" 0010 #include <QDebug> 0011 #include <QSharedPointer> 0012 #include <QTemporaryFile> 0013 #include <QTest> 0014 #include <memory> 0015 0016 using namespace Akonadi; 0017 0018 struct Volker { 0019 bool operator==(const Volker &f) const 0020 { 0021 return f.who == who; 0022 } 0023 virtual ~Volker() 0024 { 0025 } 0026 virtual Volker *clone() const = 0; 0027 QString who; 0028 }; 0029 using VolkerPtr = std::shared_ptr<Volker>; 0030 using VolkerQPtr = QSharedPointer<Volker>; 0031 0032 struct Rudi : public Volker { 0033 Rudi() 0034 { 0035 who = QStringLiteral("Rudi"); 0036 } 0037 ~Rudi() override 0038 { 0039 } 0040 Rudi *clone() const override 0041 { 0042 return new Rudi(*this); 0043 } 0044 }; 0045 0046 using RudiPtr = std::shared_ptr<Rudi>; 0047 using RudiQPtr = QSharedPointer<Rudi>; 0048 0049 struct Gerd : public Volker { 0050 Gerd() 0051 { 0052 who = QStringLiteral("Gerd"); 0053 } 0054 Gerd *clone() const override 0055 { 0056 return new Gerd(*this); 0057 } 0058 0059 using SuperClass = Volker; 0060 }; 0061 0062 using GerdPtr = std::shared_ptr<Gerd>; 0063 using GerdQPtr = QSharedPointer<Gerd>; 0064 0065 Q_DECLARE_METATYPE(Volker *) 0066 Q_DECLARE_METATYPE(Rudi *) 0067 Q_DECLARE_METATYPE(Gerd *) 0068 0069 Q_DECLARE_METATYPE(Rudi) 0070 Q_DECLARE_METATYPE(Gerd) 0071 0072 namespace Akonadi 0073 { 0074 template<> 0075 struct SuperClass<Rudi> : public SuperClassTrait<Volker> { 0076 }; 0077 } 0078 0079 QTEST_MAIN(ItemHydra) 0080 0081 ItemHydra::ItemHydra() 0082 { 0083 } 0084 0085 void ItemHydra::initTestCase() 0086 { 0087 } 0088 0089 void ItemHydra::testItemValuePayload() 0090 { 0091 Item f; 0092 Rudi rudi; 0093 f.setPayload(rudi); 0094 QVERIFY(f.hasPayload()); 0095 0096 Item b; 0097 Gerd gerd; 0098 b.setPayload(gerd); 0099 QVERIFY(b.hasPayload()); 0100 0101 QCOMPARE(f.payload<Rudi>(), rudi); 0102 QVERIFY(!(f.payload<Rudi>() == gerd)); 0103 QCOMPARE(b.payload<Gerd>(), gerd); 0104 QVERIFY(!(b.payload<Gerd>() == rudi)); 0105 } 0106 0107 void ItemHydra::testItemPointerPayload() 0108 { 0109 Item f; 0110 Rudi *rudi = new Rudi; 0111 0112 // the below should not compile 0113 // f.setPayload( rudi ); 0114 0115 // f.setPayload( std::unique_ptr<Rudi>( rudi ) ); 0116 // QVERIFY( f.hasPayload() ); 0117 // QCOMPARE( f.payload< std::unique_ptr<Rudi> >()->who, rudi->who ); 0118 0119 // below doesn't compile, hopefully 0120 // QCOMPARE( f.payload< Rudi* >()->who, rudi->who ); 0121 0122 delete rudi; 0123 } 0124 0125 void ItemHydra::testItemCopy() 0126 { 0127 Item f; 0128 Rudi rudi; 0129 f.setPayload(rudi); 0130 0131 Item r = f; 0132 QCOMPARE(r.payload<Rudi>(), rudi); 0133 0134 Item s; 0135 s = f; 0136 QVERIFY(s.hasPayload()); 0137 QCOMPARE(s.payload<Rudi>(), rudi); 0138 } 0139 0140 void ItemHydra::testEmptyPayload() 0141 { 0142 Item i1; 0143 Item i2; 0144 i1 = i2; // should not crash 0145 0146 QVERIFY(!i1.hasPayload()); 0147 QVERIFY(!i2.hasPayload()); 0148 QVERIFY(!i1.hasPayload<Rudi>()); 0149 QVERIFY(!i1.hasPayload<RudiPtr>()); 0150 0151 bool caughtException = false; 0152 bool caughtRightException = true; 0153 try { 0154 Rudi r = i1.payload<Rudi>(); 0155 } catch (const Akonadi::PayloadException &e) { 0156 qDebug() << e.what(); 0157 caughtException = true; 0158 caughtRightException = true; 0159 } catch (const Akonadi::Exception &e) { 0160 qDebug() << "Caught Akonadi exception of type " << typeid(e).name() << ": " << e.what() << ", expected type" 0161 << typeid(Akonadi::PayloadException).name(); 0162 caughtException = true; 0163 caughtRightException = false; 0164 } catch (const std::exception &e) { 0165 qDebug() << "Caught exception of type " << typeid(e).name() << ": " << e.what() << ", expected type" << typeid(Akonadi::PayloadException).name(); 0166 caughtException = true; 0167 caughtRightException = false; 0168 } catch (...) { 0169 qDebug() << "Caught unknown exception"; 0170 caughtException = true; 0171 caughtRightException = false; 0172 } 0173 QVERIFY(caughtException); 0174 QVERIFY(caughtRightException); 0175 } 0176 0177 void ItemHydra::testPointerPayload() 0178 { 0179 Rudi *r = new Rudi; 0180 RudiPtr p(r); 0181 std::weak_ptr<Rudi> w(p); 0182 QCOMPARE(p.use_count(), (long)1); 0183 0184 { 0185 Item i1; 0186 i1.setPayload(p); 0187 QVERIFY(i1.hasPayload()); 0188 QCOMPARE(p.use_count(), (long)2); 0189 { 0190 QVERIFY(i1.hasPayload<RudiPtr>()); 0191 auto p2 = i1.payload<RudiPtr>(); 0192 QCOMPARE(p.use_count(), (long)3); 0193 } 0194 0195 { 0196 QVERIFY(i1.hasPayload<VolkerPtr>()); 0197 auto p2 = i1.payload<VolkerPtr>(); 0198 QCOMPARE(p.use_count(), (long)3); 0199 } 0200 0201 QCOMPARE(p.use_count(), (long)2); 0202 } 0203 QCOMPARE(p.use_count(), (long)1); 0204 QCOMPARE(w.use_count(), (long)1); 0205 p.reset(); 0206 QCOMPARE(w.use_count(), (long)0); 0207 } 0208 0209 void ItemHydra::testPolymorphicPayloadWithTrait() 0210 { 0211 VolkerPtr p(new Rudi); 0212 0213 { 0214 Item i1; 0215 i1.setPayload(p); 0216 QVERIFY(i1.hasPayload()); 0217 QVERIFY(i1.hasPayload<VolkerPtr>()); 0218 QVERIFY(i1.hasPayload<RudiPtr>()); 0219 QVERIFY(!i1.hasPayload<GerdPtr>()); 0220 QCOMPARE(p.use_count(), (long)2); 0221 { 0222 RudiPtr p2 = std::dynamic_pointer_cast<Rudi, Volker>(i1.payload<VolkerPtr>()); 0223 QCOMPARE(p.use_count(), (long)3); 0224 QCOMPARE(p2->who, QStringLiteral("Rudi")); 0225 } 0226 0227 { 0228 auto p2 = i1.payload<RudiPtr>(); 0229 QCOMPARE(p.use_count(), (long)3); 0230 QCOMPARE(p2->who, QStringLiteral("Rudi")); 0231 } 0232 0233 bool caughtException = false; 0234 try { 0235 auto p3 = i1.payload<GerdPtr>(); 0236 } catch (const Akonadi::PayloadException &e) { 0237 qDebug() << e.what(); 0238 caughtException = true; 0239 } 0240 QVERIFY(caughtException); 0241 0242 QCOMPARE(p.use_count(), (long)2); 0243 } 0244 } 0245 0246 void ItemHydra::testPolymorphicPayloadWithTypedef() 0247 { 0248 VolkerPtr p(new Gerd); 0249 0250 { 0251 Item i1; 0252 i1.setPayload(p); 0253 QVERIFY(i1.hasPayload()); 0254 QVERIFY(i1.hasPayload<VolkerPtr>()); 0255 QVERIFY(!i1.hasPayload<RudiPtr>()); 0256 QVERIFY(i1.hasPayload<GerdPtr>()); 0257 QCOMPARE(p.use_count(), (long)2); 0258 { 0259 auto p2 = std::dynamic_pointer_cast<Gerd, Volker>(i1.payload<VolkerPtr>()); 0260 QCOMPARE(p.use_count(), (long)3); 0261 QCOMPARE(p2->who, QStringLiteral("Gerd")); 0262 } 0263 0264 { 0265 auto p2 = i1.payload<GerdPtr>(); 0266 QCOMPARE(p.use_count(), (long)3); 0267 QCOMPARE(p2->who, QStringLiteral("Gerd")); 0268 } 0269 0270 bool caughtException = false; 0271 try { 0272 auto p3 = i1.payload<RudiPtr>(); 0273 } catch (const Akonadi::PayloadException &e) { 0274 qDebug() << e.what(); 0275 caughtException = true; 0276 } 0277 QVERIFY(caughtException); 0278 0279 QCOMPARE(p.use_count(), (long)2); 0280 } 0281 } 0282 0283 void ItemHydra::testNullPointerPayload() 0284 { 0285 RudiPtr p(static_cast<Rudi *>(nullptr)); 0286 Item i; 0287 i.setPayload(p); 0288 QVERIFY(i.hasPayload()); 0289 QVERIFY(i.hasPayload<RudiPtr>()); 0290 QVERIFY(i.hasPayload<VolkerPtr>()); 0291 // Fails, because GerdQPtr is QSharedPointer, while RudiPtr is std::shared_ptr 0292 // and we cannot do sharedptr casting for null pointers 0293 QVERIFY(!i.hasPayload<GerdQPtr>()); 0294 QCOMPARE(i.payload<RudiPtr>().get(), (Rudi *)nullptr); 0295 QCOMPARE(i.payload<VolkerPtr>().get(), (Volker *)nullptr); 0296 } 0297 0298 void ItemHydra::testQSharedPointerPayload() 0299 { 0300 RudiQPtr p(new Rudi); 0301 Item i; 0302 i.setPayload(p); 0303 QVERIFY(i.hasPayload()); 0304 QVERIFY(i.hasPayload<VolkerQPtr>()); 0305 QVERIFY(i.hasPayload<RudiQPtr>()); 0306 QVERIFY(!i.hasPayload<GerdQPtr>()); 0307 0308 { 0309 auto p2 = i.payload<VolkerQPtr>(); 0310 QCOMPARE(p2->who, QStringLiteral("Rudi")); 0311 } 0312 0313 { 0314 auto p2 = i.payload<RudiQPtr>(); 0315 QCOMPARE(p2->who, QStringLiteral("Rudi")); 0316 } 0317 0318 bool caughtException = false; 0319 try { 0320 auto p3 = i.payload<GerdQPtr>(); 0321 } catch (const Akonadi::PayloadException &e) { 0322 qDebug() << e.what(); 0323 caughtException = true; 0324 } 0325 QVERIFY(caughtException); 0326 } 0327 0328 void ItemHydra::testHasPayload() 0329 { 0330 Item i1; 0331 QVERIFY(!i1.hasPayload<Rudi>()); 0332 QVERIFY(!i1.hasPayload<Gerd>()); 0333 0334 Rudi r; 0335 i1.setPayload(r); 0336 QVERIFY(i1.hasPayload<Rudi>()); 0337 QVERIFY(!i1.hasPayload<Gerd>()); 0338 } 0339 0340 void ItemHydra::testSharedPointerConversions() 0341 { 0342 Item a; 0343 RudiQPtr rudi(new Rudi); 0344 a.setPayload(rudi); 0345 // only the root base classes should show up with their metatype ids: 0346 QVERIFY(a.availablePayloadMetaTypeIds().contains(qMetaTypeId<Volker *>())); 0347 QVERIFY(a.hasPayload<RudiQPtr>()); 0348 QVERIFY(a.hasPayload<VolkerPtr>()); 0349 QVERIFY(a.hasPayload<RudiPtr>()); 0350 QVERIFY(!a.hasPayload<GerdPtr>()); 0351 QVERIFY(a.payload<RudiPtr>().get()); 0352 QVERIFY(a.payload<VolkerPtr>().get()); 0353 bool thrown = false; 0354 0355 bool thrownCorrectly = true; 0356 try { 0357 QVERIFY(!a.payload<GerdPtr>()); 0358 } catch (const Akonadi::PayloadException &e) { 0359 thrown = thrownCorrectly = true; 0360 } catch (...) { 0361 thrown = true; 0362 thrownCorrectly = false; 0363 } 0364 QVERIFY(thrown); 0365 QVERIFY(thrownCorrectly); 0366 } 0367 0368 void ItemHydra::testForeignPayload() 0369 { 0370 QTemporaryFile file; 0371 QVERIFY(file.open()); 0372 file.write("123456789"); 0373 file.close(); 0374 0375 Item a(QStringLiteral("application/octet-stream")); 0376 a.setPayloadPath(file.fileName()); 0377 QVERIFY(a.hasPayload<QByteArray>()); 0378 QCOMPARE(a.payload<QByteArray>(), QByteArray("123456789")); 0379 0380 Item b(QStringLiteral("application/octet-stream")); 0381 b.apply(a); 0382 QVERIFY(b.hasPayload<QByteArray>()); 0383 QCOMPARE(b.payload<QByteArray>(), QByteArray("123456789")); 0384 QCOMPARE(b.payloadPath(), file.fileName()); 0385 0386 Item c = b; 0387 QVERIFY(c.hasPayload<QByteArray>()); 0388 QCOMPARE(c.payload<QByteArray>(), QByteArray("123456789")); 0389 QCOMPARE(c.payloadPath(), file.fileName()); 0390 } 0391 0392 #include "moc_itemhydratest.cpp"