2026-10-12 13:14:08 +03:00
|
|
|
#include "testenv.h"
|
|
|
|
|
|
|
|
|
|
#include "launcherpaths.h"
|
|
|
|
|
#include "localization.h"
|
|
|
|
|
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFile>
|
|
|
|
|
#include <QTemporaryDir>
|
|
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
2026-10-13 08:51:07 +03:00
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
|
#include <qt_windows.h>
|
|
|
|
|
#include <stdlib.h> // _wputenv_s
|
|
|
|
|
#endif
|
2026-10-12 13:14:08 +03:00
|
|
|
|
2026-10-13 08:51:07 +03:00
|
|
|
namespace {
|
2026-10-12 13:14:08 +03:00
|
|
|
|
|
|
|
|
QTemporaryDir *g_sandbox = nullptr;
|
|
|
|
|
|
|
|
|
|
[[noreturn]] void abortSetup(const QString &message)
|
|
|
|
|
{
|
2026-10-13 08:51:07 +03:00
|
|
|
const QString line = QStringLiteral("TestEnv: ") + message + u'\n';
|
|
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
|
// В живую консоль пишем UTF-16 напрямую: кодовая страница консоли тогда не важна.
|
|
|
|
|
const HANDLE handle = GetStdHandle(STD_ERROR_HANDLE);
|
|
|
|
|
DWORD mode = 0;
|
|
|
|
|
if (handle != INVALID_HANDLE_VALUE && GetConsoleMode(handle, &mode)) {
|
|
|
|
|
DWORD written = 0;
|
|
|
|
|
WriteConsoleW(handle, reinterpret_cast<const wchar_t *>(line.utf16()),
|
|
|
|
|
DWORD(line.size()), &written, nullptr);
|
|
|
|
|
std::exit(2);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
// Вывод в трубу (ctest, CI) — UTF-8, как его и читает ctest. Локальная 8-битная
|
|
|
|
|
// кодировка Windows (cp1252/cp1251) превращала кириллицу в «???».
|
|
|
|
|
std::fputs(line.toUtf8().constData(), stderr);
|
|
|
|
|
std::fflush(stderr);
|
2026-10-12 13:14:08 +03:00
|
|
|
std::exit(2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
void TestEnv::prepareSandbox()
|
|
|
|
|
{
|
|
|
|
|
g_sandbox = new QTemporaryDir(QDir::tempPath() + QStringLiteral("/bilauncher-test-XXXXXX"));
|
|
|
|
|
if (!g_sandbox->isValid())
|
|
|
|
|
abortSetup(QStringLiteral("не удалось создать временную папку"));
|
|
|
|
|
|
2026-10-13 08:51:07 +03:00
|
|
|
const QString home = QDir::toNativeSeparators(g_sandbox->path());
|
|
|
|
|
setEnvPath("HOME", home);
|
|
|
|
|
setEnvPath("USERPROFILE", home);
|
|
|
|
|
// LauncherPaths: на Windows QDir::homePath() HOME/USERPROFILE не читает, а эту
|
|
|
|
|
// переменную лаунчер читает везде. Дочерние процессы получают её по наследству.
|
|
|
|
|
setEnvPath("BILAUNCHER_HOME", home);
|
2026-10-12 13:14:08 +03:00
|
|
|
// Чужая Java из окружения машины не должна влиять на выбор Java в тестах.
|
|
|
|
|
qunsetenv("JAVA_HOME");
|
|
|
|
|
|
|
|
|
|
std::atexit([] {
|
|
|
|
|
delete g_sandbox;
|
|
|
|
|
g_sandbox = nullptr;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestEnv::finishSetup()
|
|
|
|
|
{
|
|
|
|
|
QCoreApplication::setApplicationName(QStringLiteral("BiLauncher"));
|
|
|
|
|
QCoreApplication::setOrganizationName(QStringLiteral("GaleonDev"));
|
|
|
|
|
|
|
|
|
|
const QString root = QDir::cleanPath(LauncherPaths::rootDir());
|
|
|
|
|
const QString sandbox = QDir::cleanPath(g_sandbox->path());
|
2026-10-13 08:51:07 +03:00
|
|
|
const QString game = QDir::cleanPath(LauncherPaths::defaultMinecraftDir());
|
|
|
|
|
// Ни одна папка лаунчера не должна указывать на настоящий профиль: resetLauncherRoot()
|
|
|
|
|
// стирает rootDir() целиком.
|
|
|
|
|
for (const QString &path : {root, game}) {
|
|
|
|
|
if (!path.startsWith(sandbox + u'/'))
|
|
|
|
|
abortSetup(QStringLiteral("путь лаунчера %1 вне песочницы %2 — отказываюсь запускаться")
|
|
|
|
|
.arg(QDir::toNativeSeparators(path), QDir::toNativeSeparators(sandbox)));
|
2026-10-12 13:14:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Localization::instance().load())
|
|
|
|
|
abortSetup(QStringLiteral("не загрузился каталог переводов"));
|
|
|
|
|
Localization::instance().setLanguage(QStringLiteral("en"));
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-13 08:51:07 +03:00
|
|
|
void TestEnv::setEnvPath(const char *name, const QString &path)
|
|
|
|
|
{
|
|
|
|
|
// На Windows qputenv() пишет в ANSI-кодировке и испортил бы, например,
|
|
|
|
|
// кириллическое имя пользователя во временном пути.
|
|
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
|
_wputenv_s(reinterpret_cast<const wchar_t *>(QString::fromLatin1(name).utf16()),
|
|
|
|
|
reinterpret_cast<const wchar_t *>(path.utf16()));
|
|
|
|
|
#else
|
|
|
|
|
qputenv(name, QFile::encodeName(path));
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-12 13:14:08 +03:00
|
|
|
QString TestEnv::homeDir()
|
|
|
|
|
{
|
|
|
|
|
return g_sandbox->path();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString TestEnv::freshDir(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
const QString path = g_sandbox->path() + QStringLiteral("/work/") + name;
|
|
|
|
|
QDir(path).removeRecursively();
|
|
|
|
|
QDir().mkpath(path);
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TestEnv::resetLauncherRoot()
|
|
|
|
|
{
|
2026-10-13 08:51:07 +03:00
|
|
|
QDir(LauncherPaths::rootDir()).removeRecursively();
|
2026-10-12 13:14:08 +03:00
|
|
|
}
|