File indexing completed on 2024-05-12 05:17:29
0001 /* 0002 SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "../lib/iata/iatabcbp.h" 0008 #include "../lib/iata/iatabcbpparser.h" 0009 0010 #include <KItinerary/JsonLdDocument> 0011 #include <KItinerary/Organization> 0012 #include <KItinerary/Place> 0013 0014 #include <QDebug> 0015 #include <QFile> 0016 #include <QJsonArray> 0017 #include <QJsonDocument> 0018 #include <QObject> 0019 #include <QProcess> 0020 #include <QStandardPaths> 0021 #include <QTest> 0022 0023 using namespace KItinerary; 0024 0025 class BcbpParserTest : public QObject 0026 { 0027 Q_OBJECT 0028 private Q_SLOTS: 0029 void testParserValid_data() 0030 { 0031 QTest::addColumn<QString>("message"); 0032 QTest::addColumn<QString>("refFile"); 0033 0034 // example data from IATA resolution 792 version 5 Attachment B (with security sections shortended or omitted) 0035 QTest::newRow("single leg, mandatory only") << QStringLiteral("M1DESMARAIS/LUC EABC123 YULFRAAC 0834 326J001A0025 100") << QStringLiteral("iata-resolution792-example1"); 0036 QTest::newRow("single leg, all fields") << QStringLiteral("M1DESMARAIS/LUC EAB12C3 YULFRAAC 0834 326J003A0027 167>5321WW1325BAC 0014123456002001412346700100141234789012A0141234567890 1AC AC 1234567890123 4PCYLX58Z^108ABCDEFGH") << QStringLiteral("iata-resolution792-example2"); 0037 QTest::newRow("single leg, partial") << QStringLiteral("M1GRANDMAIRE/MELANIE EABC123 GVACDGAF 0123 339C002F0025 130>5002A0571234567890 AF AF 1234567890123456 Y^108ABCDEFGH") << QStringLiteral("iata-resolution792-example3"); 0038 QTest::newRow("multi leg, all fields") << QStringLiteral("M2DESMARAIS/LUC EAB12C3 YULFRAAC 0834 326J003A0027 167>5321WW1325BAC 0014123456002001412346700100141234789012A0141234567890 1AC AC 1234567890123 4PCYLX58ZDEF456 FRAGVALH 3664 327C012C0002 12E2A0140987654321 1AC AC 1234567890123 3PCNWQ^108ABCDEFGH") << QStringLiteral("iata-resolution792-example4"); 0039 QTest::newRow("multi leg, partial") << QStringLiteral("M2GRANDMAIRE/MELANIE EABC123 GVACDGAF 0123 339C002F0025 130>5002A0571234567890 AF AF 1234567890123456 YDEF456 CDGDTWNW 0049 339F001A0002 12C2A012098765432101 2PC ^108ABCDEFGH") << QStringLiteral("iata-resolution792-example5"); 0040 0041 // EW misses the 'E' eticket marker (BCBP item 253) 0042 QTest::newRow("missing eticket indicator") << QStringLiteral("M1DOE/JOHN XXX007 BRUTXLEW 8103 035Y012C0030 147>1181W 8033BEW 0000000000000291040000000000 0 LH 123456789012345 ") << QStringLiteral("missing-eticket-indicator"); 0043 0044 // boarding pass issue date (BCBP item 22) 0045 QTest::newRow("issue date") << QStringLiteral("M1DOE/JOHN EXXX007 TXLBRUSN 2588 034Y023D0999 35D>5181WM7034BSN 2A08200000000000 SN LH 123456789012345 *30600000K0902 ") << QStringLiteral("issue-date"); 0046 0047 // EasyJet being easy on the standard interpretation 0048 QTest::newRow("easyjet") << QStringLiteral("M1DOE/JOHN EABCDEFGMRSLGWEZY8724 99 3C 506 10Axxxxxxxxxx") << QStringLiteral("easyjet"); 0049 0050 // Brussels Airlines short codes on booking confirmation 0051 QTest::newRow("minimal1") << QStringLiteral("M1DOE/JOHN EXXX007 TXLBRUSN 2592 110Y") << QStringLiteral("minimal"); 0052 QTest::newRow("minimal2") << QStringLiteral("M1DOE/JOHN EXXX007 TXLBRUSN 2592 110") << QStringLiteral("minimal2"); 0053 0054 // TAP missing boarding pass issue date 0055 QTest::newRow("no issue date") << QStringLiteral("M1DOE/JOHN EXXX007 LISLCGTP 1080 204Y002D0003 35C>2180 B1A 2904712345678900 *306 09 BRND") << QStringLiteral("tap-missing-issue-date"); 0056 0057 // Qatar claiming zero-length field sizes 0058 QTest::newRow("zero size conditional") << QStringLiteral("M1DOE/JANE EXXX007 MXPDOHQR 0128 256Y042F0023 100>2180 0255BBR 2963456000789980 0") << QStringLiteral("qatar-zero-size-conditional-section"); 0059 } 0060 0061 void testParserValid() 0062 { 0063 QFETCH(QString, message); 0064 QFETCH(QString, refFile); 0065 0066 QVERIFY(IataBcbp::maybeIataBcbp(message)); 0067 QVERIFY(IataBcbp::maybeIataBcbp(message.toUtf8())); 0068 IataBcbp bcbp(message); 0069 QVERIFY(bcbp.isValid()); 0070 0071 QFile ref(QLatin1StringView(SOURCE_DIR "/bcbpdata/") + refFile + 0072 QLatin1String(".txt")); 0073 QVERIFY(ref.open(QFile::ReadOnly)); 0074 const auto refOut = ref.readAll(); 0075 0076 const auto exe = QStandardPaths::findExecutable(QStringLiteral("ticket-barcode-dump"), {QCoreApplication::applicationDirPath()}); 0077 QVERIFY(!exe.isEmpty()); 0078 QProcess proc; 0079 proc.setProcessChannelMode(QProcess::ForwardedErrorChannel); 0080 proc.setProgram(exe); 0081 proc.setArguments({QLatin1StringView("--context-date"), 0082 QDate(2018, 4, 2).toString(Qt::ISODate)}); 0083 proc.start(); 0084 QVERIFY(proc.waitForStarted()); 0085 proc.write(message.toUtf8()); 0086 QVERIFY(proc.waitForBytesWritten()); 0087 proc.closeWriteChannel(); 0088 QVERIFY(proc.waitForFinished()); 0089 const auto ticketDump = proc.readAllStandardOutput(); 0090 QCOMPARE(proc.exitCode(), 0); 0091 if (ticketDump != refOut) { 0092 qDebug().noquote() << ticketDump; 0093 QFile failFile(ref.fileName() + QLatin1StringView(".fail")); 0094 QVERIFY(failFile.open(QFile::WriteOnly)); 0095 failFile.write(ticketDump); 0096 } 0097 QVERIFY(ticketDump == refOut); 0098 0099 QFile f(QLatin1StringView(SOURCE_DIR "/bcbpdata/") + refFile + 0100 QLatin1String(".json")); 0101 QVERIFY(f.open(QFile::ReadOnly)); 0102 const auto refArray = QJsonDocument::fromJson(f.readAll()).array(); 0103 QVERIFY(!refArray.isEmpty()); 0104 0105 const auto res = IataBcbpParser::parse(bcbp, QDateTime({2018, 4, 2}, {})); 0106 const auto resJson = JsonLdDocument::toJson(res); 0107 0108 if (refArray != resJson) { 0109 qWarning().noquote() << QJsonDocument(resJson).toJson(); 0110 QFile failFile(f.fileName() + QLatin1StringView(".fail")); 0111 QVERIFY(failFile.open(QFile::WriteOnly)); 0112 failFile.write(QJsonDocument(resJson).toJson()); 0113 } 0114 QCOMPARE(resJson, refArray); 0115 } 0116 0117 void testParserInvalid_data() 0118 { 0119 QTest::addColumn<QString>("message"); 0120 0121 QTest::newRow("empty") << QString(); 0122 QTest::newRow("too short") << QStringLiteral("M1DESMARAIS/LUC "); 0123 QTest::newRow("wrong leg count") << QStringLiteral("M2DESMARAIS/LUC EABC123 YULFRAAC 0834 326J001A0025 100"); 0124 QTest::newRow("too short repeated mandatory section") << QStringLiteral("M1DOE/JOHN EXXX007 TXLBRUSN 2592 11"); 0125 QTest::newRow("bug 407895") << QStringLiteral("M2Mobi Lab / ML-586 [In Progress]\nSplit Fooo.Config from main Fooo\n\n========================================================"); 0126 } 0127 0128 void testParserInvalid() 0129 { 0130 QFETCH(QString, message); 0131 IataBcbp bcbp(message); 0132 QVERIFY(!bcbp.isValid()); 0133 } 0134 }; 0135 0136 QTEST_GUILESS_MAIN(BcbpParserTest) 0137 0138 #include "bcbpparsertest.moc"