Files
BiLauncher/tests/common/testenv.cpp
T

115 lines
4.2 KiB
C++
Raw Permalink Normal View History

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
}