Check stale forms, read failures and member command memory ownership

This commit is contained in:
evgeny committed 2026-10-28 00:58:59 +01:00
1 parent 49cbfe1ae0
commit f11ab51ccc
1 file changed
+45
@@ -16,6 +16,7 @@ extern "C" {
#include "utun_instance.h"
#include "chat/chat_core.h"
#include "debug_config.h"
#include "mem.h"
}
#ifdef UTUN_TEST_MEMBER_ALLOC_FAILURES
@@ -129,11 +130,14 @@ static bool save(QDialog* dialog) { return QMetaObject::invokeMethod(dialog, "on
class MemberDialogTest : public QObject {
Q_OBJECT
size_t allocationBaseline = 0;
private slots:
void initTestCase() {
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN);
debug_set_category_level(DEBUG_CATEGORY_CHAT_SYNC, DEBUG_LEVEL_DEBUG); gui_bridge_init();
}
void init() { allocationBaseline = u_get_allocated_count(); }
void cleanup() { QCoreApplication::processEvents(); QCOMPARE(u_get_allocated_count(), allocationBaseline); }
void saves_data() {
QTest::addColumn<bool>("properties"); QTest::addColumn<QString>("failure");
for (bool properties : {false, true}) for (const char* failure : {"none", "prepare", "step", "commit", "missing"})
@@ -213,6 +217,47 @@ private slots:
} else { QCOMPARE(accepted.count(), 0); QVERIFY(!errorLabel(dialog.get())->text().isEmpty()); }
if (other) { core.db.setDb(core.instance->topo_sqlite_db); QCOMPARE(sqlite3_close(other), SQLITE_OK); }
}
void failedRead_data() {
QTest::addColumn<bool>("properties");
QTest::newRow("rename") << false; QTest::newRow("properties") << true;
}
void failedRead() {
QFETCH(bool, properties); MemberCore core; QVERIFY(core.start()); const auto before = core.snapshot();
QCOMPARE(core.run([&] { return sqlite3_set_authorizer(core.db.m_db,
[](void*, int action, const char*, const char* column, const char*, const char*) {
if (action == SQLITE_READ && column && !strcmp(column, "local_nick")) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "[INJECT] initial nickname read denied"); return SQLITE_DENY;
}
return SQLITE_OK;
}, nullptr); }), SQLITE_OK);
auto dialog = makeDialog(core, properties); QSignalSpy accepted(dialog.get(), &QDialog::accepted);
QCOMPARE(core.run([&] { return sqlite3_set_authorizer(core.db.m_db, nullptr, nullptr); }), SQLITE_OK);
QVERIFY(save(dialog.get())); QCOMPARE(accepted.count(), 0); QVERIFY(!errorLabel(dialog.get())->text().isEmpty());
QCOMPARE(core.snapshot(), before);
}
void staleOwnerAndUnchangedOwner() {
MemberCore core; QVERIFY(core.start()); auto dialog = makeDialog(core, true);
QCOMPARE(core.run([&] { return chat_core_save_member(core.instance, qPrintable(core.channel), core.node,
"Newer nickname", "{\"owner_test\":\"newer\"}"); }), 0);
const auto before = core.snapshot(); QSignalSpy accepted(dialog.get(), &QDialog::accepted);
dialog->findChild<QLineEdit*>()->setText("Stale nickname"); QVERIFY(save(dialog.get())); core.resume();
QTRY_VERIFY_WITH_TIMEOUT(!errorLabel(dialog.get())->text().isEmpty(), 3000); core.pause();
QCOMPARE(accepted.count(), 0); QCOMPARE(core.snapshot(), before);
int result = -99; QObject context;
QVERIFY(gui_bridge_save_member(core.db.m_db, core.channel, core.node, "", "{}", &context, [&](int rc) { result = rc; }));
core.resume(); QTRY_COMPARE_WITH_TIMEOUT(result, 0, 3000); core.pause();
QVERIFY(core.snapshot().startsWith('\n')); // No-op owner-блок не мешает снятию локального ника.
}
void validation() {
MemberCore core; QVERIFY(core.start()); QObject context; bool called = false;
const auto callback = [&](int) { called = true; };
QVERIFY(!gui_bridge_save_member(core.db.m_db, "01", core.node, "Nick", {}, &context, callback));
QVERIFY(!gui_bridge_save_member(core.db.m_db, core.channel, 0, "Nick", {}, &context, callback));
QVERIFY(!gui_bridge_save_member(core.db.m_db, core.channel, core.node, QString(QChar(0)), {}, &context, callback));
QVERIFY(!gui_bridge_save_member(core.db.m_db, core.channel, core.node, "Nick", QByteArray(8193, 'x'), &context, callback));
QVERIFY(!gui_bridge_save_member(core.db.m_db, core.channel, core.node, "Nick", {}, nullptr, callback));
QCoreApplication::processEvents(); QVERIFY(!called);
}
#ifdef UTUN_TEST_MEMBER_ALLOC_FAILURES
void allocations_data() {
QTest::addColumn<bool>("properties"); QTest::addColumn<bool>("queue");