summaryrefslogtreecommitdiff
path: root/archived/projt-launcher/tests/FileSystem_test.cpp
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:51:45 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:51:45 +0300
commitd3261e64152397db2dca4d691a990c6bc2a6f4dd (patch)
treefac2f7be638651181a72453d714f0f96675c2b8b /archived/projt-launcher/tests/FileSystem_test.cpp
parent31b9a8949ed0a288143e23bf739f2eb64fdc63be (diff)
downloadProject-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.tar.gz
Project-Tick-d3261e64152397db2dca4d691a990c6bc2a6f4dd.zip
NOISSUE add archived projects
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'archived/projt-launcher/tests/FileSystem_test.cpp')
-rw-r--r--archived/projt-launcher/tests/FileSystem_test.cpp899
1 files changed, 899 insertions, 0 deletions
diff --git a/archived/projt-launcher/tests/FileSystem_test.cpp b/archived/projt-launcher/tests/FileSystem_test.cpp
new file mode 100644
index 0000000000..ed46154eea
--- /dev/null
+++ b/archived/projt-launcher/tests/FileSystem_test.cpp
@@ -0,0 +1,899 @@
+// SPDX-License-Identifier: GPL-3.0-only
+// SPDX-FileCopyrightText: 2026 Project Tick
+// SPDX-FileContributor: Project Tick Team
+/*
+ * ProjT Launcher - Minecraft Launcher
+ * Copyright (C) 2026 Project Tick
+ *
+ * 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, version 3.
+ *
+ * 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.
+ */
+
+#include <QDir>
+#include <QFile>
+#include <QStandardPaths>
+#include <QTemporaryDir>
+#include <QTest>
+#include <memory>
+
+#include <tasks/Task.h>
+
+#include <FileSystem.h>
+#include <StringUtils.h>
+
+#include <filesystem>
+namespace fs = std::filesystem;
+
+#if defined(Q_OS_WIN32)
+[[maybe_unused]] static bool canCreateSymlink()
+{
+ QTemporaryDir tempDir;
+ if (!tempDir.isValid())
+ return false;
+
+ const QString target = FS::PathCombine(tempDir.path(), "target.txt");
+ QFile file(target);
+ if (!file.open(QIODevice::WriteOnly))
+ return false;
+ file.write("x");
+ file.close();
+
+ const QString link = FS::PathCombine(tempDir.path(), "link.txt");
+ std::error_code ec;
+ fs::create_symlink(StringUtils::toStdString(target), StringUtils::toStdString(link), ec);
+ if (ec)
+ return false;
+
+ fs::remove(StringUtils::toStdString(link), ec);
+ return true;
+}
+#else
+[[maybe_unused]] static bool canCreateSymlink()
+{
+ return true;
+}
+#endif
+
+class LinkTask : public Task
+{
+ Q_OBJECT
+
+ friend class FileSystemTest;
+
+ LinkTask(QString src, QString dst)
+ {
+ m_lnk = new FS::create_link(src, dst, this);
+ m_lnk->debug(true);
+ }
+
+ ~LinkTask()
+ {
+ delete m_lnk;
+ }
+
+ void matcher(Filter filter)
+ {
+ m_lnk->matcher(filter);
+ }
+
+ void linkRecursively(bool recursive)
+ {
+ m_lnk->linkRecursively(recursive);
+ m_linkRecursive = recursive;
+ }
+
+ void whitelist(bool b)
+ {
+ m_lnk->whitelist(b);
+ }
+
+ void setMaxDepth(int depth)
+ {
+ m_lnk->setMaxDepth(depth);
+ }
+
+ private:
+ void executeTask() override
+ {
+ if (!(*m_lnk)())
+ {
+#if defined Q_OS_WIN32
+ if (!m_useHard)
+ {
+ qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";
+
+ qDebug() << "atempting to run with privelage";
+ connect(m_lnk,
+ &FS::create_link::finishedPrivileged,
+ this,
+ [this](bool gotResults)
+ {
+ if (gotResults)
+ {
+ emitSucceeded();
+ }
+ else
+ {
+ qDebug() << "Privileged run exited without results!";
+ emitFailed();
+ }
+ });
+ m_lnk->runPrivileged();
+ }
+ else
+ {
+ qDebug() << "Link Failed!" << m_lnk->getOSError().value() << m_lnk->getOSError().message().c_str();
+ }
+#else
+ qDebug() << "Link Failed!" << m_lnk->getOSError().value() << m_lnk->getOSError().message().c_str();
+#endif
+ }
+ else
+ {
+ emitSucceeded();
+ }
+ }
+
+ FS::create_link* m_lnk;
+#if defined Q_OS_WIN32
+ bool m_useHard = false;
+#endif
+ bool m_linkRecursive = true;
+};
+
+class FileSystemTest : public QObject
+{
+ Q_OBJECT
+
+ const QString bothSlash = "/foo/";
+ const QString trailingSlash = "foo/";
+ const QString leadingSlash = "/foo";
+
+ private slots:
+ void test_pathCombine()
+ {
+ QCOMPARE(QString("/foo/foo"), FS::PathCombine(bothSlash, bothSlash));
+ QCOMPARE(QString("foo/foo"), FS::PathCombine(trailingSlash, trailingSlash));
+ QCOMPARE(QString("/foo/foo"), FS::PathCombine(leadingSlash, leadingSlash));
+
+ QCOMPARE(QString("/foo/foo/foo"), FS::PathCombine(bothSlash, bothSlash, bothSlash));
+ QCOMPARE(QString("foo/foo/foo"), FS::PathCombine(trailingSlash, trailingSlash, trailingSlash));
+ QCOMPARE(QString("/foo/foo/foo"), FS::PathCombine(leadingSlash, leadingSlash, leadingSlash));
+ }
+
+ void test_PathCombine1_data()
+ {
+ QTest::addColumn<QString>("result");
+ QTest::addColumn<QString>("path1");
+ QTest::addColumn<QString>("path2");
+
+ QTest::newRow("qt 1") << "/abc/def/ghi/jkl" << "/abc/def" << "ghi/jkl";
+ QTest::newRow("qt 2") << "/abc/def/ghi/jkl" << "/abc/def/" << "ghi/jkl";
+#if defined(Q_OS_WIN)
+ QTest::newRow("win native, from C:") << "C:/abc" << "C:" << "abc";
+ QTest::newRow("win native 1") << "C:/abc/def/ghi/jkl" << "C:\\abc\\def" << "ghi\\jkl";
+ QTest::newRow("win native 2") << "C:/abc/def/ghi/jkl" << "C:\\abc\\def\\" << "ghi\\jkl";
+#endif
+ }
+
+ void test_PathCombine1()
+ {
+ QFETCH(QString, result);
+ QFETCH(QString, path1);
+ QFETCH(QString, path2);
+
+ QCOMPARE(FS::PathCombine(path1, path2), result);
+ }
+
+ void test_PathCombine2_data()
+ {
+ QTest::addColumn<QString>("result");
+ QTest::addColumn<QString>("path1");
+ QTest::addColumn<QString>("path2");
+ QTest::addColumn<QString>("path3");
+
+ QTest::newRow("qt 1") << "/abc/def/ghi/jkl" << "/abc" << "def" << "ghi/jkl";
+ QTest::newRow("qt 2") << "/abc/def/ghi/jkl" << "/abc/" << "def" << "ghi/jkl";
+ QTest::newRow("qt 3") << "/abc/def/ghi/jkl" << "/abc" << "def/" << "ghi/jkl";
+ QTest::newRow("qt 4") << "/abc/def/ghi/jkl" << "/abc/" << "def/" << "ghi/jkl";
+#if defined(Q_OS_WIN)
+ QTest::newRow("win 1") << "C:/abc/def/ghi/jkl" << "C:\\abc" << "def" << "ghi\\jkl";
+ QTest::newRow("win 2") << "C:/abc/def/ghi/jkl" << "C:\\abc\\" << "def" << "ghi\\jkl";
+ QTest::newRow("win 3") << "C:/abc/def/ghi/jkl" << "C:\\abc" << "def\\" << "ghi\\jkl";
+ QTest::newRow("win 4") << "C:/abc/def/ghi/jkl" << "C:\\abc\\" << "def" << "ghi\\jkl";
+#endif
+ }
+
+ void test_PathCombine2()
+ {
+ QFETCH(QString, result);
+ QFETCH(QString, path1);
+ QFETCH(QString, path2);
+ QFETCH(QString, path3);
+
+ QCOMPARE(FS::PathCombine(path1, path2, path3), result);
+ }
+
+ void test_copy()
+ {
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+ FS::copy c(folder, target_dir.path());
+ c();
+
+ for (auto entry : target_dir.entryList())
+ {
+ qDebug() << entry;
+ }
+ QVERIFY(target_dir.entryList().contains("pack.mcmeta"));
+ QVERIFY(target_dir.entryList().contains("assets"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_copy_with_blacklist()
+ {
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+ FS::copy c(folder, target_dir.path());
+ auto re = Filters::regexp(QRegularExpression("[.]?mcmeta"));
+ c.matcher(re);
+ c();
+
+ for (auto entry : target_dir.entryList())
+ {
+ qDebug() << entry;
+ }
+ QVERIFY(!target_dir.entryList().contains("pack.mcmeta"));
+ QVERIFY(target_dir.entryList().contains("assets"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_copy_with_whitelist()
+ {
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+ FS::copy c(folder, target_dir.path());
+ auto re = Filters::regexp(QRegularExpression("[.]?mcmeta"));
+ c.matcher(re);
+ c.whitelist(true);
+ c();
+
+ for (auto entry : target_dir.entryList())
+ {
+ qDebug() << entry;
+ }
+ QVERIFY(target_dir.entryList().contains("pack.mcmeta"));
+ QVERIFY(!target_dir.entryList().contains("assets"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_copy_with_dot_hidden()
+ {
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+ FS::copy c(folder, target_dir.path());
+ c();
+
+ auto filter = QDir::Filter::Files | QDir::Filter::Dirs | QDir::Filter::Hidden;
+
+ for (auto entry : target_dir.entryList(filter))
+ {
+ qDebug() << entry;
+ }
+
+ QVERIFY(target_dir.entryList(filter).contains(".secret_folder"));
+ target_dir.cd(".secret_folder");
+ QVERIFY(target_dir.entryList(filter).contains(".secret_file.txt"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_copy_single_file()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+
+ {
+ QString file = QFINDTESTDATA("testdata/FileSystem/test_folder/pack.mcmeta");
+
+ qDebug() << "From:" << file << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "pack.mcmeta"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+ FS::copy c(file, target_dir.filePath("pack.mcmeta"));
+ c();
+
+ auto filter = QDir::Filter::Files;
+
+ for (auto entry : target_dir.entryList(filter))
+ {
+ qDebug() << entry;
+ }
+
+ QVERIFY(target_dir.entryList(filter).contains("pack.mcmeta"));
+ }
+ }
+
+ void test_getDesktop()
+ {
+ QCOMPARE(FS::getDesktopDir(), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
+ }
+
+ void test_link()
+ {
+#if defined(Q_OS_WIN32)
+ if (!canCreateSymlink())
+ QSKIP("Symlink creation not permitted on this Windows runner.");
+#endif
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+
+ LinkTask lnk_tsk(folder, target_dir.path());
+ lnk_tsk.linkRecursively(false);
+ connect(&lnk_tsk,
+ &Task::finished,
+ [&lnk_tsk]
+ {
+ QVERIFY2(lnk_tsk.wasSuccessful(),
+ "Task finished but was not successful when it should have been.");
+ });
+ lnk_tsk.start();
+
+ QVERIFY2(QTest::qWaitFor([&lnk_tsk]() { return lnk_tsk.isFinished(); }, 100000),
+ "Task didn't finish as it should.");
+
+ for (auto entry : target_dir.entryList())
+ {
+ qDebug() << entry;
+ QFileInfo entry_lnk_info(target_dir.filePath(entry));
+ if (!entry_lnk_info.isDir())
+ QVERIFY(!entry_lnk_info.isSymLink());
+ }
+
+ QFileInfo lnk_info(target_dir.path());
+ QVERIFY(lnk_info.exists());
+ QVERIFY(lnk_info.isSymLink());
+
+ QVERIFY(target_dir.entryList().contains("pack.mcmeta"));
+ QVERIFY(target_dir.entryList().contains("assets"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_hard_link()
+ {
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ // use working dir to prevent makeing a hard link to a tmpfs or across devices
+ QTemporaryDir tempDir("./tmp");
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+ FS::create_link lnk(folder, target_dir.path());
+ lnk.useHardLinks(true);
+ lnk.debug(true);
+ if (!lnk())
+ {
+ qDebug() << "Link Failed!" << lnk.getOSError().value() << lnk.getOSError().message().c_str();
+ }
+
+ for (auto entry : target_dir.entryList())
+ {
+ qDebug() << entry;
+ QFileInfo entry_lnk_info(target_dir.filePath(entry));
+ QVERIFY(!entry_lnk_info.isSymLink());
+ QFileInfo entry_orig_info(QDir(folder).filePath(entry));
+ if (!entry_lnk_info.isDir())
+ {
+ qDebug() << "hard link equivalency?" << entry_lnk_info.absoluteFilePath() << "vs"
+ << entry_orig_info.absoluteFilePath();
+ QVERIFY(fs::equivalent(fs::path(StringUtils::toStdString(entry_lnk_info.absoluteFilePath())),
+ fs::path(StringUtils::toStdString(entry_orig_info.absoluteFilePath()))));
+ }
+ }
+
+ QFileInfo lnk_info(target_dir.path());
+ QVERIFY(lnk_info.exists());
+ QVERIFY(!lnk_info.isSymLink());
+
+ QVERIFY(target_dir.entryList().contains("pack.mcmeta"));
+ QVERIFY(target_dir.entryList().contains("assets"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_link_with_blacklist()
+ {
+#if defined(Q_OS_WIN32)
+ if (!canCreateSymlink())
+ QSKIP("Symlink creation not permitted on this Windows runner.");
+#endif
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+
+ LinkTask lnk_tsk(folder, target_dir.path());
+ auto re = Filters::regexp(QRegularExpression("[.]?mcmeta"));
+ lnk_tsk.matcher(re);
+ lnk_tsk.linkRecursively(true);
+ connect(&lnk_tsk,
+ &Task::finished,
+ [&lnk_tsk]
+ {
+ QVERIFY2(lnk_tsk.wasSuccessful(),
+ "Task finished but was not successful when it should have been.");
+ });
+ lnk_tsk.start();
+
+ QVERIFY2(QTest::qWaitFor([&lnk_tsk]() { return lnk_tsk.isFinished(); }, 100000),
+ "Task didn't finish as it should.");
+
+ for (auto entry : target_dir.entryList())
+ {
+ qDebug() << entry;
+ QFileInfo entry_lnk_info(target_dir.filePath(entry));
+ if (!entry_lnk_info.isDir())
+ QVERIFY(entry_lnk_info.isSymLink());
+ }
+
+ QFileInfo lnk_info(target_dir.path());
+ QVERIFY(lnk_info.exists());
+
+ QVERIFY(!target_dir.entryList().contains("pack.mcmeta"));
+ QVERIFY(target_dir.entryList().contains("assets"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_link_with_whitelist()
+ {
+#if defined(Q_OS_WIN32)
+ if (!canCreateSymlink())
+ QSKIP("Symlink creation not permitted on this Windows runner.");
+#endif
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+
+ LinkTask lnk_tsk(folder, target_dir.path());
+ auto re = Filters::regexp(QRegularExpression("[.]?mcmeta"));
+ lnk_tsk.matcher(re);
+ lnk_tsk.linkRecursively(true);
+ lnk_tsk.whitelist(true);
+ connect(&lnk_tsk,
+ &Task::finished,
+ [&lnk_tsk]
+ {
+ QVERIFY2(lnk_tsk.wasSuccessful(),
+ "Task finished but was not successful when it should have been.");
+ });
+ lnk_tsk.start();
+
+ QVERIFY2(QTest::qWaitFor([&lnk_tsk]() { return lnk_tsk.isFinished(); }, 100000),
+ "Task didn't finish as it should.");
+
+ for (auto entry : target_dir.entryList())
+ {
+ qDebug() << entry;
+ QFileInfo entry_lnk_info(target_dir.filePath(entry));
+ if (!entry_lnk_info.isDir())
+ QVERIFY(entry_lnk_info.isSymLink());
+ }
+
+ QFileInfo lnk_info(target_dir.path());
+ QVERIFY(lnk_info.exists());
+
+ QVERIFY(target_dir.entryList().contains("pack.mcmeta"));
+ QVERIFY(!target_dir.entryList().contains("assets"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_link_with_dot_hidden()
+ {
+#if defined(Q_OS_WIN32)
+ if (!canCreateSymlink())
+ QSKIP("Symlink creation not permitted on this Windows runner.");
+#endif
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+
+ LinkTask lnk_tsk(folder, target_dir.path());
+ lnk_tsk.linkRecursively(true);
+ connect(&lnk_tsk,
+ &Task::finished,
+ [&lnk_tsk]
+ {
+ QVERIFY2(lnk_tsk.wasSuccessful(),
+ "Task finished but was not successful when it should have been.");
+ });
+ lnk_tsk.start();
+
+ QVERIFY2(QTest::qWaitFor([&lnk_tsk]() { return lnk_tsk.isFinished(); }, 100000),
+ "Task didn't finish as it should.");
+
+ auto filter = QDir::Filter::Files | QDir::Filter::Dirs | QDir::Filter::Hidden;
+
+ for (auto entry : target_dir.entryList(filter))
+ {
+ qDebug() << entry;
+ QFileInfo entry_lnk_info(target_dir.filePath(entry));
+ if (!entry_lnk_info.isDir())
+ QVERIFY(entry_lnk_info.isSymLink());
+ }
+
+ QFileInfo lnk_info(target_dir.path());
+ QVERIFY(lnk_info.exists());
+
+ QVERIFY(target_dir.entryList(filter).contains(".secret_folder"));
+ target_dir.cd(".secret_folder");
+ QVERIFY(target_dir.entryList(filter).contains(".secret_file.txt"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_link_single_file()
+ {
+#if defined(Q_OS_WIN32)
+ if (!canCreateSymlink())
+ QSKIP("Symlink creation not permitted on this Windows runner.");
+#endif
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+
+ {
+ QString file = QFINDTESTDATA("testdata/FileSystem/test_folder/pack.mcmeta");
+
+ qDebug() << "From:" << file << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "pack.mcmeta"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+
+ LinkTask lnk_tsk(file, target_dir.filePath("pack.mcmeta"));
+ connect(&lnk_tsk,
+ &Task::finished,
+ [&lnk_tsk]
+ {
+ QVERIFY2(lnk_tsk.wasSuccessful(),
+ "Task finished but was not successful when it should have been.");
+ });
+ lnk_tsk.start();
+
+ QVERIFY2(QTest::qWaitFor([&lnk_tsk]() { return lnk_tsk.isFinished(); }, 100000),
+ "Task didn't finish as it should.");
+
+ auto filter = QDir::Filter::Files;
+
+ for (auto entry : target_dir.entryList(filter))
+ {
+ qDebug() << entry;
+ }
+
+ QFileInfo lnk_info(target_dir.filePath("pack.mcmeta"));
+ QVERIFY(lnk_info.exists());
+ QVERIFY(lnk_info.isSymLink());
+
+ QVERIFY(target_dir.entryList(filter).contains("pack.mcmeta"));
+ }
+ }
+
+ void test_link_with_max_depth()
+ {
+#if defined(Q_OS_WIN32)
+ if (!canCreateSymlink())
+ QSKIP("Symlink creation not permitted on this Windows runner.");
+#endif
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+
+ LinkTask lnk_tsk(folder, target_dir.path());
+ lnk_tsk.linkRecursively(true);
+ lnk_tsk.setMaxDepth(0);
+ connect(&lnk_tsk,
+ &Task::finished,
+ [&lnk_tsk]
+ {
+ QVERIFY2(lnk_tsk.wasSuccessful(),
+ "Task finished but was not successful when it should have been.");
+ });
+ lnk_tsk.start();
+
+ QVERIFY2(QTest::qWaitFor([&lnk_tsk]() { return lnk_tsk.isFinished(); }, 100000),
+ "Task didn't finish as it should.");
+
+ QVERIFY(!QFileInfo(target_dir.path()).isSymLink());
+
+ auto filter = QDir::Filter::Files | QDir::Filter::Dirs | QDir::Filter::Hidden;
+ for (auto entry : target_dir.entryList(filter))
+ {
+ qDebug() << entry;
+ if (entry == "." || entry == "..")
+ continue;
+ QFileInfo entry_lnk_info(target_dir.filePath(entry));
+ QVERIFY(entry_lnk_info.isSymLink());
+ }
+
+ QFileInfo lnk_info(target_dir.path());
+ QVERIFY(lnk_info.exists());
+ QVERIFY(!lnk_info.isSymLink());
+
+ QVERIFY(target_dir.entryList().contains("pack.mcmeta"));
+ QVERIFY(target_dir.entryList().contains("assets"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_link_with_no_max_depth()
+ {
+#if defined(Q_OS_WIN32)
+ if (!canCreateSymlink())
+ QSKIP("Symlink creation not permitted on this Windows runner.");
+#endif
+ QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
+ auto f = [&folder]()
+ {
+ QTemporaryDir tempDir;
+ tempDir.setAutoRemove(true);
+ qDebug() << "From:" << folder << "To:" << tempDir.path();
+
+ QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
+ qDebug() << tempDir.path();
+ qDebug() << target_dir.path();
+
+ LinkTask lnk_tsk(folder, target_dir.path());
+ lnk_tsk.linkRecursively(true);
+ lnk_tsk.setMaxDepth(-1);
+ connect(&lnk_tsk,
+ &Task::finished,
+ [&lnk_tsk]
+ {
+ QVERIFY2(lnk_tsk.wasSuccessful(),
+ "Task finished but was not successful when it should have been.");
+ });
+ lnk_tsk.start();
+
+ QVERIFY2(QTest::qWaitFor([&lnk_tsk]() { return lnk_tsk.isFinished(); }, 100000),
+ "Task didn't finish as it should.");
+
+ std::function<void(QString)> verify_check = [&verify_check](QString check_path)
+ {
+ QDir check_dir(check_path);
+ auto filter = QDir::Filter::Files | QDir::Filter::Dirs | QDir::Filter::Hidden;
+ for (auto entry : check_dir.entryList(filter))
+ {
+ QFileInfo entry_lnk_info(check_dir.filePath(entry));
+ qDebug() << entry << check_dir.filePath(entry);
+ if (!entry_lnk_info.isDir())
+ {
+ QVERIFY(entry_lnk_info.isSymLink());
+ }
+ else if (entry != "." && entry != "..")
+ {
+ qDebug() << "Decending tree to verify symlinks:" << check_dir.filePath(entry);
+ verify_check(entry_lnk_info.filePath());
+ }
+ }
+ };
+
+ verify_check(target_dir.path());
+
+ QFileInfo lnk_info(target_dir.path());
+ QVERIFY(lnk_info.exists());
+
+ QVERIFY(target_dir.entryList().contains("pack.mcmeta"));
+ QVERIFY(target_dir.entryList().contains("assets"));
+ };
+
+ // first try variant without trailing /
+ QVERIFY(!folder.endsWith('/'));
+ f();
+
+ // then variant with trailing /
+ folder.append('/');
+ QVERIFY(folder.endsWith('/'));
+ f();
+ }
+
+ void test_path_depth()
+ {
+ QCOMPARE(FS::pathDepth(""), 0);
+ QCOMPARE(FS::pathDepth("."), 0);
+ QCOMPARE(FS::pathDepth("foo.txt"), 0);
+ QCOMPARE(FS::pathDepth("./foo.txt"), 0);
+ QCOMPARE(FS::pathDepth("./bar/foo.txt"), 1);
+ QCOMPARE(FS::pathDepth("../bar/foo.txt"), 0);
+ QCOMPARE(FS::pathDepth("/bar/foo.txt"), 1);
+ QCOMPARE(FS::pathDepth("baz/bar/foo.txt"), 2);
+ QCOMPARE(FS::pathDepth("/baz/bar/foo.txt"), 2);
+ QCOMPARE(FS::pathDepth("./baz/bar/foo.txt"), 2);
+ QCOMPARE(FS::pathDepth("/baz/../bar/foo.txt"), 1);
+ }
+
+ void test_path_trunc()
+ {
+ QCOMPARE(FS::pathTruncate("", 0), QDir::toNativeSeparators(""));
+ QCOMPARE(FS::pathTruncate("foo.txt", 0), QDir::toNativeSeparators(""));
+ QCOMPARE(FS::pathTruncate("foo.txt", 1), QDir::toNativeSeparators(""));
+ QCOMPARE(FS::pathTruncate("./bar/foo.txt", 0), QDir::toNativeSeparators("./bar"));
+ QCOMPARE(FS::pathTruncate("./bar/foo.txt", 1), QDir::toNativeSeparators("./bar"));
+ QCOMPARE(FS::pathTruncate("/bar/foo.txt", 1), QDir::toNativeSeparators("/bar"));
+ QCOMPARE(FS::pathTruncate("bar/foo.txt", 1), QDir::toNativeSeparators("bar"));
+ QCOMPARE(FS::pathTruncate("baz/bar/foo.txt", 2), QDir::toNativeSeparators("baz/bar"));
+#if defined(Q_OS_WIN)
+ QCOMPARE(FS::pathTruncate("C:\\bar\\foo.txt", 1), QDir::toNativeSeparators("C:\\bar"));
+#endif
+ }
+};
+
+QTEST_GUILESS_MAIN(FileSystemTest)
+
+#include "FileSystem_test.moc"