File indexing completed on 2024-04-28 05:50:36

0001 /*
0002     SPDX-FileCopyrightText: 2018 Kurt Hindenburg <kurt.hindenburg@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // Own
0008 #include "Vt102EmulationTest.h"
0009 
0010 #include <QTest>
0011 
0012 // The below is to verify the old #defines match the new constexprs
0013 // Just copy/paste for now from Vt102Emulation.cpp
0014 /* clang-format off */
0015 #define TY_CONSTRUCT(T, A, N) (((((int)(N)) & 0xffff) << 16) | ((((int)(A)) & 0xff) << 8) | (((int)(T)) & 0xff))
0016 #define TY_CHR()        TY_CONSTRUCT(0, 0, 0)
0017 #define TY_CTL(A)       TY_CONSTRUCT(1, A, 0)
0018 #define TY_ESC(A)       TY_CONSTRUCT(2, A, 0)
0019 #define TY_ESC_CS(A, B) TY_CONSTRUCT(3, A, B)
0020 #define TY_ESC_DE(A)    TY_CONSTRUCT(4, A, 0)
0021 #define TY_CSI_PS(A, N) TY_CONSTRUCT(5, A, N)
0022 #define TY_CSI_PN(A)    TY_CONSTRUCT(6, A, 0)
0023 #define TY_CSI_PR(A, N) TY_CONSTRUCT(7, A, N)
0024 #define TY_VT52(A)      TY_CONSTRUCT(8, A, 0)
0025 #define TY_CSI_PG(A)    TY_CONSTRUCT(9, A, 0)
0026 #define TY_CSI_PE(A)    TY_CONSTRUCT(10, A, 0)
0027 /* clang-format on */
0028 
0029 using namespace Konsole;
0030 
0031 constexpr int token_construct(int t, int a, int n)
0032 {
0033     return (((n & 0xffff) << 16) | ((a & 0xff) << 8) | (t & 0xff));
0034 }
0035 constexpr int token_chr()
0036 {
0037     return token_construct(0, 0, 0);
0038 }
0039 constexpr int token_ctl(int a)
0040 {
0041     return token_construct(1, a, 0);
0042 }
0043 constexpr int token_esc(int a)
0044 {
0045     return token_construct(2, a, 0);
0046 }
0047 constexpr int token_esc_cs(int a, int b)
0048 {
0049     return token_construct(3, a, b);
0050 }
0051 constexpr int token_esc_de(int a)
0052 {
0053     return token_construct(4, a, 0);
0054 }
0055 constexpr int token_csi_ps(int a, int n)
0056 {
0057     return token_construct(5, a, n);
0058 }
0059 constexpr int token_csi_pn(int a)
0060 {
0061     return token_construct(6, a, 0);
0062 }
0063 constexpr int token_csi_pr(int a, int n)
0064 {
0065     return token_construct(7, a, n);
0066 }
0067 constexpr int token_vt52(int a)
0068 {
0069     return token_construct(8, a, 0);
0070 }
0071 constexpr int token_csi_pg(int a)
0072 {
0073     return token_construct(9, a, 0);
0074 }
0075 constexpr int token_csi_pe(int a)
0076 {
0077     return token_construct(10, a, 0);
0078 }
0079 constexpr int token_csi_sp(int a)
0080 {
0081     return token_construct(11, a, 0);
0082 }
0083 constexpr int token_csi_psp(int a, int n)
0084 {
0085     return token_construct(12, a, n);
0086 }
0087 constexpr int token_csi_pq(int a)
0088 {
0089     return token_construct(13, a, 0);
0090 }
0091 
0092 void Vt102EmulationTest::sendAndCompare(TestEmulation *em, const char *input, size_t inputLen, const QString &expectedPrint, const QByteArray &expectedSent)
0093 {
0094     em->_currentScreen->clearEntireScreen();
0095 
0096     em->receiveData(input, inputLen);
0097     QString printed = em->_currentScreen->text(0, em->_currentScreen->getColumns(), Screen::PlainText);
0098     printed.chop(2); // Remove trailing space and newline
0099     QCOMPARE(printed, expectedPrint);
0100     QCOMPARE(em->lastSent, expectedSent);
0101 }
0102 
0103 void Vt102EmulationTest::testParse()
0104 {
0105     TestEmulation em;
0106     em.reset();
0107     em.setCodec(TestEmulation::Utf8Codec);
0108     Q_ASSERT(em._currentScreen != nullptr);
0109 
0110     sendAndCompare(&em, "a", 1, QStringLiteral("a"), "");
0111 
0112     const char tertiaryDeviceAttributes[] = {0x1b, '[', '=', '0', 'c'};
0113     sendAndCompare(&em, tertiaryDeviceAttributes, sizeof tertiaryDeviceAttributes, QStringLiteral(""), "\033P!|7E4B4445\033\\");
0114 }
0115 
0116 Q_DECLARE_METATYPE(std::vector<TestEmulation::Item>)
0117 
0118 struct ItemToString {
0119     QString operator()(const TestEmulation::ProcessToken &item)
0120     {
0121         return QStringLiteral("processToken(0x%0, %1, %2)").arg(QString::number(item.code, 16), QString::number(item.p), QString::number(item.q));
0122     }
0123 
0124     QString operator()(TestEmulation::ProcessSessionAttributeRequest)
0125     {
0126         return QStringLiteral("ProcessSessionAttributeRequest");
0127     }
0128 
0129     QString operator()(TestEmulation::ProcessChecksumRequest)
0130     {
0131         return QStringLiteral("ProcessChecksumRequest");
0132     }
0133 
0134     QString operator()(TestEmulation::DecodingError)
0135     {
0136         return QStringLiteral("DecodingError");
0137     }
0138 };
0139 
0140 namespace QTest
0141 {
0142 template<>
0143 char *toString(const std::vector<TestEmulation::Item> &items)
0144 {
0145     QStringList res;
0146     for (auto item : items) {
0147         res.append(std::visit(ItemToString{}, item));
0148     }
0149     return toString(res.join(QStringLiteral(",")));
0150 }
0151 }
0152 
0153 void Vt102EmulationTest::testTokenizing_data()
0154 {
0155     QTest::addColumn<QVector<uint>>("input");
0156     QTest::addColumn<std::vector<TestEmulation::Item>>("expectedItems");
0157 
0158     using ProcessToken = TestEmulation::ProcessToken;
0159 
0160     using C = QVector<uint>;
0161     using I = std::vector<TestEmulation::Item>;
0162 
0163     /* clang-format off */
0164     QTest::newRow("NUL") << C{'@' - '@'} << I{ProcessToken{token_ctl('@'), 0, 0}};
0165     QTest::newRow("SOH") << C{'A' - '@'} << I{ProcessToken{token_ctl('A'), 0, 0}};
0166     QTest::newRow("STX") << C{'B' - '@'} << I{ProcessToken{token_ctl('B'), 0, 0}};
0167     QTest::newRow("ETX") << C{'C' - '@'} << I{ProcessToken{token_ctl('C'), 0, 0}};
0168     QTest::newRow("EOT") << C{'D' - '@'} << I{ProcessToken{token_ctl('D'), 0, 0}};
0169     QTest::newRow("ENQ") << C{'E' - '@'} << I{ProcessToken{token_ctl('E'), 0, 0}};
0170     QTest::newRow("ACK") << C{'F' - '@'} << I{ProcessToken{token_ctl('F'), 0, 0}};
0171     QTest::newRow("BEL") << C{'G' - '@'} << I{ProcessToken{token_ctl('G'), 0, 0}};
0172     QTest::newRow("BS")  << C{'H' - '@'} << I{ProcessToken{token_ctl('H'), 0, 0}};
0173     QTest::newRow("TAB") << C{'I' - '@'} << I{ProcessToken{token_ctl('I'), 0, 0}};
0174     QTest::newRow("LF")  << C{'J' - '@'} << I{ProcessToken{token_ctl('J'), 0, 0}};
0175     QTest::newRow("VT")  << C{'K' - '@'} << I{ProcessToken{token_ctl('K'), 0, 0}};
0176     QTest::newRow("FF")  << C{'L' - '@'} << I{ProcessToken{token_ctl('L'), 0, 0}};
0177     QTest::newRow("CR")  << C{'M' - '@'} << I{ProcessToken{token_ctl('M'), 0, 0}};
0178     QTest::newRow("SO")  << C{'N' - '@'} << I{ProcessToken{token_ctl('N'), 0, 0}};
0179     QTest::newRow("SI")  << C{'O' - '@'} << I{ProcessToken{token_ctl('O'), 0, 0}};
0180 
0181     QTest::newRow("DLE") << C{'P' - '@'} << I{ProcessToken{token_ctl('P'), 0, 0}};
0182     QTest::newRow("XON") << C{'Q' - '@'} << I{ProcessToken{token_ctl('Q'), 0, 0}};
0183     QTest::newRow("DC2") << C{'R' - '@'} << I{ProcessToken{token_ctl('R'), 0, 0}};
0184     QTest::newRow("XOFF") << C{'S' - '@'} << I{ProcessToken{token_ctl('S'), 0, 0}};
0185     QTest::newRow("DC4") << C{'T' - '@'} << I{ProcessToken{token_ctl('T'), 0, 0}};
0186     QTest::newRow("NAK") << C{'U' - '@'} << I{ProcessToken{token_ctl('U'), 0, 0}};
0187     QTest::newRow("SYN") << C{'V' - '@'} << I{ProcessToken{token_ctl('V'), 0, 0}};
0188     QTest::newRow("ETB") << C{'W' - '@'} << I{ProcessToken{token_ctl('W'), 0, 0}};
0189     QTest::newRow("CAN") << C{'X' - '@'} << I{ProcessToken{token_ctl('X'), 0, 0}};
0190     QTest::newRow("EM")  << C{'Y' - '@'} << I{ProcessToken{token_ctl('Y'), 0, 0}};
0191     QTest::newRow("SUB") << C{'Z' - '@'} << I{ProcessToken{token_ctl('Z'), 0, 0}};
0192     // [ is ESC and parsed differently
0193     QTest::newRow("FS")  << C{'\\' - '@'} << I{ProcessToken{token_ctl('\\'), 0, 0}};
0194     QTest::newRow("GS")  << C{']' - '@'} << I{ProcessToken{token_ctl(']'), 0, 0}};
0195     QTest::newRow("RS")  << C{'^' - '@'} << I{ProcessToken{token_ctl('^'), 0, 0}};
0196     QTest::newRow("US")  << C{'_' - '@'} << I{ProcessToken{token_ctl('_'), 0, 0}};
0197 
0198     QTest::newRow("DEL") << C{127} << I{};
0199 
0200     const uint ESC = '\033';
0201 
0202     QTest::newRow("ESC 7") << C{ESC, '7'} << I{ProcessToken{token_esc('7'), 0, 0}};
0203     QTest::newRow("ESC 8") << C{ESC, '8'} << I{ProcessToken{token_esc('8'), 0, 0}};
0204     QTest::newRow("ESC D") << C{ESC, 'D'} << I{ProcessToken{token_esc('D'), 0, 0}};
0205     QTest::newRow("ESC E") << C{ESC, 'E'} << I{ProcessToken{token_esc('E'), 0, 0}};
0206     QTest::newRow("ESC H") << C{ESC, 'H'} << I{ProcessToken{token_esc('H'), 0, 0}};
0207     QTest::newRow("ESC M") << C{ESC, 'M'} << I{ProcessToken{token_esc('M'), 0, 0}};
0208     QTest::newRow("ESC Z") << C{ESC, 'Z'} << I{ProcessToken{token_esc('Z'), 0, 0}};
0209 
0210     QTest::newRow("ESC c") << C{ESC, 'c'} << I{ProcessToken{token_esc('c'), 0, 0}};
0211 
0212     QTest::newRow("ESC n") << C{ESC, 'n'} << I{ProcessToken{token_esc('n'), 0, 0}};
0213     QTest::newRow("ESC o") << C{ESC, 'o'} << I{ProcessToken{token_esc('o'), 0, 0}};
0214     QTest::newRow("ESC >") << C{ESC, '>'} << I{ProcessToken{token_esc('>'), 0, 0}};
0215     QTest::newRow("ESC <") << C{ESC, '<'} << I{ProcessToken{token_esc('<'), 0, 0}};
0216     QTest::newRow("ESC =") << C{ESC, '='} << I{ProcessToken{token_esc('='), 0, 0}};
0217 
0218     QTest::newRow("ESC #3") << C{ESC, '#', '3'} << I{ProcessToken{token_esc_de('3'), 0, 0}};
0219     QTest::newRow("ESC #4") << C{ESC, '#', '4'} << I{ProcessToken{token_esc_de('4'), 0, 0}};
0220     QTest::newRow("ESC #5") << C{ESC, '#', '5'} << I{ProcessToken{token_esc_de('5'), 0, 0}};
0221     QTest::newRow("ESC #6") << C{ESC, '#', '6'} << I{ProcessToken{token_esc_de('6'), 0, 0}};
0222     QTest::newRow("ESC #8") << C{ESC, '#', '8'} << I{ProcessToken{token_esc_de('8'), 0, 0}};
0223 
0224     QTest::newRow("ESC %G") << C{ESC, '%', 'G'} << I{ProcessToken{token_esc_cs('%', 'G'), 0, 0}};
0225     QTest::newRow("ESC %@") << C{ESC, '%', '@'} << I{ProcessToken{token_esc_cs('%', '@'), 0, 0}};
0226 
0227     QTest::newRow("ESC (0") << C{ESC, '(', '0'} << I{ProcessToken{token_esc_cs('(', '0'), 0, 0}};
0228     QTest::newRow("ESC (A") << C{ESC, '(', 'A'} << I{ProcessToken{token_esc_cs('(', 'A'), 0, 0}};
0229     QTest::newRow("ESC (B") << C{ESC, '(', 'B'} << I{ProcessToken{token_esc_cs('(', 'B'), 0, 0}};
0230 
0231     QTest::newRow("ESC )0") << C{ESC, ')', '0'} << I{ProcessToken{token_esc_cs(')', '0'), 0, 0}};
0232     QTest::newRow("ESC )A") << C{ESC, ')', 'A'} << I{ProcessToken{token_esc_cs(')', 'A'), 0, 0}};
0233     QTest::newRow("ESC )B") << C{ESC, ')', 'B'} << I{ProcessToken{token_esc_cs(')', 'B'), 0, 0}};
0234 
0235     QTest::newRow("ESC *0") << C{ESC, '*', '0'} << I{ProcessToken{token_esc_cs('*', '0'), 0, 0}};
0236     QTest::newRow("ESC *A") << C{ESC, '*', 'A'} << I{ProcessToken{token_esc_cs('*', 'A'), 0, 0}};
0237     QTest::newRow("ESC *B") << C{ESC, '*', 'B'} << I{ProcessToken{token_esc_cs('*', 'B'), 0, 0}};
0238 
0239     QTest::newRow("ESC +0") << C{ESC, '+', '0'} << I{ProcessToken{token_esc_cs('+', '0'), 0, 0}};
0240     QTest::newRow("ESC +A") << C{ESC, '+', 'A'} << I{ProcessToken{token_esc_cs('+', 'A'), 0, 0}};
0241     QTest::newRow("ESC +B") << C{ESC, '+', 'B'} << I{ProcessToken{token_esc_cs('+', 'B'), 0, 0}};
0242 
0243     QTest::newRow("ESC [8;12;45t") << C{ESC, '[', '8', ';', '1', '2', ';', '4', '5', 't'} << I{ProcessToken{token_csi_ps('t', 8), 12, 45}};
0244     QTest::newRow("ESC [18t")      << C{ESC, '[', '1', '8', 't'} << I{ProcessToken{token_csi_ps('t', 18), 0, 0}};
0245     QTest::newRow("ESC [18;1;2t")  << C{ESC, '[', '1', '8', ';', '1', ';', '2', 't'} << I{ProcessToken{token_csi_ps('t', 18), 1, 2}};
0246 
0247     QTest::newRow("ESC [K")  << C{ESC, '[', 'K'} << I{ProcessToken{token_csi_ps('K', 0), 0, 0}};
0248     QTest::newRow("ESC [0K") << C{ESC, '[', '0', 'K'} << I{ProcessToken{token_csi_ps('K', 0), 0, 0}};
0249     QTest::newRow("ESC [1K") << C{ESC, '[', '1', 'K'} << I{ProcessToken{token_csi_ps('K', 1), 0, 0}};
0250 
0251     QTest::newRow("ESC [@")   << C{ESC, '[', '@'} << I{ProcessToken{token_csi_pn('@'), 0, 0}};
0252     QTest::newRow("ESC [12@") << C{ESC, '[', '1', '2', '@'} << I{ProcessToken{token_csi_pn('@'), 12, 0}};
0253     QTest::newRow("ESC [H")   << C{ESC, '[', 'H'} << I{ProcessToken{token_csi_pn('H'), 0, 0}};
0254     QTest::newRow("ESC [24H") << C{ESC, '[', '2', '4', 'H'} << I{ProcessToken{token_csi_pn('H'), 24, 0}};
0255     QTest::newRow("ESC [32,13H") << C{ESC, '[', '3', '2', ';', '1', '3', 'H'} << I{ProcessToken{token_csi_pn('H'), 32, 13}};
0256 
0257     QTest::newRow("ESC [m")   << C{ESC, '[', 'm'} << I{ProcessToken{token_csi_ps('m', 0), 0, 0}};
0258     QTest::newRow("ESC [1m")  << C{ESC, '[', '1', 'm'} << I{ProcessToken{token_csi_ps('m', 1), 0, 0}};
0259     QTest::newRow("ESC [1;2m") << C{ESC, '[', '1', ';', '2', 'm'} << I{ProcessToken{token_csi_ps('m', 1), 0, 0}, ProcessToken{token_csi_ps('m', 2), 0, 0}};
0260     QTest::newRow("ESC [38;2;193;202;218m") << C{ESC, '[', '3', '8', ';', '2', ';', '1', '9', '3', ';', '2', '0', '2', ';', '2', '1', '8', 'm'}
0261                                             << I{ProcessToken{token_csi_ps('m', 38), 4, 0xC1CADA}};
0262     QTest::newRow("ESC [38;2;193;202;218;2m") << C{ESC, '[', '3', '8', ';', '2', ';', '1', '9', '3', ';', '2', '0', '2', ';', '2', '1', '8', ';', '2', 'm'}
0263                                               << I{ProcessToken{token_csi_ps('m', 38), 4, 0xC1CADA}, ProcessToken{token_csi_ps('m', 2), 0, 0}};
0264     QTest::newRow("ESC [38:2:193:202:218m") << C{ESC, '[', '3', '8', ':', '2', ':', '1', '9', '3', ':', '2', '0', '2', ':', '2', '1', '8', 'm'}
0265                                             << I{ProcessToken{token_csi_ps('m', 38), 4, 0xC1CADA}};
0266     QTest::newRow("ESC [38:2:193:202:218;2m") << C{ESC, '[', '3', '8', ':', '2', ':', '1', '9', '3', ':', '2', '0', '2', ':', '2', '1', '8', ';', '2', 'm'}
0267                                               << I{ProcessToken{token_csi_ps('m', 38), 4, 0xC1CADA}, ProcessToken{token_csi_ps('m', 2), 0, 0}};
0268     QTest::newRow("ESC [38:2:1:193:202:218m") << C{ESC, '[', '3', '8', ':', '2', ':', '1', ':', '1', '9', '3', ':', '2', '0', '2', ':', '2', '1', '8', 'm'}
0269                                               << I{ProcessToken{token_csi_ps('m', 38), 4, 0xC1CADA}};
0270     QTest::newRow("ESC [38;5;255;2m") << C{ESC, '[', '3', '8', ';', '5', ';', '2', '5', '5', ';', '2', 'm'}
0271                                       << I{ProcessToken{token_csi_ps('m', 38), 3, 255}, ProcessToken{token_csi_ps('m', 2), 0, 0}};
0272     QTest::newRow("ESC [38:5:255m") << C{ESC, '[', '3', '8', ':', '5', ':', '2', '5', '5', 'm'}
0273                                     << I{ProcessToken{token_csi_ps('m', 38), 3, 255}};
0274 
0275     QTest::newRow("ESC [5n")  << C{ESC, '[', '5', 'n'} << I{ProcessToken{token_csi_ps('n', 5), 0, 0}};
0276 
0277     QTest::newRow("ESC [?1h") << C{ESC, '[', '?', '1', 'h'} << I{ProcessToken{token_csi_pr('h', 1), 0, 0}};
0278     QTest::newRow("ESC [?1l") << C{ESC, '[', '?', '1', 'l'} << I{ProcessToken{token_csi_pr('l', 1), 0, 0}};
0279     QTest::newRow("ESC [?1r") << C{ESC, '[', '?', '1', 'r'} << I{ProcessToken{token_csi_pr('r', 1), 0, 0}};
0280     QTest::newRow("ESC [?1s") << C{ESC, '[', '?', '1', 's'} << I{ProcessToken{token_csi_pr('s', 1), 0, 0}};
0281 
0282     QTest::newRow("ESC [?1;2h") << C{ESC, '[', '?', '1', ';', '2', 'h'}
0283                                 << I{ProcessToken{token_csi_pr('h', 1), 0, 0}, ProcessToken{token_csi_pr('h', 2), 1, 0}};
0284     QTest::newRow("ESC [?1;2l") << C{ESC, '[', '?', '1', ';', '2', 'l'}
0285                                 << I{ProcessToken{token_csi_pr('l', 1), 0, 0}, ProcessToken{token_csi_pr('l', 2), 1, 0}};
0286     QTest::newRow("ESC [?1;2r") << C{ESC, '[', '?', '1', ';', '2', 'r'}
0287                                 << I{ProcessToken{token_csi_pr('r', 1), 0, 0}, ProcessToken{token_csi_pr('r', 2), 1, 0}};
0288     QTest::newRow("ESC [?1;2s") << C{ESC, '[', '?', '1', ';', '2', 's'}
0289                                 << I{ProcessToken{token_csi_pr('s', 1), 0, 0}, ProcessToken{token_csi_pr('s', 2), 1, 0}};
0290 
0291     QTest::newRow("ESC [? q")  << C{ESC, '[', ' ', 'q'} << I{ProcessToken{token_csi_sp('q'), 0, 0}};
0292     QTest::newRow("ESC [? 1q") << C{ESC, '[', '1', ' ', 'q'} << I{ProcessToken{token_csi_psp('q', 1), 0, 0}};
0293 
0294     QTest::newRow("ESC [!p") << C{ESC, '[', '!', 'p'} << I{ProcessToken{token_csi_pe('p'), 0, 0}};
0295     QTest::newRow("ESC [=c") << C{ESC, '[', '=', 'p'} << I{ProcessToken{token_csi_pq('p'), 0, 0}};
0296     QTest::newRow("ESC [>c") << C{ESC, '[', '>', 'p'} << I{ProcessToken{token_csi_pg('p'), 0, 0}};
0297     /* clang-format on */
0298 }
0299 
0300 void Vt102EmulationTest::testTokenizing()
0301 {
0302     QFETCH(QVector<uint>, input);
0303     QFETCH(std::vector<TestEmulation::Item>, expectedItems);
0304 
0305     TestEmulation em;
0306     em.reset();
0307     em.blockFurtherProcessing = true;
0308 
0309     em._currentScreen->clearEntireScreen();
0310 
0311     em.receiveChars(input);
0312     QString printed = em._currentScreen->text(0, em._currentScreen->getColumns(), Screen::PlainText);
0313     printed.chop(2); // Remove trailing space and newline
0314 
0315     QCOMPARE(printed, QStringLiteral(""));
0316     QCOMPARE(em.items, expectedItems);
0317 }
0318 
0319 void Vt102EmulationTest::testTokenizingVT52_data()
0320 {
0321     QTest::addColumn<QVector<uint>>("input");
0322     QTest::addColumn<std::vector<TestEmulation::Item>>("expectedItems");
0323 
0324     using ProcessToken = TestEmulation::ProcessToken;
0325 
0326     using C = QVector<uint>;
0327     using I = std::vector<TestEmulation::Item>;
0328 
0329     /* clang-format off */
0330     QTest::newRow("NUL") << C{'@' - '@'} << I{ProcessToken{token_ctl('@'), 0, 0}};
0331     QTest::newRow("SOH") << C{'A' - '@'} << I{ProcessToken{token_ctl('A'), 0, 0}};
0332     QTest::newRow("STX") << C{'B' - '@'} << I{ProcessToken{token_ctl('B'), 0, 0}};
0333     QTest::newRow("ETX") << C{'C' - '@'} << I{ProcessToken{token_ctl('C'), 0, 0}};
0334     QTest::newRow("EOT") << C{'D' - '@'} << I{ProcessToken{token_ctl('D'), 0, 0}};
0335     QTest::newRow("ENQ") << C{'E' - '@'} << I{ProcessToken{token_ctl('E'), 0, 0}};
0336     QTest::newRow("ACK") << C{'F' - '@'} << I{ProcessToken{token_ctl('F'), 0, 0}};
0337     QTest::newRow("BEL") << C{'G' - '@'} << I{ProcessToken{token_ctl('G'), 0, 0}};
0338     QTest::newRow("BS")  << C{'H' - '@'} << I{ProcessToken{token_ctl('H'), 0, 0}};
0339     QTest::newRow("TAB") << C{'I' - '@'} << I{ProcessToken{token_ctl('I'), 0, 0}};
0340     QTest::newRow("LF")  << C{'J' - '@'} << I{ProcessToken{token_ctl('J'), 0, 0}};
0341     QTest::newRow("VT")  << C{'K' - '@'} << I{ProcessToken{token_ctl('K'), 0, 0}};
0342     QTest::newRow("FF")  << C{'L' - '@'} << I{ProcessToken{token_ctl('L'), 0, 0}};
0343     QTest::newRow("CR")  << C{'M' - '@'} << I{ProcessToken{token_ctl('M'), 0, 0}};
0344     QTest::newRow("SO")  << C{'N' - '@'} << I{ProcessToken{token_ctl('N'), 0, 0}};
0345     QTest::newRow("SI")  << C{'O' - '@'} << I{ProcessToken{token_ctl('O'), 0, 0}};
0346 
0347     QTest::newRow("DLE") << C{'P' - '@'} << I{ProcessToken{token_ctl('P'), 0, 0}};
0348     QTest::newRow("XON") << C{'Q' - '@'} << I{ProcessToken{token_ctl('Q'), 0, 0}};
0349     QTest::newRow("DC2") << C{'R' - '@'} << I{ProcessToken{token_ctl('R'), 0, 0}};
0350     QTest::newRow("XOFF") << C{'S' - '@'} << I{ProcessToken{token_ctl('S'), 0, 0}};
0351     QTest::newRow("DC4") << C{'T' - '@'} << I{ProcessToken{token_ctl('T'), 0, 0}};
0352     QTest::newRow("NAK") << C{'U' - '@'} << I{ProcessToken{token_ctl('U'), 0, 0}};
0353     QTest::newRow("SYN") << C{'V' - '@'} << I{ProcessToken{token_ctl('V'), 0, 0}};
0354     QTest::newRow("ETB") << C{'W' - '@'} << I{ProcessToken{token_ctl('W'), 0, 0}};
0355     QTest::newRow("CAN") << C{'X' - '@'} << I{ProcessToken{token_ctl('X'), 0, 0}};
0356     QTest::newRow("EM")  << C{'Y' - '@'} << I{ProcessToken{token_ctl('Y'), 0, 0}};
0357     QTest::newRow("SUB") << C{'Z' - '@'} << I{ProcessToken{token_ctl('Z'), 0, 0}};
0358     // [ is ESC and parsed differently
0359     QTest::newRow("FS")  << C{'\\' - '@'} << I{ProcessToken{token_ctl('\\'), 0, 0}};
0360     QTest::newRow("GS")  << C{']' - '@'} << I{ProcessToken{token_ctl(']'), 0, 0}};
0361     QTest::newRow("RS")  << C{'^' - '@'} << I{ProcessToken{token_ctl('^'), 0, 0}};
0362     QTest::newRow("US")  << C{'_' - '@'} << I{ProcessToken{token_ctl('_'), 0, 0}};
0363 
0364     QTest::newRow("DEL") << C{127} << I{};
0365 
0366     const uint ESC = '\033';
0367 
0368     QTest::newRow("ESC A") << C{ESC, 'A'} << I{ProcessToken{token_vt52('A'), 0, 0}};
0369     QTest::newRow("ESC B") << C{ESC, 'B'} << I{ProcessToken{token_vt52('B'), 0, 0}};
0370     QTest::newRow("ESC C") << C{ESC, 'C'} << I{ProcessToken{token_vt52('C'), 0, 0}};
0371     QTest::newRow("ESC D") << C{ESC, 'D'} << I{ProcessToken{token_vt52('D'), 0, 0}};
0372     QTest::newRow("ESC F") << C{ESC, 'F'} << I{ProcessToken{token_vt52('F'), 0, 0}};
0373     QTest::newRow("ESC G") << C{ESC, 'G'} << I{ProcessToken{token_vt52('G'), 0, 0}};
0374     QTest::newRow("ESC H") << C{ESC, 'H'} << I{ProcessToken{token_vt52('H'), 0, 0}};
0375     QTest::newRow("ESC I") << C{ESC, 'I'} << I{ProcessToken{token_vt52('I'), 0, 0}};
0376     QTest::newRow("ESC J") << C{ESC, 'J'} << I{ProcessToken{token_vt52('J'), 0, 0}};
0377     QTest::newRow("ESC K") << C{ESC, 'K'} << I{ProcessToken{token_vt52('K'), 0, 0}};
0378     QTest::newRow("ESC Yab") << C{ESC, 'Y', 'a', 'b'} << I{ProcessToken{token_vt52('Y'), 'a', 'b'}};
0379     QTest::newRow("ESC Z") << C{ESC, 'Z'} << I{ProcessToken{token_vt52('Z'), 0, 0}};
0380     QTest::newRow("ESC <") << C{ESC, '<'} << I{ProcessToken{token_vt52('<'), 0, 0}};
0381     QTest::newRow("ESC =") << C{ESC, '='} << I{ProcessToken{token_vt52('='), 0, 0}};
0382     QTest::newRow("ESC >") << C{ESC, '>'} << I{ProcessToken{token_vt52('>'), 0, 0}};
0383     /* clang-format on */
0384 }
0385 
0386 void Vt102EmulationTest::testTokenizingVT52()
0387 {
0388     QFETCH(QVector<uint>, input);
0389     QFETCH(std::vector<TestEmulation::Item>, expectedItems);
0390 
0391     TestEmulation em;
0392     em.reset();
0393     em.resetMode(MODE_Ansi);
0394     em.blockFurtherProcessing = true;
0395 
0396     em._currentScreen->clearEntireScreen();
0397 
0398     em.receiveChars(input);
0399     QString printed = em._currentScreen->text(0, em._currentScreen->getColumns(), Screen::PlainText);
0400     printed.chop(2); // Remove trailing space and newline
0401 
0402     QCOMPARE(printed, QStringLiteral(""));
0403     QCOMPARE(em.items, expectedItems);
0404 }
0405 
0406 void Vt102EmulationTest::testTokenFunctions()
0407 {
0408     QCOMPARE(token_construct(0, 0, 0), TY_CONSTRUCT(0, 0, 0));
0409     QCOMPARE(token_chr(), TY_CHR());
0410     QCOMPARE(token_ctl(8 + '@'), TY_CTL(8 + '@'));
0411     QCOMPARE(token_ctl('G'), TY_CTL('G'));
0412     QCOMPARE(token_csi_pe('p'), TY_CSI_PE('p'));
0413     QCOMPARE(token_csi_pg('c'), TY_CSI_PG('c'));
0414     QCOMPARE(token_csi_pn(8), TY_CSI_PN(8));
0415     QCOMPARE(token_csi_pn('N'), TY_CSI_PN('N'));
0416     QCOMPARE(token_csi_pr('r', 2), TY_CSI_PR('r', 2));
0417     QCOMPARE(token_csi_pr('s', 1000), TY_CSI_PR('s', 1000));
0418     QCOMPARE(token_csi_ps('m', 8), TY_CSI_PS('m', 8));
0419     QCOMPARE(token_csi_ps('m', 48), TY_CSI_PS('m', 48));
0420     QCOMPARE(token_csi_ps('K', 2), TY_CSI_PS('K', 2));
0421     QCOMPARE(token_esc(8), TY_ESC(8));
0422     QCOMPARE(token_esc('='), TY_ESC('='));
0423     QCOMPARE(token_esc('>'), TY_ESC('>'));
0424     QCOMPARE(token_esc_cs(8, 0), TY_ESC_CS(8, 0));
0425     QCOMPARE(token_esc_cs('(', '0'), TY_ESC_CS('(', '0'));
0426     QCOMPARE(token_esc_cs(')', 'B'), TY_ESC_CS(')', 'B'));
0427     QCOMPARE(token_esc_de(8), TY_ESC_DE(8));
0428     QCOMPARE(token_esc_de('3'), TY_ESC_DE('3'));
0429     QCOMPARE(token_vt52('A'), TY_VT52('A'));
0430     QCOMPARE(token_vt52('Z'), TY_VT52('Z'));
0431     QCOMPARE(token_vt52('='), TY_VT52('='));
0432     QCOMPARE(token_vt52('>'), TY_VT52('>'));
0433 }
0434 
0435 QTEST_GUILESS_MAIN(Vt102EmulationTest)
0436 
0437 #include "moc_Vt102EmulationTest.cpp"