/** * test_signal_editing.cpp — Tests for Step 3: signal ↔ frame byte sync. * Tests bit packing/unpacking and signal value editing. */ #include #include #include #include "main_window.h" #ifndef LDF_SAMPLE_PATH #error "LDF_SAMPLE_PATH must be defined by CMake" #endif class TestSignalEditing : public QObject { Q_OBJECT private: MainWindow* m_window; private slots: void init() { m_window = new MainWindow(); m_window->loadLdfFile(QString(LDF_SAMPLE_PATH)); } void cleanup() { delete m_window; m_window = nullptr; } // ─── Bit Packing Unit Tests ─────────────────────────────────── void test_packSingleBit() { QVector buf = {0, 0}; MainWindow::packSignal(buf, 0, 1, 1); QCOMPARE(buf[0], 0x01); } void test_packByteAtOffset8() { QVector buf = {0, 0}; MainWindow::packSignal(buf, 8, 8, 0x80); QCOMPARE(buf[1], 0x80); } void test_pack2bitAtOffset1() { QVector buf = {0, 0}; MainWindow::packSignal(buf, 1, 2, 3); QCOMPARE(buf[0], 0x06); } void test_packMultipleSignals() { QVector buf = {0, 0}; MainWindow::packSignal(buf, 0, 1, 1); // MotorEnable MainWindow::packSignal(buf, 1, 2, 2); // MotorDirection MainWindow::packSignal(buf, 8, 8, 128); // MotorSpeed QCOMPARE(buf[0], 0x05); QCOMPARE(buf[1], 0x80); } void test_extractSingleBit() { QVector buf = {0x01, 0}; QCOMPARE(MainWindow::extractSignal(buf, 0, 1), 1); } void test_extractByteAtOffset8() { QVector buf = {0, 0x80}; QCOMPARE(MainWindow::extractSignal(buf, 8, 8), 0x80); } void test_extract2bitAtOffset1() { QVector buf = {0x06, 0}; QCOMPARE(MainWindow::extractSignal(buf, 1, 2), 3); } void test_packThenExtractRoundtrip() { QVector buf = {0, 0}; MainWindow::packSignal(buf, 8, 8, 200); QCOMPARE(MainWindow::extractSignal(buf, 8, 8), 200); } // ─── Signal Value Editing ───────────────────────────────────── void test_editSignalUpdatesFrameBytes() { auto* frameItem = m_window->txTable()->topLevelItem(0); auto* speedSig = frameItem->child(2); // MotorSpeed (bit 8, width 8) // Simulate user edit speedSig->setText(4, "128"); // Frame bytes should reflect MotorSpeed=128 QVariantList bytes = frameItem->data(4, Qt::UserRole).toList(); QCOMPARE(bytes[1].toInt(), 128); } void test_editSignalPreservesOtherSignals() { auto* frameItem = m_window->txTable()->topLevelItem(0); auto* enableSig = frameItem->child(0); auto* speedSig = frameItem->child(2); enableSig->setText(4, "1"); speedSig->setText(4, "255"); QVariantList bytes = frameItem->data(4, Qt::UserRole).toList(); QVERIFY(bytes[0].toInt() & 0x01); // MotorEnable still 1 QCOMPARE(bytes[1].toInt(), 255); } void test_signalValueClampedToWidth() { auto* frameItem = m_window->txTable()->topLevelItem(0); auto* enableSig = frameItem->child(0); // width 1, max = 1 enableSig->setText(4, "5"); int stored = enableSig->data(4, Qt::UserRole).toInt(); QVERIFY(stored <= 1); } // ─── Frame Value Editing ────────────────────────────────────── void test_editFrameBytesUpdatesSignals() { auto* frameItem = m_window->txTable()->topLevelItem(0); frameItem->setText(4, "05 C8"); // MotorEnable (bit 0, w1) = 1 QCOMPARE(frameItem->child(0)->data(4, Qt::UserRole).toInt(), 1); // MotorDirection (bit 1, w2) = 2 QCOMPARE(frameItem->child(1)->data(4, Qt::UserRole).toInt(), 2); // MotorSpeed (bit 8, w8) = 200 QCOMPARE(frameItem->child(2)->data(4, Qt::UserRole).toInt(), 200); } void test_editFrameBytesInvalidReverts() { auto* frameItem = m_window->txTable()->topLevelItem(0); QVariantList oldBytes = frameItem->data(4, Qt::UserRole).toList(); frameItem->setText(4, "not valid hex"); QVariantList newBytes = frameItem->data(4, Qt::UserRole).toList(); QCOMPARE(newBytes, oldBytes); } }; QTEST_MAIN(TestSignalEditing) #include "test_signal_editing.moc"