95c03040c7
- FileStore: защита от выхода за пределы хранилища (isInsideVault), валидация имён (запрет скрытых, зарезервированных, управляющих символов), проверка destDir, лимит watcher, dailyNote валидация, openVault проверка isDir - DocumentManager: лимит 10МБ, кламп автосейва 0.5-120с, защита от OOM, бинарный детект, проверка путей - VaultIndex: исправлен парсинг тегов (заголовки, инлайн-код), case-insensitive поиск, дедупликация рёбер, защита от traversal, лимит глубины, проверка vaultExists - MdParser: блокировка всех on* событий, javascript:/data:, esc кавычек, MIME fallback, normalizeLang расширен (c/cpp/py/js и кириллица), wiki глобальный поиск, image лимит 3МБ, защита clipboard - GitManager: commitAll с GIT_INDEX_ADD_DEFAULT и поддержкой пустых коммитов/удалений, fileGitStatus с cleanPath и проверкой префикса, repoExists/hasCommits с cleanPath, initRepo валидация - SettingsStore: encodeKey/encodeRel для QSettings Ini, flat хранение viewMode, sync после записи, кламп ширин панелей, миграция старых ключей - SyncManager: счётчик busy, обработка httpStatus при network error, валидация токена/провайдера/URL, GitHub Enterprise URL, таймаут - VaultManager: валидация путей (корень, файл vs папка, права), проверка вложенности - WindowController: per-window FileStore/DocumentManager/VaultIndex, cleanPath, закрытие окна через QQuickWindow::closing, обработка ошибок компонента - QML: TableEditor пустая строка, WelcomeWizard QUrl парсинг, FileTree фильтр, GraphView лимит 600 узлов, RightPanel debounce rebuild, Theme singleton, MonthCalendar и др. - Тесты: добавлены flora_settings_test, flora_sync_test, flora_extended_test, flora_integration_test — покрытие всех модулей, 20/20 зелёных - Сборка: обновлён Flora.app (4.6М бинарь -> 173М бандл, ad-hoc подпись, проверен offscreen запуск, версия 0.0.1 + cmark 0.29 + libgit2 1.9) - .gitignore: добавлены Testing/, coverage, gcda/gcov, __pycache__, .tmp, test-vault и др.
114 lines
4.7 KiB
C++
114 lines
4.7 KiB
C++
// Тест SyncManager: каталог ошибок, busy-счётчик, валидация параметров
|
|
#include <QCoreApplication>
|
|
#include <QTimer>
|
|
#include <QEventLoop>
|
|
#include <cstdio>
|
|
|
|
#include "sync/SyncManager.h"
|
|
|
|
static int fail(const char *msg, const QString &detail = QString()) {
|
|
std::fprintf(stderr, "FAIL: %s %s\n", msg, qPrintable(detail));
|
|
return 1;
|
|
}
|
|
|
|
struct Spy {
|
|
int count=0;
|
|
bool lastOk=false;
|
|
int lastCode=0;
|
|
QString lastTitle;
|
|
void connectTo(SyncManager *sm){
|
|
QObject::connect(sm, &SyncManager::connectionResult, [this](int, bool ok, int code, const QString& t, const QString&, const QString&){
|
|
count++; lastOk=ok; lastCode=code; lastTitle=t;
|
|
});
|
|
}
|
|
void reset(){ count=0; lastOk=false; lastCode=0; lastTitle.clear(); }
|
|
};
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
QCoreApplication app(argc, argv);
|
|
|
|
SyncManager sm;
|
|
|
|
// error catalog
|
|
if (sm.errorTitle(SyncManager::Ok) != "OK") return fail("errorTitle Ok");
|
|
if (sm.errorTitle(SyncManager::Unauthorized).isEmpty()) return fail("errorTitle 401 empty");
|
|
if (sm.errorHint(SyncManager::Unauthorized).isEmpty()) return fail("errorHint 401 empty");
|
|
if (sm.errorHint(SyncManager::Timeout).isEmpty()) return fail("hint timeout");
|
|
if (!sm.errorTitle(999).contains("999")) return fail("unknown error title");
|
|
|
|
// busy initial
|
|
if (sm.busy()) return fail("initial busy should be false");
|
|
|
|
// testConnection with empty token should immediately finish with Unauthorized without network
|
|
{
|
|
Spy spy; spy.connectTo(&sm);
|
|
sm.testConnection(SyncManager::GitHub, "https://api.github.com", "", "");
|
|
// need to process events for direct connection? finish emits synchronously, but signal is direct, so count should be 1 immediately
|
|
// However finish is synchronous, so after call count should be 1
|
|
if (spy.count != 1) return fail("empty token spy count", QString::number(spy.count));
|
|
if (spy.lastOk) return fail("empty token should not ok");
|
|
if (spy.lastCode != SyncManager::Unauthorized) return fail("empty token code", QString::number(spy.lastCode));
|
|
if (sm.busy()) return fail("busy after empty token");
|
|
}
|
|
|
|
// Need new manager for isolated spy because previous connection stays
|
|
{
|
|
SyncManager sm2;
|
|
Spy spy; spy.connectTo(&sm2);
|
|
sm2.testConnection(99, "https://example.com", "", "token123");
|
|
if (spy.count!=1) return fail("invalid provider spy", QString::number(spy.count));
|
|
if (spy.lastCode != SyncManager::NetworkError) return fail("invalid provider code", QString::number(spy.lastCode));
|
|
}
|
|
|
|
// invalid URL for WebDAV
|
|
{
|
|
SyncManager sm2;
|
|
Spy spy; spy.connectTo(&sm2);
|
|
sm2.testConnection(SyncManager::WebDav, "not-a-url", "user", "pass");
|
|
if (spy.count!=1) return fail("webdav invalid url spy count", QString::number(spy.count));
|
|
if (spy.lastCode != SyncManager::NetworkError) return fail("webdav invalid url code", QString::number(spy.lastCode));
|
|
}
|
|
|
|
// Check busy counter with actual network request (will timeout or fail, but busy should be managed)
|
|
{
|
|
SyncManager sm2;
|
|
int busyChangedCount=0;
|
|
QObject::connect(&sm2, &SyncManager::busyChanged, [&](){ busyChangedCount++; });
|
|
sm2.testConnection(SyncManager::Syncthing, "http://127.0.0.1:1", "", "fake");
|
|
if (!sm2.busy()) return fail("busy should be true after request");
|
|
QEventLoop loop;
|
|
QTimer timer;
|
|
timer.setSingleShot(true);
|
|
QObject::connect(&sm2, &SyncManager::connectionResult, &loop, &QEventLoop::quit);
|
|
QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
|
|
timer.start(3000);
|
|
loop.exec();
|
|
if (sm2.busy()) return fail("busy should be false after reply");
|
|
if (busyChangedCount < 1) return fail("busyChanged not emitted");
|
|
}
|
|
|
|
// Test busy counter with two parallel requests
|
|
{
|
|
SyncManager sm2;
|
|
sm2.testConnection(SyncManager::GitHub, "https://api.github.com", "", "tok1");
|
|
sm2.testConnection(SyncManager::GitLab, "https://gitlab.com", "", "tok2");
|
|
if (!sm2.busy()) return fail("busy after two requests");
|
|
QEventLoop loop;
|
|
int count = 0;
|
|
QObject::connect(&sm2, &SyncManager::connectionResult, &loop, [&](int, bool, int, const QString&, const QString&, const QString&){
|
|
count++;
|
|
if (count>=2) loop.quit();
|
|
});
|
|
QTimer::singleShot(4000, &loop, &QEventLoop::quit);
|
|
loop.exec();
|
|
QEventLoop loop2;
|
|
QTimer::singleShot(1000, &loop2, &QEventLoop::quit);
|
|
loop2.exec();
|
|
if (count==0) return fail("no parallel results");
|
|
}
|
|
|
|
std::printf("SYNC TEST OK\n");
|
|
return 0;
|
|
}
|