2011-04-27 10:05:43 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2012-02-26 21:04:57 +00:00
|
|
|
** Copyright (C) 2012 Giuseppe D'Angelo <dangelog@gmail.com>
|
2014-08-21 13:51:22 +00:00
|
|
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
2012-09-19 12:28:29 +00:00
|
|
|
** Contact: http://www.qt-project.org/legal
|
2011-04-27 10:05:43 +00:00
|
|
|
**
|
|
|
|
** This file is part of the test suite of the Qt Toolkit.
|
|
|
|
**
|
2014-08-21 13:51:22 +00:00
|
|
|
** $QT_BEGIN_LICENSE:LGPL21$
|
2012-09-19 12:28:29 +00:00
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2014-08-21 13:51:22 +00:00
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
2012-09-19 12:28:29 +00:00
|
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
|
|
|
**
|
2011-04-27 10:05:43 +00:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-09-19 12:28:29 +00:00
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2014-08-21 13:51:22 +00:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2012-09-19 12:28:29 +00:00
|
|
|
**
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
2014-08-21 13:51:22 +00:00
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2011-04-27 10:05:43 +00:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
2012-02-26 21:04:57 +00:00
|
|
|
#include <QtTest/QtTest>
|
|
|
|
#include <QtCore/QString>
|
2011-04-27 10:05:43 +00:00
|
|
|
#include <QtCore/QCoreApplication>
|
|
|
|
#include <QtCore/QByteArray>
|
|
|
|
#include <QtCore/QDir>
|
|
|
|
#include <QtCore/QFile>
|
|
|
|
#include <QtCore/QProcess>
|
2012-02-26 21:04:57 +00:00
|
|
|
#include <QtCore/QDirIterator>
|
|
|
|
#include <QtCore/QMap>
|
|
|
|
#include <QtCore/QList>
|
|
|
|
#include <QtCore/QResource>
|
|
|
|
#include <QtCore/QLocale>
|
2012-04-01 17:53:55 +00:00
|
|
|
#include <QtCore/QtGlobal>
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2014-02-18 08:33:36 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
2012-02-26 21:04:57 +00:00
|
|
|
typedef QMap<QString, QString> QStringMap;
|
|
|
|
Q_DECLARE_METATYPE(QStringMap)
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
class tst_rcc : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
private slots:
|
2012-04-01 17:53:55 +00:00
|
|
|
void initTestCase();
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
void rcc_data();
|
|
|
|
void rcc();
|
2012-02-26 21:04:57 +00:00
|
|
|
void binary_data();
|
|
|
|
void binary();
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2012-02-26 21:04:57 +00:00
|
|
|
void cleanupTestCase();
|
2013-08-13 13:26:48 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
QString m_rcc;
|
2012-02-26 21:04:57 +00:00
|
|
|
};
|
2011-04-27 10:05:43 +00:00
|
|
|
|
2012-04-01 17:53:55 +00:00
|
|
|
void tst_rcc::initTestCase()
|
|
|
|
{
|
|
|
|
// rcc uses a QHash to store files in the resource system.
|
|
|
|
// we must force a certain hash order when testing or tst_rcc will fail, see QTBUG-25078
|
|
|
|
QVERIFY(qputenv("QT_RCC_TEST", "1"));
|
2013-08-13 13:26:48 +00:00
|
|
|
m_rcc = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QLatin1String("/rcc");
|
2012-04-01 17:53:55 +00:00
|
|
|
}
|
|
|
|
|
2011-04-27 10:05:43 +00:00
|
|
|
QString findExpectedFile(const QString &base)
|
|
|
|
{
|
|
|
|
QString expectedrccfile = base;
|
|
|
|
|
|
|
|
// Must be updated with each minor release.
|
|
|
|
if (QFileInfo(expectedrccfile + QLatin1String(".450")).exists())
|
|
|
|
expectedrccfile += QLatin1String(".450");
|
|
|
|
|
|
|
|
return expectedrccfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QString doCompare(const QStringList &actual, const QStringList &expected)
|
|
|
|
{
|
|
|
|
if (actual.size() != expected.size()) {
|
|
|
|
return QString("Length count different: actual: %1, expected: %2")
|
|
|
|
.arg(actual.size()).arg(expected.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray ba;
|
|
|
|
for (int i = 0, n = expected.size(); i != n; ++i) {
|
|
|
|
if (expected.at(i).startsWith("IGNORE:"))
|
|
|
|
continue;
|
|
|
|
if (expected.at(i) != actual.at(i)) {
|
|
|
|
qDebug() << "LINES" << i << "DIFFER";
|
|
|
|
ba.append(
|
|
|
|
"\n<<<<<< actual\n" + actual.at(i) + "\n======\n" + expected.at(i)
|
|
|
|
+ "\n>>>>>> expected\n"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ba;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_rcc::rcc_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<QString>("directory");
|
|
|
|
QTest::addColumn<QString>("qrcfile");
|
|
|
|
QTest::addColumn<QString>("expected");
|
|
|
|
|
2012-02-26 21:04:57 +00:00
|
|
|
QString dataPath = QFINDTESTDATA("data/images/");
|
|
|
|
if (dataPath.isEmpty())
|
|
|
|
QFAIL("data path not found");
|
|
|
|
QTest::newRow("images") << dataPath << "images.qrc" << "images.expected";
|
2011-04-27 10:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_rcc::rcc()
|
|
|
|
{
|
|
|
|
QFETCH(QString, directory);
|
|
|
|
QFETCH(QString, qrcfile);
|
|
|
|
QFETCH(QString, expected);
|
|
|
|
|
|
|
|
if (!QDir::setCurrent(directory)) {
|
|
|
|
QString message = QString::fromLatin1("Unable to cd from '%1' to '%2'").arg(QDir::currentPath(), directory);
|
|
|
|
QFAIL(qPrintable(message));
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the file expectedoutput.txt exists, compare the
|
|
|
|
// console output with the content of that file
|
|
|
|
const QString expected2 = findExpectedFile(expected);
|
|
|
|
QFile expectedFile(expected2);
|
|
|
|
if (!expectedFile.exists()) {
|
|
|
|
qDebug() << "NO EXPECTATIONS? " << expected2;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Launch
|
|
|
|
QProcess process;
|
2013-08-13 13:26:48 +00:00
|
|
|
process.start(m_rcc, QStringList(qrcfile));
|
2011-04-27 10:05:43 +00:00
|
|
|
if (!process.waitForFinished()) {
|
|
|
|
const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
|
|
|
|
QString message = QString::fromLatin1("'%1' could not be found when run from '%2'. Path: '%3' ").
|
2013-08-13 13:26:48 +00:00
|
|
|
arg(m_rcc, QDir::currentPath(), path);
|
2011-04-27 10:05:43 +00:00
|
|
|
QFAIL(qPrintable(message));
|
|
|
|
}
|
|
|
|
const QChar cr = QLatin1Char('\r');
|
|
|
|
const QString err = QString::fromLocal8Bit(process.readAllStandardError()).remove(cr);
|
2012-05-02 14:32:26 +00:00
|
|
|
const QString out = QString::fromLatin1(process.readAllStandardOutput()).remove(cr);
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
if (!err.isEmpty()) {
|
|
|
|
qDebug() << "UNEXPECTED STDERR CONTENTS: " << err;
|
|
|
|
QFAIL("UNEXPECTED STDERR CONTENTS");
|
|
|
|
}
|
|
|
|
|
|
|
|
const QChar nl = QLatin1Char('\n');
|
|
|
|
const QStringList actualLines = out.split(nl);
|
|
|
|
|
|
|
|
QVERIFY(expectedFile.open(QIODevice::ReadOnly|QIODevice::Text));
|
2012-05-02 14:32:26 +00:00
|
|
|
const QStringList expectedLines = QString::fromLatin1(expectedFile.readAll()).split(nl);
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
const QString diff = doCompare(actualLines, expectedLines);
|
|
|
|
if (diff.size())
|
|
|
|
QFAIL(qPrintable(diff));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-08-13 13:26:48 +00:00
|
|
|
static void createRccBinaryData(const QString &rcc, const QString &baseDir,
|
|
|
|
const QString &qrcFileName, const QString &rccFileName)
|
2012-02-26 21:04:57 +00:00
|
|
|
{
|
|
|
|
QString currentDir = QDir::currentPath();
|
|
|
|
QDir::setCurrent(baseDir);
|
|
|
|
|
|
|
|
QProcess rccProcess;
|
2013-08-13 13:26:48 +00:00
|
|
|
rccProcess.start(rcc, QStringList() << "-binary" << "-o" << rccFileName << qrcFileName);
|
2012-02-26 21:04:57 +00:00
|
|
|
bool ok = rccProcess.waitForFinished();
|
|
|
|
if (!ok) {
|
|
|
|
QString errorString = QString::fromLatin1("Could not start rcc (is it in PATH?): %1").arg(rccProcess.errorString());
|
|
|
|
QFAIL(qPrintable(errorString));
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray output = rccProcess.readAllStandardOutput();
|
|
|
|
if (!output.isEmpty()) {
|
|
|
|
QString errorMessage = QString::fromLatin1("rcc stdout: %1").arg(QString::fromLocal8Bit(output));
|
|
|
|
QWARN(qPrintable(errorMessage));
|
|
|
|
}
|
|
|
|
|
|
|
|
output = rccProcess.readAllStandardError();
|
|
|
|
if (!output.isEmpty()) {
|
|
|
|
QString errorMessage = QString::fromLatin1("rcc stderr: %1").arg(QString::fromLocal8Bit(output));
|
|
|
|
QWARN(qPrintable(errorMessage));
|
|
|
|
}
|
|
|
|
|
|
|
|
QDir::setCurrent(currentDir);
|
|
|
|
}
|
|
|
|
|
|
|
|
static QStringList readLinesFromFile(const QString &fileName)
|
|
|
|
{
|
|
|
|
QFile file(fileName);
|
|
|
|
|
|
|
|
bool ok = file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
|
|
if (!ok)
|
|
|
|
QWARN(qPrintable(QString::fromLatin1("Could not open testdata file %1: %2").arg(fileName, file.errorString())));
|
|
|
|
|
|
|
|
QStringList lines = QString::fromUtf8(file.readAll()).split(QLatin1Char('\n'), QString::SkipEmptyParts);
|
|
|
|
return lines;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QStringMap readExpectedFiles(const QString &fileName)
|
|
|
|
{
|
|
|
|
QStringMap expectedFiles;
|
|
|
|
|
|
|
|
QStringList lines = readLinesFromFile(fileName);
|
|
|
|
foreach (const QString &line, lines) {
|
|
|
|
QString resourceFileName = line.section(QLatin1Char(' '), 0, 0, QString::SectionSkipEmpty);
|
|
|
|
QString actualFileName = line.section(QLatin1Char(' '), 1, 1, QString::SectionSkipEmpty);
|
|
|
|
expectedFiles[resourceFileName] = actualFileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
return expectedFiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
The following test looks for all *.qrc files under data/binary/. For each
|
|
|
|
.qrc file found, these files are processed (assuming the file found is
|
|
|
|
called "base.qrc"):
|
|
|
|
|
|
|
|
- base.qrc : processed by rcc; creates base.rcc
|
|
|
|
- base.locale : (optional) list of locales to test, one per line
|
|
|
|
- base.expected : list of pairs (file path in resource, path to real file),
|
|
|
|
one per line; the pair separated by a whitespace; the paths to real files
|
|
|
|
relative to data/binary/ (for testing the C locale)
|
|
|
|
- base.localeName.expected : for each localeName in the base.locale file,
|
|
|
|
as the above .expected file
|
|
|
|
*/
|
|
|
|
|
|
|
|
void tst_rcc::binary_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<QString>("resourceFile");
|
|
|
|
QTest::addColumn<QLocale>("locale");
|
|
|
|
QTest::addColumn<QString>("baseDirectory");
|
|
|
|
QTest::addColumn<QStringMap>("expectedFiles");
|
|
|
|
|
|
|
|
QString dataPath = QFINDTESTDATA("data/binary/");
|
|
|
|
if (dataPath.isEmpty())
|
|
|
|
QFAIL("data path not found");
|
|
|
|
|
|
|
|
QDirIterator iter(dataPath, QStringList() << QLatin1String("*.qrc"));
|
|
|
|
while (iter.hasNext())
|
|
|
|
{
|
|
|
|
iter.next();
|
|
|
|
QFileInfo qrcFileInfo = iter.fileInfo();
|
|
|
|
QString absoluteBaseName = QFileInfo(qrcFileInfo.absolutePath(), qrcFileInfo.baseName()).absoluteFilePath();
|
|
|
|
QString rccFileName = absoluteBaseName + QLatin1String(".rcc");
|
2013-08-13 13:26:48 +00:00
|
|
|
createRccBinaryData(m_rcc, dataPath, qrcFileInfo.absoluteFilePath(), rccFileName);
|
2012-02-26 21:04:57 +00:00
|
|
|
|
|
|
|
QString localeFileName = absoluteBaseName + QLatin1String(".locale");
|
|
|
|
QFile localeFile(localeFileName);
|
|
|
|
if (localeFile.exists()) {
|
|
|
|
QStringList locales = readLinesFromFile(localeFileName);
|
|
|
|
foreach (const QString &locale, locales) {
|
|
|
|
QString expectedFileName = QString::fromLatin1("%1.%2.%3").arg(absoluteBaseName, locale, QLatin1String("expected"));
|
|
|
|
QStringMap expectedFiles = readExpectedFiles(expectedFileName);
|
|
|
|
QTest::newRow(qPrintable(qrcFileInfo.baseName() + QLatin1Char('_') + locale)) << rccFileName
|
|
|
|
<< QLocale(locale)
|
|
|
|
<< dataPath
|
|
|
|
<< expectedFiles;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// always test for the C locale as well
|
|
|
|
QString expectedFileName = absoluteBaseName + QLatin1String(".expected");
|
|
|
|
QStringMap expectedFiles = readExpectedFiles(expectedFileName);
|
|
|
|
QTest::newRow(qPrintable(qrcFileInfo.baseName() + QLatin1String("_C"))) << rccFileName
|
|
|
|
<< QLocale::c()
|
|
|
|
<< dataPath
|
|
|
|
<< expectedFiles;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_rcc::binary()
|
|
|
|
{
|
|
|
|
QFETCH(QString, baseDirectory);
|
|
|
|
QFETCH(QString, resourceFile);
|
|
|
|
QFETCH(QLocale, locale);
|
|
|
|
QFETCH(QStringMap, expectedFiles);
|
|
|
|
|
|
|
|
const QString rootPrefix = QLatin1String("/test_root/");
|
|
|
|
const QString resourceRootPrefix = QLatin1Char(':') + rootPrefix;
|
|
|
|
|
|
|
|
QLocale oldDefaultLocale;
|
|
|
|
QLocale::setDefault(locale);
|
|
|
|
QVERIFY(QFile::exists(resourceFile));
|
|
|
|
QVERIFY(QResource::registerResource(resourceFile, rootPrefix));
|
|
|
|
|
|
|
|
{ // need to destroy the iterators on the resource, in order to be able to unregister it
|
|
|
|
|
|
|
|
// read all the files inside the resources
|
|
|
|
QDirIterator iter(resourceRootPrefix, QDir::Files, QDirIterator::Subdirectories);
|
|
|
|
QList<QString> filesFound;
|
|
|
|
while (iter.hasNext())
|
|
|
|
filesFound << iter.next();
|
|
|
|
|
|
|
|
// add the test root prefix to the expected file names
|
|
|
|
QList<QString> expectedFileNames = expectedFiles.keys();
|
|
|
|
for (QList<QString>::iterator i = expectedFileNames.begin(); i < expectedFileNames.end(); ++i) {
|
|
|
|
// poor man's canonicalPath, which doesn't work with resources
|
|
|
|
if ((*i).startsWith(QLatin1Char('/')))
|
|
|
|
(*i).remove(0, 1);
|
|
|
|
*i = resourceRootPrefix + *i;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check that we have all (and only) the expected files
|
2014-02-18 08:33:36 +00:00
|
|
|
std::sort(filesFound.begin(), filesFound.end());
|
|
|
|
std::sort(expectedFileNames.begin(), expectedFileNames.end());
|
2012-02-26 21:04:57 +00:00
|
|
|
QCOMPARE(filesFound, expectedFileNames);
|
|
|
|
|
|
|
|
// now actually check the file contents
|
|
|
|
QDir directory(baseDirectory);
|
|
|
|
for (QStringMap::const_iterator i = expectedFiles.constBegin(); i != expectedFiles.constEnd(); ++i) {
|
|
|
|
QString resourceFileName = i.key();
|
|
|
|
QString actualFileName = i.value();
|
|
|
|
|
|
|
|
QFile resourceFile(resourceRootPrefix + resourceFileName);
|
|
|
|
QVERIFY(resourceFile.open(QIODevice::ReadOnly));
|
|
|
|
QByteArray resourceData = resourceFile.readAll();
|
|
|
|
resourceFile.close();
|
|
|
|
|
|
|
|
QFile actualFile(QFileInfo(directory, actualFileName).absoluteFilePath());
|
|
|
|
QVERIFY(actualFile.open(QIODevice::ReadOnly));
|
|
|
|
QByteArray actualData = actualFile.readAll();
|
|
|
|
actualFile.close();
|
|
|
|
QCOMPARE(resourceData, actualData);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
QVERIFY(QResource::unregisterResource(resourceFile, rootPrefix));
|
|
|
|
QLocale::setDefault(oldDefaultLocale);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void tst_rcc::cleanupTestCase()
|
|
|
|
{
|
|
|
|
QString dataPath = QFINDTESTDATA("data/binary/");
|
|
|
|
if (dataPath.isEmpty())
|
|
|
|
return;
|
|
|
|
QDir dataDir(dataPath);
|
|
|
|
QFileInfoList entries = dataDir.entryInfoList(QStringList() << QLatin1String("*.rcc"));
|
|
|
|
foreach (const QFileInfo &entry, entries)
|
|
|
|
QFile::remove(entry.absoluteFilePath());
|
|
|
|
}
|
|
|
|
|
2012-06-05 04:03:35 +00:00
|
|
|
QTEST_MAIN(tst_rcc)
|
2011-04-27 10:05:43 +00:00
|
|
|
|
|
|
|
#include "tst_rcc.moc"
|