/* * SPDX-License-Identifier: LGPL-2.0-or-later * * Unit tests for the plumb message codec. The golden bytes are taken verbatim * from a live plan9port plumber on the edit port (captured during design), so * these tests pin our pack/unpack to the real wire format, not to a guess. */ #include "plumbmsg.h" #include #include using namespace deft; class TestPlumbMsg : public QObject { Q_OBJECT private Q_SLOTS: void unpackEditFileWithAddr(); void unpackEditUrlEmptyAddr(); void packRoundTrip(); void attrQuotingRoundTrip(); void attrDoubledQuote(); void shortNdataTolerated(); }; // Golden message #1 (file:line -> edit): captured bytes were // "plumb\nedit\n/tmp\ntext\naddr=2\n18\n/tmp/plumbtest.txt" void TestPlumbMsg::unpackEditFileWithAddr() { const QByteArray buf = QByteArrayLiteral( "plumb\nedit\n/tmp\ntext\naddr=2\n18\n/tmp/plumbtest.txt"); PlumbMsg m; QVERIFY(PlumbMsg::unpack(buf, &m)); QCOMPARE(m.src, QStringLiteral("plumb")); QCOMPARE(m.dst, QStringLiteral("edit")); QCOMPARE(m.wdir, QStringLiteral("/tmp")); QCOMPARE(m.type, QStringLiteral("text")); QCOMPARE(m.lookup(QStringLiteral("addr")), QStringLiteral("2")); QCOMPARE(QString::fromUtf8(m.data), QStringLiteral("/tmp/plumbtest.txt")); } // Golden message #2 (url -> edit, empty addr): captured bytes were // "plumb\nedit\n/tmp\ntext\n\n19\nhttps://example.com" void TestPlumbMsg::unpackEditUrlEmptyAddr() { const QByteArray buf = QByteArrayLiteral( "plumb\nedit\n/tmp\ntext\n\n19\nhttps://example.com"); PlumbMsg m; QVERIFY(PlumbMsg::unpack(buf, &m)); QVERIFY(m.attr.isEmpty()); QCOMPARE(m.lookup(QStringLiteral("addr")), QString()); QCOMPARE(QString::fromUtf8(m.data), QStringLiteral("https://example.com")); } void TestPlumbMsg::packRoundTrip() { PlumbMsg m; m.src = QStringLiteral("kate"); m.dst = QString(); m.wdir = QStringLiteral("/home/user/proj"); m.type = QStringLiteral("text"); m.setAttr(QStringLiteral("addr"), QStringLiteral("42")); m.data = QByteArrayLiteral("main.cpp"); const QByteArray packed = m.pack(); // Header shape: six '\n'-terminated lines then data with no trailing \n. QCOMPARE(packed, QByteArrayLiteral( "kate\n\n/home/user/proj\ntext\naddr=42\n8\nmain.cpp")); PlumbMsg back; QVERIFY(PlumbMsg::unpack(packed, &back)); QCOMPARE(back.src, m.src); QCOMPARE(back.dst, m.dst); QCOMPARE(back.wdir, m.wdir); QCOMPARE(back.type, m.type); QCOMPARE(back.lookup(QStringLiteral("addr")), QStringLiteral("42")); QCOMPARE(back.data, m.data); } void TestPlumbMsg::attrQuotingRoundTrip() { // A value with a space must be single-quoted on the wire. QList attr{{QStringLiteral("click"), QStringLiteral("1 2")}}; const QByteArray packed = packPlumbAttr(attr); QCOMPARE(packed, QByteArrayLiteral("click='1 2'")); const QList back = unpackPlumbAttr(packed); QCOMPARE(back, attr); } void TestPlumbMsg::attrDoubledQuote() { // A literal ' is doubled inside quotes. QList attr{{QStringLiteral("x"), QStringLiteral("a'b c")}}; const QByteArray packed = packPlumbAttr(attr); QCOMPARE(packed, QByteArrayLiteral("x='a''b c'")); const QList back = unpackPlumbAttr(packed); QCOMPARE(back.size(), 1); QCOMPARE(back.first().value, QStringLiteral("a'b c")); } void TestPlumbMsg::shortNdataTolerated() { // libplumb clamps ndata to the actual trailing bytes; a wrong count still // yields the real data (mirrors plumbunpackpartial behaviour). const QByteArray buf = QByteArrayLiteral("s\nd\nw\ntext\n\n999\nhello"); PlumbMsg m; QVERIFY(PlumbMsg::unpack(buf, &m)); QCOMPARE(QString::fromUtf8(m.data), QStringLiteral("hello")); } QTEST_MAIN(TestPlumbMsg) #include "test_plumbmsg.moc"