Files
vdm/gui/tests/tst_fileinfodialog.cpp
samiandClaude Sonnet 5 a71d904a1f gui: finish Add URL -> File Info -> Progress dialog flow
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
2026-09-11 12:11:13 +04:00

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"