qbittorrent/test/testpath.cpp
2026-10-30 12:10:00 +03:00

509 lines
18 KiB
C++

/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2022 Mike Tzou (Chocobo1)
*
* 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) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include <QtSystemDetection>
#include <QObject>
#include <QTest>
#include "base/path.h"
using namespace Qt::Literals::StringLiterals;
class TestPath final : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(TestPath)
public:
TestPath() = default;
private slots:
void testConstructors() const
{
QCOMPARE_EQ(Path(u""_s), Path(std::string("")));
QCOMPARE_EQ(Path(u"abc"_s), Path(std::string("abc")));
QCOMPARE_EQ(Path(u"/abc"_s), Path(std::string("/abc")));
QCOMPARE_EQ(Path(uR"(\abc)"_s), Path(std::string(R"(\abc)")));
#ifdef Q_OS_WIN
QCOMPARE_EQ(Path(uR"(c:)"_s), Path(std::string(R"(c:)")));
QCOMPARE_EQ(Path(uR"(c:/)"_s), Path(std::string(R"(c:/)")));
QCOMPARE_EQ(Path(uR"(c:/)"_s), Path(std::string(R"(c:\)")));
QCOMPARE_EQ(Path(uR"(c:\)"_s), Path(std::string(R"(c:/)")));
QCOMPARE_EQ(Path(uR"(c:\)"_s), Path(std::string(R"(c:\)")));
QCOMPARE_EQ(Path(uR"(\\?\C:)"_s), Path(std::string(R"(\\?\C:)")));
QCOMPARE_EQ(Path(uR"(\\?\C:/)"_s), Path(std::string(R"(\\?\C:/)")));
QCOMPARE_EQ(Path(uR"(\\?\C:/)"_s), Path(std::string(R"(\\?\C:\)")));
QCOMPARE_EQ(Path(uR"(\\?\C:\)"_s), Path(std::string(R"(\\?\C:/)")));
QCOMPARE_EQ(Path(uR"(\\?\C:\)"_s), Path(std::string(R"(\\?\C:\)")));
QCOMPARE_EQ(Path(uR"(\\?\C:\abc)"_s), Path(std::string(R"(\\?\C:\abc)")));
#endif
}
void testIsValid() const
{
QCOMPARE(Path().isValid(), false);
QCOMPARE(Path(u""_s).isValid(), false);
QCOMPARE(Path(u"/"_s).isValid(), true);
QCOMPARE(Path(uR"(\)"_s).isValid(), true);
QCOMPARE(Path(u"a"_s).isValid(), true);
QCOMPARE(Path(u"/a"_s).isValid(), true);
QCOMPARE(Path(uR"(\a)"_s).isValid(), true);
QCOMPARE(Path(u"a/b"_s).isValid(), true);
QCOMPARE(Path(uR"(a\b)"_s).isValid(), true);
QCOMPARE(Path(u"/a/b"_s).isValid(), true);
QCOMPARE(Path(uR"(/a\b)"_s).isValid(), true);
QCOMPARE(Path(uR"(\a/b)"_s).isValid(), true);
QCOMPARE(Path(uR"(\a\b)"_s).isValid(), true);
QCOMPARE(Path(u"."_s).isValid(), true);
QCOMPARE(Path(u".."_s).isValid(), true);
QCOMPARE(Path(u"../"_s).isValid(), true);
QCOMPARE(Path(u"./"_s).isValid(), true);
QCOMPARE(Path(uR"(..\)"_s).isValid(), true);
QCOMPARE(Path(uR"(.\)"_s).isValid(), true);
QCOMPARE(Path(u"../a"_s).isValid(), true);
QCOMPARE(Path(u"./a"_s).isValid(), true);
QCOMPARE(Path(uR"(..\a)"_s).isValid(), true);
QCOMPARE(Path(uR"(.\a)"_s).isValid(), true);
QCOMPARE(Path(u"a/../b"_s).isValid(), true);
QCOMPARE(Path(u"a/./b"_s).isValid(), true);
QCOMPARE(Path(u"a/./../b"_s).isValid(), true);
QCOMPARE(Path(u"a/.././b"_s).isValid(), true);
QCOMPARE(Path(u"a/.././../b"_s).isValid(), true);
QCOMPARE(Path(uR"(a\..\b)"_s).isValid(), true);
QCOMPARE(Path(uR"(a\.\b)"_s).isValid(), true);
QCOMPARE(Path(uR"(a\.\..\b)"_s).isValid(), true);
QCOMPARE(Path(u"a/.."_s).isValid(), true);
QCOMPARE(Path(u"a/b/.."_s).isValid(), true);
QCOMPARE(Path(u"a/."_s).isValid(), true);
QCOMPARE(Path(u"a/b/."_s).isValid(), true);
QCOMPARE(Path(uR"(a\..)"_s).isValid(), true);
QCOMPARE(Path(uR"(a\b\..)"_s).isValid(), true);
QCOMPARE(Path(uR"(a\.)"_s).isValid(), true);
QCOMPARE(Path(uR"(a\b\.)"_s).isValid(), true);
QCOMPARE(Path(u"../../a/b"_s).isValid(), true);
QCOMPARE(Path(u"../.."_s).isValid(), true);
QCOMPARE(Path(u"../../../"_s).isValid(), true);
QCOMPARE(Path(u"./../a/../b"_s).isValid(), true);
QCOMPARE(Path(uR"(..\..\a\b\..)"_s).isValid(), true);
QCOMPARE(Path(uR"(a\.\..\b\.)"_s).isValid(), true);
QCOMPARE(Path(u"//"_s).isValid(), true);
QCOMPARE(Path(uR"(\\)"_s).isValid(), true);
QCOMPARE(Path(u"//a"_s).isValid(), true);
QCOMPARE(Path(uR"(\\a)"_s).isValid(), true);
QCOMPARE(Path(u"a//b"_s).isValid(), true);
QCOMPARE(Path(uR"(a\\b)"_s).isValid(), true);
QCOMPARE(Path(u"/a//b"_s).isValid(), true);
QCOMPARE(Path(uR"(/a\\b)"_s).isValid(), true);
for (int i = 0; i <= 31; ++i)
QCOMPARE(Path(QChar(i)).isValid(), false);
QCOMPARE(Path(QChar(127)).isValid(), false);
#if defined Q_OS_MACOS
QCOMPARE(Path(u"\0"_s).isValid(), false);
QCOMPARE(Path(u":"_s).isValid(), false);
#elif defined Q_OS_WIN
QCOMPARE(Path(u"c:"_s).isValid(), false);
QCOMPARE(Path(u"c:/"_s).isValid(), true);
QCOMPARE(Path(uR"(c:\)"_s).isValid(), true);
QCOMPARE(Path(uR"(c:\a)"_s).isValid(), true);
QCOMPARE(Path(uR"(c:\a\b)"_s).isValid(), true);
QCOMPARE(Path(u":"_s).isValid(), false);
QCOMPARE(Path(u"?"_s).isValid(), false);
QCOMPARE(Path(u"\""_s).isValid(), false);
QCOMPARE(Path(u"*"_s).isValid(), false);
QCOMPARE(Path(u"<"_s).isValid(), false);
QCOMPARE(Path(u">"_s).isValid(), false);
QCOMPARE(Path(u"|"_s).isValid(), false);
QCOMPARE(Path(u"a."_s).isValid(), false);
QCOMPARE(Path(u"a.txt."_s).isValid(), false);
QCOMPARE(Path(u"a "_s).isValid(), false);
QCOMPARE(Path(u"a.txt "_s).isValid(), false);
QCOMPARE(Path(u"CON"_s).isValid(), false);
QCOMPARE(Path(u"con"_s).isValid(), false);
QCOMPARE(Path(u"CON.txt"_s).isValid(), false);
QCOMPARE(Path(u"con.txt"_s).isValid(), false);
QCOMPARE(Path(u"CONCON"_s).isValid(), true);
QCOMPARE(Path(u"CONCON.txt"_s).isValid(), true);
QCOMPARE(Path(u"a/CON"_s).isValid(), false);
QCOMPARE(Path(u"a/CON.txt"_s).isValid(), false);
QCOMPARE(Path(u"CON."_s).isValid(), false);
QCOMPARE(Path(u"con."_s).isValid(), false);
#else
QCOMPARE(Path(u"\0"_s).isValid(), false);
#endif
}
void testIsEmpty() const
{
QCOMPARE(Path().isEmpty(), true);
QCOMPARE(Path(u""_s).isEmpty(), true);
QCOMPARE(Path(u"\0"_s).isEmpty(), false);
QCOMPARE(Path(u"/"_s).isEmpty(), false);
QCOMPARE(Path(uR"(\)"_s).isEmpty(), false);
QCOMPARE(Path(u"a"_s).isEmpty(), false);
QCOMPARE(Path(u"/a"_s).isEmpty(), false);
QCOMPARE(Path(uR"(\a)"_s).isEmpty(), false);
QCOMPARE(Path(uR"(c:)"_s).isEmpty(), false);
QCOMPARE(Path(uR"(c:/)"_s).isEmpty(), false);
QCOMPARE(Path(uR"(c:\)"_s).isEmpty(), false);
}
void testIsAbsolute() const
{
QCOMPARE(Path().isAbsolute(), false);
QCOMPARE(Path(u""_s).isAbsolute(), false);
#ifdef Q_OS_WIN
QCOMPARE(Path(u"/"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\)"_s).isAbsolute(), true);
QCOMPARE(Path(u"a"_s).isAbsolute(), false);
QCOMPARE(Path(u"/a"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\a)"_s).isAbsolute(), true);
QCOMPARE(Path(u"//"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\\)"_s).isAbsolute(), true);
QCOMPARE(Path(u"//a"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\\a)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(c:)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(c:/)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(c:\)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(c:\a)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(c:\a\b)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\\?\C:)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\\?\C:/)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\\?\C:\)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\\?\C:\a)"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\\?\C:\a\b)"_s).isAbsolute(), true);
#else
QCOMPARE(Path(u"/"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\)"_s).isAbsolute(), false);
QCOMPARE(Path(u"a"_s).isAbsolute(), false);
QCOMPARE(Path(u"/a"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\a)"_s).isAbsolute(), false);
QCOMPARE(Path(u"//"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\\)"_s).isAbsolute(), false);
QCOMPARE(Path(u"//a"_s).isAbsolute(), true);
QCOMPARE(Path(uR"(\\a)"_s).isAbsolute(), false);
#endif
}
void testIsRelative() const
{
QCOMPARE(Path().isRelative(), true);
QCOMPARE(Path(u""_s).isRelative(), true);
#if defined Q_OS_WIN
QCOMPARE(Path(u"/"_s).isRelative(), false);
QCOMPARE(Path(uR"(\)"_s).isRelative(), false);
QCOMPARE(Path(u"a"_s).isRelative(), true);
QCOMPARE(Path(u"/a"_s).isRelative(), false);
QCOMPARE(Path(uR"(\a)"_s).isRelative(), false);
QCOMPARE(Path(u"//"_s).isRelative(), false);
QCOMPARE(Path(uR"(\\)"_s).isRelative(), false);
QCOMPARE(Path(u"//a"_s).isRelative(), false);
QCOMPARE(Path(uR"(\\a)"_s).isRelative(), false);
QCOMPARE(Path(uR"(c:)"_s).isRelative(), false);
QCOMPARE(Path(uR"(c:/)"_s).isRelative(), false);
QCOMPARE(Path(uR"(c:\)"_s).isRelative(), false);
QCOMPARE(Path(uR"(c:\a)"_s).isRelative(), false);
QCOMPARE(Path(uR"(c:\a\b)"_s).isRelative(), false);
QCOMPARE(Path(uR"(\\?\C:)"_s).isRelative(), false);
QCOMPARE(Path(uR"(\\?\C:/)"_s).isRelative(), false);
QCOMPARE(Path(uR"(\\?\C:\)"_s).isRelative(), false);
QCOMPARE(Path(uR"(\\?\C:\a)"_s).isRelative(), false);
QCOMPARE(Path(uR"(\\?\C:\a\b)"_s).isRelative(), false);
#else
QCOMPARE(Path(u"/"_s).isRelative(), false);
QCOMPARE(Path(uR"(\)"_s).isRelative(), true);
QCOMPARE(Path(u"a"_s).isRelative(), true);
QCOMPARE(Path(u"/a"_s).isRelative(), false);
QCOMPARE(Path(uR"(\a)"_s).isRelative(), true);
QCOMPARE(Path(u"//"_s).isRelative(), false);
QCOMPARE(Path(uR"(\\)"_s).isRelative(), true);
QCOMPARE(Path(u"//a"_s).isRelative(), false);
QCOMPARE(Path(uR"(\\a)"_s).isRelative(), true);
#endif
}
void testRootItem() const
{
QCOMPARE(Path().rootItem(), Path());
QCOMPARE(Path(u""_s).rootItem(), Path());
QCOMPARE(Path(u"/"_s).rootItem(), Path(u"/"_s));
QCOMPARE(Path(uR"(\)"_s).rootItem(), Path(uR"(\)"_s));
QCOMPARE(Path(u"a"_s).rootItem(), Path(u"a"_s));
QCOMPARE(Path(u"/a"_s).rootItem(), Path(u"/"_s));
QCOMPARE(Path(u"/a/b"_s).rootItem(), Path(u"/"_s));
QCOMPARE(Path(u"//"_s).rootItem(), Path(u"/"_s));
QCOMPARE(Path(uR"(\\)"_s).rootItem(), Path(uR"(\\)"_s));
QCOMPARE(Path(u"//a"_s).rootItem(), Path(u"/"_s));
#ifdef Q_OS_WIN
QCOMPARE(Path(uR"(\a)"_s).rootItem(), Path(uR"(\)"_s));
QCOMPARE(Path(uR"(\\a)"_s).rootItem(), Path(uR"(\)"_s));
QCOMPARE(Path(uR"(c:)"_s).rootItem(), Path(uR"(c:)"_s));
QCOMPARE(Path(uR"(c:/)"_s).rootItem(), Path(uR"(c:/)"_s));
QCOMPARE(Path(uR"(c:\)"_s).rootItem(), Path(uR"(c:\)"_s));
QCOMPARE(Path(uR"(c:\)"_s).rootItem(), Path(uR"(c:/)"_s));
QCOMPARE(Path(uR"(c:\a)"_s).rootItem(), Path(uR"(c:\)"_s));
QCOMPARE(Path(uR"(c:\a\b)"_s).rootItem(), Path(uR"(c:\)"_s));
#else
QCOMPARE(Path(uR"(\a)"_s).rootItem(), Path(uR"(\a)"_s));
QCOMPARE(Path(uR"(\\a)"_s).rootItem(), Path(uR"(\\a)"_s));
#endif
}
void testParentPath() const
{
QCOMPARE(Path().parentPath(), Path());
QCOMPARE(Path(u""_s).parentPath(), Path());
QCOMPARE(Path(u"/"_s).parentPath(), Path());
QCOMPARE(Path(uR"(\)"_s).parentPath(), Path());
QCOMPARE(Path(u"a"_s).parentPath(), Path());
QCOMPARE(Path(u"/a"_s).parentPath(), Path(u"/"_s));
QCOMPARE(Path(u"//"_s).parentPath(), Path());
QCOMPARE(Path(uR"(\\)"_s).parentPath(), Path());
QCOMPARE(Path(u"//a"_s).parentPath(), Path(u"/"_s));
QCOMPARE(Path(u"a/b"_s).parentPath(), Path(u"a"_s));
#ifdef Q_OS_WIN
QCOMPARE(Path(uR"(\a)"_s).parentPath(), Path(uR"(\)"_s));
QCOMPARE(Path(uR"(\\a)"_s).parentPath(), Path(uR"(\)"_s));
QCOMPARE(Path(uR"(a\b)"_s).parentPath(), Path(u"a"_s));
QCOMPARE(Path(uR"(c:)"_s).parentPath(), Path());
QCOMPARE(Path(uR"(c:/)"_s).parentPath(), Path());
QCOMPARE(Path(uR"(c:\)"_s).parentPath(), Path());
QCOMPARE(Path(uR"(c:\a)"_s).parentPath(), Path(uR"(c:\)"_s));
QCOMPARE(Path(uR"(c:\a\b)"_s).parentPath(), Path(uR"(c:\a)"_s));
#else
QCOMPARE(Path(uR"(\a)"_s).parentPath(), Path());
QCOMPARE(Path(uR"(\\a)"_s).parentPath(), Path());
QCOMPARE(Path(uR"(a\b)"_s).parentPath(), Path());
#endif
}
// Path &operator/=(const Path &other);
void testOperatorPathAppendAssign() const
{
QCOMPARE((Path() /= Path()), Path());
QCOMPARE((Path(u"a"_s) /= Path()), Path(u"a"_s));
QCOMPARE((Path() /= Path(u"b"_s)), Path(u"b"_s));
QCOMPARE((Path(u"a"_s) /= Path(u"b"_s)), Path(u"a/b"_s));
#ifdef Q_OS_WIN
QCOMPARE((Path(u"c:/"_s) /= Path(u"/"_s)), Path(u"c:/"_s));
QCOMPARE((Path(u"c:/"_s) /= Path(u"a/"_s)), Path(u"c:/a"_s));
#else
QCOMPARE((Path(u"/"_s) /= Path(u"/"_s)), Path(u"/"_s));
QCOMPARE((Path(u"/"_s) /= Path(u"a/"_s)), Path(u"/a"_s));
#endif
}
// Path &operator+=(QStringView str);
void testOperatorAppendAssign() const
{
QCOMPARE((Path() += QString()), Path());
QCOMPARE((Path(u"a"_s) += QString()), Path(u"a"_s));
QCOMPARE((Path() += u"b"), Path(u"b"_s));
QCOMPARE((Path(u"a"_s) += u"b"), Path(u"ab"_s));
QCOMPARE((Path(u"a"_s) += u"/b/"), Path(u"a/b"_s));
}
// Path operator/(const Path &lhs, const Path &rhs)
void testOperatorPathConcat() const
{
QCOMPARE((Path() / Path()), Path());
QCOMPARE((Path(u"a"_s) / Path()), Path(u"a"_s));
QCOMPARE((Path() / Path(u"b"_s)), Path(u"b"_s));
QCOMPARE((Path(u"a"_s) / Path(u"b"_s)), Path(u"a/b"_s));
#ifdef Q_OS_WIN
QCOMPARE((Path(u"c:/"_s) / Path(u"/"_s)), Path(u"c:/"_s));
QCOMPARE((Path(u"c:/"_s) / Path(u"a/"_s)), Path(u"c:/a"_s));
#else
QCOMPARE((Path(u"/"_s) / Path(u"/"_s)), Path(u"/"_s));
QCOMPARE((Path(u"/"_s) / Path(u"a/"_s)), Path(u"/a"_s));
#endif
}
// Path operator+(const Path &lhs, QStringView rhs);
void testOperatorAppend() const
{
QCOMPARE((Path() + QString()), Path());
QCOMPARE((Path(u"a"_s) + QString()), Path(u"a"_s));
QCOMPARE((Path() + u"b"), Path(u"b"_s));
QCOMPARE((Path(u"a"_s) + u"b"), Path(u"ab"_s));
QCOMPARE((Path(u"a"_s) + u"/b/"), Path(u"a/b"_s));
}
void testIterator() const
{
{
const Path emptyPath;
QCOMPARE(emptyPath.begin(), emptyPath.end());
}
{
const Path path {u"/usr/bin/qbittorrent"_s};
QCOMPARE_NE(path.begin(), path.end());
auto iter = path.begin();
QCOMPARE(*iter, Path(u"/usr"_s));
++iter;
QCOMPARE(*iter, Path(u"/usr/bin"_s));
++iter;
QCOMPARE(*iter, Path(u"/usr/bin/qbittorrent"_s));
++iter;
QCOMPARE(iter, path.end());
}
{
const Path path {u"some/path/qbittorrent"_s};
QCOMPARE_NE(path.begin(), path.end());
auto iter = path.begin();
QCOMPARE(*iter, Path(u"some"_s));
++iter;
QCOMPARE(*iter, Path(u"some/path"_s));
++iter;
QCOMPARE(*iter, Path(u"some/path/qbittorrent"_s));
++iter;
QCOMPARE(iter, path.end());
}
#ifdef Q_OS_WIN
{
const Path path {u"C:\\qBittorrent\\qbittorrent.exe"_s};
QCOMPARE_NE(path.begin(), path.end());
auto iter = path.begin();
QCOMPARE(*iter, Path(u"C:\\"_s));
++iter;
QCOMPARE(*iter, Path(u"C:\\qBittorrent"_s));
++iter;
QCOMPARE(*iter, Path(u"C:\\qBittorrent\\qbittorrent.exe"_s));
++iter;
QCOMPARE(iter, path.end());
}
#endif
{
const Path path {u"some//path"_s};
QCOMPARE_NE(path.begin(), path.end());
auto iter = path.begin();
QCOMPARE(*iter, Path(u"some"_s));
++iter;
QCOMPARE(*iter, Path(u"some//path"_s));
QCOMPARE(*iter, Path(u"some/path"_s));
++iter;
QCOMPARE(iter, path.end());
}
}
void testFindRootFolder() const
{
QCOMPARE(Path::findRootFolder({}), {});
QCOMPARE(Path::findRootFolder({Path(u"a"_s)}), {});
QCOMPARE(Path::findRootFolder({Path(u"a"_s), Path(u"b"_s)}), {});
QCOMPARE(Path::findRootFolder({Path(u"a/b"_s)}), Path(u"a"_s));
QCOMPARE(Path::findRootFolder({Path(u"a/b"_s), Path(u"b/c"_s)}), {});
QCOMPARE(Path::findRootFolder({Path(u"a/b"_s), Path(u"a/b/c"_s), Path(u"a/b/d"_s)}), Path(u"a"_s));
}
// TODO: add tests for remaining methods
};
QTEST_APPLESS_MAIN(TestPath)
#include "testpath.moc"