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"