File indexing completed on 2024-05-12 05:10:00
0001 /*************************************************************************** 0002 Copyright (C) 2015 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 "htmlexportertest.h" 0028 0029 #include "../translators/htmlexporter.h" 0030 #include "../translators/tellicoimporter.h" 0031 #include "../collections/bookcollection.h" 0032 #include "../collections/videocollection.h" 0033 #include "../collections/musiccollection.h" 0034 #include "../collectionfactory.h" 0035 #include "../entry.h" 0036 #include "../document.h" 0037 #include "../images/imagefactory.h" 0038 #include "../utils/datafileregistry.h" 0039 #include "../config/tellico_config.h" 0040 0041 #include <KLocalizedString> 0042 0043 #include <QTest> 0044 #include <QRegularExpression> 0045 #include <QTemporaryDir> 0046 #include <QFile> 0047 #include <QStandardPaths> 0048 #include <QProcess> 0049 0050 QTEST_GUILESS_MAIN( HtmlExporterTest ) 0051 0052 void HtmlExporterTest::initTestCase() { 0053 QStandardPaths::setTestModeEnabled(true); 0054 KLocalizedString::setApplicationDomain("tellico"); 0055 Tellico::ImageFactory::init(); 0056 Tellico::RegisterCollection<Tellico::Data::BookCollection> registerBook(Tellico::Data::Collection::Book, "book"); 0057 Tellico::RegisterCollection<Tellico::Data::VideoCollection> registerVideo(Tellico::Data::Collection::Video, "video"); 0058 Tellico::RegisterCollection<Tellico::Data::VideoCollection> registerMusic(Tellico::Data::Collection::Album, "album"); 0059 Tellico::DataFileRegistry::self()->addDataLocation(QFINDTESTDATA("../../xslt/tellico2html.xsl")); 0060 Tellico::DataFileRegistry::self()->addDataLocation(QFINDTESTDATA("../../xslt/entry-templates/Fancy.xsl")); 0061 Tellico::DataFileRegistry::self()->addDataLocation(QFINDTESTDATA("../../xslt/report-templates/Column_View.xsl")); 0062 } 0063 0064 void HtmlExporterTest::cleanupTestCase() { 0065 Tellico::ImageFactory::clean(true); 0066 } 0067 0068 void HtmlExporterTest::testHtml() { 0069 Tellico::Config::setImageLocation(Tellico::Config::ImagesInLocalDir); 0070 // the default collection will use a temporary directory as a local image dir 0071 QVERIFY(!Tellico::ImageFactory::localDir().isEmpty()); 0072 0073 QString tempDirName; 0074 QTemporaryDir tempDir; 0075 QVERIFY(tempDir.isValid()); 0076 tempDir.setAutoRemove(true); 0077 tempDirName = tempDir.path(); 0078 QString fileName = tempDirName + "/with-image.tc"; 0079 QString imageDirName = tempDirName + "/with-image_files/"; 0080 0081 // copy a collection file that includes an image into the temporary directory 0082 QVERIFY(QFile::copy(QFINDTESTDATA("data/with-image.tc"), fileName)); 0083 0084 Tellico::Data::Document* doc = Tellico::Data::Document::self(); 0085 QVERIFY(doc->openDocument(QUrl::fromLocalFile(fileName))); 0086 QCOMPARE(Tellico::ImageFactory::localDir(), imageDirName); 0087 // save the document, so the images get copied out of the .tc file into the local image directory 0088 QVERIFY(doc->saveDocument(QUrl::fromLocalFile(fileName))); 0089 0090 Tellico::Data::CollPtr coll = doc->collection(); 0091 QVERIFY(coll); 0092 0093 Tellico::Export::HTMLExporter exp(coll); 0094 exp.setEntries(coll->entries()); 0095 exp.setExportEntryFiles(true); 0096 exp.setEntryXSLTFile(QStringLiteral("Fancy")); 0097 exp.setColumns(QStringList() << QStringLiteral("Title") << QStringLiteral("Gift") 0098 << QStringLiteral("Rating") << QStringLiteral("Front Cover")); 0099 exp.setURL(QUrl::fromLocalFile(tempDirName + "/testHtml.html")); 0100 0101 QString output = exp.text(); 0102 QVERIFY(!output.isEmpty()); 0103 0104 // verify the relative location of the tellico2html.js file 0105 QVERIFY(output.contains(QStringLiteral("src=\"testHtml_files/tellico2html.js"))); 0106 // verify relative location of image pics 0107 QVERIFY(output.contains(QStringLiteral("src=\"testHtml_files/pics/checkmark.png"))); 0108 // verify relative location of entry link 0109 QVERIFY(output.contains(QStringLiteral("href=\"testHtml_files/Catching_Fire__The_Second_Book_of_the_Hunger_Games_-1.html"))); 0110 // verify relative location of image file 0111 QVERIFY(output.contains(QStringLiteral("src=\"testHtml_files/17b54b2a742c6d342a75f122d615a793.jpeg"))); 0112 0113 QVERIFY(exp.exec()); 0114 QFile f(tempDirName + "/testHtml.html"); 0115 QVERIFY(f.exists()); 0116 QVERIFY(f.open(QIODevice::ReadOnly | QIODevice::Text)); 0117 0118 QTextStream in(&f); 0119 QString fileText = in.readAll(); 0120 QVERIFY(fileText.contains(QStringLiteral("src=\"testHtml_files/tellico2html.js"))); 0121 QVERIFY(fileText.contains(QStringLiteral("src=\"testHtml_files/pics/checkmark.png"))); 0122 QVERIFY(fileText.contains(QStringLiteral("href=\"testHtml_files/Catching_Fire__The_Second_Book_of_the_Hunger_Games_-1.html"))); 0123 QVERIFY(fileText.contains(QStringLiteral("src=\"testHtml_files/17b54b2a742c6d342a75f122d615a793.jpeg"))); 0124 0125 QVERIFY(QFile::exists(tempDirName + "/testHtml_files/tellico2html.js")); 0126 QVERIFY(QFile::exists(tempDirName + "/testHtml_files/pics/checkmark.png")); 0127 QVERIFY(QFile::exists(tempDirName + "/testHtml_files/17b54b2a742c6d342a75f122d615a793.jpeg")); 0128 0129 // check entry html output 0130 QFile f2(tempDirName + "/testHtml_files/Catching_Fire__The_Second_Book_of_the_Hunger_Games_-1.html"); 0131 QVERIFY(f2.exists()); 0132 QVERIFY(f2.open(QIODevice::ReadOnly | QIODevice::Text)); 0133 0134 QTextStream in2(&f2); 0135 QString entryText = in2.readAll(); 0136 // verify relative location of image file 0137 QVERIFY(entryText.contains(QStringLiteral("src=\"./17b54b2a742c6d342a75f122d615a793.jpeg"))); 0138 // verify relative location of image pics 0139 QVERIFY(entryText.contains(QStringLiteral("src=\"pics/checkmark.png"))); 0140 // verify link to parent html file 0141 QVERIFY(entryText.contains(QStringLiteral("href=\"../testHtml.html"))); 0142 0143 // sanity check, the directory should not exists after QTemporaryDir destruction 0144 tempDir.remove(); 0145 QVERIFY(!QDir(tempDirName).exists()); 0146 } 0147 0148 void HtmlExporterTest::testHtmlTitle() { 0149 Tellico::Data::CollPtr coll(new Tellico::Data::BookCollection(true)); 0150 coll->setTitle(QStringLiteral("Robby's Books")); 0151 0152 Tellico::Data::EntryPtr e(new Tellico::Data::Entry(coll)); 0153 coll->addEntries(e); 0154 0155 Tellico::Export::HTMLExporter exporter(coll); 0156 exporter.setEntries(coll->entries()); 0157 0158 QString output = exporter.text(); 0159 // qDebug() << output; 0160 QVERIFY(!output.isEmpty()); 0161 0162 // check https://bugs.kde.org/show_bug.cgi?id=348381 0163 static const QRegularExpression rx("<title>.*</title>"); 0164 QRegularExpressionMatch match = rx.match(output); 0165 QVERIFY(match.hasMatch()); 0166 QCOMPARE(match.captured(), QStringLiteral("<title>Robby's Books</title>")); 0167 } 0168 0169 void HtmlExporterTest::testReportHtml() { 0170 Tellico::Data::CollPtr coll(new Tellico::Data::BookCollection(true)); 0171 coll->setTitle(QStringLiteral("Robby's Books")); 0172 0173 Tellico::Data::EntryPtr e(new Tellico::Data::Entry(coll)); 0174 e->setField(QStringLiteral("title"), QStringLiteral("My Title")); 0175 e->setField(QStringLiteral("rating"), QStringLiteral("3")); 0176 coll->addEntries(e); 0177 0178 Tellico::Export::HTMLExporter exporter(coll); 0179 exporter.setXSLTFile(QFINDTESTDATA("../../xslt/report-templates/Column_View.xsl")); 0180 exporter.setEntries(coll->entries()); 0181 0182 QString output = exporter.text(); 0183 QVERIFY(!output.isEmpty()); 0184 0185 // check that cdate is passed correctly 0186 static const QRegularExpression rx("<p id=\"header-right\">(.*)</p>"); 0187 QRegularExpressionMatch match = rx.match(output); 0188 QVERIFY(match.hasMatch()); 0189 QCOMPARE(match.captured(1), QLocale().toString(QDate::currentDate())); 0190 0191 // test image location in tmp directory 0192 Tellico::Export::HTMLExporter exporter2(coll); 0193 exporter2.setXSLTFile(QFINDTESTDATA("../../xslt/report-templates/Image_List.xsl")); 0194 exporter2.setEntries(coll->entries()); 0195 exporter2.setColumns(QStringList() << QStringLiteral("Title") << QStringLiteral("Rating")); 0196 0197 QString output2 = exporter2.text(); 0198 QVERIFY(!output2.isEmpty()); 0199 // the rating pic image needs to be an absolute local path 0200 QRegularExpression starsPathRx(QStringLiteral("src=\"(.+stars3.png)\"")); 0201 auto starsMatch = starsPathRx.match(output2); 0202 QVERIFY(starsMatch.hasMatch()); 0203 QFileInfo starsInfo(starsMatch.captured(1)); 0204 qDebug() << "Looking for absolute path:" << starsInfo.filePath(); 0205 QVERIFY(starsInfo.isAbsolute()); 0206 } 0207 0208 void HtmlExporterTest::testDirectoryNames() { 0209 Tellico::Data::CollPtr coll(new Tellico::Data::BookCollection(true)); 0210 Tellico::Export::HTMLExporter exp(coll); 0211 0212 exp.setURL(QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/test.html"))); 0213 QCOMPARE(exp.fileDir(), QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/test_files/"))); 0214 QCOMPARE(exp.fileDirName(), QStringLiteral("test_files/")); 0215 0216 // setCollectionUrl used when exporting entry files only 0217 exp.setCollectionURL(QUrl::fromLocalFile(QDir::homePath())); 0218 QCOMPARE(exp.fileDirName(), QStringLiteral("/")); 0219 } 0220 0221 void HtmlExporterTest::testTemplatesTidy() { 0222 const QString tidy = QStandardPaths::findExecutable(QStringLiteral("tidy")); 0223 if(tidy.isEmpty()) { 0224 QSKIP("This test requires tidy", SkipAll); 0225 } 0226 0227 QFETCH(QString, xsltFile); 0228 QFETCH(QString, tellicoFile); 0229 Tellico::ImageFactory::clean(true); 0230 0231 QStringList tidyArgs = { QStringLiteral("-errors"), 0232 QStringLiteral("-quiet"), 0233 QStringLiteral("--show-warnings"), 0234 QStringLiteral("no"), 0235 QStringLiteral("--strict-tags-attributes"), 0236 QStringLiteral("yes") }; 0237 QProcessEnvironment tidyEnv; 0238 // suppress warning about no tidyrc file 0239 tidyEnv.insert("HTML_TIDY", "/dev/null"); 0240 0241 QUrl url = QUrl::fromLocalFile(tellicoFile); 0242 Tellico::Import::TellicoImporter importer(url); 0243 Tellico::Data::CollPtr coll = importer.collection(); 0244 QVERIFY(coll); 0245 0246 Tellico::Export::HTMLExporter exporter(coll); 0247 exporter.setParseDOM(false); // shows error for <wbr> tags and is not necessary for check 0248 exporter.setEntries(coll->entries()); 0249 exporter.setXSLTFile(xsltFile); 0250 exporter.setPrintGrouped(true); 0251 long opt = exporter.options(); 0252 opt |= Tellico::Export::ExportComplete; // include loan info 0253 exporter.setOptions(opt); 0254 0255 const QString output = exporter.text(); 0256 QVERIFY(!output.contains(QStringLiteral("<p><p>"))); 0257 QProcess tidyProc; 0258 tidyProc.setProcessEnvironment(tidyEnv); 0259 tidyProc.setProcessChannelMode(QProcess::SeparateChannels); 0260 tidyProc.setReadChannel(QProcess::StandardError); 0261 tidyProc.start(tidy, tidyArgs); 0262 QVERIFY(tidyProc.waitForStarted()); 0263 0264 tidyProc.write(output.toUtf8() + '\n'); 0265 QVERIFY(tidyProc.waitForBytesWritten()); 0266 tidyProc.closeWriteChannel(); 0267 QVERIFY(tidyProc.waitForFinished()); 0268 0269 QTextStream ts(&tidyProc); 0270 QString errorOutput = ts.readLine(); 0271 while(!errorOutput.isEmpty()) { 0272 qDebug() << errorOutput; 0273 errorOutput = ts.readLine(); 0274 } 0275 0276 tidyProc.close(); 0277 QCOMPARE(tidyProc.exitStatus(), QProcess::NormalExit); 0278 // tidy exit codes are 0 for none, 1 for warnings only, 2 for errors 0279 QVERIFY(tidyProc.exitCode() < 2); 0280 } 0281 0282 void HtmlExporterTest::testTemplatesTidy_data() { 0283 QTest::addColumn<QString>("xsltFile"); 0284 QTest::addColumn<QString>("tellicoFile"); 0285 0286 QString ted = QFINDTESTDATA(QStringLiteral("data/ted_lasso.xml")); 0287 QString moody = QFINDTESTDATA(QStringLiteral("data/moody_blue.xml")); 0288 0289 QDir entryDir(QFINDTESTDATA(QStringLiteral("../../xslt/entry-templates/Default.xsl"))); 0290 entryDir.cdUp(); 0291 foreach(const QString& file, entryDir.entryList({"*.xsl"}, QDir::Files)) { 0292 QTest::newRow(file.toUtf8().constData()) << file << ted; 0293 QTest::newRow(file.toUtf8().constData()) << file << moody; 0294 } 0295 QDir reportDir(QFINDTESTDATA(QStringLiteral("../../xslt/report-templates/Column_View.xsl"))); 0296 reportDir.cdUp(); 0297 foreach(const QString& file, reportDir.entryList({"*.xsl"}, QDir::Files)) { 0298 QTest::newRow(file.toUtf8().constData()) << file << ted; 0299 QTest::newRow(file.toUtf8().constData()) << file << moody; 0300 } 0301 } 0302 0303 void HtmlExporterTest::testEntryTemplates() { 0304 QFETCH(QString, xsltFile); 0305 Tellico::ImageFactory::clean(true); 0306 0307 QUrl url = QUrl::fromLocalFile(QFINDTESTDATA(QStringLiteral("data/books-format11.bc"))); 0308 Tellico::Import::TellicoImporter importer(url); 0309 Tellico::Data::CollPtr coll = importer.collection(); 0310 QVERIFY(coll); 0311 0312 Tellico::Export::HTMLExporter exporter(coll); 0313 exporter.setParseDOM(false); // shows error for <wbr> tags and is not necessary for check 0314 exporter.setEntries(coll->entries()); 0315 exporter.setXSLTFile(xsltFile); 0316 exporter.setPrintGrouped(true); 0317 long opt = exporter.options(); 0318 opt |= Tellico::Export::ExportComplete; // include loan info 0319 exporter.setOptions(opt); 0320 0321 // check that the loan info appears in all generated HTML 0322 const QString output = exporter.text(); 0323 // expect failure for the non-book templates since the file is a book collection 0324 if(xsltFile.contains(QStringLiteral("Album")) || xsltFile.contains(QStringLiteral("Video"))) { 0325 QEXPECT_FAIL("", "The test data is valid for a book collection only", Continue); 0326 } 0327 QVERIFY(output.contains(QStringLiteral("Robby"))); 0328 } 0329 0330 void HtmlExporterTest::testEntryTemplates_data() { 0331 QTest::addColumn<QString>("xsltFile"); 0332 0333 QDir entryDir(QFINDTESTDATA(QStringLiteral("../../xslt/entry-templates/Default.xsl"))); 0334 entryDir.cdUp(); 0335 foreach(const QString& file, entryDir.entryList({"*.xsl"}, QDir::Files)) { 0336 QTest::newRow(file.toUtf8().constData()) << file; 0337 } 0338 }