File indexing completed on 2024-05-05 04:00:57

0001 /*
0002     SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: MIT
0005 */
0006 
0007 #include "../src/lib/aztecbarcode_p.h"
0008 #include "../src/lib/bitvector_p.h"
0009 
0010 #include <prison.h>
0011 
0012 #include <QImage>
0013 #include <QObject>
0014 #include <QTest>
0015 
0016 #include <memory>
0017 
0018 Q_DECLARE_METATYPE(Prison::BitVector)
0019 
0020 using namespace Prison;
0021 
0022 class AztecBarcodeTest : public QObject
0023 {
0024     Q_OBJECT
0025 private Q_SLOTS:
0026     void testAztecEncode_data()
0027     {
0028         QTest::addColumn<QByteArray>("input");
0029         QTest::addColumn<BitVector>("output");
0030 
0031         QTest::newRow("empty") << QByteArray() << BitVector();
0032         BitVector v;
0033         v.appendMSB(12, 5);
0034         v.appendMSB(5, 5);
0035         v.appendMSB(6, 5);
0036         QTest::newRow("all uppper") << QByteArray("KDE") << v;
0037         v.clear();
0038         v.appendMSB(28, 5);
0039         v.appendMSB(12, 5);
0040         v.appendMSB(5, 5);
0041         v.appendMSB(6, 5);
0042         QTest::newRow("all lower") << QByteArray("kde") << v;
0043         v.clear();
0044         v.appendMSB(12, 5);
0045         v.appendMSB(28, 5);
0046         v.appendMSB(5, 5);
0047         v.appendMSB(6, 5);
0048         QTest::newRow("upper -> lower latch") << QByteArray("Kde") << v;
0049         v.clear();
0050         v.appendMSB(28, 5);
0051         v.appendMSB(2, 5);
0052         v.appendMSB(29, 5);
0053         v.appendMSB(30, 5);
0054         v.appendMSB(16, 5);
0055         v.appendMSB(16, 5);
0056         QTest::newRow("lower -> punct latch") << QByteArray("a++") << v;
0057         v.clear();
0058         v.appendMSB(30, 5);
0059         v.appendMSB(6, 4);
0060         v.appendMSB(4, 4);
0061         QTest::newRow("digit") << QByteArray("42") << v;
0062         v.clear();
0063         v.appendMSB(29, 5);
0064         v.appendMSB(30, 5);
0065         v.appendMSB(25, 5);
0066         v.appendMSB(24, 5);
0067         v.appendMSB(31, 5);
0068         v.appendMSB(30, 5);
0069         v.appendMSB(11, 4);
0070         v.appendMSB(2, 4);
0071         QTest::newRow("punct -> digit latch") << QByteArray(">=90") << v;
0072         v.clear();
0073         v.appendMSB(30, 5);
0074         v.appendMSB(10, 4);
0075         v.appendMSB(3, 4);
0076         v.appendMSB(14, 4);
0077         v.appendMSB(29, 5);
0078         v.appendMSB(30, 5);
0079         v.appendMSB(13, 5);
0080         v.appendMSB(14, 5);
0081         QTest::newRow("digit -> punct latch") << QByteArray("81()") << v;
0082         v.clear();
0083         v.appendMSB(29, 5);
0084         v.appendMSB(11, 5);
0085         v.appendMSB(8, 5);
0086         QTest::newRow("mixed") << QByteArray("\n\a") << v;
0087         v.clear();
0088         v.appendMSB(29, 5);
0089         v.appendMSB(30, 5);
0090         v.appendMSB(2, 5);
0091         v.appendMSB(2, 5);
0092         QTest::newRow("CR LF") << QByteArray("\r\n\r\n") << v;
0093         v.clear();
0094         v.appendMSB(31, 5);
0095         v.appendMSB(2, 5);
0096         v.appendMSB(128, 8);
0097         v.appendMSB(129, 8);
0098         QTest::newRow("binary") << QByteArray("\x80\x81") << v;
0099         v.clear();
0100         v.appendMSB(31, 5);
0101         v.appendMSB(2, 5);
0102         v.appendMSB(255, 8);
0103         v.appendMSB(254, 8);
0104         v.appendMSB(28, 5);
0105         v.appendMSB(3, 5);
0106         QTest::newRow("binary/lower") << QByteArray(
0107             "\xff\xfe"
0108             "b") << v;
0109         v.clear();
0110         v.appendMSB(12, 5);
0111         v.appendMSB(0, 5);
0112         v.appendMSB(6, 5);
0113         QTest::newRow("upper -> punct shift") << QByteArray("K!") << v;
0114         v.clear();
0115         v.appendMSB(30, 5);
0116         v.appendMSB(9, 4);
0117         v.appendMSB(4, 4);
0118         v.appendMSB(15, 4);
0119         v.appendMSB(6, 5);
0120         v.appendMSB(5, 4);
0121         QTest::newRow("digit -> upper shift") << QByteArray("72E3") << v;
0122         v.clear();
0123         v.appendMSB(25, 5);
0124         v.appendMSB(1, 5);
0125         v.appendMSB(26, 5);
0126         QTest::newRow("upper space") << QByteArray("X Y") << v;
0127         v.clear();
0128         v.appendMSB(20, 5);
0129         v.appendMSB(0, 5);
0130         v.appendMSB(4, 5);
0131         v.appendMSB(23, 5);
0132         QTest::newRow("upper punct double char shift") << QByteArray("S, V") << v;
0133         v.clear();
0134         v.appendMSB(17, 5);
0135         v.appendMSB(0, 5);
0136         v.appendMSB(17, 5);
0137         v.appendMSB(18, 5);
0138         QTest::newRow("upper ambiguous punct shift") << QByteArray("P,Q") << v;
0139         v.clear();
0140         v.appendMSB(30, 5);
0141         v.appendMSB(13, 4);
0142         v.appendMSB(7, 4);
0143         QTest::newRow("digit ambiguous punct latch") << QByteArray(".5") << v;
0144         v.clear();
0145         v.appendMSB(29, 5);
0146         v.appendMSB(30, 5);
0147         v.appendMSB(25, 5);
0148         v.appendMSB(26, 5);
0149         v.appendMSB(31, 5);
0150         v.appendMSB(29, 5);
0151         v.appendMSB(20, 5);
0152         v.appendMSB(29, 5);
0153         v.appendMSB(2, 5);
0154         QTest::newRow("punct/mixed/upper sequence") << QByteArray(">?@A") << v;
0155         v.clear();
0156         v.appendMSB(2, 5);
0157         v.appendMSB(3, 5);
0158         v.appendMSB(4, 5);
0159         v.appendMSB(29, 5); // latch to Punct via latch to Mixed, shift to Punct directly would be more efficient here
0160         v.appendMSB(30, 5);
0161         v.appendMSB(19, 5);
0162         v.appendMSB(31, 5); // latch to Upper due to shift to Binary not available in Punct
0163         v.appendMSB(31, 5);
0164         v.appendMSB(2, 5);
0165         v.appendMSB(0, 8);
0166         v.appendMSB(0, 8);
0167         QTest::newRow("upper/special -> binary") << QByteArray("ABC.\x00\x00", 6) << v;
0168     }
0169 
0170     void testAztecEncode()
0171     {
0172         QFETCH(QByteArray, input);
0173         QFETCH(BitVector, output);
0174 
0175         AztecBarcode code;
0176         const auto v = code.aztecEncode(input);
0177         if (v != output) {
0178             qDebug() << "Actual  :" << v;
0179             qDebug() << "Expected:" << output;
0180         }
0181         QCOMPARE(v, output);
0182     }
0183 
0184     void testStuffAndPad_data()
0185     {
0186         QTest::addColumn<BitVector>("input");
0187         QTest::addColumn<BitVector>("output");
0188         QTest::addColumn<int>("codeWordSize");
0189 
0190         BitVector in;
0191         BitVector out;
0192         QTest::newRow("empty") << in << out << 4;
0193         in.appendMSB(0x2, 2);
0194         out.appendMSB(0xB, 4);
0195         QTest::newRow("pad only") << in << out << 4;
0196         in.clear();
0197         out.clear();
0198         in.appendMSB(0x3, 2);
0199         out.appendMSB(0xE, 4);
0200         QTest::newRow("pad only inverted") << in << out << 4;
0201         in.clear();
0202         out.clear();
0203         in.appendMSB(0xe0, 8);
0204         out.appendMSB(0xe13, 12);
0205         QTest::newRow("stuff and pad") << in << out << 4;
0206         in.clear();
0207         out.clear();
0208         in.appendMSB(0, 6);
0209         out.appendMSB(0x11, 8);
0210         QTest::newRow("stuff only") << in << out << 4;
0211     }
0212 
0213     void testStuffAndPad()
0214     {
0215         QFETCH(BitVector, input);
0216         QFETCH(BitVector, output);
0217         QFETCH(int, codeWordSize);
0218         AztecBarcode code;
0219         const auto res = code.bitStuffAndPad(input, codeWordSize);
0220         QCOMPARE(res.size(), output.size());
0221         if (res != output) {
0222             qDebug() << "Actual  :" << res;
0223             qDebug() << "Expected:" << output;
0224         }
0225         QCOMPARE(res, output);
0226     }
0227 
0228     void testFullGrid()
0229     {
0230         AztecBarcode code;
0231         QImage img(151, 151, QImage::Format_ARGB32_Premultiplied);
0232         img.fill(code.m_background);
0233         code.paintFullGrid(&img);
0234 
0235         QImage ref(QStringLiteral(":/aztec/rendering/aztec-full-grid.png"));
0236         ref = ref.convertToFormat(img.format());
0237         QCOMPARE(img, ref);
0238     }
0239 
0240     void testCompactGrid()
0241     {
0242         AztecBarcode code;
0243         QImage img(27, 27, QImage::Format_ARGB32_Premultiplied);
0244         img.fill(code.m_background);
0245         code.paintCompactGrid(&img);
0246         img.save(QStringLiteral("aztec-compact-grid.png"));
0247 
0248         QImage ref(QStringLiteral(":/aztec/rendering/aztec-compact-grid.png"));
0249         ref = ref.convertToFormat(img.format());
0250         QCOMPARE(img, ref);
0251     }
0252 
0253     void testFullData_data()
0254     {
0255         QTest::addColumn<BitVector>("data");
0256         QTest::addColumn<QString>("refName");
0257         QTest::addColumn<int>("layer");
0258 
0259         BitVector v;
0260         for (int i = 0; i < 1248; ++i) {
0261             v.appendLSB(0x9249, 16);
0262         }
0263         QTest::newRow("1001-31") << v << QStringLiteral("aztec-full-data-1001.png") << 32;
0264 
0265         v.clear();
0266         for (int i = 0; i < 1248 * 8; ++i) {
0267             v.appendLSB(0x2, 2);
0268         }
0269         QTest::newRow("0101-31") << v << QStringLiteral("aztec-full-data-0101.png") << 32;
0270 
0271         v.clear();
0272         for (int i = 0; i < 1248; ++i) {
0273             v.appendLSB(0xffff, 16);
0274         }
0275         QTest::newRow("1111-31") << v << QStringLiteral("aztec-full-data-1111.png") << 32;
0276 
0277         v.clear();
0278         for (int i = 0; i < 704 * 4; ++i) {
0279             v.appendLSB(0x1, 2);
0280         }
0281         QTest::newRow("1010-15") << v << QStringLiteral("aztec-full-data-1010.png") << 16;
0282 
0283         v.clear();
0284         for (int i = 0; i < 16; ++i) {
0285             v.appendLSB(0xCC, 8);
0286         }
0287         QTest::newRow("0011-0") << v << QStringLiteral("aztec-full-data-0011.png") << 1;
0288     }
0289 
0290     void testFullData()
0291     {
0292         QFETCH(BitVector, data);
0293         QFETCH(QString, refName);
0294         QFETCH(int, layer);
0295 
0296         AztecBarcode code;
0297         QImage img(151, 151, QImage::Format_ARGB32_Premultiplied);
0298         img.fill(code.m_background);
0299         code.paintFullData(&img, data, layer);
0300         img.save(refName);
0301 
0302         QImage ref(QStringLiteral(":/aztec/rendering/") + refName);
0303         ref = ref.convertToFormat(img.format());
0304         QCOMPARE(img, ref);
0305     }
0306 
0307     void testFullModeMessage_data()
0308     {
0309         QTest::addColumn<BitVector>("data");
0310         QTest::addColumn<QString>("refName");
0311 
0312         BitVector v;
0313         for (int i = 0; i < 8; ++i) {
0314             v.appendMSB(i + 1, 5);
0315         }
0316         QTest::newRow("1234") << v << QStringLiteral("aztec-full-mode-1234.png");
0317 
0318         v.clear();
0319         for (int i = 0; i < 8; ++i) {
0320             v.appendLSB(i + 1, 5);
0321         }
0322         QTest::newRow("1234-rev") << v << QStringLiteral("aztec-full-mode-1234-rev.png");
0323 
0324         v.clear();
0325         for (int i = 0; i < 4; ++i) {
0326             v.appendMSB(0xffff, 10);
0327         }
0328         QTest::newRow("1111") << v << QStringLiteral("aztec-full-mode-1111.png");
0329     }
0330 
0331     void testFullModeMessage()
0332     {
0333         QFETCH(BitVector, data);
0334         QFETCH(QString, refName);
0335 
0336         AztecBarcode code;
0337         QImage img(151, 151, QImage::Format_ARGB32_Premultiplied);
0338         img.fill(code.m_background);
0339         code.paintFullModeMessage(&img, data);
0340         img.save(refName);
0341 
0342         QImage ref(QStringLiteral(":/aztec/rendering/") + refName);
0343         ref = ref.convertToFormat(img.format());
0344         QCOMPARE(img, ref);
0345     }
0346 
0347     void testCompactData_data()
0348     {
0349         QTest::addColumn<BitVector>("data");
0350         QTest::addColumn<QString>("refName");
0351         QTest::addColumn<int>("layer");
0352 
0353         BitVector v;
0354         for (int i = 0; i < 304; ++i) {
0355             v.appendLSB(0x9249, 16);
0356         }
0357         QTest::newRow("1001-3") << v << QStringLiteral("aztec-compact-data-1001.png") << 4;
0358 
0359         v.clear();
0360         for (int i = 0; i < 608 * 4; ++i) {
0361             v.appendLSB(0x2, 2);
0362         }
0363         QTest::newRow("0101-3") << v << QStringLiteral("aztec-compact-data-0101.png") << 4;
0364 
0365         v.clear();
0366         for (int i = 0; i < 304; ++i) {
0367             v.appendLSB(0xffff, 16);
0368         }
0369         QTest::newRow("1111-3") << v << QStringLiteral("aztec-compact-data-1111.png") << 4;
0370 
0371         v.clear();
0372         for (int i = 0; i < 102 * 4; ++i) {
0373             v.appendLSB(0x1, 2);
0374         }
0375         QTest::newRow("1010-2") << v << QStringLiteral("aztec-compact-data-1010.png") << 3;
0376 
0377         v.clear();
0378         for (int i = 0; i < 13; ++i) {
0379             v.appendLSB(0xCC, 8);
0380         }
0381         QTest::newRow("0011-0") << v << QStringLiteral("aztec-compact-data-0011.png") << 1;
0382     }
0383 
0384     void testCompactData()
0385     {
0386         QFETCH(BitVector, data);
0387         QFETCH(QString, refName);
0388         QFETCH(int, layer);
0389 
0390         AztecBarcode code;
0391         QImage img(27, 27, QImage::Format_ARGB32_Premultiplied);
0392         img.fill(code.m_background);
0393         code.paintCompactData(&img, data, layer);
0394         img.save(refName);
0395 
0396         QImage ref(QStringLiteral(":/aztec/rendering/") + refName);
0397         ref = ref.convertToFormat(img.format());
0398         QCOMPARE(img, ref);
0399     }
0400 
0401     void testCompactModeMessage_data()
0402     {
0403         QTest::addColumn<BitVector>("data");
0404         QTest::addColumn<QString>("refName");
0405 
0406         BitVector v;
0407         for (int i = 0; i < 4; ++i) {
0408             v.appendMSB(i + 1, 7);
0409         }
0410         QTest::newRow("1234") << v << QStringLiteral("aztec-compact-mode-1234.png");
0411 
0412         v.clear();
0413         for (int i = 0; i < 4; ++i) {
0414             v.appendLSB(i + 1, 7);
0415         }
0416         QTest::newRow("1234-rev") << v << QStringLiteral("aztec-compact-mode-1234-rev.png");
0417 
0418         v.clear();
0419         for (int i = 0; i < 4; ++i) {
0420             v.appendMSB(0xffff, 7);
0421         }
0422         QTest::newRow("1111") << v << QStringLiteral("aztec-compact-mode-1111.png");
0423     }
0424 
0425     void testCompactModeMessage()
0426     {
0427         QFETCH(BitVector, data);
0428         QFETCH(QString, refName);
0429 
0430         AztecBarcode code;
0431         QImage img(151, 151, QImage::Format_ARGB32_Premultiplied);
0432         img.fill(code.m_background);
0433         code.paintCompactModeMessage(&img, data);
0434         img.save(refName);
0435 
0436         QImage ref(QStringLiteral(":/aztec/rendering/") + refName);
0437         ref = ref.convertToFormat(img.format());
0438         QCOMPARE(img, ref);
0439     }
0440 
0441     void testCodeGen_data()
0442     {
0443         QTest::addColumn<QByteArray>("input");
0444         QTest::addColumn<QString>("refName");
0445 
0446         QTest::newRow("short compact") << QByteArray("KF5::Prison") << "aztec-complete-compact1.png";
0447         QTest::newRow("compact 3 layer") << QByteArray("M1KRAUSE/VOLKER       ABCDEFG TXLRIXBT 0212 309Y014E0063 100") << "aztec-complete-compact3.png";
0448         QTest::newRow("long compact") << QByteArray("KF5::Prison - the barcode generation library of KDE Frameworks 5!") << "aztec-complete-compact4.png";
0449         QTest::newRow("short full") << QByteArray("KF5::Prison - the MIT licensed free software barcode generation library of KDE Frameworks 5!")
0450                                     << "aztec-complete-full5.png";
0451         QTest::newRow("long full") << QByteArray(
0452             "Permission is hereby granted, free of charge, to any person\n"
0453             "obtaining a copy of this software and associated documentation\n"
0454             "files (the \"Software\"), to deal in the Software without\n"
0455             "restriction, including without limitation the rights to use,\n"
0456             "copy, modify, merge, publish, distribute, sublicense, and/or sell\n"
0457             "copies of the Software, and to permit persons to whom the\n"
0458             "Software is furnished to do so, subject to the following\n"
0459             "conditions:\n\n"
0460             "The above copyright notice and this permission notice shall be\n"
0461             "included in all copies or substantial portions of the Software.\n\n"
0462             "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
0463             "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n"
0464             "OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n"
0465             "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n"
0466             "HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n"
0467             "WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n"
0468             "FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n"
0469             "OTHER DEALINGS IN THE SOFTWARE.")
0470                                    << "aztec-complete-big.png";
0471         QTest::newRow("binary") << QByteArray("KDE\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9kde", 16) << "aztec-binary.png";
0472     }
0473 
0474     void testCodeGen()
0475     {
0476         QFETCH(QByteArray, input);
0477         QFETCH(QString, refName);
0478 
0479         {
0480             auto code = Prison::Barcode::create(Prison::Aztec);
0481             QVERIFY(code);
0482             code->setData(QString::fromLatin1(input.constData(), input.size()));
0483             const auto img = code->toImage(code->minimumSize());
0484             img.save(refName);
0485 
0486             QImage ref(QStringLiteral(":/aztec/encoding/") + refName);
0487             ref = ref.convertToFormat(img.format());
0488             QCOMPARE(img, ref);
0489         }
0490 
0491         {
0492             auto code = Prison::Barcode::create(Prison::Aztec);
0493             QVERIFY(code);
0494             code->setData(input);
0495             const auto img = code->toImage(code->minimumSize());
0496             img.save(refName);
0497 
0498             QImage ref(QStringLiteral(":/aztec/encoding/") + refName);
0499             ref = ref.convertToFormat(img.format());
0500             QCOMPARE(img, ref);
0501         }
0502     }
0503 
0504     void testDimension()
0505     {
0506         auto barcode = Prison::Barcode::create(Prison::Aztec);
0507         QVERIFY(barcode);
0508         QCOMPARE(barcode->format(), Prison::Aztec);
0509         QCOMPARE(barcode->dimensions(), Prison::Barcode::TwoDimensions);
0510     }
0511 
0512     void testSize()
0513     {
0514         auto barcode = Prison::Barcode::create(Prison::Aztec);
0515         QVERIFY(barcode);
0516         QCOMPARE(barcode->format(), Prison::Aztec);
0517         barcode->setData(QStringLiteral("UNIT TEST"));
0518         QCOMPARE(barcode->minimumSize(), QSize(15, 15));
0519         QCOMPARE(barcode->preferredSize(1), QSize(60, 60));
0520         QCOMPARE(barcode->preferredSize(2), QSize(30, 30));
0521         QCOMPARE(barcode->toImage(barcode->preferredSize(1)).size(), QSize(60, 60));
0522         QCOMPARE(barcode->toImage({1, 1}).isNull(), true);
0523     }
0524 };
0525 
0526 QTEST_APPLESS_MAIN(AztecBarcodeTest)
0527 
0528 #include "aztecbarcodetest.moc"