From 8323be7272beacf4cb72b10edd274c39b6660729 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 27 Oct 2026 16:08:34 +0100 Subject: [PATCH] Cover settings string limits, snapshots and late allocation failures --- tools/chatgui/CMakeLists.txt | 2 +- tools/chatgui/tests/test_settings_save.cpp | 87 +++++++++++++++++++++- 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/tools/chatgui/CMakeLists.txt b/tools/chatgui/CMakeLists.txt index 26cc6e2b..b4bfdf41 100644 --- a/tools/chatgui/CMakeLists.txt +++ b/tools/chatgui/CMakeLists.txt @@ -896,7 +896,7 @@ add_test(NAME test_voice_file COMMAND test_voice_file) if(WIN32) # AudioDevice закрывает неисправный WASAPI в worker с собственным COM apartment. foreach(audio_target vibechat test_file_drop test_invite_links test_video_engine test_stream_view test_stream_publish - test_voice_file test_sound_settings) + test_voice_file test_sound_settings test_settings_save) target_link_libraries(${audio_target} PRIVATE ole32) endforeach() endif() diff --git a/tools/chatgui/tests/test_settings_save.cpp b/tools/chatgui/tests/test_settings_save.cpp index f0bc289b..955f0099 100644 --- a/tools/chatgui/tests/test_settings_save.cpp +++ b/tools/chatgui/tests/test_settings_save.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,9 @@ class SettingsSaveTest : public QObject { QCOMPARE(core.db.getUiStateInt("storage_autoload_maxsize_mb", -1), 17); QCOMPARE(core.db.getUiStateInt("storage_maxsize_gb", -1), 3); QCOMPARE(chat_setting_get_int(core.inst, "storage_autoload", -1), 1); + QSettings config(core.path(), QSettings::IniFormat); + QCOMPARE(config.value("chatserver/storage_unit_size").toString(), QString("17M")); + QCOMPARE(config.value("chatserver/storage_total_size").toString(), QString("3G")); } if (kind != Storage) { QCOMPARE(core.db.getUiStateInt("opus_codec_preset", -1), 2); @@ -197,18 +201,82 @@ private slots: } #ifdef UTUN_TEST_SETTINGS_ALLOC_FAILURES QCOMPARE(outstanding.size(), size_t(0)); +#endif + } + void pairLimits_data() { + QTest::addColumn("target"); QTest::addColumn("key"); QTest::addColumn("value"); + QTest::addColumn("accepted"); + for (int target : {int(GUI_SETTING_UI_STATE), int(GUI_SETTING_CHAT)}) { + const int capacity = target == GUI_SETTING_UI_STATE ? sizeof(save_ui_state_arg::data) : sizeof(chat_setting_arg::data); + const auto row = [target](const char* name) { return qPrintable(QString("%1-%2").arg(target).arg(name)); }; + Q_UNUSED(row); + const QByteArray prefix = QByteArray::number(target) + '-'; + QTest::newRow((prefix + "null-key").constData()) << target << QByteArray() << QByteArray("v") << false; + QTest::newRow((prefix + "empty-key").constData()) << target << QByteArray("") << QByteArray("v") << false; + QTest::newRow((prefix + "null-value").constData()) << target << QByteArray("k") << QByteArray() << false; + QTest::newRow((prefix + "empty-value").constData()) << target << QByteArray("k") << QByteArray("") << true; + QTest::newRow((prefix + "exact-fit").constData()) << target << QByteArray("k") << QByteArray(capacity - 3, 'v') << true; + QTest::newRow((prefix + "long-value").constData()) << target << QByteArray("k") << QByteArray(capacity - 2, 'v') << false; + QTest::newRow((prefix + "long-key").constData()) << target << QByteArray(capacity, 'k') << QByteArray("") << false; + } + } + void pairLimits() { + QFETCH(int, target); QFETCH(QByteArray, key); QFETCH(QByteArray, value); QFETCH(bool, accepted); + SettingsCore core; QVERIFY(core.start()); + const auto baseline = u_get_allocated_count(); + QCOMPARE(gui_bridge_post_setting(static_cast(target), key.isNull() ? nullptr : key.constData(), + value.isNull() ? nullptr : value.constData()), accepted ? 0 : -1); + gui_bridge_set_inst(nullptr); + QCOMPARE(u_get_allocated_count(), baseline); + } + void nameLimits_data() { + QTest::addColumn("name"); QTest::addColumn("accepted"); + QTest::newRow("null") << QByteArray() << false; + QTest::newRow("empty") << QByteArray("") << true; + QTest::newRow("exact-fit") << QByteArray(sizeof(update_my_name_arg::name) - 1, 'n') << true; + QTest::newRow("too-long") << QByteArray(sizeof(update_my_name_arg::name), 'n') << false; + } + void nameLimits() { + QFETCH(QByteArray, name); QFETCH(bool, accepted); + SettingsCore core; QVERIFY(core.start()); + const auto baseline = u_get_allocated_count(); + QCOMPARE(gui_bridge_update_name(name.isNull() ? nullptr : name.constData()), accepted ? 0 : -1); + gui_bridge_set_inst(nullptr); + QCOMPARE(u_get_allocated_count(), baseline); + } + void copiesInputsBeforeReturning() { + SettingsCore core; QVERIFY(core.start()); +#ifdef UTUN_TEST_SETTINGS_ALLOC_FAILURES + watching = true; +#endif + QByteArray key("snapshot"), value("before"), name("After"), setting("storage_autoload"), enabled("1"); + QCOMPARE(gui_bridge_post_setting(GUI_SETTING_UI_STATE, key.constData(), value.constData()), 0); + QCOMPARE(gui_bridge_post_setting(GUI_SETTING_CHAT, setting.constData(), enabled.constData()), 0); + QCOMPARE(gui_bridge_update_name(name.constData()), 0); + key.fill('x'); value.fill('x'); name.fill('x'); setting.fill('x'); enabled.fill('0'); + uasync_poll(core.ua, 0); + QCOMPARE(core.db.getUiState("snapshot"), QString("before")); + QCOMPARE(chat_setting_get_int(core.inst, "storage_autoload", -1), 1); + QCOMPARE(QString::fromUtf8(core.inst->name), QString("After")); +#ifdef UTUN_TEST_SETTINGS_ALLOC_FAILURES + QCOMPARE(outstanding.size(), size_t(0)); #endif } #ifdef UTUN_TEST_SETTINGS_ALLOC_FAILURES void allocationFailure_data() { QTest::addColumn("kind"); QTest::addColumn("payload"); QTest::addColumn("position"); QTest::addColumn("cancel"); - for (int kind : {Storage, Audio, Dialog}) - for (bool payload : {false, true}) - for (int position : {1, 2}) + for (int kind : {Storage, Audio, Dialog}) { + for (bool payload : {false, true}) { + const int count = kind == Storage ? 4 : kind == Audio ? 22 : payload ? 38 : 56; + QList positions{1, 2, count}; + if (count / 2 > 2) positions.append(count / 2); + for (int position : positions) for (bool cancel : {false, true}) QTest::newRow(qPrintable(QString("%1-%2-%3-%4").arg(kind).arg(payload).arg(position).arg(cancel))) << kind << payload << position << cancel; + } + } } void allocationFailure() { QFETCH(int, kind); QFETCH(bool, payload); QFETCH(int, position); QFETCH(bool, cancel); @@ -221,6 +289,19 @@ private slots: else uasync_poll(core.ua, 0); QCOMPARE(outstanding.size(), size_t(0)); } + void nameAllocationFailure_data() { + QTest::addColumn("payload"); + QTest::newRow("payload") << true; QTest::newRow("queue") << false; + } + void nameAllocationFailure() { + QFETCH(bool, payload); + SettingsCore core; QVERIFY(core.start()); + watching = true; failMalloc = payload; failAllocation = 1; + QCOMPARE(gui_bridge_update_name("After"), -1); + QCOMPARE(failAllocation, 0); + QCOMPARE(outstanding.size(), size_t(0)); + QVERIFY(!core.ua->posted_tasks_head); + } #endif };