File indexing completed on 2024-05-12 16:46:18

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