kde-extraapps/kdevplatform/util/tests/test_path.cpp
2015-07-26 14:23:17 +03:00

537 lines
16 KiB
C++

/*
* This file is part of KDevelop
* Copyright 2012 Milian Wolff <mail@milianw.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "test_path.h"
#include <util/path.h>
#include <tests/autotestshell.h>
#include <tests/testcore.h>
#include <QtTest>
#include <KUrl>
QTEST_MAIN(TestPath);
using namespace KDevelop;
static const int FILES_PER_FOLDER = 10;
static const int FOLDERS_PER_FOLDER = 5;
static const int TREE_DEPTH = 5;
namespace QTest {
template<>
char *toString(const KUrl &url)
{
return qstrdup(qPrintable(url.pathOrUrl()));
}
}
template<typename T>
T stringToUrl(const QString& path)
{
return T(path);
}
template<>
QStringList stringToUrl(const QString& path)
{
return path.split('/');
}
template<typename T>
T childUrl(const T& parent, const QString& child)
{
return T(parent, child);
}
template<>
QStringList childUrl(const QStringList& parent, const QString& child)
{
QStringList ret = parent;
ret << child;
return ret;
}
template<>
QUrl childUrl(const QUrl& parent, const QString& child)
{
QUrl ret = parent;
ret.setPath(ret.path() + '/' + child);
return ret;
}
template<>
KUrl childUrl(const KUrl& parent, const QString& child)
{
KUrl ret = parent;
ret.addPath(child);
return ret;
}
template<typename T>
QVector<T> generateData(const T& parent, int level)
{
QVector<T> ret;
// files per folder
for (int i = 0; i < FILES_PER_FOLDER; ++i) {
const QString fileName = QString("file%1.txt").arg(i);
const T file = childUrl<T>(parent, fileName);
Q_ASSERT(!ret.contains(file));
ret << file;
}
// nesting depth
if (level < TREE_DEPTH) {
// folders per folder
for (int i = 0; i < FOLDERS_PER_FOLDER; ++i) {
const QString folderName = QString("folder%1").arg(i);
const T folder = childUrl<T>(parent, folderName);
Q_ASSERT(!ret.contains(folder));
ret << folder;
ret += generateData<T>(folder, level + 1);
}
}
return ret;
}
template<typename T>
void runBenchmark()
{
QBENCHMARK {
const T base = stringToUrl<T>("/tmp/foo/bar");
generateData(base, 0);
}
}
void TestPath::initTestCase()
{
AutoTestShell::init();
TestCore::initialize(Core::NoUi);
}
void TestPath::cleanupTestCase()
{
TestCore::shutdown();
}
void TestPath::bench_kurl()
{
runBenchmark<KUrl>();
}
void TestPath::bench_qurl()
{
runBenchmark<QUrl>();
}
void TestPath::bench_qstringlist()
{
runBenchmark<QStringList>();
}
void TestPath::bench_path()
{
runBenchmark<Path>();
}
void TestPath::bench_fromLocalPath()
{
QFETCH(int, variant);
const QString input("/foo/bar/asdf/bla/blub.h");
const int repeat = 1000;
if (variant == 1) {
QBENCHMARK {
for(int i = 0; i < repeat; ++i) {
Path path = Path(KUrl(input));
Q_UNUSED(path);
}
}
} else if (variant == 2) {
QBENCHMARK {
for(int i = 0; i < repeat; ++i) {
Path path = Path(KUrl::fromPath(input));
Q_UNUSED(path);
}
}
} else if (variant == 3) {
QBENCHMARK {
for(int i = 0; i < repeat; ++i) {
Path path = Path(QUrl::fromLocalFile(input));
Q_UNUSED(path);
}
}
} else {
QFAIL("unexpected variant");
}
}
void TestPath::bench_fromLocalPath_data()
{
QTest::addColumn<int>("variant");
QTest::newRow("KUrl::KUrl") << 1;
QTest::newRow("KUrl::fromPath") << 2;
QTest::newRow("QUrl::fromLocalFile") << 3;
}
void TestPath::bench_hash()
{
const Path path("/my/very/long/path/to/a/file.cpp");
QBENCHMARK {
auto hash = qHash(path);
Q_UNUSED(hash);
}
}
KUrl comparableUpUrl(const KUrl& url)
{
KUrl ret = url.upUrl();
ret.adjustPath(KUrl::RemoveTrailingSlash);
if (ret.hasPass()) {
ret.setPass(QString());
}
return ret;
}
void TestPath::testPath()
{
QFETCH(QString, input);
KUrl url(input);
url.cleanPath();
url.adjustPath(KUrl::RemoveTrailingSlash);
Path optUrl(input);
if (url.hasPass()) {
KUrl urlNoPass = url;
urlNoPass.setPass(QString());
QCOMPARE(optUrl.toUrl(), urlNoPass);
} else {
QCOMPARE(optUrl.toUrl(), url);
}
QCOMPARE(optUrl.isLocalFile(), url.isLocalFile());
QCOMPARE(optUrl.pathOrUrl(), url.pathOrUrl());
QCOMPARE(optUrl.isValid(), url.isValid());
QCOMPARE(optUrl.lastPathSegment(), url.fileName());
QCOMPARE(optUrl.path(), url.path());
QCOMPARE(optUrl.parent().toUrl(), comparableUpUrl(url));
QCOMPARE(optUrl.toLocalFile(), url.toLocalFile());
QCOMPARE(optUrl, Path(input));
QCOMPARE(optUrl, Path(optUrl));
QVERIFY(optUrl != Path(input + "/asdf"));
if (url.isLocalFile() && !input.startsWith("file://")) {
QCOMPARE(optUrl, Path(KUrl::fromPath(input)));
}
QCOMPARE(optUrl, Path(url));
if (url.isValid()) {
QVERIFY(optUrl.relativePath(optUrl).isEmpty());
Path relativePath(optUrl, "foo/bar");
QCOMPARE(optUrl.relativePath(relativePath), QLatin1String("foo/bar"));
QCOMPARE(relativePath.relativePath(optUrl), QLatin1String("../../"));
QVERIFY(optUrl.isParentOf(relativePath));
QVERIFY(!relativePath.isParentOf(optUrl));
Path absolutePath(optUrl, "/laa/loo");
QCOMPARE(absolutePath.path(), QLatin1String("/laa/loo"));
QCOMPARE(KUrl(url, "/laa/loo").path(), QLatin1String("/laa/loo"));
Path absolutePath2(optUrl, "/");
QCOMPARE(absolutePath2.path(), QLatin1String("/"));
QCOMPARE(KUrl(url, "/").path(), QLatin1String("/"));
Path unrelatedPath("https://test@blubasdf.com:12345/");
QCOMPARE(optUrl.relativePath(unrelatedPath), unrelatedPath.pathOrUrl());
QCOMPARE(unrelatedPath.relativePath(optUrl), optUrl.pathOrUrl());
QVERIFY(!unrelatedPath.isParentOf(optUrl));
QVERIFY(!optUrl.isParentOf(unrelatedPath));
}
QCOMPARE(Path().relativePath(optUrl), optUrl.pathOrUrl());
QVERIFY(optUrl.relativePath(Path()).isEmpty());
QVERIFY(Path().relativePath(Path()).isEmpty());
QVERIFY(!optUrl.isParentOf(Path()));
QVERIFY(!Path().isParentOf(optUrl));
QVERIFY(!Path().isParentOf(Path()));
QVERIFY(!optUrl.isParentOf(optUrl));
QCOMPARE(optUrl.isRemote(), optUrl.isValid() && !optUrl.isLocalFile());
QCOMPARE(optUrl.isRemote(), optUrl.isValid() && !optUrl.remotePrefix().isEmpty());
url.addPath("test/foo/bar");
optUrl.addPath("test/foo/bar");
QCOMPARE(optUrl.lastPathSegment(), url.fileName());
QCOMPARE(optUrl.path(), url.path());
url.setFileName("lalalala_adsf.txt");
optUrl.setLastPathSegment("lalalala_adsf.txt");
QCOMPARE(optUrl.lastPathSegment(), url.fileName());
QCOMPARE(optUrl.path(), url.path());
QCOMPARE(optUrl.parent().toUrl(), comparableUpUrl(url));
QVERIFY(optUrl.parent().isDirectParentOf(optUrl));
QVERIFY(!optUrl.parent().parent().isDirectParentOf(optUrl));
Path a("/foo/bar/asdf/");
Path b("/foo/bar/");
QVERIFY(b.isDirectParentOf(a));
Path c("/foo/bar");
QVERIFY(c.isDirectParentOf(a));
optUrl.clear();
url.clear();
QCOMPARE(optUrl.toUrl(), url);
}
void TestPath::testPath_data()
{
QTest::addColumn<QString>("input");
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"\"");
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"\"");
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"\"");
QTest::newRow("invalid") << "";
QTest::newRow("path") << "/tmp/foo/asdf.txt";
QTest::newRow("path-folder") << "/tmp/foo/asdf/";
QTest::newRow("root") << "/";
QTest::newRow("clean-path") << "/tmp/..///asdf/";
QTest::newRow("remote-root") << "http://www.test.com/";
QTest::newRow("http") << "http://www.test.com/tmp/asdf.txt";
QTest::newRow("file") << "file:///tmp/foo/asdf.txt";
QTest::newRow("file-folder") << "file:///tmp/foo/bar/";
QTest::newRow("ftps") << "ftps://user@host.com/tmp/foo/asdf.txt";
QTest::newRow("password") << "ftps://user:password@host.com/tmp/asdf.txt";
QTest::newRow("port") << "http://localhost:8080/foo/bar/test.txt";
}
void TestPath::testPathInvalid()
{
QFETCH(QString, input);
Path url(input);
QVERIFY(!url.isValid());
}
void TestPath::testPathInvalid_data()
{
QTest::addColumn<QString>("input");
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"\"");
QTest::newRow("empty") << "";
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"http://test.com/#hello\"");
QTest::newRow("fragment") << "http://test.com/#hello";
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"http://test.com/?hello\"");
QTest::newRow("query") << "http://test.com/?hello";
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"file:///home/weis/kde.tgz#gzip:/%23tar:/kdebase\"");
QTest::newRow("suburl") << "file:///home/weis/kde.tgz#gzip:/#tar:/kdebase";
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"../foo/bar\"");
QTest::newRow("relative") << "../foo/bar";
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"asdfasdf\"");
QTest::newRow("name") << "asdfasdf";
QTest::ignoreMessage(QtWarningMsg, "Path::init: invalid/unsupported Path encountered: \"http://www.test.com\"");
QTest::newRow("remote-nopath") << "http://www.test.com";
}
void TestPath::testPathOperators()
{
QFETCH(Path, left);
QFETCH(Path, right);
QFETCH(bool, equal);
QFETCH(bool, less);
bool greater = !equal && !less;
QVERIFY(left == left);
QVERIFY(right == right);
QCOMPARE(left == right, equal);
QCOMPARE(right == left, equal);
QCOMPARE(left < right, less);
QCOMPARE(left <= right, less || equal);
QCOMPARE(left > right, greater);
QCOMPARE(left >= right, greater || equal);
QCOMPARE(right < left, greater);
QCOMPARE(right <= left, greater || equal);
QCOMPARE(right > left, less);
QCOMPARE(right >= left, less || equal);
}
void TestPath::testPathOperators_data()
{
QTest::addColumn<Path>("left");
QTest::addColumn<Path>("right");
QTest::addColumn<bool>("equal");
QTest::addColumn<bool>("less");
Path a("/tmp/a");
Path b("/tmp/b");
Path c("/tmp/ac");
Path d("/d");
Path e("/tmp");
Path f("/tmp/");
Path invalid;
QTest::newRow("a-b") << a << b << false << true;
QTest::newRow("a-copy") << a << Path(a) << true << false;
QTest::newRow("c-a") << c << a << false << false;
QTest::newRow("c-invalid") << c << invalid << false << false;
QTest::newRow("c-d") << c << d << false << false;
QTest::newRow("e-f") << e << f << true << false;
}
void TestPath::testPathAddData()
{
QFETCH(QString, pathToAdd);
const QStringList bases = QStringList()
<< "/foo/bar/asdf/"
<< "file:///foo/bar/asdf/"
<< "http://www.asdf.com/foo/bar/asdf/"
<< "/"
;
foreach(const QString& base, bases) {
KUrl baseUrl(base);
baseUrl.addPath(pathToAdd);
baseUrl.cleanPath();
baseUrl.adjustPath(KUrl::RemoveTrailingSlash);
Path basePath(base);
basePath.addPath(pathToAdd);
QCOMPARE(basePath.toUrl(), baseUrl);
QCOMPARE(basePath.pathOrUrl(), baseUrl.pathOrUrl());
}
}
void TestPath::testPathAddData_data()
{
QTest::addColumn<QString>("pathToAdd");
const QStringList paths = QStringList()
<< "file.txt"
<< "path/file.txt"
<< "path//file.txt"
<< "/absolute"
<< "../"
<< ".."
<< "../../../"
<< "./foo"
<< "../relative"
<< "../../relative"
<< "../foo/../bar"
<< "../foo/./bar"
<< "../../../../../../../invalid";
foreach(const QString &path, paths) {
QTest::newRow(qstrdup(path.toUtf8().constData())) << path;
}
}
void TestPath::testPathBaseCtor()
{
QFETCH(QString, base);
QFETCH(QString, subPath);
const Path basePath(base);
const Path path(basePath, subPath);
KUrl url(base);
if (KUrl(subPath).isRelative()) {
url.addPath(subPath);
} else {
url.setPath(subPath);
}
url.cleanPath();
QCOMPARE(path.pathOrUrl(), url.pathOrUrl(KUrl::RemoveTrailingSlash));
}
void TestPath::testPathBaseCtor_data()
{
QTest::addColumn<QString>("base");
QTest::addColumn<QString>("subPath");
QTest::newRow("empty") << "" << "";
QTest::newRow("root-empty") << "/" << "";
QTest::newRow("root-root") << "/" << "/";
QTest::newRow("root-relative") << "/" << "bar";
QTest::newRow("root-relative-dirty") << "/" << "bar//foo/a/..";
QTest::newRow("empty-relative") << "" << "bar/foo/";
QTest::newRow("path-relative") << "/foo/bar" << "bar/foo";
QTest::newRow("path-absolute") << "/foo/bar" << "/bar/foo";
QTest::newRow("remote-path-absolute") << "http://foo.com/foo/bar" << "/bar/foo";
QTest::newRow("remote-path-relative") << "http://foo.com/foo/bar" << "bar/foo";
}
void TestPath::testPathCd()
{
QFETCH(QString, base);
QFETCH(QString, change);
Path path = base.isEmpty() ? Path() : Path(base);
KUrl url(base);
Path changed = path.cd(change);
if (url.cd(change)) {
QVERIFY(changed.isValid());
}
url.cleanPath();
QCOMPARE(changed.pathOrUrl(), url.pathOrUrl(KUrl::RemoveTrailingSlash));
}
void TestPath::testPathCd_data()
{
QTest::addColumn<QString>("base");
QTest::addColumn<QString>("change");
const QVector<QString> bases{"", "/foo", "/foo/bar/asdf", "http://foo.com/", "http://foo.com/foo", "http://foo.com/foo/bar/asdf"};
foreach (const QString& base, bases) {
QTest::newRow(qstrdup(qPrintable(base + "-"))) << base << "";
QTest::newRow(qstrdup(qPrintable(base + "-.."))) << base << "..";
QTest::newRow(qstrdup(qPrintable(base + "-../"))) << base << "../";
QTest::newRow(qstrdup(qPrintable(base + "v../foo"))) << base << "../foo";
QTest::newRow(qstrdup(qPrintable(base + "-."))) << base << ".";
QTest::newRow(qstrdup(qPrintable(base + "-./"))) << base << "./";
QTest::newRow(qstrdup(qPrintable(base + "-./foo"))) << base << "./foo";
QTest::newRow(qstrdup(qPrintable(base + "-./foo/bar"))) << base << "./foo/bar";
QTest::newRow(qstrdup(qPrintable(base + "-foo/.."))) << base << "foo/..";
QTest::newRow(qstrdup(qPrintable(base + "-foo/"))) << base << "foo/";
QTest::newRow(qstrdup(qPrintable(base + "-foo/../bar"))) << base << "foo/../bar";
QTest::newRow(qstrdup(qPrintable(base + "-/foo"))) << base << "/foo";
QTest::newRow(qstrdup(qPrintable(base + "-/foo/../bar"))) << base << "/foo/../bar";
}
}
#include "moc_test_path.cpp"