File indexing completed on 2024-11-10 04:40:09

0001 /*
0002     SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "collectionattributetest.h"
0008 #include "collectionpathresolver.h"
0009 
0010 #include "attributefactory.h"
0011 #include "collection.h"
0012 #include "collectioncreatejob.h"
0013 #include "collectiondeletejob.h"
0014 #include "collectionfetchjob.h"
0015 #include "collectionidentificationattribute.h"
0016 #include "collectionmodifyjob.h"
0017 #include "collectionrightsattribute_p.h"
0018 #include "control.h"
0019 
0020 #include "qtest_akonadi.h"
0021 
0022 using namespace Akonadi;
0023 
0024 QTEST_AKONADIMAIN(CollectionAttributeTest)
0025 
0026 class TestAttribute : public Attribute
0027 {
0028 public:
0029     TestAttribute() = default;
0030 
0031     explicit TestAttribute(const QByteArray &data)
0032         : mData(data)
0033     {
0034     }
0035     TestAttribute *clone() const override
0036     {
0037         return new TestAttribute(mData);
0038     }
0039     QByteArray type() const override
0040     {
0041         return "TESTATTRIBUTE";
0042     }
0043     QByteArray serialized() const override
0044     {
0045         return mData;
0046     }
0047     void deserialize(const QByteArray &data) override
0048     {
0049         mData = data;
0050     }
0051 
0052 private:
0053     QByteArray mData;
0054 };
0055 
0056 static int parentColId = -1;
0057 
0058 void CollectionAttributeTest::initTestCase()
0059 {
0060     AkonadiTest::checkTestIsIsolated();
0061     Control::start();
0062     AttributeFactory::registerAttribute<TestAttribute>();
0063 
0064     auto resolver = new CollectionPathResolver(QStringLiteral("res3"), this);
0065     AKVERIFYEXEC(resolver);
0066     parentColId = resolver->collection();
0067     QVERIFY(parentColId > 0);
0068 }
0069 
0070 void CollectionAttributeTest::testAttributes_data()
0071 {
0072     QTest::addColumn<QByteArray>("attr1");
0073     QTest::addColumn<QByteArray>("attr2");
0074 
0075     QTest::newRow("basic") << QByteArray("foo") << QByteArray("bar");
0076     QTest::newRow("empty1") << QByteArray("") << QByteArray("non-empty");
0077 #if 0 // This one is failing on the CI with SQLite. Can't reproduce locally and
0078       // it works with other DB backends, so I have no idea what is going on...
0079     QTest::newRow("empty2") << QByteArray("non-empty") << QByteArray("");
0080 #endif
0081     QTest::newRow("space") << QByteArray("foo bar") << QByteArray("bar foo");
0082     QTest::newRow("newline") << QByteArray("\n") << QByteArray("no newline");
0083     QTest::newRow("newline2") << QByteArray(" \\\n\\\nnn") << QByteArray("no newline");
0084     QTest::newRow("cr") << QByteArray("\r") << QByteArray("\\\r\n");
0085     QTest::newRow("quotes") << QByteArray(R"("quoted \ test")") << QByteArray("single \" quote \\");
0086     QTest::newRow("parenthesis") << QByteArray(")") << QByteArray("(");
0087     QTest::newRow("binary") << QByteArray("\000") << QByteArray("\001");
0088 }
0089 
0090 void CollectionAttributeTest::testAttributes()
0091 {
0092     QFETCH(QByteArray, attr1);
0093     QFETCH(QByteArray, attr2);
0094 
0095     struct Cleanup {
0096         explicit Cleanup(const Collection &col)
0097             : m_col(col)
0098         {
0099         }
0100         ~Cleanup()
0101         {
0102             // cleanup
0103             auto del = new CollectionDeleteJob(m_col);
0104             AKVERIFYEXEC(del);
0105         }
0106         Collection m_col;
0107     };
0108 
0109     // add a custom attribute
0110     auto attr = new TestAttribute();
0111     attr->deserialize(attr1);
0112     Collection col;
0113     col.setName(QStringLiteral("attribute test"));
0114     col.setParentCollection(Collection(parentColId));
0115     col.addAttribute(attr);
0116     auto create = new CollectionCreateJob(col, this);
0117     AKVERIFYEXEC(create);
0118     col = create->collection();
0119     QVERIFY(col.isValid());
0120     Cleanup cleanup(col);
0121 
0122     attr = col.attribute<TestAttribute>();
0123     QVERIFY(attr != nullptr);
0124     QCOMPARE(attr->serialized(), QByteArray(attr1));
0125 
0126     auto list = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0127     AKVERIFYEXEC(list);
0128     QCOMPARE(list->collections().count(), 1);
0129     col = list->collections().at(0);
0130 
0131     QVERIFY(col.isValid());
0132     attr = col.attribute<TestAttribute>();
0133     QVERIFY(attr != nullptr);
0134     QCOMPARE(attr->serialized(), QByteArray(attr1));
0135 
0136     auto attrB = new TestAttribute();
0137     attrB->deserialize(attr2);
0138     col.addAttribute(attrB);
0139     attrB = col.attribute<TestAttribute>();
0140     QVERIFY(attrB != nullptr);
0141     QCOMPARE(attrB->serialized(), QByteArray(attr2));
0142 
0143     attrB->deserialize(attr1);
0144     col.addAttribute(attrB);
0145     attrB = col.attribute<TestAttribute>();
0146     QVERIFY(attrB != nullptr);
0147     QCOMPARE(attrB->serialized(), QByteArray(attr1));
0148 
0149     // this will mark the attribute as modified in the storage, but should not create trouble further down
0150     QVERIFY(!col.attribute("does_not_exist"));
0151 
0152     // modify a custom attribute
0153     col.attribute<TestAttribute>(Collection::AddIfMissing)->deserialize(attr2);
0154     auto modify = new CollectionModifyJob(col, this);
0155     AKVERIFYEXEC(modify);
0156 
0157     list = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0158     AKVERIFYEXEC(list);
0159     QCOMPARE(list->collections().count(), 1);
0160     col = list->collections().at(0);
0161 
0162     QVERIFY(col.isValid());
0163     attr = col.attribute<TestAttribute>();
0164     QVERIFY(attr != nullptr);
0165     QCOMPARE(attr->serialized(), QByteArray(attr2));
0166 
0167     // delete a custom attribute
0168     col.removeAttribute<TestAttribute>();
0169     modify = new CollectionModifyJob(col, this);
0170     AKVERIFYEXEC(modify);
0171 
0172     list = new CollectionFetchJob(col, CollectionFetchJob::Base, this);
0173     AKVERIFYEXEC(list);
0174     QCOMPARE(list->collections().count(), 1);
0175     col = list->collections().at(0);
0176 
0177     QVERIFY(col.isValid());
0178     attr = col.attribute<TestAttribute>();
0179     QVERIFY(attr == nullptr);
0180 
0181     // Give the knut resource a bit of time to modify the collection and add a remote ID (after adding)
0182     // and reparent attributes (after modifying).
0183     // Otherwise we can delete it faster than it can do that, and we end up with a confusing warning
0184     // "No such collection" from the resource's modify job.
0185     QTest::qWait(100); // ideally we'd loop over "fetch and check there's a remote id"
0186 }
0187 
0188 void CollectionAttributeTest::testDefaultAttributes()
0189 {
0190     Collection col;
0191     QCOMPARE(col.attributes().count(), 0);
0192     Attribute *attr = AttributeFactory::createAttribute("TYPE");
0193     QVERIFY(attr);
0194     attr->deserialize("VALUE");
0195     col.addAttribute(attr);
0196     QCOMPARE(col.attributes().count(), 1);
0197     QVERIFY(col.hasAttribute("TYPE"));
0198     QCOMPARE(col.attribute("TYPE")->serialized(), QByteArray("VALUE"));
0199 }
0200 
0201 void CollectionAttributeTest::testCollectionRightsAttribute()
0202 {
0203     CollectionRightsAttribute attribute;
0204     Collection::Rights rights;
0205 
0206     QCOMPARE(attribute.rights(), rights);
0207 
0208     for (int mask = 0; mask <= Collection::AllRights; ++mask) {
0209         rights = Collection::AllRights;
0210         rights &= mask;
0211         QCOMPARE(rights, mask);
0212 
0213         attribute.setRights(rights);
0214         QCOMPARE(attribute.rights(), rights);
0215 
0216         QByteArray data = attribute.serialized();
0217         attribute.deserialize(data);
0218         QCOMPARE(attribute.rights(), rights);
0219     }
0220 }
0221 
0222 void CollectionAttributeTest::testCollectionIdentificationAttribute()
0223 {
0224     QByteArray id("identifier");
0225     QByteArray ns("namespace");
0226     CollectionIdentificationAttribute attribute(id, ns);
0227     QCOMPARE(attribute.identifier(), id);
0228     QCOMPARE(attribute.collectionNamespace(), ns);
0229 
0230     QByteArray result = attribute.serialized();
0231     CollectionIdentificationAttribute parsed;
0232     parsed.deserialize(result);
0233     qDebug() << parsed.identifier() << parsed.collectionNamespace() << result;
0234     QCOMPARE(parsed.identifier(), id);
0235     QCOMPARE(parsed.collectionNamespace(), ns);
0236 }
0237 
0238 void CollectionAttributeTest::testDetach()
0239 {
0240     // GIVEN a collection with an attribute
0241     Collection col;
0242     col.attribute<TestAttribute>(Akonadi::Collection::AddIfMissing);
0243     Collection col2 = col; // and a copy, so that non-const access detaches
0244 
0245     // WHEN
0246     auto attr = col2.attribute<TestAttribute>(Akonadi::Collection::AddIfMissing);
0247     auto attr2 = col2.attribute<TestAttribute>();
0248 
0249     // THEN
0250     QCOMPARE(attr, attr2);
0251 }
0252 
0253 #include "moc_collectionattributetest.cpp"