Step 2 - LDF Loading: - ldfparser integration (Python) / custom regex parser (C++) - QTreeWidget with expandable signal rows, merged Value column - Hex/Dec toggle, FreeFormat schedule entries, auto-reload - Baud rate auto-detection from LDF Step 3 - Signal Editing: - Bit packing/unpacking (signal value ↔ frame bytes) - ReadOnlyColumnDelegate for per-column editability - Value clamping to signal width, recursion guard Step 4 - Rx Panel: - receive_rx_frame() API with timestamp, signal unpacking - Change highlighting (yellow), auto-scroll toggle, clear button - Dashboard view (in-place update per frame_id) Step 5 - Connection Panel: - ConnectionManager with state machine (Disconnected/Connecting/Connected/Error) - Port scanning (pyserial / QSerialPort), connect/disconnect with UI mapping Step 6 - BabyLIN Backend: - BabyLinBackend wrapping Lipowsky BabyLIN_library.py DLL - Mock mode for macOS/CI, device scan, SDF loading, signal access - Frame callbacks, raw command access Step 7 - Master Scheduler: - QTimer-based schedule execution with start/stop/pause - Frame sent callback with visual highlighting - Mock Rx simulation, manual send, global rate override Tests: Python 171 | C++ 124 (Steps 1-5 parity, Steps 6-7 Python-first) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
93 lines
6.0 KiB
C++
93 lines
6.0 KiB
C++
/**
|
|
* test_main_window.cpp — Tests for the GUI skeleton + LDF loading (C++).
|
|
* Uses QTreeWidget instead of QTableWidget.
|
|
*/
|
|
|
|
#include <QtTest/QtTest>
|
|
#include <QDockWidget>
|
|
#include <QTreeWidget>
|
|
#include <QSpinBox>
|
|
#include <QLineEdit>
|
|
#include <QPushButton>
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QLabel>
|
|
#include "main_window.h"
|
|
|
|
class TestMainWindow : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private:
|
|
MainWindow* m_window;
|
|
|
|
private slots:
|
|
void init() { m_window = new MainWindow(); }
|
|
void cleanup() { delete m_window; m_window = nullptr; }
|
|
|
|
// ─── Window Basics ────────────────────────────────────────────
|
|
void test_windowTitle() { QCOMPARE(m_window->windowTitle(), QString("LIN Simulator")); }
|
|
void test_minimumSize() { QVERIFY(m_window->minimumWidth() >= 1024); QVERIFY(m_window->minimumHeight() >= 768); }
|
|
void test_centralWidgetExists() { QVERIFY(m_window->centralWidget() != nullptr); }
|
|
|
|
// ─── Menu Bar ─────────────────────────────────────────────────
|
|
void test_menuBarExists() { QVERIFY(m_window->menuBar() != nullptr); }
|
|
void test_loadLdfActionExists() { QVERIFY(m_window->loadLdfAction() != nullptr); QCOMPARE(m_window->loadLdfAction()->text(), QString("&Load LDF...")); }
|
|
void test_loadLdfShortcut() { QCOMPARE(m_window->loadLdfAction()->shortcut().toString(), QString("Ctrl+O")); }
|
|
|
|
// ─── LDF Toolbar ──────────────────────────────────────────────
|
|
void test_ldfPathFieldExists() { QVERIFY(m_window->ldfPathEdit() != nullptr); QVERIFY(m_window->ldfPathEdit()->isReadOnly()); }
|
|
void test_ldfPathPlaceholder() { QCOMPARE(m_window->ldfPathEdit()->placeholderText(), QString("No LDF file loaded")); }
|
|
void test_browseButtonExists() { QVERIFY(m_window->browseButton() != nullptr); }
|
|
void test_autoReloadDefaultChecked() { QVERIFY(m_window->autoReloadCheck()->isChecked()); }
|
|
void test_hexModeDefaultChecked() { QVERIFY(m_window->hexModeCheck()->isChecked()); }
|
|
|
|
// ─── Tx Tree ──────────────────────────────────────────────────
|
|
void test_txTableExists() { QVERIFY(qobject_cast<QTreeWidget*>(m_window->txTable()) != nullptr); }
|
|
void test_txTableColumns()
|
|
{
|
|
QCOMPARE(m_window->txTable()->columnCount(), 6);
|
|
QStringList expected = {"Name", "ID / Bit", "Length / Width", "Interval (ms)", "Value", "Action"};
|
|
for (int i = 0; i < m_window->txTable()->columnCount(); ++i)
|
|
QCOMPARE(m_window->txTable()->headerItem()->text(i), expected[i]);
|
|
}
|
|
void test_txTableAlternatingColors() { QVERIFY(m_window->txTable()->alternatingRowColors()); }
|
|
void test_txTableIsDecorated() { QVERIFY(m_window->txTable()->rootIsDecorated()); }
|
|
|
|
// ─── Rx Tree ──────────────────────────────────────────────────
|
|
void test_rxTableExists() { QVERIFY(qobject_cast<QTreeWidget*>(m_window->rxTable()) != nullptr); }
|
|
void test_rxTableColumns()
|
|
{
|
|
QCOMPARE(m_window->rxTable()->columnCount(), 5);
|
|
QStringList expected = {"Timestamp", "Name", "ID / Bit", "Length / Width", "Value"};
|
|
for (int i = 0; i < m_window->rxTable()->columnCount(); ++i)
|
|
QCOMPARE(m_window->rxTable()->headerItem()->text(i), expected[i]);
|
|
}
|
|
void test_rxTableIsDecorated() { QVERIFY(m_window->rxTable()->rootIsDecorated()); }
|
|
|
|
// ─── Connection Dock ──────────────────────────────────────────
|
|
void test_dockExists() { auto docks = m_window->findChildren<QDockWidget*>(); QCOMPARE(docks.size(), 1); QCOMPARE(docks[0]->windowTitle(), QString("Connection")); }
|
|
void test_deviceComboExists() { QVERIFY(m_window->deviceCombo() != nullptr); }
|
|
void test_connectButtonExists() { QVERIFY(m_window->connectButton() != nullptr); QVERIFY(m_window->connectButton()->isEnabled()); }
|
|
void test_disconnectButtonDisabledInitially() { QVERIFY(!m_window->disconnectButton()->isEnabled()); }
|
|
void test_statusLabelShowsDisconnected() { QVERIFY(m_window->connStatusLabel()->text().contains("Disconnected")); }
|
|
void test_baudRateLabelExists() { QVERIFY(m_window->baudRateLabel() != nullptr); }
|
|
void test_baudRateShowsPlaceholderBeforeLdf() { QVERIFY(m_window->baudRateLabel()->text().contains("load LDF")); }
|
|
|
|
// ─── Control Bar ──────────────────────────────────────────────
|
|
void test_scheduleComboExists() { QVERIFY(m_window->scheduleCombo() != nullptr); }
|
|
void test_schedulerButtonsDisabledInitially() { QVERIFY(!m_window->startButton()->isEnabled()); QVERIFY(!m_window->stopButton()->isEnabled()); QVERIFY(!m_window->pauseButton()->isEnabled()); }
|
|
void test_manualSendDisabledInitially() { QVERIFY(!m_window->manualSendButton()->isEnabled()); }
|
|
void test_globalRateSpinboxExists() { QVERIFY(m_window->globalRateSpin() != nullptr); }
|
|
void test_globalRateDefault50ms() { QCOMPARE(m_window->globalRateSpin()->value(), 50); }
|
|
void test_globalRateRange() { QCOMPARE(m_window->globalRateSpin()->minimum(), 1); QCOMPARE(m_window->globalRateSpin()->maximum(), 10000); }
|
|
void test_globalRateSuffix() { QCOMPARE(m_window->globalRateSpin()->suffix(), QString(" ms")); }
|
|
|
|
// ─── Status Bar ───────────────────────────────────────────────
|
|
void test_statusBarExists() { QVERIFY(m_window->statusBar() != nullptr); }
|
|
void test_connectionStatusLabel() { QVERIFY(m_window->statusConnectionLabel()->text().contains("Disconnected")); }
|
|
};
|
|
|
|
QTEST_MAIN(TestMainWindow)
|
|
#include "test_main_window.moc"
|