gui: Options — Capture tab, saveTo.allowedRoots, lock coverage to the schema

Options was missing 8 of the 43 real settings.* keys: capture.enabled,
monitoredExtensions, monitoredMimeTypes, minSizeBytes, excludedHosts,
bypassModifier, autoStartTypes, and saveTo.allowedRoots. The capture.* keys
were dropped in an earlier pass on the mistaken read that the spec's "File
Types" tab meant per-category extension lists (which do live on Category,
not settings.*) — they're real settings.* keys for a real daemon feature
(the extension's auto-capture policy), so the tab exists now, named
"Capture" to match what it actually configures rather than the spec's
label.

New tst_optionsdialog case (allKeysMatchesTheSchemaExactly) loads
Settings.schema.json itself at test time and diffs its property set against
OptionsDialog::allKeys() — this drifted silently once already, so the
regression is now a build-time gate an unused import or a future key
addition would trip, not something that needs re-discovering by hand again.

Verified against a real veloxd (not just mockd): settings.get across all
43 keys, a settings.set/get round trip on a scalar (connection.timeoutSec)
and on array-valued keys in the shapes OptionsDialog::currentValues()
actually produces (capture.monitoredExtensions, proxy.bypassHosts,
saveTo.allowedRoots), and event.settings.changed fanning out to a second
subscribed client — all round-tripped and restored to their original
values afterward. The real OptionsDialog widget also loads and renders
correctly against that same daemon's live defaults with no crash under
ASan+UBSan.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NSCdCWFXBTSBBK3MzWtJiC
This commit is contained in:
2026-09-12 21:29:19 +04:00
co-authored by Claude Sonnet 5
parent 755d85964e
commit 1fd2e0a0db
4 changed files with 137 additions and 11 deletions
+22
View File
@@ -5,6 +5,8 @@
// effect" contract and spams event.settings.changed with noise), or a key present in
// `current` but absent from `original` stops being treated as changed.
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QtTest>
@@ -20,6 +22,7 @@ class TstOptionsDialog : public QObject {
void onlyChangedKeysAreReturned();
void keyAbsentFromOriginalCountsAsChanged();
void allKeysAreNonEmptyAndUnique();
void allKeysMatchesTheSchemaExactly();
};
void TstOptionsDialog::identicalValuesProduceNoDiff() {
@@ -50,5 +53,24 @@ void TstOptionsDialog::allKeysAreNonEmptyAndUnique() {
QCOMPARE(QSet<QString>(keys.begin(), keys.end()).size(), keys.size());
}
// Red when a key is added to (or removed from) Settings.schema.json without the same
// change landing here — either direction is a real bug: an invented key settings.set
// would reject with -32602, or a real key the dialog silently never shows.
void TstOptionsDialog::allKeysMatchesTheSchemaExactly() {
QFile f(QStringLiteral(VELOX_REPO_ROOT "/contracts/schema/types/Settings.schema.json"));
QVERIFY2(f.open(QIODevice::ReadOnly), qUtf8Printable(f.errorString()));
const QJsonObject schema = QJsonDocument::fromJson(f.readAll()).object();
const QJsonObject properties = schema.value("properties").toObject();
QVERIFY(!properties.isEmpty());
QSet<QString> schemaKeys;
for (auto it = properties.constBegin(); it != properties.constEnd(); ++it) {
schemaKeys.insert(it.key());
}
const QStringList dialogKeysList = OptionsDialog::allKeys();
const QSet<QString> dialogKeys(dialogKeysList.begin(), dialogKeysList.end());
QCOMPARE(dialogKeys, schemaKeys);
}
QTEST_MAIN(TstOptionsDialog)
#include "tst_optionsdialog.moc"