Wires up the three dialogs from build order step 5 (docs/03-gui-spec.md §§2-3) and the MainWindow slots that were declared but never implemented: - AddUrlDialog: clipboard prefill is the explicit path docs/06 R2 calls for (no passive monitoring, not advertised). - FileInfoDialog: async download.probe never blocks the UI; ends by calling download.add itself (Now / Later / Add to Queue). buildSpec() is a pure static so the optional-field-omission logic is unit-testable without touching a widget. - ProgressDialog: non-modal, WA_DeleteOnClose, driven by the taskProgress/ taskStateChanged signals RpcClient already re-broadcasts; download.get seeds state once for a dialog opened mid-transfer. Hosts SegmentBarsWidget and SpeedGraphWidget. MainWindow: openAddUrlDialog/openPropertiesForSelection/showTableContextMenu now have bodies; category.list/queue.list responses are cached so File Info can populate its category combo and queue menu without a second round trip. The row context menu covers what already exists (Resume/Pause/Stop/Delete/ Properties) and deliberately leaves out Open/Open With/Move-Rename/ Redownload/Add to Queue — those need dialogs later build-order steps haven't reached yet. util/Format.hpp: pulled the bytes/rate/eta formatting out of MainWindow and DownloadTableModel once the dialogs wanted the same strings a third time. Verified end-to-end against a running mockd (category.list/queue.list, download.probe, download.add, download.get, and live event.task.progress/ event.task.state) under ASan+UBSan: all three dialogs render correctly against real fixture data and the flow runs clean with no leaks or sanitizer reports. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NSCdCWFXBTSBBK3MzWtJiC
67 lines
2.8 KiB
C++
67 lines
2.8 KiB
C++
// FileInfoDialog::buildSpec unit tests. Lane GUI.
|
|
//
|
|
// Pure function, no widgets involved — see the comment on the declaration. Red when an
|
|
// optional field starts being sent empty instead of omitted, or queueId leaks into a spec
|
|
// whose startMode isn't "queue".
|
|
|
|
#include <QJsonObject>
|
|
#include <QtTest>
|
|
|
|
#include "dialogs/FileInfoDialog.hpp"
|
|
|
|
using velox::gui::FileInfoDialog;
|
|
|
|
class TstFileInfoDialog : public QObject {
|
|
Q_OBJECT
|
|
|
|
private slots:
|
|
void requiredFieldsAlwaysPresent();
|
|
void emptyOptionalFieldsAreOmitted();
|
|
void fullSpecIncludesEveryField();
|
|
void queueIdOnlySentForQueueStartMode();
|
|
};
|
|
|
|
void TstFileInfoDialog::requiredFieldsAlwaysPresent() {
|
|
const QJsonObject spec =
|
|
FileInfoDialog::buildSpec("https://example.test/file.bin", "", "", "", "", 0, 0, "now", "");
|
|
QCOMPARE(spec.value("url").toString(), QStringLiteral("https://example.test/file.bin"));
|
|
QCOMPARE(spec.value("startMode").toString(), QStringLiteral("now"));
|
|
}
|
|
|
|
void TstFileInfoDialog::emptyOptionalFieldsAreOmitted() {
|
|
const QJsonObject spec =
|
|
FileInfoDialog::buildSpec("https://example.test/file.bin", "", "", "", "", 0, 0, "now", "");
|
|
QVERIFY(!spec.contains("filename"));
|
|
QVERIFY(!spec.contains("saveDir"));
|
|
QVERIFY(!spec.contains("categoryId"));
|
|
QVERIFY(!spec.contains("description"));
|
|
QVERIFY(!spec.contains("segments"));
|
|
QVERIFY(!spec.contains("bufferBytes"));
|
|
QVERIFY(!spec.contains("queueId"));
|
|
}
|
|
|
|
void TstFileInfoDialog::fullSpecIncludesEveryField() {
|
|
const QJsonObject spec =
|
|
FileInfoDialog::buildSpec("https://example.test/file.bin", "file.bin", "/home/x/Downloads",
|
|
"cat1", "a note", 8, 4 * 1024 * 1024, "later", "");
|
|
QCOMPARE(spec.value("filename").toString(), QStringLiteral("file.bin"));
|
|
QCOMPARE(spec.value("saveDir").toString(), QStringLiteral("/home/x/Downloads"));
|
|
QCOMPARE(spec.value("categoryId").toString(), QStringLiteral("cat1"));
|
|
QCOMPARE(spec.value("description").toString(), QStringLiteral("a note"));
|
|
QCOMPARE(spec.value("segments").toInt(), 8);
|
|
QCOMPARE(spec.value("bufferBytes").toDouble(), static_cast<double>(4 * 1024 * 1024));
|
|
}
|
|
|
|
void TstFileInfoDialog::queueIdOnlySentForQueueStartMode() {
|
|
const QJsonObject queued = FileInfoDialog::buildSpec("https://example.test/file.bin", "", "",
|
|
"", "", 0, 0, "queue", "q1");
|
|
QCOMPARE(queued.value("queueId").toString(), QStringLiteral("q1"));
|
|
|
|
const QJsonObject notQueued = FileInfoDialog::buildSpec("https://example.test/file.bin", "", "",
|
|
"", "", 0, 0, "now", "q1");
|
|
QVERIFY(!notQueued.contains("queueId"));
|
|
}
|
|
|
|
QTEST_MAIN(TstFileInfoDialog)
|
|
#include "tst_fileinfodialog.moc"
|