File indexing completed on 2024-05-12 05:09:59

0001 /***************************************************************************
0002     Copyright (C) 2011 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 "filtertest.h"
0028 
0029 #include "../filter.h"
0030 #include "../entry.h"
0031 #include "../collections/bookcollection.h"
0032 #include "../collections/videocollection.h"
0033 #include "../images/imageinfo.h"
0034 #include "../images/imagefactory.h"
0035 
0036 #include <KLocalizedString>
0037 
0038 #include <QTest>
0039 #include <QStandardPaths>
0040 
0041 QTEST_GUILESS_MAIN( FilterTest )
0042 
0043 void FilterTest::initTestCase() {
0044   QStandardPaths::setTestModeEnabled(true);
0045   KLocalizedString::setApplicationDomain("tellico");
0046   Tellico::ImageFactory::init();
0047 }
0048 
0049 void FilterTest::testFilter() {
0050   Tellico::Data::CollPtr coll(new Tellico::Data::Collection(true, QStringLiteral("TestCollection")));
0051   Tellico::Data::EntryPtr entry(new Tellico::Data::Entry(coll));
0052   entry->setField(QStringLiteral("title"), QStringLiteral("Star Wars"));
0053 
0054   Tellico::FilterRule* rule1 = new Tellico::FilterRule(QStringLiteral("title"),
0055                                                        QStringLiteral("Star Wars"),
0056                                                        Tellico::FilterRule::FuncEquals);
0057   QCOMPARE(rule1->fieldName(), QStringLiteral("title"));
0058   QCOMPARE(rule1->pattern(), QStringLiteral("Star Wars"));
0059   QCOMPARE(rule1->function(), Tellico::FilterRule::FuncEquals);
0060 
0061   Tellico::Filter filter(Tellico::Filter::MatchAny);
0062   filter.append(rule1);
0063   QVERIFY(filter.matches(entry));
0064   rule1->setFunction(Tellico::FilterRule::FuncNotEquals);
0065   QVERIFY(!filter.matches(entry));
0066 
0067   rule1->setFunction(Tellico::FilterRule::FuncContains);
0068   QVERIFY(filter.matches(entry));
0069 
0070   rule1->setFieldName(QStringLiteral("author"));
0071   QVERIFY(!filter.matches(entry));
0072   rule1->setFunction(Tellico::FilterRule::FuncNotContains);
0073   QVERIFY(filter.matches(entry));
0074 
0075   rule1->setFieldName(QString());
0076   rule1->setFunction(Tellico::FilterRule::FuncEquals);
0077   QVERIFY(filter.matches(entry));
0078 
0079   Tellico::FilterRule* rule2 = new Tellico::FilterRule(QStringLiteral("title"),
0080                                                        QStringLiteral("Star"),
0081                                                        Tellico::FilterRule::FuncEquals);
0082   filter.clear();
0083   filter.append(rule2);
0084   QVERIFY(!filter.matches(entry));
0085 
0086   rule2->setFunction(Tellico::FilterRule::FuncContains);
0087   QVERIFY(filter.matches(entry));
0088   rule2->setFunction(Tellico::FilterRule::FuncNotContains);
0089   QVERIFY(!filter.matches(entry));
0090 
0091   rule2->setFieldName(QStringLiteral("author"));
0092   rule2->setFunction(Tellico::FilterRule::FuncContains);
0093   QVERIFY(!filter.matches(entry));
0094 
0095   rule2->setFieldName(QString());
0096   QVERIFY(filter.matches(entry));
0097 
0098   Tellico::FilterRule* rule3 = new Tellico::FilterRule(QStringLiteral("title"),
0099                                                        QStringLiteral("Sta[rt]"),
0100                                                        Tellico::FilterRule::FuncRegExp);
0101   QCOMPARE(rule3->pattern(), QStringLiteral("Sta[rt]"));
0102   filter.clear();
0103   filter.append(rule3);
0104   QVERIFY(filter.matches(entry));
0105 
0106   rule3->setFunction(Tellico::FilterRule::FuncNotRegExp);
0107   QVERIFY(!filter.matches(entry));
0108 
0109   rule3->setFieldName(QStringLiteral("author"));
0110   QVERIFY(filter.matches(entry));
0111 
0112   rule3->setFieldName(QString());
0113   rule3->setFunction(Tellico::FilterRule::FuncRegExp);
0114   QVERIFY(filter.matches(entry));
0115 
0116   entry->setField(QStringLiteral("title"), QStringLiteral("Tmavomodrý Svět"));
0117 
0118   Tellico::FilterRule* rule4 = new Tellico::FilterRule(QStringLiteral("title"),
0119                                                        QStringLiteral("Tmavomodrý Svět"),
0120                                                        Tellico::FilterRule::FuncEquals);
0121   filter.clear();
0122   filter.append(rule4);
0123   QVERIFY(filter.matches(entry));
0124 
0125   rule4->setFunction(Tellico::FilterRule::FuncContains);
0126   QVERIFY(filter.matches(entry));
0127 
0128   rule4->setFunction(Tellico::FilterRule::FuncRegExp);
0129   QVERIFY(filter.matches(entry));
0130 
0131   Tellico::FilterRule* rule5 = new Tellico::FilterRule(QStringLiteral("title"),
0132                                                        QStringLiteral("Tmavomodry Svet"),
0133                                                        Tellico::FilterRule::FuncEquals);
0134 
0135   filter.clear();
0136   filter.append(rule5);
0137   QVERIFY(!filter.matches(entry));
0138 
0139   rule5->setFunction(Tellico::FilterRule::FuncContains);
0140   QVERIFY(filter.matches(entry));
0141 
0142   rule5->setFunction(Tellico::FilterRule::FuncRegExp);
0143   QVERIFY(!filter.matches(entry));
0144 
0145   Tellico::Data::FieldPtr date(new Tellico::Data::Field(QStringLiteral("date"),
0146                                                         QStringLiteral("Date"),
0147                                                         Tellico::Data::Field::Date));
0148   coll->addField(date);
0149 
0150   Tellico::FilterRule* rule6 = new Tellico::FilterRule(QStringLiteral("date"),
0151                                                        QStringLiteral("2011-01-24"),
0152                                                        Tellico::FilterRule::FuncAfter);
0153   QCOMPARE(rule6->pattern(), QStringLiteral("2011-01-24"));
0154   filter.clear();
0155   filter.append(rule6);
0156   // test Bug 361625
0157   entry->setField(QStringLiteral("date"), QStringLiteral("2011-1-25"));
0158   QVERIFY(filter.matches(entry));
0159   entry->setField(QStringLiteral("date"), QStringLiteral("2011-01-25"));
0160   QVERIFY(filter.matches(entry));
0161 
0162   rule6->setFunction(Tellico::FilterRule::FuncBefore);
0163   QVERIFY(!filter.matches(entry));
0164 
0165   // check that a date match is neither before or after
0166   entry->setField(QStringLiteral("date"), rule6->pattern());
0167   rule6->setFunction(Tellico::FilterRule::FuncAfter);
0168   QVERIFY(!filter.matches(entry));
0169   rule6->setFunction(Tellico::FilterRule::FuncBefore);
0170   QVERIFY(!filter.matches(entry));
0171 
0172   // check that an invalid date never matches
0173   entry->setField(QStringLiteral("date"), QStringLiteral("test"));
0174   rule6->setFunction(Tellico::FilterRule::FuncAfter);
0175   QVERIFY(!filter.matches(entry));
0176   rule6->setFunction(Tellico::FilterRule::FuncBefore);
0177   QVERIFY(!filter.matches(entry));
0178 
0179   Tellico::Data::FieldPtr number(new Tellico::Data::Field(QStringLiteral("number"),
0180                                                           QStringLiteral("Number"),
0181                                                           Tellico::Data::Field::Number));
0182   coll->addField(number);
0183   entry->setField(QStringLiteral("number"), QStringLiteral("3"));
0184 
0185   Tellico::FilterRule* rule7 = new Tellico::FilterRule(QStringLiteral("number"),
0186                                                        QStringLiteral("5.0"),
0187                                                        Tellico::FilterRule::FuncLess);
0188   QCOMPARE(rule7->pattern(), QStringLiteral("5.0"));
0189   filter.clear();
0190   filter.append(rule7);
0191   QVERIFY(filter.matches(entry));
0192 
0193   rule7->setFunction(Tellico::FilterRule::FuncGreater);
0194   QVERIFY(!filter.matches(entry));
0195 
0196   entry->setField(QStringLiteral("number"), QStringLiteral("6"));
0197   QVERIFY(filter.matches(entry));
0198 
0199   // check that a rating can use greater than
0200   Tellico::Data::FieldPtr rating(new Tellico::Data::Field(QStringLiteral("rating"),
0201                                                           QStringLiteral("Rating"),
0202                                                           Tellico::Data::Field::Rating));
0203   coll->addField(rating);
0204   entry->setField(QStringLiteral("rating"), QStringLiteral("3"));
0205 
0206   Tellico::FilterRule* rule8 = new Tellico::FilterRule(QStringLiteral("rating"),
0207                                                        QStringLiteral("2.0"),
0208                                                        Tellico::FilterRule::FuncGreater);
0209   QCOMPARE(rule8->pattern(), QStringLiteral("2.0"));
0210   filter.clear();
0211   filter.append(rule8);
0212   QVERIFY(filter.matches(entry));
0213 
0214   rule8->setFunction(Tellico::FilterRule::FuncLess);
0215   QVERIFY(!filter.matches(entry));
0216 
0217   entry->setField(QStringLiteral("rating"), QStringLiteral("1"));
0218   QVERIFY(filter.matches(entry));
0219 
0220   // check image size comparisons
0221   Tellico::Data::FieldPtr imageField(new Tellico::Data::Field(QStringLiteral("image"),
0222                                                               QStringLiteral("image"),
0223                                                               Tellico::Data::Field::Image));
0224   coll->addField(imageField);
0225   const QString imageName(QStringLiteral("image.png"));
0226   entry->setField(QStringLiteral("image"), imageName);
0227   // insert image size into cache (128x128)
0228   Tellico::Data::ImageInfo imageInfo(imageName, "PNG", 128, 96, false);
0229   Tellico::ImageFactory::cacheImageInfo(imageInfo);
0230 
0231   Tellico::FilterRule* rule9 = new Tellico::FilterRule(QStringLiteral("image"),
0232                                                        QStringLiteral("96"),
0233                                                        Tellico::FilterRule::FuncGreater);
0234   QVERIFY(!rule9->isEmpty());
0235   QCOMPARE(rule9->pattern(), QStringLiteral("96"));
0236   filter.clear();
0237   filter.append(rule9);
0238   // compares against larger image dimension, so 128 > 96 matches
0239   QVERIFY(filter.matches(entry));
0240 
0241   // compares against larger image dimension, so 128 < 96 fails
0242   rule9->setFunction(Tellico::FilterRule::FuncLess);
0243   QVERIFY(!filter.matches(entry));
0244 
0245   Tellico::Data::ImageInfo imageInfo2(imageName, "PNG", 96, 96, false);
0246   Tellico::ImageFactory::cacheImageInfo(imageInfo2);
0247 
0248   rule9->setFunction(Tellico::FilterRule::FuncLess);
0249   QVERIFY(!filter.matches(entry));
0250   rule9->setFunction(Tellico::FilterRule::FuncEquals);
0251   QVERIFY(filter.matches(entry));
0252   // an empty image should also match less than size
0253   entry->setField(QStringLiteral("image"), QString());
0254   rule9->setFunction(Tellico::FilterRule::FuncLess);
0255   QVERIFY(filter.matches(entry));
0256 
0257   // test a filter for matching against an empty string
0258   Tellico::Data::FieldPtr testField(new Tellico::Data::Field(QStringLiteral("test"),
0259                                                              QStringLiteral("Test")));
0260   coll->addField(testField);
0261   Tellico::FilterRule* rule10 = new Tellico::FilterRule(QStringLiteral("test"),
0262                                                         QString(),
0263                                                         Tellico::FilterRule::FuncEquals);
0264   QVERIFY(!rule10->isEmpty());
0265   filter.clear();
0266   filter.append(rule10);
0267   QVERIFY(filter.matches(entry));
0268   rule10->setFunction(Tellico::FilterRule::FuncNotEquals);
0269   QVERIFY(!rule10->isEmpty());
0270   QVERIFY(!filter.matches(entry));
0271 }
0272 
0273 void FilterTest::testGroupViewFilter() {
0274   // ideally, I'd instantiate a GroupView object and test that, but it's tough with all the dependencies
0275   // so this code is identical to what is in Tellico::GroupView::slotFilterGroup()
0276   Tellico::Data::CollPtr coll(new Tellico::Data::BookCollection(true, QStringLiteral("TestCollection")));
0277   Tellico::Data::EntryPtr entry1(new Tellico::Data::Entry(coll));
0278   entry1->setField(QStringLiteral("author"), QStringLiteral("John Author"));
0279   Tellico::Data::EntryPtr entry2(new Tellico::Data::Entry(coll));
0280   entry2->setField(QStringLiteral("author"), QStringLiteral("John Q. Author"));
0281   Tellico::Data::EntryPtr entry3(new Tellico::Data::Entry(coll));
0282   entry3->setField(QStringLiteral("author"), QStringLiteral("John Author") +
0283                                             Tellico::FieldFormat::delimiterString() +
0284                                             QStringLiteral("James Author"));
0285   Tellico::Data::EntryPtr entry4(new Tellico::Data::Entry(coll));
0286   entry4->setField(QStringLiteral("author"), QStringLiteral("James Author") +
0287                                             Tellico::FieldFormat::delimiterString() +
0288                                             QStringLiteral("John Author"));
0289   Tellico::Data::EntryPtr entry5(new Tellico::Data::Entry(coll));
0290   entry5->setField(QStringLiteral("author"), QStringLiteral("James Author") +
0291                                             Tellico::FieldFormat::delimiterString() +
0292                                             QStringLiteral("John Q. Author"));
0293 
0294   QString pattern(entry1->formattedField(QStringLiteral("author")));
0295   // the filter should match all since it was the initial way the group view filter was constructed
0296   Tellico::Filter filter1(Tellico::Filter::MatchAny);
0297   filter1.append(new Tellico::FilterRule(QStringLiteral("author"), pattern, Tellico::FilterRule::FuncContains));
0298   QVERIFY(filter1.matches(entry1));
0299   QVERIFY(filter1.matches(entry2));
0300   QVERIFY(filter1.matches(entry3));
0301   QVERIFY(filter1.matches(entry4));
0302   QVERIFY(filter1.matches(entry5));
0303 
0304   QString rxPattern = Tellico::FieldFormat::matchValueRegularExpression(pattern);
0305   // the filter should match entry1, entry3, and entry 4 but not entry2 or entry5
0306   Tellico::Filter filter2(Tellico::Filter::MatchAny);
0307   filter2.append(new Tellico::FilterRule(QStringLiteral("author"), rxPattern, Tellico::FilterRule::FuncRegExp));
0308   QVERIFY(filter2.matches(entry1));
0309   QVERIFY(!filter2.matches(entry2)); // does not match
0310   QVERIFY(filter2.matches(entry3));
0311   QVERIFY(filter2.matches(entry4));
0312   QVERIFY(!filter2.matches(entry5));
0313 
0314   // Bug 415886
0315   Tellico::Data::CollPtr coll2(new Tellico::Data::VideoCollection(true, QStringLiteral("TestCollection2")));
0316   Tellico::Data::EntryPtr movie(new Tellico::Data::Entry(coll2));
0317   movie->setField(QStringLiteral("cast"), QStringLiteral("John Author") +
0318                                           Tellico::FieldFormat::columnDelimiterString() +
0319                                           QStringLiteral("role"));
0320   Tellico::Filter castFilter(Tellico::Filter::MatchAny);
0321   castFilter.append(new Tellico::FilterRule(QStringLiteral("cast"), rxPattern, Tellico::FilterRule::FuncRegExp));
0322   // single table row with value
0323   QVERIFY(castFilter.matches(movie));
0324   movie->setField(QStringLiteral("cast"), QStringLiteral("John Author") +
0325                                           Tellico::FieldFormat::rowDelimiterString() +
0326                                           QStringLiteral("Second Author"));
0327   // multiple table row with value only
0328   QVERIFY(castFilter.matches(movie));
0329   movie->setField(QStringLiteral("cast"), QStringLiteral("No one") +
0330                                           Tellico::FieldFormat::rowDelimiterString() +
0331                                           QStringLiteral("John Author") +
0332                                           Tellico::FieldFormat::rowDelimiterString() +
0333                                           QStringLiteral("Second Author"));
0334   // multiple table row with value second
0335   QVERIFY(castFilter.matches(movie));
0336 }
0337 
0338 void FilterTest::testQuickFilter() {
0339   Tellico::Data::CollPtr coll(new Tellico::Data::BookCollection(true, QStringLiteral("TestCollection")));
0340   Tellico::Data::EntryPtr entry(new Tellico::Data::Entry(coll));
0341   entry->setField(QStringLiteral("title"), QStringLiteral("C++ Coding Standards"));
0342 
0343   Tellico::FilterPtr filter(new Tellico::Filter(Tellico::Filter::MatchAll));
0344   QString fieldName; // empty means any field
0345 
0346   Tellico::Filter::populateQuickFilter(filter, fieldName, QStringLiteral("C++"), true /* allow regexps */);
0347   QVERIFY(filter->matches(entry));
0348 
0349   entry->setField(QStringLiteral("title"), QStringLiteral("Coding Standards"));
0350   QVERIFY(filter->matches(entry)); // still matches due to c++ being interpreted as a regexp
0351 
0352   Tellico::FilterPtr filter2(new Tellico::Filter(Tellico::Filter::MatchAll));
0353 
0354   Tellico::Filter::populateQuickFilter(filter2, fieldName, QStringLiteral("C++"), false /* allow regexps */);
0355   entry->setField(QStringLiteral("title"), QStringLiteral("C++ Coding Standards"));
0356   QVERIFY(filter2->matches(entry));
0357 
0358   entry->setField(QStringLiteral("title"), QStringLiteral("Coding Standards"));
0359   QVERIFY(!filter2->matches(entry)); // no longer matches
0360 }