File indexing completed on 2024-05-12 05:10:05

0001 /***************************************************************************
0002     Copyright (C) 2017 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #undef QT_NO_CAST_FROM_ASCII
0026 
0027 #include "tellicomodeltest.h"
0028 #include "modeltest.h"
0029 #include "../models/entrymodel.h"
0030 #include "../models/entryiconmodel.h"
0031 #include "../models/entrysortmodel.h"
0032 #include "../models/filtermodel.h"
0033 #include "../models/borrowermodel.h"
0034 #include "../models/entrygroupmodel.h"
0035 #include "../models/groupsortmodel.h"
0036 #include "../models/modeliterator.h"
0037 #include "../models/entryselectionmodel.h"
0038 #include "../collections/bookcollection.h"
0039 #include "../collectionfactory.h"
0040 #include "../document.h"
0041 #include "../entrygroup.h"
0042 #include "../images/imagefactory.h"
0043 #include "../images/image.h"
0044 
0045 #include <KLocalizedString>
0046 
0047 #include <QTest>
0048 #include <QSignalSpy>
0049 #include <QStandardPaths>
0050 #include <QLoggingCategory>
0051 
0052 QTEST_MAIN( TellicoModelTest )
0053 
0054 void TellicoModelTest::initTestCase() {
0055   QStandardPaths::setTestModeEnabled(true);
0056   KLocalizedString::setApplicationDomain("tellico");
0057   Tellico::ImageFactory::init();
0058   Tellico::RegisterCollection<Tellico::Data::BookCollection> registerBook(Tellico::Data::Collection::Book, "book");
0059   QLoggingCategory::setFilterRules(QStringLiteral("tellico.debug = true\ntellico.info = false"));
0060 }
0061 
0062 void TellicoModelTest::testEntryModel() {
0063   Tellico::Data::CollPtr coll(new Tellico::Data::BookCollection(true)); // add default fields
0064   Tellico::Data::EntryPtr entry1(new Tellico::Data::Entry(coll));
0065   entry1->setField(QStringLiteral("title"), QStringLiteral("Star Wars"));
0066   const QUrl u = QUrl::fromLocalFile(QFINDTESTDATA("../../icons/128-apps-tellico.png"));
0067   const QString imageId = Tellico::ImageFactory::addImage(u);
0068   entry1->setField(QStringLiteral("cover"), imageId);
0069   coll->addEntries(entry1);
0070 
0071   Tellico::EntryModel entryModel(this);
0072   ModelTest test1(&entryModel);
0073 
0074   Tellico::EntryIconModel iconModel(this);
0075   ModelTest test2(&iconModel);
0076 
0077   Tellico::EntrySortModel sortModel(this);
0078   ModelTest test3(&sortModel);
0079 
0080   iconModel.setSourceModel(&entryModel);
0081   sortModel.setSourceModel(&entryModel);
0082 
0083   entryModel.setFields(coll->fields());
0084   entryModel.setEntries(coll->entries());
0085   QCOMPARE(entryModel.index(0, 0), entryModel.indexFromEntry(entry1));
0086 
0087   Tellico::Data::FieldPtr field1(new Tellico::Data::Field(QStringLiteral("test"), QStringLiteral("test")));
0088   coll->addField(field1);
0089   entryModel.setFields(coll->fields());
0090 
0091   Tellico::Data::EntryPtr entry2(new Tellico::Data::Entry(coll));
0092   coll->addEntries(entry2);
0093   entryModel.addEntries(Tellico::Data::EntryList() << entry2);
0094 
0095   Tellico::Data::FieldPtr field2(new Tellico::Data::Field(QStringLiteral("test2"), QStringLiteral("test2")));
0096   coll->addField(field2);
0097   entryModel.addFields(Tellico::Data::FieldList() << field2);
0098 
0099   // Check FieldPtrRole in model data
0100   QModelIndex index = entryModel.index(0, entryModel.columnCount()-1);
0101   QVERIFY(index.isValid());
0102   QCOMPARE(entryModel.data(index, Tellico::FieldPtrRole),
0103            QVariant::fromValue(field2));
0104   //check FieldPtrRole in header model data
0105   QCOMPARE(entryModel.headerData(entryModel.columnCount()-1, Qt::Horizontal, Tellico::FieldPtrRole),
0106            QVariant::fromValue(field2));
0107 
0108   sortModel.setSortColumn(0);
0109   sortModel.setSecondarySortColumn(1);
0110   sortModel.setTertiarySortColumn(2);
0111   QCOMPARE(sortModel.sortColumn(), 0);
0112   QCOMPARE(sortModel.secondarySortColumn(), 1);
0113   QCOMPARE(sortModel.tertiarySortColumn(), 2);
0114   sortModel.sort(0);
0115   sortModel.setSortRole(Tellico::RowCountRole);
0116   sortModel.sort(0);
0117   sortModel.setSortRole(Tellico::EntryPtrRole);
0118   sortModel.sort(0);
0119 
0120   QVariant icon1 = iconModel.data(iconModel.index(0, 0), Qt::DecorationRole);
0121   QVERIFY(icon1.isValid());
0122   QVERIFY(!icon1.isNull());
0123   QVERIFY(icon1.canConvert<QIcon>());
0124   auto& img1 = Tellico::ImageFactory::imageById(imageId);
0125   QVERIFY(!img1.isNull());
0126 
0127   Tellico::FilterRule* rule1 = new Tellico::FilterRule(QStringLiteral("title"),
0128                                                        QStringLiteral("Star Wars"),
0129                                                        Tellico::FilterRule::FuncEquals);
0130   Tellico::FilterPtr filter(new Tellico::Filter(Tellico::Filter::MatchAny));
0131   filter->append(rule1);
0132 
0133   sortModel.setFilter(filter);
0134 
0135   entryModel.clear();
0136   entryModel.setFields(coll->fields());
0137   entryModel.setEntries(coll->entries());
0138   QCOMPARE(entryModel.index(0, 0), entryModel.indexFromEntry(entry1));
0139 
0140   Tellico::Data::FieldPtr field3(new Tellico::Data::Field(QStringLiteral("test"), QStringLiteral("test-new")));
0141   coll->modifyField(field3);
0142   QCOMPARE(coll->fields().count(), entryModel.columnCount(QModelIndex()));
0143   entryModel.modifyField(field2, field3);
0144 
0145   coll->removeField(field3);
0146   entryModel.removeFields(Tellico::Data::FieldList() << field3);
0147   QCOMPARE(coll->fields().count(), entryModel.columnCount(QModelIndex()));
0148 
0149   QCOMPARE(coll->entries().count(), entryModel.rowCount(QModelIndex()));
0150   coll->removeEntries(Tellico::Data::EntryList() << entry2);
0151   QCOMPARE(coll->entries().count() + 1, entryModel.rowCount(QModelIndex()));
0152   entryModel.removeEntries(Tellico::Data::EntryList() << entry2);
0153   QCOMPARE(coll->entries().count(), entryModel.rowCount(QModelIndex()));
0154 
0155   for(Tellico::ModelIterator eIt(&entryModel); eIt.entry(); ++eIt) {
0156     QVERIFY(eIt.isValid());
0157   }
0158 }
0159 
0160 void TellicoModelTest::testFilterModel() {
0161   Tellico::FilterModel filterModel(this);
0162   ModelTest test1(&filterModel);
0163 
0164   Tellico::FilterRule* rule1 = new Tellico::FilterRule(QStringLiteral("title"),
0165                                                        QStringLiteral("Star Wars"),
0166                                                        Tellico::FilterRule::FuncEquals);
0167   Tellico::FilterPtr filter(new Tellico::Filter(Tellico::Filter::MatchAny));
0168   filter->append(rule1);
0169   filterModel.addFilter(filter);
0170 
0171   Tellico::Data::CollPtr c = Tellico::Data::Document::self()->collection();
0172   Tellico::Data::EntryPtr entry1(new Tellico::Data::Entry(c));
0173   entry1->setField(QStringLiteral("title"), QStringLiteral("Star Wars"));
0174   c->addEntries(entry1);
0175 
0176   filterModel.clear();
0177   filterModel.addFilter(filter);
0178   QCOMPARE(filter, filterModel.filter(filterModel.index(0, 0)));
0179   QVERIFY(filterModel.indexContainsEntry(filterModel.index(0, 0), entry1));
0180 
0181   filterModel.invalidate(filterModel.index(0, 0));
0182   QCOMPARE(filter, filterModel.filter(filterModel.index(0, 0)));
0183   QVERIFY(filterModel.indexContainsEntry(filterModel.index(0, 0), entry1));
0184 }
0185 
0186 void TellicoModelTest::testGroupModel() {
0187   Tellico::Data::CollPtr coll(new Tellico::Data::BookCollection(true)); // add default fields
0188   Tellico::Data::EntryPtr entry1(new Tellico::Data::Entry(coll));
0189   entry1->setField(QStringLiteral("title"), QStringLiteral("Star Wars"));
0190   entry1->setField(QStringLiteral("author"), QStringLiteral("George Lucas"));
0191   coll->addEntries(entry1);
0192   Tellico::Data::EntryPtr entry2(new Tellico::Data::Entry(coll));
0193   entry2->setField(QStringLiteral("title"), QStringLiteral("Empire Strikes Back"));
0194   entry2->setField(QStringLiteral("author"), QStringLiteral("George Lucas"));
0195   coll->addEntries(entry2);
0196   Tellico::Data::EntryPtr entry3(new Tellico::Data::Entry(coll));
0197   entry3->setField(QStringLiteral("title"), QStringLiteral("1632"));
0198   entry3->setField(QStringLiteral("author"), QStringLiteral("Eric Flint"));
0199   coll->addEntries(entry3);
0200 
0201   Tellico::EntryGroupModel groupModel(this);
0202   ModelTest test1(&groupModel);
0203 
0204   Tellico::GroupSortModel sortModel(this);
0205   ModelTest test2(&sortModel);
0206 
0207   sortModel.setSourceModel(&groupModel);
0208 
0209   Tellico::Data::EntryGroupDict* dict = coll->entryGroupDictByName(QStringLiteral("author"));
0210   groupModel.addGroups(dict->values(), QString());
0211   QCOMPARE(sortModel.rowCount(), 2);
0212 
0213   sortModel.sort(0);
0214   sortModel.setEntrySortField(QStringLiteral("author"));
0215   QCOMPARE(sortModel.entrySortField(), QLatin1String("author"));
0216   sortModel.sort(0, Qt::AscendingOrder);
0217 
0218   Tellico::ModelIterator gIt(&sortModel);
0219   QVERIFY(gIt.isValid());
0220   auto group = gIt.group();
0221   QVERIFY(group);
0222   QCOMPARE(group->groupName(), QStringLiteral("Flint, Eric"));
0223   QCOMPARE(group->fieldName(), QStringLiteral("author"));
0224   QCOMPARE(group->size(), 1);
0225   QVERIFY(!group->hasEmptyGroupName());
0226 
0227   ++gIt;
0228   QVERIFY(gIt.isValid());
0229   group = gIt.group();
0230   QVERIFY(group);
0231   QCOMPARE(group->groupName(), QStringLiteral("Lucas, George"));
0232   QCOMPARE(group->fieldName(), QStringLiteral("author"));
0233   QCOMPARE(group->size(), 2);
0234   QVERIFY(!group->hasEmptyGroupName());
0235 
0236   ++gIt;
0237   QVERIFY(!gIt.group());
0238 }
0239 
0240 void TellicoModelTest::testSelectionModel() {
0241   qRegisterMetaType<Tellico::Data::EntryList>("Tellico::Data::EntryList");
0242   // this mimics the model dependencies used in mainwindow.cpp
0243   Tellico::EntryModel entryModel(this);
0244   ModelTest test1(&entryModel);
0245   Tellico::EntryIconModel iconModel(this);
0246   ModelTest test2(&iconModel);
0247   iconModel.setSourceModel(&entryModel);
0248 
0249   QItemSelectionModel selModel(&entryModel, this);
0250   Tellico::EntrySelectionModel proxySelect(&iconModel, &selModel, this);
0251 
0252   Tellico::Data::CollPtr coll(new Tellico::Data::Collection(true)); // add default fields
0253   Tellico::Data::EntryPtr entry1(new Tellico::Data::Entry(coll));
0254   entry1->setField(QStringLiteral("title"), QStringLiteral("Test1"));
0255   coll->addEntries(entry1);
0256 
0257   entryModel.setFields(coll->fields());
0258   entryModel.setEntries(coll->entries());
0259 
0260   QSignalSpy entriesSelectedSpy(&proxySelect, SIGNAL(entriesSelected(Tellico::Data::EntryList)));
0261   selModel.select(entryModel.index(0,0), QItemSelectionModel::Select);
0262   QCOMPARE(entriesSelectedSpy.count(), 1);
0263 
0264   Tellico::Data::EntryList entries = proxySelect.selectedEntries();
0265   QCOMPARE(entries.count(), 1);
0266   QCOMPARE(entries.at(0)->title(), QStringLiteral("Test1"));
0267 
0268   Tellico::Data::EntryPtr entry2(new Tellico::Data::Entry(coll));
0269   entry2->setField(QStringLiteral("title"), QStringLiteral("test2"));
0270   coll->addEntries(entry2);
0271   entryModel.addEntries(Tellico::Data::EntryList() << entry2);
0272 
0273   entries = proxySelect.selectedEntries();
0274   QCOMPARE(entries.count(), 1);
0275   QCOMPARE(entries.at(0)->title(), QStringLiteral("Test1"));
0276 
0277   selModel.select(entryModel.index(1,0), QItemSelectionModel::Select);
0278   entries = proxySelect.selectedEntries();
0279   QCOMPARE(entries.count(), 2);
0280   QCOMPARE(entries.at(0)->title(), QStringLiteral("Test1"));
0281   QCOMPARE(entries.at(1)->title(), QStringLiteral("Test2"));
0282 
0283   selModel.select(entryModel.index(0,0), QItemSelectionModel::Toggle);
0284   entries = proxySelect.selectedEntries();
0285   QCOMPARE(entries.count(), 1);
0286   QCOMPARE(entries.at(0)->title(), QStringLiteral("Test2"));
0287 
0288   entryModel.clear();
0289   // now there should be no selection since EntryModel::clear calls modelReset()
0290   // and the proxy selection is connected to that signal
0291   entries = proxySelect.selectedEntries();
0292   QCOMPARE(entries.count(), 0);
0293 }
0294 
0295 void TellicoModelTest::testBorrowerModel() {
0296   Tellico::BorrowerModel borrowerModel(this);
0297   ModelTest test1(&borrowerModel);
0298 
0299   Tellico::Data::BorrowerPtr borr(new Tellico::Data::Borrower(QStringLiteral("name1"), QStringLiteral("uid1")));
0300   borrowerModel.addBorrower(borr);
0301 
0302   Tellico::Data::CollPtr c = Tellico::Data::Document::self()->collection();
0303   Tellico::Data::EntryPtr entry(new Tellico::Data::Entry(c));
0304   entry->setField(QStringLiteral("title"), QStringLiteral("Star Wars"));
0305   c->addEntries(entry);
0306   Tellico::Data::LoanPtr loan(new Tellico::Data::Loan(entry,
0307                                                       QDate::currentDate(),
0308                                                       QDate::currentDate(),
0309                                                       QStringLiteral("note")));
0310   borr->addLoan(loan);
0311 
0312   borrowerModel.clear();
0313   borrowerModel.addBorrower(borr);
0314 
0315   QModelIndex borrIndex = borrowerModel.index(0, 0);
0316   QVERIFY(borrIndex.isValid());
0317   QModelIndex loanIndex = borrowerModel.index(0, 0, borrIndex);
0318   QVERIFY(loanIndex.isValid());
0319 
0320   QCOMPARE(borr, borrowerModel.borrower(borrIndex));
0321   QCOMPARE(loan, borrowerModel.loan(loanIndex));
0322   QCOMPARE(entry, borrowerModel.entry(loanIndex));
0323 }