diff --git a/src/tests/collectiontest.cpp b/src/tests/collectiontest.cpp index efc36802..8b8f7891 100644 --- a/src/tests/collectiontest.cpp +++ b/src/tests/collectiontest.cpp @@ -1,717 +1,719 @@ /*************************************************************************** Copyright (C) 2009-2016 Robby Stephenson ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 2 of * * the License or (at your option) version 3 or any later version * * accepted by the membership of KDE e.V. (or its successor approved * * by the membership of KDE e.V.), which shall act as a proxy * * defined in Section 14 of version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #include "collectiontest.h" #include "../collection.h" #include "../field.h" #include "../entry.h" #include "../collectionfactory.h" #include "../collections/collectioninitializer.h" #include "../collections/bookcollection.h" #include "../collections/gamecollection.h" #include "../translators/tellicoxmlexporter.h" #include "../translators/tellicoimporter.h" #include "../images/imagefactory.h" #include "../document.h" #include "../entrycomparison.h" #include #include #include QTEST_GUILESS_MAIN( CollectionTest ) Q_DECLARE_METATYPE(Tellico::EntryComparison::MatchValue) class TestResolver : public Tellico::MergeConflictResolver { public: TestResolver(Tellico::MergeConflictResolver::Result ret) : m_ret(ret) {}; Tellico::MergeConflictResolver::Result resolve(Tellico::Data::EntryPtr, Tellico::Data::EntryPtr, Tellico::Data::FieldPtr, const QString& value1 = QString(), const QString& value2 = QString()) Q_DECL_OVERRIDE { Q_UNUSED(value1); Q_UNUSED(value2); return m_ret; } private: Tellico::MergeConflictResolver::Result m_ret; }; void CollectionTest::initTestCase() { qRegisterMetaType(); Tellico::ImageFactory::init(); // need to register the collection types Tellico::CollectionInitializer ci; // create the collection and entry used for testMatchScore() m_coll = Tellico::Data::CollPtr(new Tellico::Data::BookCollection(true)); m_entry = Tellico::Data::EntryPtr(new Tellico::Data::Entry(m_coll)); m_entry->setField(QStringLiteral("title"), QStringLiteral("title1")); m_entry->setField(QStringLiteral("author"), QStringLiteral("John Doe")); m_entry->setField(QStringLiteral("isbn"), QStringLiteral("1234367890")); m_entry->setField(QStringLiteral("lccn"), QStringLiteral("89456")); Tellico::Data::FieldPtr f(new Tellico::Data::Field(QStringLiteral("arxiv"), QStringLiteral("Arxiv ID"))); m_coll->addField(f); m_entry->setField(QStringLiteral("arxiv"), QStringLiteral("hep-lat/0110180")); m_coll->addEntries(m_entry); } void CollectionTest::cleanupTestCase() { Tellico::ImageFactory::clean(true); } void CollectionTest::testEmpty() { Tellico::Data::CollPtr nullColl; QVERIFY(!nullColl); Tellico::Data::Collection coll(false, QStringLiteral("Title")); QCOMPARE(coll.id(), 2); // ID is 2 since ID of 1 is created in initTestCase() QCOMPARE(coll.entryCount(), 0); QCOMPARE(coll.type(), Tellico::Data::Collection::Base); QVERIFY(coll.fields().isEmpty()); QCOMPARE(coll.title(), QStringLiteral("Title")); } void CollectionTest::testCollection() { Tellico::Data::CollPtr coll(new Tellico::Data::Collection(true)); // add default fields QCOMPARE(coll->entryCount(), 0); QCOMPARE(coll->type(), Tellico::Data::Collection::Base); QCOMPARE(coll->fields().count(), 4); QVERIFY(coll->hasField(QStringLiteral("title"))); QVERIFY(coll->hasField(QStringLiteral("id"))); QVERIFY(coll->hasField(QStringLiteral("cdate"))); QVERIFY(coll->hasField(QStringLiteral("mdate"))); QVERIFY(coll->peopleFields().isEmpty()); QVERIFY(coll->imageFields().isEmpty()); QVERIFY(!coll->hasImages()); Tellico::Data::EntryPtr entry1(new Tellico::Data::Entry(coll)); coll->addEntries(entry1); // check derived value QCOMPARE(entry1->field(QStringLiteral("id")), QStringLiteral("1")); // check created and modified values QCOMPARE(entry1->field(QStringLiteral("cdate")), QDate::currentDate().toString(Qt::ISODate)); QCOMPARE(entry1->field(QStringLiteral("mdate")), QDate::currentDate().toString(Qt::ISODate)); // also verify that the empty string is included in list of group names Tellico::Data::FieldPtr field1(new Tellico::Data::Field(QStringLiteral("test"), QStringLiteral("test"))); coll->addField(field1); QStringList groupNames = entry1->groupNamesByFieldName(QStringLiteral("test")); QCOMPARE(groupNames.count(), 1); QVERIFY(groupNames.at(0).isEmpty()); Tellico::Data::EntryPtr entry2(new Tellico::Data::Entry(coll)); // add created and modified dates from earlier, to make sure they don't get overwritten QDate weekAgo = QDate::currentDate().addDays(-7); QDate yesterday = QDate::currentDate().addDays(-1); entry2->setField(QStringLiteral("cdate"), weekAgo.toString(Qt::ISODate)); entry2->setField(QStringLiteral("mdate"), yesterday.toString(Qt::ISODate)); coll->addEntries(entry2); // check derived value QCOMPARE(entry2->field(QStringLiteral("id")), QStringLiteral("2")); // check created and modified values QCOMPARE(entry2->field(QStringLiteral("cdate")), weekAgo.toString(Qt::ISODate)); QCOMPARE(entry2->field(QStringLiteral("mdate")), yesterday.toString(Qt::ISODate)); // check that mdate gets updates entry2->setField(QStringLiteral("title"), QStringLiteral("new title")); QCOMPARE(entry2->field(QStringLiteral("cdate")), weekAgo.toString(Qt::ISODate)); QCOMPARE(entry2->field(QStringLiteral("mdate")), QDate::currentDate().toString(Qt::ISODate)); // check Bug 361622 - properly handling empty rows in table Tellico::Data::FieldPtr tableField(new Tellico::Data::Field(QStringLiteral("table"), QStringLiteral("Table"), Tellico::Data::Field::Table)); tableField->setFormatType(Tellico::FieldFormat::FormatName); coll->addField(tableField); QString tableValue = QStringLiteral("Value1") + Tellico::FieldFormat::rowDelimiterString() + Tellico::FieldFormat::rowDelimiterString() + QStringLiteral("Value2"); entry2->setField(QStringLiteral("table"), tableValue); QCOMPARE(entry2->formattedField(QStringLiteral("table")), tableValue); - QCOMPARE(QSet::fromList(entry2->groupNamesByFieldName(QStringLiteral("table"))), - QSet() << QStringLiteral("Value1") << QStringLiteral("Value2")); + groupNames = entry2->groupNamesByFieldName(QStringLiteral("table")); + QCOMPARE(groupNames.count(), 2); + QVERIFY(groupNames.contains(QStringLiteral("Value1"))); + QVERIFY(groupNames.contains(QStringLiteral("Value2"))); } void CollectionTest::testFields() { Tellico::Data::CollPtr coll(new Tellico::Data::Collection(true)); // add default fields QCOMPARE(coll->fields().count(), 4); QVERIFY(coll->peopleFields().isEmpty()); QVERIFY(coll->imageFields().isEmpty()); Tellico::Data::FieldPtr aField(new Tellico::Data::Field(QStringLiteral("author"), QStringLiteral("Author"))); aField->setFlags(Tellico::Data::Field::AllowMultiple | Tellico::Data::Field::AllowGrouped); aField->setFormatType(Tellico::FieldFormat::FormatName); QCOMPARE(coll->addField(aField), true); QVERIFY(coll->hasField(QStringLiteral("author"))); QCOMPARE(coll->defaultGroupField(), QStringLiteral("author")); QCOMPARE(coll->fields().count(), 5); QCOMPARE(coll->peopleFields().count(), 1); QVERIFY(coll->imageFields().isEmpty()); QVERIFY(!coll->hasImages()); QCOMPARE(coll->fieldsByCategory(QStringLiteral("General")).size(), 2); Tellico::Data::FieldPtr bField(new Tellico::Data::Field(QStringLiteral("cover"), QStringLiteral("Cover"), Tellico::Data::Field::Image)); QCOMPARE(coll->addField(bField), true); QVERIFY(coll->hasField(QStringLiteral("cover"))); QVERIFY(!coll->hasField(QStringLiteral("Ccover"))); QCOMPARE(coll->fields().count(), 6); QCOMPARE(coll->peopleFields().count(), 1); QCOMPARE(coll->imageFields().count(), 1); QVERIFY(coll->hasImages()); QStringList cats = coll->fieldCategories(); QCOMPARE(cats.size(), 3); QVERIFY(cats.contains(QStringLiteral("General"))); QVERIFY(cats.contains(QStringLiteral("Personal"))); QVERIFY(cats.contains(QStringLiteral("Cover"))); const QStringList names = coll->fieldNames(); QCOMPARE(names.size(), 6); QVERIFY(names.contains(QStringLiteral("author"))); QVERIFY(names.contains(QStringLiteral("cover"))); const QStringList titles = coll->fieldTitles(); QCOMPARE(titles.size(), 6); QVERIFY(titles.contains(QStringLiteral("Author"))); QVERIFY(titles.contains(QStringLiteral("Cover"))); QCOMPARE(coll->fieldByName(QStringLiteral("author")), aField); QCOMPARE(coll->fieldByTitle(QStringLiteral("Author")), aField); QCOMPARE(coll->fieldNameByTitle(QStringLiteral("Author")), QStringLiteral("author")); QCOMPARE(coll->fieldNameByTitle(QStringLiteral("author")), QString()); QCOMPARE(coll->fieldTitleByName(QStringLiteral("Author")), QString()); QCOMPARE(coll->fieldTitleByName(QStringLiteral("author")), QStringLiteral("Author")); QVERIFY(coll->removeField(QStringLiteral("cover"))); QVERIFY(!coll->hasField(QStringLiteral("cover"))); QCOMPARE(coll->fields().count(), 5); QVERIFY(!coll->hasImages()); QCOMPARE(coll->fieldTitleByName(QStringLiteral("cover")), QString()); QCOMPARE(coll->fieldCategories().size(), 2); Tellico::Data::FieldPtr cField(new Tellico::Data::Field(QStringLiteral("editor"), QStringLiteral("Editor"))); cField->setFlags(Tellico::Data::Field::AllowGrouped); cField->setFormatType(Tellico::FieldFormat::FormatName); cField->setCategory(QStringLiteral("People")); // since the field name does not match an existing field, modifying should fail QVERIFY(!coll->modifyField(cField)); cField->setName(QStringLiteral("author")); QVERIFY(coll->modifyField(cField)); QCOMPARE(coll->fieldByName(QStringLiteral("author")), cField); QCOMPARE(coll->fieldByTitle(QStringLiteral("Author")), Tellico::Data::FieldPtr()); QCOMPARE(coll->fieldByTitle(QStringLiteral("Editor")), cField); QCOMPARE(coll->peopleFields().count(), 1); cats = coll->fieldCategories(); QCOMPARE(cats.size(), 3); QVERIFY(cats.contains(QStringLiteral("General"))); QVERIFY(cats.contains(QStringLiteral("Personal"))); QVERIFY(cats.contains(QStringLiteral("People"))); QCOMPARE(coll->fieldsByCategory(QStringLiteral("General")).size(), 1); QCOMPARE(coll->fieldsByCategory(QStringLiteral("People")).size(), 1); coll->clear(); QVERIFY(coll->fields().isEmpty()); QVERIFY(coll->peopleFields().isEmpty()); QVERIFY(coll->imageFields().isEmpty()); QVERIFY(coll->fieldCategories().isEmpty()); QVERIFY(coll->defaultGroupField().isEmpty()); QCOMPARE(coll->fieldByName(QStringLiteral("author")), Tellico::Data::FieldPtr()); QCOMPARE(coll->fieldByTitle(QStringLiteral("Editor")), Tellico::Data::FieldPtr()); } void CollectionTest::testDerived() { Tellico::Data::CollPtr coll(new Tellico::Data::Collection(true)); // add default field Tellico::Data::FieldPtr aField(new Tellico::Data::Field(QStringLiteral("author"), QStringLiteral("Author"))); aField->setFlags(Tellico::Data::Field::AllowMultiple); aField->setFormatType(Tellico::FieldFormat::FormatName); coll->addField(aField); Tellico::Data::EntryPtr entry(new Tellico::Data::Entry(coll)); entry->setField(QStringLiteral("author"), QStringLiteral("Albert Einstein; Niels Bohr")); coll->addEntries(entry); Tellico::Data::FieldPtr field(new Tellico::Data::Field(QStringLiteral("test"), QStringLiteral("Test"))); field->setProperty(QStringLiteral("template"), QStringLiteral("%{author}")); field->setFlags(Tellico::Data::Field::Derived); field->setFormatType(Tellico::FieldFormat::FormatName); coll->addField(field); QCOMPARE(entry->field(QStringLiteral("test")), QStringLiteral("Albert Einstein; Niels Bohr")); field->setProperty(QStringLiteral("template"), QStringLiteral("%{test3}")); Tellico::Data::FieldPtr field2(new Tellico::Data::Field(QStringLiteral("test2"), QStringLiteral("Test"))); field2->setProperty(QStringLiteral("template"), QStringLiteral("%{test}")); field2->setFlags(Tellico::Data::Field::Derived); coll->addField(field2); Tellico::Data::FieldPtr field3(new Tellico::Data::Field(QStringLiteral("test3"), QStringLiteral("Test"))); field3->setProperty(QStringLiteral("template"), QStringLiteral("%{test3:1}")); field3->setFlags(Tellico::Data::Field::Derived); coll->addField(field3); // recursive, so template should be empty now QCOMPARE(field3->property(QStringLiteral("template")), QString()); // now test all the possible format options field->setProperty(QStringLiteral("template"), QStringLiteral("%{author:1}")); QCOMPARE(entry->field(QStringLiteral("test")), QStringLiteral("Albert Einstein")); field->setProperty(QStringLiteral("template"), QStringLiteral("%{author:1/l}")); QCOMPARE(entry->field(QStringLiteral("test")), QStringLiteral("albert einstein")); field->setProperty(QStringLiteral("template"), QStringLiteral("%{author:1/u}")); QCOMPARE(entry->field(QStringLiteral("test")), QStringLiteral("ALBERT EINSTEIN")); field->setProperty(QStringLiteral("template"), QStringLiteral("%{author:1}")); QCOMPARE(entry->formattedField(QStringLiteral("test"), Tellico::FieldFormat::ForceFormat), QStringLiteral("Einstein, Albert")); field->setProperty(QStringLiteral("template"), QStringLiteral("%{author:2}")); QCOMPARE(entry->field(QStringLiteral("test")), QStringLiteral("Niels Bohr")); field->setProperty(QStringLiteral("template"), QStringLiteral("%{author:-1}")); QCOMPARE(entry->field(QStringLiteral("test")), QStringLiteral("Niels Bohr")); field->setProperty(QStringLiteral("template"), QStringLiteral("%{author:-1}")); QCOMPARE(entry->formattedField(QStringLiteral("test"), Tellico::FieldFormat::ForceFormat), QStringLiteral("Bohr, Niels")); field->setProperty(QStringLiteral("template"), QStringLiteral("%{author:-2}")); QCOMPARE(entry->field(QStringLiteral("test")), QStringLiteral("Albert Einstein")); } void CollectionTest::testValue() { QFETCH(QString, string); QFETCH(QString, formatted); QFETCH(int, typeInt); Tellico::FieldFormat::Type type = static_cast(typeInt); Tellico::Data::CollPtr coll(new Tellico::Data::Collection(true)); // add default field Tellico::Data::FieldPtr field1(new Tellico::Data::Field(QStringLiteral("test"), QStringLiteral("Test"))); field1->setFlags(Tellico::Data::Field::AllowMultiple); field1->setFormatType(type); coll->addField(field1); Tellico::Data::FieldPtr field2(new Tellico::Data::Field(QStringLiteral("table"), QStringLiteral("Table"), Tellico::Data::Field::Table)); field2->setFormatType(type); coll->addField(field2); Tellico::Data::EntryPtr entry(new Tellico::Data::Entry(coll)); coll->addEntries(entry); entry->setField(field1, string); const QString dummy = Tellico::FieldFormat::columnDelimiterString() + QStringLiteral("dummy, the; Dummy, The; the dummy"); entry->setField(field2, string + dummy); QCOMPARE(entry->formattedField(field1, Tellico::FieldFormat::ForceFormat), formatted); QCOMPARE(entry->formattedField(field2, Tellico::FieldFormat::ForceFormat), formatted.append(dummy)); } void CollectionTest::testValue_data() { QTest::addColumn("string"); QTest::addColumn("formatted"); QTest::addColumn("typeInt"); QTest::newRow("test1") << "name" << "Name" << int(Tellico::FieldFormat::FormatName); QTest::newRow("test2") << "name1; name2" << "Name1; Name2" << int(Tellico::FieldFormat::FormatName); QTest::newRow("test3") << "Bob Dylan;Randy Quaid" << "Dylan, Bob; Quaid, Randy" << int(Tellico::FieldFormat::FormatName); QTest::newRow("test4") << "the return of the king" << "Return of the King, The" << int(Tellico::FieldFormat::FormatTitle); QTest::newRow("test5") << "the return of the king;the who" << "Return of the King, The; Who, The" << int(Tellico::FieldFormat::FormatTitle); } void CollectionTest::testDtd() { const QString xmllint = QStandardPaths::findExecutable(QStringLiteral("xmllint")); if(xmllint.isEmpty()) { QSKIP("This test requires xmllint", SkipAll); } // xmllint doesn't seem to support spaces in path. Is this an XML thing? if(QFINDTESTDATA("../../tellico.dtd").contains(QRegExp(QStringLiteral("\\s")))) { QSKIP("This test prohibits whitespace in the build path", SkipAll); } QFETCH(int, typeInt); Tellico::Data::Collection::Type type = static_cast(typeInt); Tellico::Data::CollPtr coll = Tellico::CollectionFactory::collection(type, true); QVERIFY(coll); Tellico::Data::EntryPtr entry1(new Tellico::Data::Entry(coll)); coll->addEntries(entry1); foreach(Tellico::Data::FieldPtr field, coll->fields()) { switch(field->type()) { case Tellico::Data::Field::Line: entry1->setField(field, field->title()); break; case Tellico::Data::Field::Para: entry1->setField(field, field->title()); break; case Tellico::Data::Field::URL: entry1->setField(field, field->title()); break; case Tellico::Data::Field::Table: entry1->setField(field, field->title()); break; case Tellico::Data::Field::Image: entry1->setField(field, field->title()); break; case Tellico::Data::Field::Number: entry1->setField(field, QStringLiteral("1")); break; case Tellico::Data::Field::Rating: entry1->setField(field, QStringLiteral("1")); break; case Tellico::Data::Field::Date: entry1->setField(field, QStringLiteral("2009-01-10")); break; case Tellico::Data::Field::Bool: entry1->setField(field, QStringLiteral("true")); break; case Tellico::Data::Field::Choice: entry1->setField(field, field->allowed().first()); break; default: break; } } Tellico::Export::TellicoXMLExporter exporter(coll); exporter.setEntries(coll->entries()); KProcess proc; proc.setProgram(QStringLiteral("xmllint"), QStringList() << QStringLiteral("--noout") << QStringLiteral("--nonet") << QStringLiteral("--nowarning") << QStringLiteral("--dtdvalid") << QFINDTESTDATA("../../tellico.dtd") << QStringLiteral("-")); proc.start(); proc.write(exporter.text().toUtf8()); proc.closeWriteChannel(); proc.waitForFinished(); QCOMPARE(proc.exitCode(), 0); } void CollectionTest::testDtd_data() { QTest::addColumn("typeInt"); QTest::newRow("book") << int(Tellico::Data::Collection::Book); QTest::newRow("video") << int(Tellico::Data::Collection::Video); QTest::newRow("album") << int(Tellico::Data::Collection::Album); QTest::newRow("bibtex") << int(Tellico::Data::Collection::Bibtex); QTest::newRow("comic") << int(Tellico::Data::Collection::ComicBook); QTest::newRow("wine") << int(Tellico::Data::Collection::Wine); QTest::newRow("coin") << int(Tellico::Data::Collection::Coin); QTest::newRow("stamp") << int(Tellico::Data::Collection::Stamp); QTest::newRow("card") << int(Tellico::Data::Collection::Card); QTest::newRow("game") << int(Tellico::Data::Collection::Game); QTest::newRow("file") << int(Tellico::Data::Collection::File); QTest::newRow("board") << int(Tellico::Data::Collection::BoardGame); } void CollectionTest::testDuplicate() { Tellico::Data::CollPtr coll(new Tellico::Data::Collection(true)); QCOMPARE(coll->entryCount(), 0); Tellico::Data::EntryPtr entry1(new Tellico::Data::Entry(coll)); entry1->setField(QStringLiteral("title"), QStringLiteral("title1")); coll->addEntries(entry1); QCOMPARE(coll->entryCount(), 1); // this is how Controller::slotCopySelectedEntries() does it Tellico::Data::EntryPtr entry2(new Tellico::Data::Entry(*entry1)); coll->addEntries(entry2); QCOMPARE(coll->entryCount(), 2); QCOMPARE(entry1->title(), entry2->title()); QVERIFY(entry1->id() != entry2->id()); bool ret = Tellico::Data::Document::mergeEntry(entry1, entry2); QCOMPARE(ret, true); TestResolver cancelMerge(Tellico::MergeConflictResolver::CancelMerge); ret = Tellico::Data::Document::mergeEntry(entry1, entry2, &cancelMerge); QCOMPARE(ret, true); entry2->setField(QStringLiteral("title"), QStringLiteral("title2")); ret = Tellico::Data::Document::mergeEntry(entry1, entry2, &cancelMerge); QCOMPARE(ret, false); QCOMPARE(entry1->title(), QStringLiteral("title1")); QCOMPARE(entry2->title(), QStringLiteral("title2")); TestResolver keepFirst(Tellico::MergeConflictResolver::KeepFirst); ret = Tellico::Data::Document::mergeEntry(entry1, entry2, &keepFirst); QCOMPARE(ret, true); QCOMPARE(entry1->title(), QStringLiteral("title1")); // the second entry never gets changed QCOMPARE(entry2->title(), QStringLiteral("title2")); entry2->setField(QStringLiteral("title"), QStringLiteral("title2")); TestResolver keepSecond(Tellico::MergeConflictResolver::KeepSecond); ret = Tellico::Data::Document::mergeEntry(entry1, entry2, &keepSecond); QCOMPARE(ret, true); QCOMPARE(entry1->title(), QStringLiteral("title2")); QCOMPARE(entry2->title(), QStringLiteral("title2")); entry1->setField(QStringLiteral("title"), QStringLiteral("title1")); // returns true, ("merge successful") even if values were not merged ret = Tellico::Data::Document::mergeEntry(entry1, entry2); QCOMPARE(ret, true); QCOMPARE(entry1->title(), QStringLiteral("title1")); QCOMPARE(entry2->title(), QStringLiteral("title2")); } void CollectionTest::testMergeFields() { // here, we want to verify that when entries and fields from outside a collection are merged in // the allowed values for the Choice fields are retained in the same order, and new values are only // added if they are used Tellico::Data::CollPtr coll1 = Tellico::CollectionFactory::collection(Tellico::Data::Collection::Game, true); Tellico::Data::CollPtr coll2 = Tellico::CollectionFactory::collection(Tellico::Data::Collection::Game, true); // modify the allowed values for "platform" in collection 1 Tellico::Data::FieldPtr platform1 = coll1->fieldByName(QStringLiteral("platform")); QVERIFY(platform1); QStringList newValues1 = QStringList() << QStringLiteral("PSP") << QStringLiteral("Xbox 360"); platform1->setAllowed(newValues1); QVERIFY(coll1->modifyField(platform1)); QCOMPARE(platform1->allowed(), newValues1); Tellico::Data::EntryPtr entry2(new Tellico::Data::Entry(coll2)); entry2->setField(QStringLiteral("platform"), QStringLiteral("PlayStation")); QCOMPARE(entry2->field(QStringLiteral("platform")), QStringLiteral("PlayStation")); coll2->addEntries(entry2); QPair p = Tellico::Data::Document::mergeFields(coll1, Tellico::Data::FieldList() << coll2->fieldByName(QStringLiteral("platform")), Tellico::Data::EntryList() << entry2); Tellico::Data::FieldList modifiedFields = p.first; QCOMPARE(modifiedFields.count(), 1); // this is the zinger right here. The list of allowed values should be the original // with only the new existing value tacked on the end QCOMPARE(modifiedFields.first()->allowed(), newValues1 << entry2->field(QStringLiteral("platform"))); Tellico::Data::FieldList addedFields = p.second; QVERIFY(addedFields.isEmpty()); } void CollectionTest::testAppendCollection() { // appending a collection adds new fields, merges existing one, and add new entries // the new entries should belong to the original collection and the existing entries should // remain in the source collection Tellico::Data::CollPtr coll1 = Tellico::CollectionFactory::collection(Tellico::Data::Collection::Game, true); Tellico::Data::CollPtr coll2 = Tellico::CollectionFactory::collection(Tellico::Data::Collection::Game, true); // modify the allowed values for "platform" in collection 1 Tellico::Data::FieldPtr platform1 = coll1->fieldByName(QStringLiteral("platform")); QVERIFY(platform1); QStringList newValues1 = QStringList() << QStringLiteral("My Box"); platform1->setAllowed(newValues1); QVERIFY(coll1->modifyField(platform1)); // add a new field Tellico::Data::FieldPtr field1(new Tellico::Data::Field(QStringLiteral("test"), QStringLiteral("test"))); QVERIFY(coll1->addField(field1)); Tellico::Data::EntryPtr entry1(new Tellico::Data::Entry(coll1)); QCOMPARE(entry1->collection(), coll1); coll1->addEntries(entry1); Tellico::Data::EntryPtr entry2(new Tellico::Data::Entry(coll2)); QCOMPARE(entry2->collection(), coll2); coll2->addEntries(entry2); // append coll1 into coll2 Tellico::Data::Document::appendCollection(coll2, coll1); // verify that the test field was added QVERIFY(coll2->hasField(QStringLiteral("test"))); // verified that the modified field was merged Tellico::Data::FieldPtr platform2 = coll2->fieldByName(QStringLiteral("platform")); QVERIFY(platform2); QVERIFY(platform2->allowed().contains(QStringLiteral("My Box"))); // coll2 should have two entries now, both with proper parent QCOMPARE(coll2->entryCount(), 2); Tellico::Data::EntryList e2 = coll2->entries(); QCOMPARE(e2.at(0)->collection(), coll2); QCOMPARE(e2.at(1)->collection(), coll2); QCOMPARE(coll1->entryCount(), 1); Tellico::Data::EntryList e1 = coll1->entries(); QCOMPARE(e1.at(0)->collection(), coll1); } void CollectionTest::testMergeCollection() { QUrl url = QUrl::fromLocalFile(QFINDTESTDATA("data/movies-many.tc")); Tellico::Import::TellicoImporter importer1(url); Tellico::Data::CollPtr coll1 = importer1.collection(); QVERIFY(coll1); Tellico::Import::TellicoImporter importer2(url); Tellico::Data::CollPtr coll2 = importer2.collection(); QVERIFY(coll2); Tellico::Data::EntryPtr entryToAdd(new Tellico::Data::Entry(coll2)); QCOMPARE(entryToAdd->collection(), coll2); coll2->addEntries(entryToAdd); QCOMPARE(coll1->entryCount()+1, coll2->entryCount()); // merge coll2 into coll1 // first item is a vector of all entries that got added in the merge process // second item is a pair of entries that had their table field modified // typedef QVector< QPair > PairVector; // typedef QPair MergePair; Tellico::Data::MergePair mergePair = Tellico::Data::Document::mergeCollection(coll1, coll2); // one new entry was added QCOMPARE(mergePair.first.count(), 1); // no table fields edited either QVERIFY(mergePair.second.isEmpty()); // check item count QCOMPARE(coll1->fields().count(), coll2->fields().count()); QCOMPARE(coll1->entryCount(), coll2->entryCount()); } void CollectionTest::testBookMatch() { Tellico::Data::CollPtr c(new Tellico::Data::BookCollection(true)); // first check merging with same isbn Tellico::Data::EntryPtr e1(new Tellico::Data::Entry(c)); e1->setField(QStringLiteral("title"), QStringLiteral("title1")); e1->setField(QStringLiteral("author"), QStringLiteral("author1")); e1->setField(QStringLiteral("edition"), QStringLiteral("edition1")); e1->setField(QStringLiteral("pur_price"), QStringLiteral("price1")); e1->setField(QStringLiteral("isbn"), QStringLiteral("1234567890")); c->addEntries(e1); Tellico::Data::EntryPtr e2(new Tellico::Data::Entry(c)); e2->setField(QStringLiteral("title"), QStringLiteral("title2")); e2->setField(QStringLiteral("author"), QStringLiteral("author2")); e2->setField(QStringLiteral("edition"), QStringLiteral("edition2")); e2->setField(QStringLiteral("pur_price"), QStringLiteral("price2")); e2->setField(QStringLiteral("isbn"), QStringLiteral("000000000")); // not a good match QVERIFY(c->sameEntry(e1, e2) < Tellico::EntryComparison::ENTRY_GOOD_MATCH); // perfect match now e2->setField(QStringLiteral("isbn"), QStringLiteral("1234567890")); QCOMPARE(c->sameEntry(e1, e2), int(Tellico::EntryComparison::ENTRY_PERFECT_MATCH)); QBENCHMARK { QCOMPARE(c->sameEntry(e1, e2), int(Tellico::EntryComparison::ENTRY_PERFECT_MATCH)); } } void CollectionTest::testMergeBenchmark() { QUrl url = QUrl::fromLocalFile(QFINDTESTDATA("data/movies-many.tc")); Tellico::Data::EntryList entriesToAdd; QBENCHMARK { Tellico::Import::TellicoImporter importer1(url, false /* load all images */); Tellico::Data::CollPtr coll1 = importer1.collection(); QVERIFY(coll1); Tellico::Import::TellicoImporter importer2(url); Tellico::Data::CollPtr coll2 = importer2.collection(); QVERIFY(coll2); entriesToAdd.clear(); for(int i = 0; i < 500; ++i) { Tellico::Data::EntryPtr entryToAdd(new Tellico::Data::Entry(coll2)); entryToAdd->setField(QStringLiteral("title"), QString::number(qrand())); entryToAdd->setField(QStringLiteral("studio"), QString::number(i)); entriesToAdd += entryToAdd; } coll2->addEntries(entriesToAdd); Tellico::Data::Document::mergeCollection(coll1, coll2); } } void CollectionTest::testMatchScore() { QFETCH(QString, field); QFETCH(QString, value); QFETCH(Tellico::EntryComparison::MatchValue, score); QVERIFY(m_coll); Tellico::Data::EntryPtr e(new Tellico::Data::Entry(m_coll)); e->setField(field, value); QCOMPARE(Tellico::EntryComparison::score(m_entry, e, field, m_coll.data()), int(score)); } void CollectionTest::testMatchScore_data() { QTest::addColumn("field"); QTest::addColumn("value"); QTest::addColumn("score"); QTest::newRow("empty title") << QStringLiteral("title") << QString() << Tellico::EntryComparison::MATCH_VALUE_NONE; QTest::newRow("title match") << QStringLiteral("title") << QStringLiteral("title1") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("title match case") << QStringLiteral("title") << QStringLiteral("TITLE1") << Tellico::EntryComparison::MATCH_VALUE_STRONG; // QTest::newRow("title match articles") << QStringLiteral("title") << QStringLiteral("THE TITLE1") << Tellico::EntryComparison::MATCH_VALUE_WEAK; QTest::newRow("title match non alphanum") << QStringLiteral("title") << QStringLiteral("title1.") << Tellico::EntryComparison::MATCH_VALUE_STRONG; // QTest::newRow("title match paren") << QStringLiteral("title") << QStringLiteral("title1 (old)") << Tellico::EntryComparison::MATCH_VALUE_WEAK; QTest::newRow("isbn match") << QStringLiteral("isbn") << QStringLiteral("1234367890") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("isbn match formatted") << QStringLiteral("isbn") << QStringLiteral("1-234-36789-0") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("lccn match") << QStringLiteral("lccn") << QStringLiteral("89456") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("lccn match formatted") << QStringLiteral("lccn") << QStringLiteral("89-456") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("arxiv") << QStringLiteral("arxiv") << QStringLiteral("hep-lat/0110180") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("arxiv format1") << QStringLiteral("arxiv") << QStringLiteral("hep-lat/0110180v1") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("arxiv format2") << QStringLiteral("arxiv") << QStringLiteral("arxiv:hep-lat/0110180v1") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("author") << QStringLiteral("author") << QStringLiteral("John Doe") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("author formatted") << QStringLiteral("author") << QStringLiteral("Doe, John") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("author formatted2") << QStringLiteral("author") << QStringLiteral("doe, john") << Tellico::EntryComparison::MATCH_VALUE_STRONG; QTest::newRow("author multiple") << QStringLiteral("author") << QStringLiteral("John Doe; Jane Doe") << Tellico::EntryComparison::MATCH_VALUE_STRONG; } void CollectionTest::testGamePlatform() { // test that the platform name guessing heuristic works on its own names for(int i = 1; i < Tellico::Data::GameCollection::LastPlatform; i++) { QString pName = Tellico::Data::GameCollection::platformName(Tellico::Data::GameCollection::GamePlatform(i)); int pGuess = Tellico::Data::GameCollection::guessPlatform(pName); QCOMPARE(i, pGuess); } // test some specific platform names that some data sources might return // thegamesdb.net returns "Nintendo Game Boy" int gameBoy = Tellico::Data::GameCollection::guessPlatform(QStringLiteral("Nintendo Game Boy")); QCOMPARE(gameBoy, int(Tellico::Data::GameCollection::GameBoy)); gameBoy = Tellico::Data::GameCollection::guessPlatform(QStringLiteral("gameboy")); QCOMPARE(gameBoy, int(Tellico::Data::GameCollection::GameBoy)); gameBoy = Tellico::Data::GameCollection::guessPlatform(QStringLiteral("gameboy color")); QCOMPARE(gameBoy, int(Tellico::Data::GameCollection::GameBoyColor)); gameBoy = Tellico::Data::GameCollection::guessPlatform(QStringLiteral("Gameboy Advance")); QCOMPARE(gameBoy, int(Tellico::Data::GameCollection::GameBoyAdvance)); }