1 parent
41599fa82f
commit
0dd6bef715
12 files changed
+161
-64
No files matched your search
@@ -21,6 +21,19 @@
|
|||||||
|
|
||||||
На Linux папка лаунчера получается `~/BiLauncher`, без точки, то есть видимая.
|
На Linux папка лаунчера получается `~/BiLauncher`, без точки, то есть видимая.
|
||||||
|
|
||||||
|
## BILAUNCHER_HOME
|
||||||
|
|
||||||
|
`homeOverride()` читает переменную окружения `BILAUNCHER_HOME`. Если в ней абсолютный путь, он
|
||||||
|
заменяет домашнюю папку (`~` и `%USERPROFILE%` в таблице выше) для всех путей лаунчера, включая
|
||||||
|
папку игры по умолчанию. Пустое или относительное значение не учитывается. Остальной Qt
|
||||||
|
(`QDir::homePath()`, `QStandardPaths`) эту переменную не видит.
|
||||||
|
|
||||||
|
Переменная нужна тестам и дымовой проверке на Windows: там `QDir::homePath()` спрашивает профиль
|
||||||
|
у системы и `USERPROFILE` игнорирует, так что иначе их нельзя увести из настоящего
|
||||||
|
`%APPDATA%\BiLauncher`. Новых возможностей она не даёт: кто управляет окружением процесса, на
|
||||||
|
Linux и macOS и так подменит `HOME`. Чтобы случайно оставленную переменную было видно, `main.cpp`
|
||||||
|
при старте пишет в лог предупреждение с итоговой папкой лаунчера.
|
||||||
|
|
||||||
Внутри `rootDir()`:
|
Внутри `rootDir()`:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
+8
-7
@@ -70,13 +70,14 @@ CMake, тесты появятся в панели «Тесты».
|
|||||||
|
|
||||||
## Как тесты изолированы
|
## Как тесты изолированы
|
||||||
|
|
||||||
**Файлы.** `LauncherPaths` строит пути от `QDir::homePath()`. Общий `main` тестов
|
**Файлы.** `LauncherPaths` строит пути от домашней папки. Общий `main` тестов
|
||||||
(`tests/common/testenv.h`) до создания приложения подменяет `HOME` на временную папку, и каждый
|
(`tests/common/testenv.h`) до создания приложения направляет `BILAUNCHER_HOME` (а заодно `HOME`
|
||||||
процесс работает в своей. Если путь лаунчера всё же оказался вне песочницы, процесс сразу
|
и `USERPROFILE`) на временную папку, и каждый процесс работает в своей, на всех ОС, параллельно.
|
||||||
завершается. На Windows `QDir::homePath()` переменные окружения не читает, поэтому там тесты идут
|
`BILAUNCHER_HOME` нужна ради Windows: там `QDir::homePath()` берёт профиль у системы и `HOME`
|
||||||
в настоящей `%APPDATA%\BiLauncher` учётной записи раннера, строго по одному, а за собой папку
|
с `USERPROFILE` не читает. Дочерние процессы наследуют переменную. Если папка лаунчера или папка
|
||||||
стирают. Если папка уже есть и создана не тестами (нет метки `.bilauncher-test-sandbox`), тесты
|
игры по умолчанию всё же оказалась вне песочницы, процесс сразу завершается с кодом 2 и ничего не
|
||||||
отказываются запускаться.
|
трогает. Дымовая проверка установленной сборки на Windows (`smoke_installed.ps1`) тоже запускает
|
||||||
|
лаунчер с `BILAUNCHER_HOME` на временную папку.
|
||||||
|
|
||||||
**Сеть.** Адреса серверов в сервисах зашиты константами, а свои `QNetworkAccessManager` они
|
**Сеть.** Адреса серверов в сервисах зашиты константами, а свои `QNetworkAccessManager` они
|
||||||
создают сами. Зато прокси и SSL-настройки у Qt общие на процесс, и код лаунчера их не трогает.
|
создают сами. Зато прокси и SSL-настройки у Qt общие на процесс, и код лаунчера их не трогает.
|
||||||
|
|||||||
+6
-1
@@ -8,6 +8,7 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QtCore/private/qzipreader_p.h>
|
#include <QtCore/private/qzipreader_p.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -46,7 +47,11 @@ bool isNativeLibraryFile(const QString &fileName)
|
|||||||
for (const QString &suffix : suffixes)
|
for (const QString &suffix : suffixes)
|
||||||
if (fileName.endsWith(suffix, Qt::CaseInsensitive))
|
if (fileName.endsWith(suffix, Qt::CaseInsensitive))
|
||||||
return true;
|
return true;
|
||||||
return fileName.contains(QStringLiteral(".so.")); // libfoo.so.1
|
// Версионированные so (libfoo.so.1, libfoo.so.1.2.3). Хвост — строго цифры,
|
||||||
|
// иначе в натив попадают служебные файлы LWJGL вроде liblwjgl.so.sha1 / .so.git.
|
||||||
|
static const QRegularExpression versionedSo(QStringLiteral("\\.so(\\.\\d+)+$"),
|
||||||
|
QRegularExpression::CaseInsensitiveOption);
|
||||||
|
return versionedSo.match(fileName).hasMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
+20
-3
@@ -3,21 +3,38 @@
|
|||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const QString kFolderName = QStringLiteral("BiLauncher");
|
const QString kFolderName = QStringLiteral("BiLauncher");
|
||||||
|
|
||||||
|
// Домашняя папка, от которой строятся все пути (см. LauncherPaths::homeOverride()).
|
||||||
|
QString homeBase()
|
||||||
|
{
|
||||||
|
const QString overridden = LauncherPaths::homeOverride();
|
||||||
|
return overridden.isEmpty() ? QDir::homePath() : overridden;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
QString LauncherPaths::homeOverride()
|
||||||
|
{
|
||||||
|
// Относительный путь зависел бы от текущей папки процесса — такой не принимаем.
|
||||||
|
const QString value = QDir::fromNativeSeparators(qEnvironmentVariable("BILAUNCHER_HOME"));
|
||||||
|
if (value.isEmpty() || !QDir::isAbsolutePath(value))
|
||||||
|
return QString();
|
||||||
|
return QDir::cleanPath(value);
|
||||||
|
}
|
||||||
|
|
||||||
QString LauncherPaths::containerDir()
|
QString LauncherPaths::containerDir()
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
return QDir::homePath() + QStringLiteral("/AppData/Roaming");
|
return homeBase() + QStringLiteral("/AppData/Roaming");
|
||||||
#elif defined(Q_OS_MACOS)
|
#elif defined(Q_OS_MACOS)
|
||||||
return QDir::homePath() + QStringLiteral("/Library/Application Support");
|
return homeBase() + QStringLiteral("/Library/Application Support");
|
||||||
#else // Linux и прочие Unix-системы
|
#else // Linux и прочие Unix-системы
|
||||||
return QDir::homePath();
|
return homeBase();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,14 @@
|
|||||||
|
|
||||||
namespace LauncherPaths {
|
namespace LauncherPaths {
|
||||||
|
|
||||||
|
// Все пути строятся от домашней папки пользователя (QDir::homePath()). Переменная
|
||||||
|
// окружения BILAUNCHER_HOME с абсолютным путём подменяет её — только для путей
|
||||||
|
// лаунчера (папка лаунчера и папка игры по умолчанию), остальной Qt её не видит.
|
||||||
|
// Нужна тестам и дымовой проверке на Windows: там QDir::homePath() спрашивает
|
||||||
|
// профиль у системы и HOME/USERPROFILE игнорирует. Пустое или относительное
|
||||||
|
// значение не учитывается. Возвращает подменённую папку или пустую строку.
|
||||||
|
QString homeOverride();
|
||||||
|
|
||||||
QString containerDir();
|
QString containerDir();
|
||||||
QString rootDir();
|
QString rootDir();
|
||||||
QString defaultMinecraftDir();
|
QString defaultMinecraftDir();
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
#include "launcherpaths.h"
|
||||||
#include "localization.h"
|
#include "localization.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
@@ -33,6 +36,10 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
QGuiApplication::setDesktopFileName(QStringLiteral("bilauncher"));
|
QGuiApplication::setDesktopFileName(QStringLiteral("bilauncher"));
|
||||||
|
|
||||||
|
// Случайно оставленная BILAUNCHER_HOME увела бы данные в чужую папку — пусть это будет видно в логе.
|
||||||
|
if (!LauncherPaths::homeOverride().isEmpty())
|
||||||
|
qWarning().noquote() << "BILAUNCHER_HOME: данные лаунчера в" << QDir::toNativeSeparators(LauncherPaths::rootDir());
|
||||||
|
|
||||||
if (!Localization::instance().load())
|
if (!Localization::instance().load())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|||||||
@@ -116,8 +116,6 @@ function(bilauncher_add_test name)
|
|||||||
TIMEOUT ${ARG_TIMEOUT}
|
TIMEOUT ${ARG_TIMEOUT}
|
||||||
ENVIRONMENT "${BILAUNCHER_TEST_ENV}")
|
ENVIRONMENT "${BILAUNCHER_TEST_ENV}")
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
# На Windows все тесты делят настоящую %APPDATA%\BiLauncher (см. common/testenv.h).
|
|
||||||
set_tests_properties(${name} PROPERTIES RESOURCE_LOCK launcher_profile)
|
|
||||||
# DLL Qt — из установки Qt, без windeployqt для каждого теста.
|
# DLL Qt — из установки Qt, без windeployqt для каждого теста.
|
||||||
set_property(TEST ${name} APPEND PROPERTY ENVIRONMENT_MODIFICATION
|
set_property(TEST ${name} APPEND PROPERTY ENVIRONMENT_MODIFICATION
|
||||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:Qt6::Core>")
|
"PATH=path_list_prepend:$<TARGET_FILE_DIR:Qt6::Core>")
|
||||||
|
|||||||
+47
-29
@@ -10,16 +10,33 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
#include <qt_windows.h>
|
||||||
|
#include <stdlib.h> // _wputenv_s
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const char kMarker[] = ".bilauncher-test-sandbox";
|
|
||||||
|
|
||||||
QTemporaryDir *g_sandbox = nullptr;
|
QTemporaryDir *g_sandbox = nullptr;
|
||||||
bool g_realProfile = false; // Windows: работаем в настоящем профиле под меткой
|
|
||||||
|
|
||||||
[[noreturn]] void abortSetup(const QString &message)
|
[[noreturn]] void abortSetup(const QString &message)
|
||||||
{
|
{
|
||||||
std::fprintf(stderr, "TestEnv: %s\n", qPrintable(message));
|
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);
|
||||||
std::exit(2);
|
std::exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,15 +48,16 @@ void TestEnv::prepareSandbox()
|
|||||||
if (!g_sandbox->isValid())
|
if (!g_sandbox->isValid())
|
||||||
abortSetup(QStringLiteral("не удалось создать временную папку"));
|
abortSetup(QStringLiteral("не удалось создать временную папку"));
|
||||||
|
|
||||||
const QByteArray home = QDir::toNativeSeparators(g_sandbox->path()).toLocal8Bit();
|
const QString home = QDir::toNativeSeparators(g_sandbox->path());
|
||||||
qputenv("HOME", home);
|
setEnvPath("HOME", home);
|
||||||
qputenv("USERPROFILE", home);
|
setEnvPath("USERPROFILE", home);
|
||||||
|
// LauncherPaths: на Windows QDir::homePath() HOME/USERPROFILE не читает, а эту
|
||||||
|
// переменную лаунчер читает везде. Дочерние процессы получают её по наследству.
|
||||||
|
setEnvPath("BILAUNCHER_HOME", home);
|
||||||
// Чужая Java из окружения машины не должна влиять на выбор Java в тестах.
|
// Чужая Java из окружения машины не должна влиять на выбор Java в тестах.
|
||||||
qunsetenv("JAVA_HOME");
|
qunsetenv("JAVA_HOME");
|
||||||
|
|
||||||
std::atexit([] {
|
std::atexit([] {
|
||||||
if (g_realProfile)
|
|
||||||
QDir(LauncherPaths::rootDir()).removeRecursively();
|
|
||||||
delete g_sandbox;
|
delete g_sandbox;
|
||||||
g_sandbox = nullptr;
|
g_sandbox = nullptr;
|
||||||
});
|
});
|
||||||
@@ -52,19 +70,13 @@ void TestEnv::finishSetup()
|
|||||||
|
|
||||||
const QString root = QDir::cleanPath(LauncherPaths::rootDir());
|
const QString root = QDir::cleanPath(LauncherPaths::rootDir());
|
||||||
const QString sandbox = QDir::cleanPath(g_sandbox->path());
|
const QString sandbox = QDir::cleanPath(g_sandbox->path());
|
||||||
if (!root.startsWith(sandbox + u'/')) {
|
const QString game = QDir::cleanPath(LauncherPaths::defaultMinecraftDir());
|
||||||
#if defined(Q_OS_WIN)
|
// Ни одна папка лаунчера не должна указывать на настоящий профиль: resetLauncherRoot()
|
||||||
if (QDir(root).exists() && !QFile::exists(root + u'/' + QLatin1String(kMarker))) {
|
// стирает rootDir() целиком.
|
||||||
abortSetup(QStringLiteral(
|
for (const QString &path : {root, game}) {
|
||||||
"%1 уже существует и создана не тестами — отказываюсь её трогать. "
|
if (!path.startsWith(sandbox + u'/'))
|
||||||
"Запускайте тесты под отдельной учётной записью.")
|
abortSetup(QStringLiteral("путь лаунчера %1 вне песочницы %2 — отказываюсь запускаться")
|
||||||
.arg(QDir::toNativeSeparators(root)));
|
.arg(QDir::toNativeSeparators(path), QDir::toNativeSeparators(sandbox)));
|
||||||
}
|
|
||||||
g_realProfile = true;
|
|
||||||
resetLauncherRoot();
|
|
||||||
#else
|
|
||||||
abortSetup(QStringLiteral("папка лаунчера %1 вне песочницы %2").arg(root, sandbox));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Localization::instance().load())
|
if (!Localization::instance().load())
|
||||||
@@ -72,6 +84,18 @@ void TestEnv::finishSetup()
|
|||||||
Localization::instance().setLanguage(QStringLiteral("en"));
|
Localization::instance().setLanguage(QStringLiteral("en"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
QString TestEnv::homeDir()
|
QString TestEnv::homeDir()
|
||||||
{
|
{
|
||||||
return g_sandbox->path();
|
return g_sandbox->path();
|
||||||
@@ -87,11 +111,5 @@ QString TestEnv::freshDir(const QString &name)
|
|||||||
|
|
||||||
void TestEnv::resetLauncherRoot()
|
void TestEnv::resetLauncherRoot()
|
||||||
{
|
{
|
||||||
const QString root = LauncherPaths::rootDir();
|
QDir(LauncherPaths::rootDir()).removeRecursively();
|
||||||
QDir(root).removeRecursively();
|
|
||||||
if (g_realProfile) {
|
|
||||||
QDir().mkpath(root);
|
|
||||||
QFile marker(root + u'/' + QLatin1String(kMarker));
|
|
||||||
marker.open(QIODevice::WriteOnly);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+13
-12
@@ -2,16 +2,14 @@
|
|||||||
|
|
||||||
// Общая обвязка тестов: песочница для домашней папки и main для QtTest.
|
// Общая обвязка тестов: песочница для домашней папки и main для QtTest.
|
||||||
//
|
//
|
||||||
// LauncherPaths строит все пути от QDir::homePath(). На Linux и macOS он берёт
|
// LauncherPaths строит все пути от домашней папки. Каждый тестовый процесс до
|
||||||
// HOME, поэтому каждый тестовый процесс до создания QCoreApplication
|
// создания QCoreApplication заводит свою временную папку и направляет туда
|
||||||
// подменяет HOME на свою временную папку — реальные ~/BiLauncher и .minecraft
|
// BILAUNCHER_HOME (её LauncherPaths читает на всех ОС), а заодно HOME и
|
||||||
// машины, на которой гоняются тесты, не трогаются.
|
// USERPROFILE (их читает QDir::homePath() на Linux и macOS). На Windows
|
||||||
//
|
// QDir::homePath() переменные окружения игнорирует, поэтому без BILAUNCHER_HOME
|
||||||
// На Windows QDir::homePath() спрашивает профиль у системы и переменные
|
// там не обойтись. Реальные папка лаунчера и .minecraft машины, на которой гоняются
|
||||||
// окружения игнорирует. Там тесты работают в настоящей
|
// тесты, не трогаются: если путь лаунчера всё же оказался вне песочницы,
|
||||||
// %APPDATA%\BiLauncher, но только если её ещё нет либо она создана тестами
|
// процесс сразу завершается с кодом 2.
|
||||||
// (в ней лежит метка .bilauncher-test-sandbox). Иначе процесс отказывается
|
|
||||||
// запускаться, чтобы не испортить данные живого лаунчера.
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@@ -19,14 +17,17 @@
|
|||||||
|
|
||||||
namespace TestEnv {
|
namespace TestEnv {
|
||||||
|
|
||||||
// До QCoreApplication: временная папка и подмена HOME/USERPROFILE.
|
// До QCoreApplication: временная папка и подмена BILAUNCHER_HOME/HOME/USERPROFILE.
|
||||||
void prepareSandbox();
|
void prepareSandbox();
|
||||||
|
|
||||||
// После QCoreApplication: проверка, что пути лаунчера ушли в песочницу,
|
// После QCoreApplication: проверка, что пути лаунчера ушли в песочницу,
|
||||||
// загрузка переводов, английский язык (тексты ошибок не зависят от локали машины).
|
// загрузка переводов, английский язык (тексты ошибок не зависят от локали машины).
|
||||||
void finishSetup();
|
void finishSetup();
|
||||||
|
|
||||||
// Корень песочницы — то, что сейчас возвращает QDir::homePath() в тестах.
|
// Переменная окружения с путём, без потерь символов вне ANSI-кодировки на Windows.
|
||||||
|
void setEnvPath(const char *name, const QString &path);
|
||||||
|
|
||||||
|
// Корень песочницы — домашняя папка, от которой LauncherPaths строит пути в тестах.
|
||||||
QString homeDir();
|
QString homeDir();
|
||||||
|
|
||||||
// Свежая пустая папка внутри песочницы (для .minecraft, архивов и т. п.).
|
// Свежая пустая папка внутри песочницы (для .minecraft, архивов и т. п.).
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
# лаунчер запускается без окна и через 10 секунд ещё жив, а в логе нет ошибок
|
# лаунчер запускается без окна и через 10 секунд ещё жив, а в логе нет ошибок
|
||||||
# загрузки модулей.
|
# загрузки модулей.
|
||||||
#
|
#
|
||||||
# На Windows лаунчер берёт папку профиля у системы, а не из переменных окружения,
|
# QDir::homePath() на Windows берёт профиль у системы и USERPROFILE не читает,
|
||||||
# поэтому работает в настоящей %APPDATA%\BiLauncher учётной записи раннера. Если
|
# поэтому лаунчер запускается с BILAUNCHER_HOME на временную папку (см.
|
||||||
# её до запуска не было, скрипт убирает её за собой.
|
# launcherpaths.h) — настоящая %APPDATA%\BiLauncher раннера не трогается.
|
||||||
|
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory = $true)][string]$Prefix,
|
[Parameter(Mandatory = $true)][string]$Prefix,
|
||||||
@@ -28,14 +28,17 @@ if (-not (Get-ChildItem (Join-Path $Prefix "bin\tls") -Filter "*.dll" -ErrorActi
|
|||||||
Fail "нет TLS-плагина (bin\tls) — лаунчер не сможет ходить по https"
|
Fail "нет TLS-плагина (bin\tls) — лаунчер не сможет ходить по https"
|
||||||
}
|
}
|
||||||
|
|
||||||
$profileRoot = Join-Path $env:APPDATA "BiLauncher"
|
$realProfile = Join-Path $env:APPDATA "BiLauncher"
|
||||||
$existedBefore = Test-Path $profileRoot
|
$realExisted = Test-Path $realProfile
|
||||||
|
|
||||||
$log = Join-Path $env:TEMP ("bilauncher-smoke-" + [guid]::NewGuid().ToString("N"))
|
$sandbox = Join-Path $env:TEMP ("bilauncher-smoke-" + [guid]::NewGuid().ToString("N"))
|
||||||
|
$log = Join-Path $sandbox "log"
|
||||||
New-Item -ItemType Directory -Force $log | Out-Null
|
New-Item -ItemType Directory -Force $log | Out-Null
|
||||||
$stdout = Join-Path $log "stdout.log"
|
$stdout = Join-Path $log "stdout.log"
|
||||||
$stderr = Join-Path $log "stderr.log"
|
$stderr = Join-Path $log "stderr.log"
|
||||||
|
$profileRoot = Join-Path $sandbox "AppData\Roaming\BiLauncher"
|
||||||
|
|
||||||
|
$env:BILAUNCHER_HOME = $sandbox
|
||||||
$env:QT_QPA_PLATFORM = "offscreen"
|
$env:QT_QPA_PLATFORM = "offscreen"
|
||||||
$env:QT_FORCE_STDERR_LOGGING = "1"
|
$env:QT_FORCE_STDERR_LOGGING = "1"
|
||||||
$env:QTWEBENGINE_CHROMIUM_FLAGS = "--disable-gpu"
|
$env:QTWEBENGINE_CHROMIUM_FLAGS = "--disable-gpu"
|
||||||
@@ -58,9 +61,9 @@ try {
|
|||||||
Fail "в логе ошибки загрузки модулей"
|
Fail "в логе ошибки загрузки модулей"
|
||||||
}
|
}
|
||||||
if (-not (Test-Path (Join-Path $profileRoot "settings.json"))) { Fail "лаунчер не создал $profileRoot\settings.json" }
|
if (-not (Test-Path (Join-Path $profileRoot "settings.json"))) { Fail "лаунчер не создал $profileRoot\settings.json" }
|
||||||
|
if (-not $realExisted -and (Test-Path $realProfile)) { Fail "лаунчер создал настоящую $realProfile мимо BILAUNCHER_HOME" }
|
||||||
Write-Host "SMOKE OK: $bin"
|
Write-Host "SMOKE OK: $bin"
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
Remove-Item -Recurse -Force $log -ErrorAction SilentlyContinue
|
Remove-Item -Recurse -Force $sandbox -ErrorAction SilentlyContinue
|
||||||
if (-not $existedBefore) { Remove-Item -Recurse -Force $profileRoot -ErrorAction SilentlyContinue }
|
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,11 @@ class TestGameLauncher : public QObject
|
|||||||
Fixtures::makeZip(m_game + "/libraries/org/lwjgl/lwjgl-3.3.1-natives.jar",
|
Fixtures::makeZip(m_game + "/libraries/org/lwjgl/lwjgl-3.3.1-natives.jar",
|
||||||
{{QStringLiteral("META-INF/MANIFEST.MF"), "x"},
|
{{QStringLiteral("META-INF/MANIFEST.MF"), "x"},
|
||||||
{QStringLiteral("linux/x64/org/lwjgl/") + kNativeName, "native-bytes"},
|
{QStringLiteral("linux/x64/org/lwjgl/") + kNativeName, "native-bytes"},
|
||||||
{QStringLiteral("skip/") + kNativeName + ".sha1", "hash"}});
|
{QStringLiteral("skip/") + kNativeName + ".sha1", "hash"},
|
||||||
|
// Служебные файлы LWJGL рядом с .so: не должны приниматься
|
||||||
|
// за версионированную библиотеку (libfoo.so.1) ни на одной ОС.
|
||||||
|
{QStringLiteral("skip/liblwjgl.so.sha1"), "hash"},
|
||||||
|
{QStringLiteral("skip/liblwjgl.so.git"), "git"}});
|
||||||
Fixtures::write(m_game + "/assets/indexes/5.json", "{}");
|
Fixtures::write(m_game + "/assets/indexes/5.json", "{}");
|
||||||
QDir().mkpath(m_game + "/assets/objects");
|
QDir().mkpath(m_game + "/assets/objects");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QScopeGuard>
|
||||||
|
|
||||||
class TestLauncherPaths : public QObject
|
class TestLauncherPaths : public QObject
|
||||||
{
|
{
|
||||||
@@ -22,7 +23,9 @@ private slots:
|
|||||||
|
|
||||||
void containerPerPlatform()
|
void containerPerPlatform()
|
||||||
{
|
{
|
||||||
const QString home = QDir::homePath();
|
// Не QDir::homePath(): на Windows он смотрит в настоящий профиль, а пути
|
||||||
|
// лаунчера в тестах идут от BILAUNCHER_HOME (песочницы).
|
||||||
|
const QString home = QDir::cleanPath(TestEnv::homeDir());
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
QCOMPARE(LauncherPaths::containerDir(), home + QStringLiteral("/AppData/Roaming"));
|
QCOMPARE(LauncherPaths::containerDir(), home + QStringLiteral("/AppData/Roaming"));
|
||||||
QCOMPARE(LauncherPaths::defaultMinecraftDir(), LauncherPaths::containerDir() + "/.minecraft");
|
QCOMPARE(LauncherPaths::defaultMinecraftDir(), LauncherPaths::containerDir() + "/.minecraft");
|
||||||
@@ -35,6 +38,25 @@ private slots:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void homeOverrideFromEnvironment()
|
||||||
|
{
|
||||||
|
const QString saved = qEnvironmentVariable("BILAUNCHER_HOME");
|
||||||
|
const auto restore = qScopeGuard([&] { TestEnv::setEnvPath("BILAUNCHER_HOME", saved); });
|
||||||
|
|
||||||
|
QCOMPARE(LauncherPaths::homeOverride(), QDir::cleanPath(TestEnv::homeDir()));
|
||||||
|
|
||||||
|
const QString other = TestEnv::freshDir("other-home");
|
||||||
|
TestEnv::setEnvPath("BILAUNCHER_HOME", QDir::toNativeSeparators(other));
|
||||||
|
QCOMPARE(LauncherPaths::homeOverride(), QDir::cleanPath(other));
|
||||||
|
QVERIFY(LauncherPaths::rootDir().startsWith(QDir::cleanPath(other) + u'/'));
|
||||||
|
|
||||||
|
// Относительный путь зависел бы от текущей папки — игнорируется, как и пустой.
|
||||||
|
for (const char *ignored : {"relative/home", ""}) {
|
||||||
|
qputenv("BILAUNCHER_HOME", ignored);
|
||||||
|
QVERIFY2(LauncherPaths::homeOverride().isEmpty(), ignored);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void filesLayout_data()
|
void filesLayout_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("actual");
|
QTest::addColumn<QString>("actual");
|
||||||
|
|||||||
Reference in new issue
Block a user