/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "report.h" #include "baselineprotocol.h" #include "baselineserver.h" #include #include #include Report::Report() : written(false), numItems(0), numMismatches(0) { } Report::~Report() { end(); } QString Report::filePath() { return path; } void Report::init(const BaselineHandler *h, const QString &r, const PlatformInfo &p) { handler = h; runId = r; plat = p; rootDir = BaselineServer::storagePath() + QLC('/'); reportDir = plat.value(PI_TestCase) + QLC('/') + (plat.value(PI_PulseGitBranch).isEmpty() ? QLS("reports/adhoc/") : QLS("reports/pulse/")); QString dir = rootDir + reportDir; QDir cwd; if (!cwd.exists(dir)) cwd.mkpath(dir); path = reportDir + QLS("Report_") + runId + QLS(".html"); } void Report::addItems(const ImageItemList &items) { if (items.isEmpty()) return; numItems += items.size(); QString func = items.at(0).testFunction; if (!testFunctions.contains(func)) testFunctions.append(func); itemLists[func] += items; } void Report::addMismatch(const ImageItem &item) { if (!testFunctions.contains(item.testFunction)) { qWarning() << "Report::addMismatch: unknown testfunction" << item.testFunction; return; } bool found = false; ImageItemList &list = itemLists[item.testFunction]; for (ImageItemList::iterator it = list.begin(); it != list.end(); ++it) { if (it->itemName == item.itemName && it->itemChecksum == item.itemChecksum) { it->status = ImageItem::Mismatch; found = true; break; } } if (found) numMismatches++; else qWarning() << "Report::addMismatch: unknown item" << item.itemName << "in testfunction" << item.testFunction; } void Report::end() { if (written || !numMismatches) return; write(); written = true; } void Report::write() { QFile file(rootDir + path); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { qWarning() << "Failed to open report file" << file.fileName(); return; } out.setDevice(&file); writeHeader(); foreach(const QString &func, testFunctions) { writeFunctionResults(itemLists.value(func)); } writeFooter(); file.close(); } void Report::writeHeader() { QString title = plat.value(PI_TestCase) + QLS(" Qt Baseline Test Report"); out << "" << title << "\n" << "

" << title << "

\n" << "

Run Id: " << runId << "

\n" << "

Summary: " << numMismatches << " of " << numItems << " items reported mismatching

\n\n"; out << "

Platform Info:

\n" << "\n"; foreach (QString key, plat.keys()) out << "\n"; out << "
" << key << "" << plat.value(key) << "
\n\n"; } void Report::writeFunctionResults(const ImageItemList &list) { QString testFunction = list.at(0).testFunction; QString pageUrl = BaselineServer::baseUrl() + path; QString ctx = handler->pathForItem(list.at(0), true, false).section(QLC('/'), 0, -2); out << "\n

 

Test function: " << testFunction << "

\n"; out << "

Clear all baselines (They will be recreated by the next run)

\n\n"; out << "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n\n"; foreach (const ImageItem &item, list) { out << "\n"; out << "\n"; QString baseline = handler->pathForItem(item, true, false) + QLS(FileFormat); if (item.status == ImageItem::Mismatch) { QString rendered = handler->pathForItem(item, false, false) + QLS(FileFormat); writeItem(baseline, rendered, item, ctx); } else { out << "\n" << "\n" << "\n"; } out << "\n\n"; } out << "
ItemBaselineRenderedComparison (diffs are RED)Info/Action
" << item.itemName << "viewn/a"; switch (item.status) { case ImageItem::BaselineNotFound: out << "Baseline not found/regenerated"; break; case ImageItem::IgnoreItem: out << "Blacklisted " << "Whitelist this item"; break; case ImageItem::Ok: out << "No mismatch reported"; break; default: out << "?"; break; } out << "
\n"; } void Report::writeItem(const QString &baseline, const QString &rendered, const ImageItem &item, const QString &ctx) { QString compared = generateCompared(baseline, rendered); QString pageUrl = BaselineServer::baseUrl() + path; QStringList images = QStringList() << baseline << rendered << compared; foreach (const QString& img, images) out << "\n"; out << "\n" << "

Mismatch reported

\n" << "

Replace baseline with rendered

\n" << "

Blacklist this item

\n" << "

Inspect

\n" << "\n"; } void Report::writeFooter() { out << "\n\n"; } QString Report::generateCompared(const QString &baseline, const QString &rendered, bool fuzzy) { QString res = rendered; QFileInfo fi(res); res.chop(fi.suffix().length() + 1); res += QLS(fuzzy ? "_fuzzycompared.png" : "_compared.png"); QStringList args; if (fuzzy) args << QLS("-fuzz") << QLS("5%"); args << rootDir+baseline << rootDir+rendered << rootDir+res; QProcess::execute(QLS("compare"), args); return res; } QString Report::generateThumbnail(const QString &image) { QString res = image; QFileInfo imgFI(rootDir+image); res.chop(imgFI.suffix().length() + 1); res += QLS("_thumbnail.jpg"); QFileInfo resFI(rootDir+res); if (resFI.exists() && resFI.lastModified() > imgFI.lastModified()) return res; QStringList args; args << rootDir+image << QLS("-resize") << QLS("240x240>") << QLS("-quality") << QLS("50") << rootDir+res; QProcess::execute(QLS("convert"), args); return res; } void Report::handleCGIQuery(const QString &query) { QUrl cgiUrl(QLS("http://dummy/cgi-bin/dummy.cgi?") + query); QTextStream s(stdout); s << "Content-Type: text/html\r\n\r\n" << ""; QString command(cgiUrl.queryItemValue("cmd")); if (command == QLS("view")) { s << BaselineHandler::view(cgiUrl.queryItemValue(QLS("baseline")), cgiUrl.queryItemValue(QLS("rendered")), cgiUrl.queryItemValue(QLS("compared"))); } else if (command == QLS("updateSingleBaseline")) { s << BaselineHandler::updateSingleBaseline(cgiUrl.queryItemValue(QLS("oldBaseline")), cgiUrl.queryItemValue(QLS("newBaseline"))); } else if (command == QLS("clearAllBaselines")) { s << BaselineHandler::clearAllBaselines(cgiUrl.queryItemValue(QLS("context"))); } else if (command == QLS("blacklist")) { // blacklist a test s << BaselineHandler::blacklistTest(cgiUrl.queryItemValue(QLS("context")), cgiUrl.queryItemValue(QLS("itemId"))); } else if (command == QLS("whitelist")) { // whitelist a test s << BaselineHandler::blacklistTest(cgiUrl.queryItemValue(QLS("context")), cgiUrl.queryItemValue(QLS("itemId")), true); } else { s << "Unknown query:
" << query << "
"; } s << "

Back to report"; s << ""; }