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
77 lines
3.1 KiB
C++
77 lines
3.1 KiB
C++
// OptionsDialog::diffChanged unit tests. Lane GUI.
|
|
//
|
|
// Red when a key that didn't actually change starts getting resent to settings.set (it
|
|
// would still work, but it defeats the fixture's "changed[] names exactly what took
|
|
// 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>
|
|
|
|
#include "dialogs/OptionsDialog.hpp"
|
|
|
|
using velox::gui::OptionsDialog;
|
|
|
|
class TstOptionsDialog : public QObject {
|
|
Q_OBJECT
|
|
|
|
private slots:
|
|
void identicalValuesProduceNoDiff();
|
|
void onlyChangedKeysAreReturned();
|
|
void keyAbsentFromOriginalCountsAsChanged();
|
|
void allKeysAreNonEmptyAndUnique();
|
|
void allKeysMatchesTheSchemaExactly();
|
|
};
|
|
|
|
void TstOptionsDialog::identicalValuesProduceNoDiff() {
|
|
const QJsonObject original{{"connection.timeoutSec", 30}, {"proxy.mode", "system"}};
|
|
const QJsonObject current = original;
|
|
QVERIFY(OptionsDialog::diffChanged(original, current).isEmpty());
|
|
}
|
|
|
|
void TstOptionsDialog::onlyChangedKeysAreReturned() {
|
|
const QJsonObject original{{"connection.timeoutSec", 30}, {"proxy.mode", "system"}};
|
|
const QJsonObject current{{"connection.timeoutSec", 60}, {"proxy.mode", "system"}};
|
|
const QJsonObject changed = OptionsDialog::diffChanged(original, current);
|
|
QCOMPARE(changed.size(), 1);
|
|
QCOMPARE(changed.value("connection.timeoutSec").toInt(), 60);
|
|
}
|
|
|
|
void TstOptionsDialog::keyAbsentFromOriginalCountsAsChanged() {
|
|
const QJsonObject original{{"proxy.mode", "system"}};
|
|
const QJsonObject current{{"proxy.mode", "system"}, {"proxy.port", 1080}};
|
|
const QJsonObject changed = OptionsDialog::diffChanged(original, current);
|
|
QCOMPARE(changed.size(), 1);
|
|
QVERIFY(changed.contains("proxy.port"));
|
|
}
|
|
|
|
void TstOptionsDialog::allKeysAreNonEmptyAndUnique() {
|
|
const QStringList keys = OptionsDialog::allKeys();
|
|
QVERIFY(!keys.isEmpty());
|
|
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"
|