mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 12:22:34 +00:00
Beginning port of tests for qrcode from c++
This commit is contained in:
124
src/qrcode/cpp_port/test/MQRDecoderTest.cpp
Normal file
124
src/qrcode/cpp_port/test/MQRDecoderTest.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2008 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "qrcode/QRDecoder.h"
|
||||
|
||||
#include "BitMatrix.h"
|
||||
#include "BitMatrixIO.h"
|
||||
#include "DecoderResult.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace ZXing;
|
||||
using namespace ZXing::QRCode;
|
||||
|
||||
TEST(MQRDecoderTest, MQRCodeM3L)
|
||||
{
|
||||
const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X\n"
|
||||
"X X X X \n"
|
||||
"X XXX X XXXXXXX\n"
|
||||
"X XXX X X X XX\n"
|
||||
"X XXX X X XX\n"
|
||||
"X X X X X X\n"
|
||||
"XXXXXXX X XX \n"
|
||||
" X X X\n"
|
||||
"XXXXXX X X X\n"
|
||||
" X XX XXX\n"
|
||||
"XXX XX XXXX XXX\n"
|
||||
" X X XXX X \n"
|
||||
"X XXXXX XXX X X\n"
|
||||
" X X X XXX \n"
|
||||
"XXX XX X X XXXX\n",
|
||||
88, false);
|
||||
|
||||
const auto result = Decode(bitMatrix);
|
||||
EXPECT_TRUE(result.isValid());
|
||||
}
|
||||
|
||||
TEST(MQRDecoderTest, MQRCodeM3M)
|
||||
{
|
||||
const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X\n"
|
||||
"X X XX\n"
|
||||
"X XXX X X XX XX\n"
|
||||
"X XXX X X X \n"
|
||||
"X XXX X XX XXXX\n"
|
||||
"X X XX \n"
|
||||
"XXXXXXX X XXXX\n"
|
||||
" X XXX \n"
|
||||
"X XX XX X X\n"
|
||||
" X X XX \n"
|
||||
"XX XX XXXXXXX\n"
|
||||
" X X X\n"
|
||||
"XX X X X \n"
|
||||
" X X X \n"
|
||||
"X X XXXX XXX\n",
|
||||
88, false);
|
||||
|
||||
const auto result = Decode(bitMatrix);
|
||||
EXPECT_TRUE(result.isValid());
|
||||
}
|
||||
|
||||
TEST(MQRDecoderTest, MQRCodeM1)
|
||||
{
|
||||
const auto bitMatrix = ParseBitMatrix("XXXXXXX X X\n"
|
||||
"X X \n"
|
||||
"X XXX X XXX\n"
|
||||
"X XXX X XX\n"
|
||||
"X XXX X X\n"
|
||||
"X X XX \n"
|
||||
"XXXXXXX X \n"
|
||||
" X \n"
|
||||
"XX X \n"
|
||||
" X XXXXX X\n"
|
||||
"X XXXXXX X\n",
|
||||
88, false);
|
||||
const auto result = Decode(bitMatrix);
|
||||
EXPECT_TRUE(result.isValid());
|
||||
EXPECT_EQ(L"123", result.text());
|
||||
}
|
||||
|
||||
TEST(MQRDecoderTest, MQRCodeM1Error4Bits)
|
||||
{
|
||||
const auto bitMatrix = ParseBitMatrix("XXXXXXX X X\n"
|
||||
"X X XX\n"
|
||||
"X XXX X X \n"
|
||||
"X XXX X XX\n"
|
||||
"X XXX X X\n"
|
||||
"X X XX \n"
|
||||
"XXXXXXX X \n"
|
||||
" X \n"
|
||||
"XX X \n"
|
||||
" X XXXXXX \n"
|
||||
"X XXXXXXX \n",
|
||||
88, false);
|
||||
const auto result = Decode(bitMatrix);
|
||||
EXPECT_EQ(Error::Checksum, result.error());
|
||||
EXPECT_TRUE(result.text().empty());
|
||||
}
|
||||
|
||||
TEST(MQRDecoderTest, MQRCodeM4)
|
||||
{
|
||||
const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X X\n"
|
||||
"X X XX X XX\n"
|
||||
"X XXX X X X XX\n"
|
||||
"X XXX X XX XX XX\n"
|
||||
"X XXX X X XXXXX\n"
|
||||
"X X XX X\n"
|
||||
"XXXXXXX XX X XX\n"
|
||||
" X XX XX\n"
|
||||
"X X XXX X XXX\n"
|
||||
" XX X XX XX X \n"
|
||||
"XX XXXX X XX XX\n"
|
||||
" XX XX X XX XX\n"
|
||||
"XXX XXX XXX XX XX\n"
|
||||
" X X X XX X\n"
|
||||
"X X XX XXXXX \n"
|
||||
" X X X X X \n"
|
||||
"X XXXXXXX X X X\n",
|
||||
88, false);
|
||||
const auto result = Decode(bitMatrix);
|
||||
EXPECT_TRUE(result.isValid());
|
||||
}
|
||||
73
src/qrcode/cpp_port/test/QRBitMatrixParserTest.cpp
Normal file
73
src/qrcode/cpp_port/test/QRBitMatrixParserTest.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2008 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "BitMatrix.h"
|
||||
#include "BitMatrixIO.h"
|
||||
#include "ByteArray.h"
|
||||
#include "qrcode/QRBitMatrixParser.h"
|
||||
#include "qrcode/QRFormatInformation.h"
|
||||
#include "qrcode/QRVersion.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace ZXing;
|
||||
using namespace ZXing::QRCode;
|
||||
|
||||
TEST(QRBitMatrixParserTest, MQRCodeM3L)
|
||||
{
|
||||
const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X\n"
|
||||
"X X X X \n"
|
||||
"X XXX X XXXXXXX\n"
|
||||
"X XXX X X X XX\n"
|
||||
"X XXX X X XX\n"
|
||||
"X X X X X X\n"
|
||||
"XXXXXXX X XX \n"
|
||||
" X X X\n"
|
||||
"XXXXXX X X X\n"
|
||||
" X XX XXX\n"
|
||||
"XXX XX XXXX XXX\n"
|
||||
" X X XXX X \n"
|
||||
"X XXXXX XXX X X\n"
|
||||
" X X X XXX \n"
|
||||
"XXX XX X X XXXX\n",
|
||||
88, false);
|
||||
|
||||
const auto version = ReadVersion(bitMatrix);
|
||||
EXPECT_EQ(3, version->versionNumber());
|
||||
const auto format = ReadFormatInformation(bitMatrix, true);
|
||||
const auto codewords = ReadCodewords(bitMatrix, *version, format);
|
||||
EXPECT_EQ(17, codewords.size());
|
||||
EXPECT_EQ(0x0, codewords[10]);
|
||||
EXPECT_EQ(0xd1, codewords[11]);
|
||||
}
|
||||
|
||||
TEST(QRBitMatrixParserTest, MQRCodeM3M)
|
||||
{
|
||||
const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X\n"
|
||||
"X X XX\n"
|
||||
"X XXX X X XX XX\n"
|
||||
"X XXX X X X \n"
|
||||
"X XXX X XX XXXX\n"
|
||||
"X X XX \n"
|
||||
"XXXXXXX X XXXX\n"
|
||||
" X XXX \n"
|
||||
"X XX XX X X\n"
|
||||
" X X XX \n"
|
||||
"XX XX XXXXXXX\n"
|
||||
" X X X\n"
|
||||
"XX X X X \n"
|
||||
" X X X \n"
|
||||
"X X XXXX XXX\n",
|
||||
88, false);
|
||||
|
||||
const auto version = ReadVersion(bitMatrix);
|
||||
EXPECT_EQ(3, version->versionNumber());
|
||||
const auto format = ReadFormatInformation(bitMatrix, true);
|
||||
const auto codewords = ReadCodewords(bitMatrix, *version, format);
|
||||
EXPECT_EQ(17, codewords.size());
|
||||
EXPECT_EQ(0x0, codewords[8]);
|
||||
EXPECT_EQ(0x89, codewords[9]);
|
||||
}
|
||||
100
src/qrcode/cpp_port/test/QRDataMaskTest.cpp
Normal file
100
src/qrcode/cpp_port/test/QRDataMaskTest.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2007 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "qrcode/QRDataMask.h"
|
||||
#include "BitMatrix.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <functional>
|
||||
|
||||
using namespace ZXing;
|
||||
using namespace ZXing::QRCode;
|
||||
|
||||
namespace {
|
||||
|
||||
void TestMaskAcrossDimensionsImpl(int maskIndex, bool isMicro, const int versionMax, const int dimensionStart, const int dimensionStep, std::function<bool(int, int)> condition)
|
||||
{
|
||||
for (int version = 1; version <= versionMax; version++) {
|
||||
int dimension = dimensionStart + dimensionStep * version;
|
||||
BitMatrix bits(dimension);
|
||||
|
||||
for (int i = 0; i < dimension; i++)
|
||||
for (int j = 0; j < dimension; j++)
|
||||
EXPECT_EQ(GetMaskedBit(bits, j, i, maskIndex, isMicro), condition(i, j)) << "(" << i << ',' << j << ')';
|
||||
}
|
||||
}
|
||||
|
||||
void TestMaskAcrossDimensions(int maskIndex, std::function<bool(int, int)> condition)
|
||||
{
|
||||
TestMaskAcrossDimensionsImpl(maskIndex, false, 40, 17, 4, condition);
|
||||
}
|
||||
|
||||
void TestMicroMaskAcrossDimensions(int maskIndex, std::function<bool(int, int)> condition)
|
||||
{
|
||||
TestMaskAcrossDimensionsImpl(maskIndex, true, 4, 9, 2, condition);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, Mask0)
|
||||
{
|
||||
TestMaskAcrossDimensions(0, [](int i, int j) { return (i + j) % 2 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, Mask1)
|
||||
{
|
||||
TestMaskAcrossDimensions(1, [](int i, int) { return i % 2 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, Mask2)
|
||||
{
|
||||
TestMaskAcrossDimensions(2, [](int, int j) { return j % 3 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, Mask3)
|
||||
{
|
||||
TestMaskAcrossDimensions(3, [](int i, int j) { return (i + j) % 3 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, Mask4)
|
||||
{
|
||||
TestMaskAcrossDimensions(4, [](int i, int j) { return (i / 2 + j / 3) % 2 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, Mask5)
|
||||
{
|
||||
TestMaskAcrossDimensions(5, [](int i, int j) { return (i * j) % 2 + (i * j) % 3 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, Mask6)
|
||||
{
|
||||
TestMaskAcrossDimensions(6, [](int i, int j) { return ((i * j) % 2 + (i * j) % 3) % 2 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, Mask7)
|
||||
{
|
||||
TestMaskAcrossDimensions(7, [](int i, int j) { return ((i + j) % 2 + (i * j) % 3) % 2 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, MicroMask0)
|
||||
{
|
||||
TestMicroMaskAcrossDimensions(0, [](int i, int) { return i % 2 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, MicroMask1)
|
||||
{
|
||||
TestMicroMaskAcrossDimensions(1, [](int i, int j) { return (i / 2 + j / 3) % 2 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, MicroMask2)
|
||||
{
|
||||
TestMicroMaskAcrossDimensions(2, [](int i, int j) { return ((i * j) % 2 + (i * j) % 3) % 2 == 0; });
|
||||
}
|
||||
|
||||
TEST(QRDataMaskTest, MicroMask3)
|
||||
{
|
||||
TestMicroMaskAcrossDimensions(3, [](int i, int j) { return ((i + j) % 2 + (i * j) % 3) % 2 == 0; });
|
||||
}
|
||||
134
src/qrcode/cpp_port/test/QRDecodedBitStreamParserTest.cpp
Normal file
134
src/qrcode/cpp_port/test/QRDecodedBitStreamParserTest.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2008 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "BitArray.h"
|
||||
#include "ByteArray.h"
|
||||
#include "DecoderResult.h"
|
||||
#include "qrcode/QRDataMask.h"
|
||||
#include "qrcode/QRDecoder.h"
|
||||
#include "qrcode/QRErrorCorrectionLevel.h"
|
||||
#include "qrcode/QRVersion.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace ZXing {
|
||||
namespace QRCode {
|
||||
DecoderResult DecodeBitStream(ByteArray&& bytes, const Version& version, ErrorCorrectionLevel ecLevel);
|
||||
}
|
||||
}
|
||||
|
||||
using namespace ZXing;
|
||||
using namespace ZXing::QRCode;
|
||||
|
||||
TEST(QRDecodedBitStreamParserTest, SimpleByteMode)
|
||||
{
|
||||
BitArray ba;
|
||||
ba.appendBits(0x04, 4); // Byte mode
|
||||
ba.appendBits(0x03, 8); // 3 bytes
|
||||
ba.appendBits(0xF1, 8);
|
||||
ba.appendBits(0xF2, 8);
|
||||
ba.appendBits(0xF3, 8);
|
||||
auto result = DecodeBitStream(ba.toBytes(), *Version::FromNumber(1), ErrorCorrectionLevel::Medium).text();
|
||||
EXPECT_EQ(L"\xF1\xF2\xF3", result);
|
||||
}
|
||||
|
||||
TEST(QRDecodedBitStreamParserTest, SimpleSJIS)
|
||||
{
|
||||
BitArray ba;
|
||||
ba.appendBits(0x04, 4); // Byte mode
|
||||
ba.appendBits(0x04, 8); // 4 bytes
|
||||
ba.appendBits(0xA1, 8);
|
||||
ba.appendBits(0xA2, 8);
|
||||
ba.appendBits(0xA3, 8);
|
||||
ba.appendBits(0xD0, 8);
|
||||
auto result = DecodeBitStream(ba.toBytes(), *Version::FromNumber(1), ErrorCorrectionLevel::Medium).text();
|
||||
EXPECT_EQ(L"\uff61\uff62\uff63\uff90", result);
|
||||
}
|
||||
|
||||
TEST(QRDecodedBitStreamParserTest, ECI)
|
||||
{
|
||||
BitArray ba;
|
||||
ba.appendBits(0x07, 4); // ECI mode
|
||||
ba.appendBits(0x02, 8); // ECI 2 = CP437 encoding
|
||||
ba.appendBits(0x04, 4); // Byte mode
|
||||
ba.appendBits(0x03, 8); // 3 bytes
|
||||
ba.appendBits(0xA1, 8);
|
||||
ba.appendBits(0xA2, 8);
|
||||
ba.appendBits(0xA3, 8);
|
||||
auto result = DecodeBitStream(ba.toBytes(), *Version::FromNumber(1), ErrorCorrectionLevel::Medium).text();
|
||||
EXPECT_EQ(L"\xED\xF3\xFA", result);
|
||||
}
|
||||
|
||||
TEST(QRDecodedBitStreamParserTest, Hanzi)
|
||||
{
|
||||
BitArray ba;
|
||||
ba.appendBits(0x0D, 4); // Hanzi mode
|
||||
ba.appendBits(0x01, 4); // Subset 1 = GB2312 encoding
|
||||
ba.appendBits(0x01, 8); // 1 characters
|
||||
ba.appendBits(0x03C1, 13);
|
||||
auto result = DecodeBitStream(ba.toBytes(), *Version::FromNumber(1), ErrorCorrectionLevel::Medium).text();
|
||||
EXPECT_EQ(L"\u963f", result);
|
||||
}
|
||||
|
||||
TEST(QRDecodedBitStreamParserTest, HanziLevel1)
|
||||
{
|
||||
BitArray ba;
|
||||
ba.appendBits(0x0D, 4); // Hanzi mode
|
||||
ba.appendBits(0x01, 4); // Subset 1 = GB2312 encoding
|
||||
ba.appendBits(0x01, 8); // 1 characters
|
||||
// A5A2 (U+30A2) => A5A2 - A1A1 = 401, 4*60 + 01 = 0181
|
||||
ba.appendBits(0x0181, 13);
|
||||
|
||||
auto result = DecodeBitStream(ba.toBytes(), *Version::FromNumber(1), ErrorCorrectionLevel::Medium).text();
|
||||
EXPECT_EQ(L"\u30a2", result);
|
||||
}
|
||||
|
||||
TEST(QRDecodedBitStreamParserTest, SymbologyIdentifier)
|
||||
{
|
||||
const Version& version = *Version::FromNumber(1);
|
||||
const ErrorCorrectionLevel ecLevel = ErrorCorrectionLevel::Medium;
|
||||
DecoderResult result;
|
||||
|
||||
// Plain "ANUM(1) A"
|
||||
result = DecodeBitStream({0x20, 0x09, 0x40}, version, ecLevel);
|
||||
EXPECT_EQ(result.symbologyIdentifier(), "]Q1");
|
||||
EXPECT_EQ(result.text(), L"A");
|
||||
|
||||
// GS1 "FNC1(1st) NUM(4) 2001"
|
||||
result = DecodeBitStream({0x51, 0x01, 0x0C, 0x81, 0x00}, version, ecLevel);
|
||||
EXPECT_EQ(result.symbologyIdentifier(), "]Q3");
|
||||
EXPECT_EQ(result.text(), L"2001"); // "(20)01"
|
||||
|
||||
// GS1 "NUM(4) 2001 FNC1(1st) 301" - FNC1(1st) can occur anywhere (this actually violates the specification)
|
||||
result = DecodeBitStream({0x10, 0x10, 0xC8, 0x15, 0x10, 0x0D, 0x2D, 0x00}, version, ecLevel);
|
||||
EXPECT_EQ(result.symbologyIdentifier(), "]Q3");
|
||||
EXPECT_EQ(result.text(), L"2001301"); // "(20)01(30)1"
|
||||
|
||||
// AIM "FNC1(2nd) 99 (0x63) ANUM(1) A"
|
||||
result = DecodeBitStream({0x96, 0x32, 0x00, 0x94, 0x00}, version, ecLevel);
|
||||
EXPECT_EQ(result.symbologyIdentifier(), "]Q5");
|
||||
EXPECT_EQ(result.text(), L"99A");
|
||||
|
||||
// AIM "BYTE(1) A FNC1(2nd) 99 (0x63) BYTE(1) B" - FNC1(2nd) can occur anywhere
|
||||
// Disabled this test, since this violates the specification and the code does support it anymore
|
||||
// result = DecodeBitStream({0x40, 0x14, 0x19, 0x63, 0x40, 0x14, 0x20, 0x00}, version, ecLevel, "");
|
||||
// EXPECT_EQ(result.symbologyIdentifier(), "]Q5");
|
||||
// EXPECT_EQ(result.text(), L"99AB"); // Application Indicator prefixed to data
|
||||
|
||||
// AIM "FNC1(2nd) A (100 + 61 = 0xA5) ANUM(1) B"
|
||||
result = DecodeBitStream({0x9A, 0x52, 0x00, 0x96, 0x00}, version, ecLevel);
|
||||
EXPECT_EQ(result.symbologyIdentifier(), "]Q5");
|
||||
EXPECT_EQ(result.text(), L"AB");
|
||||
|
||||
// AIM "FNC1(2nd) a (100 + 97 = 0xC5) ANUM(1) B"
|
||||
result = DecodeBitStream({0x9C, 0x52, 0x00, 0x96, 0x00}, version, ecLevel);
|
||||
EXPECT_EQ(result.symbologyIdentifier(), "]Q5");
|
||||
EXPECT_EQ(result.text(), L"aB");
|
||||
|
||||
// Bad AIM Application Indicator "FNC1(2nd) @ (0xA4) ANUM(1) B"
|
||||
result = DecodeBitStream({0x9A, 0x42, 0x00, 0x96, 0x00}, version, ecLevel);
|
||||
EXPECT_FALSE(result.isValid());
|
||||
}
|
||||
657
src/qrcode/cpp_port/test/QREncoderTest.cpp
Normal file
657
src/qrcode/cpp_port/test/QREncoderTest.cpp
Normal file
@@ -0,0 +1,657 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "BitArray.h"
|
||||
#include "BitArrayUtility.h"
|
||||
#include "BitMatrixIO.h"
|
||||
#include "CharacterSet.h"
|
||||
#include "TextDecoder.h"
|
||||
#include "Utf.h"
|
||||
#include "qrcode/QREncoder.h"
|
||||
#include "qrcode/QRCodecMode.h"
|
||||
#include "qrcode/QREncodeResult.h"
|
||||
#include "qrcode/QRErrorCorrectionLevel.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace ZXing {
|
||||
namespace QRCode {
|
||||
int GetAlphanumericCode(int code);
|
||||
CodecMode ChooseMode(const std::wstring& content, CharacterSet encoding);
|
||||
void AppendModeInfo(CodecMode mode, BitArray& bits);
|
||||
void AppendLengthInfo(int numLetters, const Version& version, CodecMode mode, BitArray& bits);
|
||||
void AppendNumericBytes(const std::wstring& content, BitArray& bits);
|
||||
void AppendAlphanumericBytes(const std::wstring& content, BitArray& bits);
|
||||
void Append8BitBytes(const std::wstring& content, CharacterSet encoding, BitArray& bits);
|
||||
void AppendKanjiBytes(const std::wstring& content, BitArray& bits);
|
||||
void AppendBytes(const std::wstring& content, CodecMode mode, CharacterSet encoding, BitArray& bits);
|
||||
void TerminateBits(int numDataBytes, BitArray& bits);
|
||||
void GetNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, int numRSBlocks, int blockID, int& numDataBytesInBlock, int& numECBytesInBlock);
|
||||
void GenerateECBytes(const ByteArray& dataBytes, int numEcBytesInBlock, ByteArray& ecBytes);
|
||||
BitArray InterleaveWithECBytes(const BitArray& bits, int numTotalBytes, int numDataBytes, int numRSBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
using namespace ZXing;
|
||||
using namespace ZXing::QRCode;
|
||||
using namespace ZXing::Utility;
|
||||
|
||||
namespace {
|
||||
std::wstring ShiftJISString(const std::vector<uint8_t>& bytes)
|
||||
{
|
||||
std::string str;
|
||||
TextDecoder::Append(str, bytes.data(), bytes.size(), CharacterSet::Shift_JIS);
|
||||
return FromUtf8(str);
|
||||
}
|
||||
|
||||
std::string RemoveSpace(std::string s)
|
||||
{
|
||||
s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, GetAlphanumericCode)
|
||||
{
|
||||
// The first ten code points are numbers.
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
EXPECT_EQ(i, GetAlphanumericCode('0' + i));
|
||||
}
|
||||
|
||||
// The next 26 code points are capital alphabet letters.
|
||||
for (int i = 10; i < 36; ++i) {
|
||||
EXPECT_EQ(i, GetAlphanumericCode('A' + i - 10));
|
||||
}
|
||||
|
||||
// Others are symbol letters
|
||||
EXPECT_EQ(36, GetAlphanumericCode(' '));
|
||||
EXPECT_EQ(37, GetAlphanumericCode('$'));
|
||||
EXPECT_EQ(38, GetAlphanumericCode('%'));
|
||||
EXPECT_EQ(39, GetAlphanumericCode('*'));
|
||||
EXPECT_EQ(40, GetAlphanumericCode('+'));
|
||||
EXPECT_EQ(41, GetAlphanumericCode('-'));
|
||||
EXPECT_EQ(42, GetAlphanumericCode('.'));
|
||||
EXPECT_EQ(43, GetAlphanumericCode('/'));
|
||||
EXPECT_EQ(44, GetAlphanumericCode(':'));
|
||||
|
||||
// Should return -1 for other letters;
|
||||
EXPECT_EQ(-1, GetAlphanumericCode('a'));
|
||||
EXPECT_EQ(-1, GetAlphanumericCode('#'));
|
||||
EXPECT_EQ(-1, GetAlphanumericCode('\0'));
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, ChooseMode)
|
||||
{
|
||||
// Numeric mode.
|
||||
EXPECT_EQ(CodecMode::NUMERIC, ChooseMode(L"0", CharacterSet::Unknown));
|
||||
EXPECT_EQ(CodecMode::NUMERIC, ChooseMode(L"0123456789", CharacterSet::Unknown));
|
||||
// Alphanumeric mode.
|
||||
EXPECT_EQ(CodecMode::ALPHANUMERIC, ChooseMode(L"A", CharacterSet::Unknown));
|
||||
EXPECT_EQ(CodecMode::ALPHANUMERIC,
|
||||
ChooseMode(L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:", CharacterSet::Unknown));
|
||||
// 8-bit byte mode.
|
||||
EXPECT_EQ(CodecMode::BYTE, ChooseMode(L"a", CharacterSet::Unknown));
|
||||
EXPECT_EQ(CodecMode::BYTE, ChooseMode(L"#", CharacterSet::Unknown));
|
||||
EXPECT_EQ(CodecMode::BYTE, ChooseMode(L"", CharacterSet::Unknown));
|
||||
// Kanji mode. We used to use MODE_KANJI for these, but we stopped
|
||||
// doing that as we cannot distinguish Shift_JIS from other encodings
|
||||
// from data bytes alone. See also comments in qrcode_encoder.h.
|
||||
|
||||
// AIUE in Hiragana in Shift_JIS
|
||||
EXPECT_EQ(CodecMode::BYTE,
|
||||
ChooseMode(ShiftJISString({0x8, 0xa, 0x8, 0xa, 0x8, 0xa, 0x8, 0xa6}), CharacterSet::Unknown));
|
||||
|
||||
// Nihon in Kanji in Shift_JIS.
|
||||
EXPECT_EQ(CodecMode::BYTE, ChooseMode(ShiftJISString({0x9, 0xf, 0x9, 0x7b}), CharacterSet::Unknown));
|
||||
|
||||
// Sou-Utsu-Byou in Kanji in Shift_JIS.
|
||||
EXPECT_EQ(CodecMode::BYTE, ChooseMode(ShiftJISString({0xe, 0x4, 0x9, 0x5, 0x9, 0x61}), CharacterSet::Unknown));
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, Encode)
|
||||
{
|
||||
auto qrCode = Encode(L"ABCDEF", ErrorCorrectionLevel::High, CharacterSet::Unknown, 0, false, -1);
|
||||
EXPECT_EQ(qrCode.mode, CodecMode::ALPHANUMERIC);
|
||||
EXPECT_EQ(qrCode.ecLevel, ErrorCorrectionLevel::High);
|
||||
ASSERT_NE(qrCode.version, nullptr);
|
||||
EXPECT_EQ(qrCode.version->versionNumber(), 1);
|
||||
EXPECT_EQ(qrCode.maskPattern, 4);
|
||||
EXPECT_EQ(ToString(qrCode.matrix),
|
||||
"X X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X X X \n"
|
||||
" X X \n"
|
||||
" X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X \n"
|
||||
" X X X X X X \n"
|
||||
"X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X \n"
|
||||
"X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n");
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, EncodeWithVersion)
|
||||
{
|
||||
auto qrCode = Encode(L"ABCDEF", ErrorCorrectionLevel::High, CharacterSet::Unknown, 7, false, -1);
|
||||
ASSERT_NE(qrCode.version, nullptr);
|
||||
EXPECT_EQ(qrCode.version->versionNumber(), 7);
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, EncodeWithVersionTooSmall)
|
||||
{
|
||||
EXPECT_THROW(
|
||||
Encode(L"THISMESSAGEISTOOLONGFORAQRCODEVERSION3", ErrorCorrectionLevel::High, CharacterSet::Unknown, 3, false, -1)
|
||||
, std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, SimpleUTF8ECI)
|
||||
{
|
||||
auto qrCode = Encode(L"hello", ErrorCorrectionLevel::High, CharacterSet::UTF8, 0, false, -1);
|
||||
EXPECT_EQ(qrCode.mode, CodecMode::BYTE);
|
||||
EXPECT_EQ(qrCode.ecLevel, ErrorCorrectionLevel::High);
|
||||
ASSERT_NE(qrCode.version, nullptr);
|
||||
EXPECT_EQ(qrCode.version->versionNumber(), 1);
|
||||
EXPECT_EQ(qrCode.maskPattern, 6);
|
||||
EXPECT_EQ(ToString(qrCode.matrix), // break the line comment
|
||||
"X X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X \n"
|
||||
"X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X \n"
|
||||
" X X X X X X X \n"
|
||||
" X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
" X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X \n"
|
||||
"X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X \n"
|
||||
"X X X X X X X X X X X \n");
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, SimpleBINARYECI)
|
||||
{
|
||||
auto qrCode = Encode(L"\u00E9", ErrorCorrectionLevel::High, CharacterSet::BINARY, 0, false, -1);
|
||||
EXPECT_EQ(qrCode.mode, CodecMode::BYTE);
|
||||
EXPECT_EQ(qrCode.ecLevel, ErrorCorrectionLevel::High);
|
||||
ASSERT_NE(qrCode.version, nullptr);
|
||||
EXPECT_EQ(qrCode.version->versionNumber(), 1);
|
||||
EXPECT_EQ(qrCode.maskPattern, 6);
|
||||
EXPECT_EQ(ToString(qrCode.matrix),
|
||||
"X X X X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X \n"
|
||||
"X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X \n"
|
||||
" X X X X X X X \n"
|
||||
"X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X \n"
|
||||
" X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X \n");
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, EncodeKanjiMode)
|
||||
{
|
||||
auto qrCode = Encode(L"\u65e5\u672c", ErrorCorrectionLevel::Medium, CharacterSet::Shift_JIS, 0, false, -1);
|
||||
EXPECT_EQ(qrCode.mode, CodecMode::KANJI);
|
||||
EXPECT_EQ(qrCode.ecLevel, ErrorCorrectionLevel::Medium);
|
||||
ASSERT_NE(qrCode.version, nullptr);
|
||||
EXPECT_EQ(qrCode.version->versionNumber(), 1);
|
||||
EXPECT_EQ(qrCode.maskPattern, 0);
|
||||
EXPECT_EQ(ToString(qrCode.matrix),
|
||||
"X X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X X X \n"
|
||||
" X \n"
|
||||
"X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X \n"
|
||||
" X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n");
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, EncodeShiftjisNumeric)
|
||||
{
|
||||
auto qrCode = Encode(L"0123", ErrorCorrectionLevel::Medium, CharacterSet::Shift_JIS, 0, false, -1);
|
||||
EXPECT_EQ(qrCode.mode, CodecMode::NUMERIC);
|
||||
EXPECT_EQ(qrCode.ecLevel, ErrorCorrectionLevel::Medium);
|
||||
ASSERT_NE(qrCode.version, nullptr);
|
||||
EXPECT_EQ(qrCode.version->versionNumber(), 1);
|
||||
EXPECT_EQ(qrCode.maskPattern, 2);
|
||||
EXPECT_EQ(ToString(qrCode.matrix),
|
||||
"X X X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X \n"
|
||||
" X X X X X X X X \n"
|
||||
" X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n");
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, EncodeGS1)
|
||||
{
|
||||
auto qrCode = Encode(L"100001%11171218", ErrorCorrectionLevel::High, CharacterSet::Unknown, 0, true, -1);
|
||||
EXPECT_EQ(qrCode.mode, CodecMode::ALPHANUMERIC);
|
||||
EXPECT_EQ(qrCode.ecLevel, ErrorCorrectionLevel::High);
|
||||
ASSERT_NE(qrCode.version, nullptr);
|
||||
EXPECT_EQ(qrCode.version->versionNumber(), 2);
|
||||
EXPECT_EQ(qrCode.maskPattern, 4);
|
||||
EXPECT_EQ(ToString(qrCode.matrix),
|
||||
"X X X X X X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X \n"
|
||||
" X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n");
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, EncodeGS1ModeHeaderWithECI)
|
||||
{
|
||||
auto qrCode = Encode(L"hello", ErrorCorrectionLevel::High, CharacterSet::UTF8, 0, true, -1);
|
||||
EXPECT_EQ(qrCode.mode, CodecMode::BYTE);
|
||||
EXPECT_EQ(qrCode.ecLevel, ErrorCorrectionLevel::High);
|
||||
ASSERT_NE(qrCode.version, nullptr);
|
||||
EXPECT_EQ(qrCode.version->versionNumber(), 1);
|
||||
EXPECT_EQ(qrCode.maskPattern, 5);
|
||||
EXPECT_EQ(ToString(qrCode.matrix),
|
||||
"X X X X X X X X X X X X X X X X X \n"
|
||||
"X X X X X X \n"
|
||||
"X X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X \n"
|
||||
" X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
" X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X \n"
|
||||
"X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X \n"
|
||||
"X X X X X X X X X \n"
|
||||
"X X X X X X X X X X X X X X \n");
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, AppendModeInfo)
|
||||
{
|
||||
BitArray bits;
|
||||
AppendModeInfo(CodecMode::NUMERIC, bits);
|
||||
EXPECT_EQ(ToString(bits), "...X");
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, AppendLengthInfo)
|
||||
{
|
||||
BitArray bits;
|
||||
AppendLengthInfo(1, // 1 letter (1/1).
|
||||
*Version::FromNumber(1), CodecMode::NUMERIC, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("........ .X")); // 10 bits.
|
||||
|
||||
bits = BitArray();
|
||||
AppendLengthInfo(2, // 2 letters (2/1).
|
||||
*Version::FromNumber(10), CodecMode::ALPHANUMERIC, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("........ .X.")); // 11 bits.
|
||||
|
||||
bits = BitArray();
|
||||
AppendLengthInfo(255, // 255 letter (255/1).
|
||||
*Version::FromNumber(27), CodecMode::BYTE, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("........ XXXXXXXX")); // 16 bits.
|
||||
|
||||
bits = BitArray();
|
||||
AppendLengthInfo(512, // 512 letters (1024/2).
|
||||
*Version::FromNumber(40), CodecMode::KANJI, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("..X..... ....")); // 12 bits.
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, AppendNumericBytes)
|
||||
{
|
||||
// 1 = 01 = 0001 in 4 bits.
|
||||
BitArray bits;
|
||||
AppendNumericBytes(L"1", bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("...X"));
|
||||
|
||||
// 12 = 0xc = 0001100 in 7 bits.
|
||||
bits = BitArray();
|
||||
AppendNumericBytes(L"12", bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("...XX.."));
|
||||
|
||||
// 123 = 0x7b = 0001111011 in 10 bits.
|
||||
bits = BitArray();
|
||||
AppendNumericBytes(L"123", bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("...XXXX. XX"));
|
||||
|
||||
// 1234 = "123" + "4" = 0001111011 + 0100
|
||||
bits = BitArray();
|
||||
AppendNumericBytes(L"1234", bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("...XXXX. XX.X.."));
|
||||
|
||||
// Empty.
|
||||
bits = BitArray();
|
||||
AppendNumericBytes(L"", bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace(""));
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, AppendAlphanumericBytes)
|
||||
{
|
||||
// A = 10 = 0xa = 001010 in 6 bits
|
||||
BitArray bits;
|
||||
AppendAlphanumericBytes(L"A", bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("..X.X."));
|
||||
|
||||
// AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
|
||||
bits = BitArray();
|
||||
AppendAlphanumericBytes(L"AB", bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("..XXX..X X.X"));
|
||||
|
||||
// ABC = "AB" + "C" = 00111001101 + 001100
|
||||
bits = BitArray();
|
||||
AppendAlphanumericBytes(L"ABC", bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("..XXX..X X.X..XX. ."));
|
||||
|
||||
// Empty.
|
||||
bits = BitArray();
|
||||
AppendAlphanumericBytes(L"", bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace(""));
|
||||
|
||||
// Invalid data.
|
||||
EXPECT_THROW(AppendAlphanumericBytes(L"abc", bits), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, Append8BitBytes)
|
||||
{
|
||||
// 0x61, 0x62, 0x63
|
||||
BitArray bits;
|
||||
Append8BitBytes(L"abc", CharacterSet::Unknown, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace(".XX....X .XX...X. .XX...XX"));
|
||||
|
||||
// Empty.
|
||||
bits = BitArray();
|
||||
Append8BitBytes(L"", CharacterSet::Unknown, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace(""));
|
||||
}
|
||||
|
||||
// Numbers are from page 21 of JISX0510:2004
|
||||
TEST(QREncoderTest, AppendKanjiBytes)
|
||||
{
|
||||
BitArray bits;
|
||||
AppendKanjiBytes(ShiftJISString({ 0x93, 0x5f }), bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace(".XX.XX.. XXXXX"));
|
||||
|
||||
AppendKanjiBytes(ShiftJISString({ 0xe4, 0xaa }), bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace(".XX.XX.. XXXXXXX. X.X.X.X. X."));
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, AppendBytes)
|
||||
{
|
||||
// Should use appendNumericBytes.
|
||||
// 1 = 01 = 0001 in 4 bits.
|
||||
BitArray bits;
|
||||
AppendBytes(L"1", CodecMode::NUMERIC, CharacterSet::Unknown, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("...X"));
|
||||
|
||||
// Should use appendAlphanumericBytes.
|
||||
// A = 10 = 0xa = 001010 in 6 bits
|
||||
bits = BitArray();
|
||||
AppendBytes(L"A", CodecMode::ALPHANUMERIC, CharacterSet::Unknown, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace("..X.X."));
|
||||
|
||||
// Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
|
||||
bits = BitArray();
|
||||
EXPECT_THROW(AppendBytes(L"a", CodecMode::ALPHANUMERIC, CharacterSet::Unknown, bits), std::invalid_argument);
|
||||
|
||||
// Should use append8BitBytes.
|
||||
// 0x61, 0x62, 0x63
|
||||
bits = BitArray();
|
||||
AppendBytes(L"abc", CodecMode::BYTE, CharacterSet::Unknown, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace(".XX....X .XX...X. .XX...XX"));
|
||||
|
||||
// Anything can be encoded in QRCode.MODE_8BIT_BYTE.
|
||||
AppendBytes(L"\0", CodecMode::BYTE, CharacterSet::Unknown, bits);
|
||||
|
||||
// Should use appendKanjiBytes.
|
||||
// 0x93, 0x5f
|
||||
bits = BitArray();
|
||||
AppendBytes(ShiftJISString({0x93, 0x5f}), CodecMode::KANJI, CharacterSet::Unknown, bits);
|
||||
EXPECT_EQ(ToString(bits), RemoveSpace(".XX.XX.. XXXXX"));
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, TerminateBits)
|
||||
{
|
||||
BitArray v;
|
||||
TerminateBits(0, v);
|
||||
EXPECT_EQ(ToString(v), RemoveSpace(""));
|
||||
|
||||
v = BitArray();
|
||||
TerminateBits(1, v);
|
||||
EXPECT_EQ(ToString(v), RemoveSpace("........"));
|
||||
|
||||
v = BitArray();
|
||||
v.appendBits(0, 3);
|
||||
TerminateBits(1, v);
|
||||
EXPECT_EQ(ToString(v), RemoveSpace("........"));
|
||||
|
||||
v = BitArray();
|
||||
v.appendBits(0, 5);
|
||||
TerminateBits(1, v);
|
||||
EXPECT_EQ(ToString(v), RemoveSpace("........"));
|
||||
|
||||
v = BitArray();
|
||||
v.appendBits(0, 8);
|
||||
TerminateBits(1, v);
|
||||
EXPECT_EQ(ToString(v), RemoveSpace("........"));
|
||||
|
||||
v = BitArray();
|
||||
TerminateBits(2, v);
|
||||
EXPECT_EQ(ToString(v), RemoveSpace("........ XXX.XX.."));
|
||||
|
||||
v = BitArray();
|
||||
v.appendBits(0, 1);
|
||||
TerminateBits(3, v);
|
||||
EXPECT_EQ(ToString(v), RemoveSpace("........ XXX.XX.. ...X...X"));
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, GetNumDataBytesAndNumECBytesForBlockID)
|
||||
{
|
||||
int numDataBytes;
|
||||
int numEcBytes;
|
||||
// Version 1-H.
|
||||
GetNumDataBytesAndNumECBytesForBlockID(26, 9, 1, 0, numDataBytes, numEcBytes);
|
||||
EXPECT_EQ(9, numDataBytes);
|
||||
EXPECT_EQ(17, numEcBytes);
|
||||
|
||||
// Version 3-H. 2 blocks.
|
||||
GetNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 0, numDataBytes, numEcBytes);
|
||||
EXPECT_EQ(13, numDataBytes);
|
||||
EXPECT_EQ(22, numEcBytes);
|
||||
GetNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 1, numDataBytes, numEcBytes);
|
||||
EXPECT_EQ(13, numDataBytes);
|
||||
EXPECT_EQ(22, numEcBytes);
|
||||
|
||||
// Version 7-H. (4 + 1) blocks.
|
||||
GetNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 0, numDataBytes, numEcBytes);
|
||||
EXPECT_EQ(13, numDataBytes);
|
||||
EXPECT_EQ(26, numEcBytes);
|
||||
GetNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 4, numDataBytes, numEcBytes);
|
||||
EXPECT_EQ(14, numDataBytes);
|
||||
EXPECT_EQ(26, numEcBytes);
|
||||
|
||||
// Version 40-H. (20 + 61) blocks.
|
||||
GetNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 0, numDataBytes, numEcBytes);
|
||||
EXPECT_EQ(15, numDataBytes);
|
||||
EXPECT_EQ(30, numEcBytes);
|
||||
GetNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 20, numDataBytes, numEcBytes);
|
||||
EXPECT_EQ(16, numDataBytes);
|
||||
EXPECT_EQ(30, numEcBytes);
|
||||
GetNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 80, numDataBytes, numEcBytes);
|
||||
EXPECT_EQ(16, numDataBytes);
|
||||
EXPECT_EQ(30, numEcBytes);
|
||||
}
|
||||
|
||||
// Numbers are from http://www.swetake.com/qr/qr3.html and
|
||||
// http://www.swetake.com/qr/qr9.html
|
||||
TEST(QREncoderTest, GenerateECBytes)
|
||||
{
|
||||
ByteArray ecBytes;
|
||||
GenerateECBytes({ 32, 65, 205, 69, 41, 220, 46, 128, 236 }, 17, ecBytes);
|
||||
ByteArray expected = { 42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61 };
|
||||
EXPECT_EQ(ecBytes, expected);
|
||||
|
||||
GenerateECBytes({ 67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214 }, 18, ecBytes);
|
||||
expected = { 175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187 };
|
||||
EXPECT_EQ(ecBytes, expected);
|
||||
|
||||
// High-order zero coefficient case.
|
||||
GenerateECBytes({ 32, 49, 205, 69, 42, 20, 0, 236, 17 }, 17, ecBytes);
|
||||
expected = { 0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213 };
|
||||
EXPECT_EQ(ecBytes, expected);
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, InterleaveWithECBytes)
|
||||
{
|
||||
BitArray in;
|
||||
for (int dataByte : {32, 65, 205, 69, 41, 220, 46, 128, 236})
|
||||
in.appendBits(dataByte, 8);
|
||||
|
||||
BitArray out = InterleaveWithECBytes(in, 26, 9, 1);
|
||||
std::vector<uint8_t> expected = {
|
||||
32, 65, 205, 69, 41, 220, 46, 128, 236,
|
||||
|
||||
42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61,
|
||||
}; // Error correction bytes in second block
|
||||
ASSERT_EQ(Size(expected), out.sizeInBytes());
|
||||
EXPECT_EQ(expected, out.toBytes());
|
||||
|
||||
// Numbers are from http://www.swetake.com/qr/qr8.html
|
||||
in = BitArray();
|
||||
for (int dataByte :
|
||||
{67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214, 230, 247, 7, 23, 39, 55,
|
||||
71, 87, 103, 119, 135, 151, 166, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214, 230,
|
||||
247, 7, 23, 39, 55, 71, 87, 103, 119, 135, 151, 160, 236, 17, 236, 17, 236, 17, 236, 17})
|
||||
in.appendBits(dataByte, 8);
|
||||
|
||||
out = InterleaveWithECBytes(in, 134, 62, 4);
|
||||
expected = {
|
||||
67, 230, 54, 55, 70, 247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39, 118, 119, 70,
|
||||
55, 134, 135, 86, 71, 150, 151, 102, 87, 166, 160, 118, 103, 182, 236, 134, 119, 198, 17, 150, 135,
|
||||
214, 236, 166, 151, 230, 17, 182, 166, 247, 236, 198, 22, 7, 17, 214, 38, 23, 236, 39, 17,
|
||||
|
||||
175, 155, 245, 236, 80, 146, 56, 74, 155, 165, 133, 142, 64, 183, 132, 13, 178, 54, 132, 108, 45,
|
||||
113, 53, 50, 214, 98, 193, 152, 233, 147, 50, 71, 65, 190, 82, 51, 209, 199, 171, 54, 12, 112,
|
||||
57, 113, 155, 117, 211, 164, 117, 30, 158, 225, 31, 190, 242, 38, 140, 61, 179, 154, 214, 138, 147,
|
||||
87, 27, 96, 77, 47, 187, 49, 156, 214,
|
||||
}; // Error correction bytes in second block
|
||||
EXPECT_EQ(Size(expected), out.sizeInBytes());
|
||||
EXPECT_EQ(expected, out.toBytes());
|
||||
}
|
||||
|
||||
TEST(QREncoderTest, BugInBitVectorNumBytes)
|
||||
{
|
||||
// There was a bug in BitVector.sizeInBytes() that caused it to return a
|
||||
// smaller-by-one value (ex. 1465 instead of 1466) if the number of bits
|
||||
// in the vector is not 8-bit aligned. In QRCodeEncoder::InitQRCode(),
|
||||
// BitVector::sizeInBytes() is used for finding the smallest QR Code
|
||||
// version that can fit the given data. Hence there were corner cases
|
||||
// where we chose a wrong QR Code version that cannot fit the given
|
||||
// data. Note that the issue did not occur with MODE_8BIT_BYTE, as the
|
||||
// bits in the bit vector are always 8-bit aligned.
|
||||
//
|
||||
// Before the bug was fixed, the following test didn't pass, because:
|
||||
//
|
||||
// - MODE_NUMERIC is chosen as all bytes in the data are '0'
|
||||
// - The 3518-byte numeric data needs 1466 bytes
|
||||
// - 3518 / 3 * 10 + 7 = 11727 bits = 1465.875 bytes
|
||||
// - 3 numeric bytes are encoded in 10 bits, hence the first
|
||||
// 3516 bytes are encoded in 3516 / 3 * 10 = 11720 bits.
|
||||
// - 2 numeric bytes can be encoded in 7 bits, hence the last
|
||||
// 2 bytes are encoded in 7 bits.
|
||||
// - The version 27 QR Code with the EC level L has 1468 bytes for data.
|
||||
// - 1828 - 360 = 1468
|
||||
// - In InitQRCode(), 3 bytes are reserved for a header. Hence 1465 bytes
|
||||
// (1468 -3) are left for data.
|
||||
// - Because of the bug in BitVector::sizeInBytes(), InitQRCode() determines
|
||||
// the given data can fit in 1465 bytes, despite it needs 1466 bytes.
|
||||
// - Hence QRCodeEncoder.encode() failed and returned false.
|
||||
// - To be precise, it needs 11727 + 4 (getMode info) + 14 (length info) =
|
||||
// 11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468
|
||||
// bytes).
|
||||
Encode(std::wstring(3518, L'0'), ErrorCorrectionLevel::Low, CharacterSet::Unknown, 0, false, -1);
|
||||
}
|
||||
45
src/qrcode/cpp_port/test/QRErrorCorrectionLevelTest.cpp
Normal file
45
src/qrcode/cpp_port/test/QRErrorCorrectionLevelTest.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2008 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "qrcode/QRErrorCorrectionLevel.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace ZXing;
|
||||
using namespace ZXing::QRCode;
|
||||
|
||||
TEST(QRErrorCorrectionLevelTest, ForBits)
|
||||
{
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Medium, ECLevelFromBits(0));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(1));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::High, ECLevelFromBits(2));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Quality, ECLevelFromBits(3));
|
||||
}
|
||||
|
||||
TEST(QRErrorCorrectionLevelTest, ForMicroBits)
|
||||
{
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(0, true));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(1, true));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Medium, ECLevelFromBits(2, true));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(3, true));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Medium, ECLevelFromBits(4, true));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(5, true));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Medium, ECLevelFromBits(6, true));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Quality, ECLevelFromBits(7, true));
|
||||
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Quality, ECLevelFromBits(-1, true));
|
||||
EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(8, true));
|
||||
}
|
||||
|
||||
TEST(QRErrorCorrectionLevelTest, ToString)
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
EXPECT_EQ("L"s, ToString(ErrorCorrectionLevel::Low));
|
||||
EXPECT_EQ("M"s, ToString(ErrorCorrectionLevel::Medium));
|
||||
EXPECT_EQ("Q"s, ToString(ErrorCorrectionLevel::Quality));
|
||||
EXPECT_EQ("H"s, ToString(ErrorCorrectionLevel::High));
|
||||
}
|
||||
124
src/qrcode/cpp_port/test/QRFormatInformationTest.rs
Normal file
124
src/qrcode/cpp_port/test/QRFormatInformationTest.rs
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2007 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::qrcode::decoder::{ErrorCorrectionLevel, FormatInformation};
|
||||
|
||||
const MASKED_TEST_FORMAT_INFO: u32 = 0x2BED;
|
||||
const MASKED_TEST_FORMAT_INFO2: u32 =
|
||||
((0x2BED << 1) & 0b1111111000000000) | 0b100000000 | (0x2BED & 0b11111111); // insert the 'Dark Module'
|
||||
const UNMASKED_TEST_FORMAT_INFO: u32 = MASKED_TEST_FORMAT_INFO ^ 0x5412;
|
||||
const MICRO_MASKED_TEST_FORMAT_INFO: u32 = 0x3BBA;
|
||||
// const MICRO_UNMASKED_TEST_FORMAT_INFO: u32 = MICRO_MASKED_TEST_FORMAT_INFO ^ 0x4445;
|
||||
|
||||
fn DoFormatInformationTest(formatInfo: u32, expectedMask: u8, expectedECL: ErrorCorrectionLevel) {
|
||||
let parsedFormat = FormatInformation::DecodeMQR(formatInfo);
|
||||
assert!(parsedFormat.isValid());
|
||||
assert_eq!(expectedMask, parsedFormat.data_mask);
|
||||
assert_eq!(expectedECL, parsedFormat.error_correction_level);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn Decode() {
|
||||
// Normal case
|
||||
let expected = FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO2);
|
||||
assert!(expected.isValid());
|
||||
assert_eq!(0x07, expected.data_mask);
|
||||
assert_eq!(ErrorCorrectionLevel::Q, expected.error_correction_level);
|
||||
// where the code forgot the mask!
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::DecodeQR(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO2)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn DecodeWithBitDifference() {
|
||||
let expected = FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO2);
|
||||
// 1,2,3,4 bits difference
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::DecodeQR(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x01,
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x01
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::DecodeQR(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x03,
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x03
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::DecodeQR(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x07,
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x07
|
||||
)
|
||||
);
|
||||
assert!(!FormatInformation::DecodeQR(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x0F,
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x0F
|
||||
)
|
||||
.isValid());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn DecodeWithMisread() {
|
||||
let expected = FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO2);
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::DecodeQR(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x03,
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x0F
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn DecodeMicro() {
|
||||
// Normal cases.
|
||||
DoFormatInformationTest(0x4445, 0x0, ErrorCorrectionLevel::L);
|
||||
DoFormatInformationTest(0x4172, 0x1, ErrorCorrectionLevel::L);
|
||||
DoFormatInformationTest(0x5fc0, 0x2, ErrorCorrectionLevel::L);
|
||||
DoFormatInformationTest(0x5af7, 0x3, ErrorCorrectionLevel::L);
|
||||
DoFormatInformationTest(0x6793, 0x0, ErrorCorrectionLevel::M);
|
||||
DoFormatInformationTest(0x62a4, 0x1, ErrorCorrectionLevel::M);
|
||||
DoFormatInformationTest(0x3e8d, 0x2, ErrorCorrectionLevel::Q);
|
||||
DoFormatInformationTest(MICRO_MASKED_TEST_FORMAT_INFO, 0x3, ErrorCorrectionLevel::Q);
|
||||
|
||||
// where the code forgot the mask!
|
||||
// DoFormatInformationTest(MICRO_UNMASKED_TEST_FORMAT_INFO, 0x3, ErrorCorrectionLevel::Quality);
|
||||
}
|
||||
|
||||
// This doesn't work as expected because the implementation of the decode tries with
|
||||
// and without the mask (0x4445). This effectively adds a tolerance of 5 bits to the Hamming
|
||||
// distance calculation.
|
||||
#[test]
|
||||
fn DecodeMicroWithBitDifference() {
|
||||
let expected = FormatInformation::DecodeMQR(MICRO_MASKED_TEST_FORMAT_INFO);
|
||||
|
||||
// 1,2,3 bits difference
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::DecodeMQR(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x01)
|
||||
);
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::DecodeMQR(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x03)
|
||||
);
|
||||
assert_eq!(
|
||||
expected,
|
||||
FormatInformation::DecodeMQR(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x07)
|
||||
);
|
||||
|
||||
// Bigger bit differences can return valid FormatInformation objects but the data mask and error
|
||||
// correction levels do not match.
|
||||
// EXPECT_TRUE(FormatInformation::DecodeFormatInformation(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x3f).isValid());
|
||||
// EXPECT_NE(expected.dataMask(), FormatInformation::DecodeFormatInformation(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x3f).dataMask());
|
||||
// EXPECT_NE(expected.errorCorrectionLevel(),
|
||||
// FormatInformation::DecodeFormatInformation(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x3f).errorCorrectionLevel());
|
||||
}
|
||||
135
src/qrcode/cpp_port/test/QRModeTest.rs
Normal file
135
src/qrcode/cpp_port/test/QRModeTest.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2008 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::qrcode::decoder::{Mode, Version};
|
||||
|
||||
#[test]
|
||||
fn ForBits() {
|
||||
assert_eq!(
|
||||
Mode::TERMINATOR,
|
||||
Mode::CodecModeForBits(0x00, None).unwrap()
|
||||
);
|
||||
assert_eq!(Mode::NUMERIC, Mode::CodecModeForBits(0x01, None).unwrap());
|
||||
assert_eq!(
|
||||
Mode::ALPHANUMERIC,
|
||||
Mode::CodecModeForBits(0x02, None).unwrap()
|
||||
);
|
||||
assert_eq!(Mode::BYTE, Mode::CodecModeForBits(0x04, None).unwrap());
|
||||
assert_eq!(Mode::KANJI, Mode::CodecModeForBits(0x08, None).unwrap());
|
||||
assert!(Mode::CodecModeForBits(0x10, None).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn CharacterCount() {
|
||||
// Spot check a few values
|
||||
assert_eq!(
|
||||
10,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(5, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
12,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(26, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
14,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(40, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
9,
|
||||
Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::FromNumber(6, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
8,
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(7, false).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
8,
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(8, false).unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn MicroForBits() {
|
||||
// M1
|
||||
assert_eq!(
|
||||
Mode::NUMERIC,
|
||||
Mode::CodecModeForBits(0x00, Some(true)).unwrap()
|
||||
);
|
||||
// M2
|
||||
assert_eq!(
|
||||
Mode::NUMERIC,
|
||||
Mode::CodecModeForBits(0x00, Some(true)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Mode::ALPHANUMERIC,
|
||||
Mode::CodecModeForBits(0x01, Some(true)).unwrap()
|
||||
);
|
||||
// M3
|
||||
assert_eq!(
|
||||
Mode::NUMERIC,
|
||||
Mode::CodecModeForBits(0x00, Some(true)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Mode::ALPHANUMERIC,
|
||||
Mode::CodecModeForBits(0x01, Some(true)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Mode::BYTE,
|
||||
Mode::CodecModeForBits(0x02, Some(true)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Mode::KANJI,
|
||||
Mode::CodecModeForBits(0x03, Some(true)).unwrap()
|
||||
);
|
||||
// M4
|
||||
assert_eq!(
|
||||
Mode::NUMERIC,
|
||||
Mode::CodecModeForBits(0x00, Some(true)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Mode::ALPHANUMERIC,
|
||||
Mode::CodecModeForBits(0x01, Some(true)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Mode::BYTE,
|
||||
Mode::CodecModeForBits(0x02, Some(true)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
Mode::KANJI,
|
||||
Mode::CodecModeForBits(0x03, Some(true)).unwrap()
|
||||
);
|
||||
|
||||
assert!(Mode::CodecModeForBits(0x04, Some(true)).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn MicroCharacterCount() {
|
||||
// Spot check a few values
|
||||
assert_eq!(
|
||||
3,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(1, true).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
4,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(2, true).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
6,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(4, true).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
3,
|
||||
Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::FromNumber(2, true).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
4,
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(3, true).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
4,
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(4, true).unwrap())
|
||||
);
|
||||
}
|
||||
122
src/qrcode/cpp_port/test/QRVersionTest.rs
Normal file
122
src/qrcode/cpp_port/test/QRVersionTest.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2008 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{
|
||||
common::BitMatrix,
|
||||
qrcode::decoder::{Version, VersionRef},
|
||||
};
|
||||
|
||||
fn CheckVersion(version: VersionRef, number: u32, dimension: u32) {
|
||||
// assert_ne!(version, nullptr);
|
||||
assert_eq!(number, version.getVersionNumber());
|
||||
if (number > 1 && !version.isMicroQRCode()) {
|
||||
assert!(!version.getAlignmentPatternCenters().is_empty());
|
||||
}
|
||||
assert_eq!(dimension, version.getDimensionForVersion());
|
||||
}
|
||||
|
||||
fn DoTestVersion(expectedVersion: u32, mask: i32) {
|
||||
let version = Version::DecodeVersionInformation(mask, 0).expect("should exist");
|
||||
// assert_ne!(version, nullptr);
|
||||
assert_eq!(expectedVersion, version.getVersionNumber());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn VersionForNumber() {
|
||||
let version = Version::FromNumber(0, false);
|
||||
assert!(version.is_err(), "There is version with number 0");
|
||||
|
||||
for i in 1..=40 {
|
||||
// for (int i = 1; i <= 40; i++) {
|
||||
CheckVersion(
|
||||
Version::FromNumber(i, false).expect("version number found"),
|
||||
i,
|
||||
4 * i + 17,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn GetProvisionalVersionForDimension() {
|
||||
for i in 1..=40 {
|
||||
// for (int i = 1; i <= 40; i++) {
|
||||
let prov =
|
||||
Version::FromDimension(4 * i + 17).expect(&format!("version should exist for {i}"));
|
||||
// assert_ne!(prov, nullptr);
|
||||
assert_eq!(i, prov.getVersionNumber());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn DecodeVersionInformation() {
|
||||
// Spot check
|
||||
DoTestVersion(7, 0x07C94);
|
||||
DoTestVersion(12, 0x0C762);
|
||||
DoTestVersion(17, 0x1145D);
|
||||
DoTestVersion(22, 0x168C9);
|
||||
DoTestVersion(27, 0x1B08E);
|
||||
DoTestVersion(32, 0x209D5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn MicroVersionForNumber() {
|
||||
let version = Version::FromNumber(0, true);
|
||||
assert!(version.is_err(), "There is version with number 0");
|
||||
|
||||
for i in 1..=4 {
|
||||
// for (int i = 1; i <= 4; i++) {
|
||||
CheckVersion(
|
||||
Version::FromNumber(i, true).expect(&format!("version for {i} should exist")),
|
||||
i,
|
||||
2 * i + 9,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn GetProvisionalMicroVersionForDimension() {
|
||||
for i in 1..=4 {
|
||||
// for (int i = 1; i <= 4; i++) {
|
||||
let prov = Version::FromDimension(2 * i + 9)
|
||||
.expect(&format!("version for micro {i} should exist"));
|
||||
// assert_ne!(prov, nullptr);
|
||||
assert_eq!(i, prov.getVersionNumber());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn FunctionPattern() {
|
||||
let testFinderPatternRegion = |bitMatrix: &BitMatrix| {
|
||||
for row in 0..9 {
|
||||
// for (int row = 0; row < 9; row++){
|
||||
for col in 0..9 {
|
||||
// for (int col = 0; col < 9; col++) {
|
||||
assert!(bitMatrix.get(col, row));
|
||||
}
|
||||
}
|
||||
};
|
||||
for i in 1..=4 {
|
||||
// for (int i = 1; i <= 4; i++) {
|
||||
let version = Version::FromNumber(i, true).expect("version must be found");
|
||||
let functionPattern = version
|
||||
.buildFunctionPattern()
|
||||
.expect("function pattern must be found");
|
||||
testFinderPatternRegion(&functionPattern);
|
||||
|
||||
// Check timing pattern areas.
|
||||
let dimension = version.getDimensionForVersion();
|
||||
for row in dimension..functionPattern.height()
|
||||
// for (int row = dimension; row < functionPattern.height(); row++)
|
||||
{
|
||||
assert!(functionPattern.get(0, row));
|
||||
}
|
||||
for col in dimension..functionPattern.width()
|
||||
// for (int col = dimension; col < functionPattern.width(); col++)
|
||||
{
|
||||
assert!(functionPattern.get(col, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
160
src/qrcode/cpp_port/test/QRWriterTest.cpp
Normal file
160
src/qrcode/cpp_port/test/QRWriterTest.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2017 Huy Cuong Nguyen
|
||||
* Copyright 2008 ZXing authors
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#include "BitMatrixIO.h"
|
||||
#include "qrcode/QRWriter.h"
|
||||
#include "qrcode/QRErrorCorrectionLevel.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace ZXing;
|
||||
using namespace ZXing::QRCode;
|
||||
|
||||
namespace {
|
||||
|
||||
void DoTest(const std::wstring& contents, ErrorCorrectionLevel ecLevel, int resolution, const char* expected) {
|
||||
Writer writer;
|
||||
writer.setErrorCorrectionLevel(ecLevel);
|
||||
auto matrix = writer.encode(contents, resolution, resolution);
|
||||
auto actual = ToString(matrix, 'X', ' ', true);
|
||||
EXPECT_EQ(matrix.width(), resolution);
|
||||
EXPECT_EQ(matrix.height(), resolution);
|
||||
EXPECT_EQ(actual, expected);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST(QRWriterTest, OverSize)
|
||||
{
|
||||
// The QR should be multiplied up to fit, with extra padding if necessary
|
||||
int bigEnough = 256;
|
||||
Writer writer;
|
||||
BitMatrix matrix = writer.encode(L"http://www.google.com/", bigEnough, bigEnough);
|
||||
EXPECT_EQ(matrix.width(), bigEnough);
|
||||
EXPECT_EQ(matrix.height(), bigEnough);
|
||||
|
||||
// The QR will not fit in this size, so the matrix should come back bigger
|
||||
int tooSmall = 20;
|
||||
matrix = writer.encode(L"http://www.google.com/", tooSmall, tooSmall);
|
||||
EXPECT_GT(matrix.width(), tooSmall);
|
||||
EXPECT_GT(matrix.height(), tooSmall);
|
||||
|
||||
// We should also be able to handle non-square requests by padding them
|
||||
int strangeWidth = 500;
|
||||
int strangeHeight = 100;
|
||||
matrix = writer.encode(L"http://www.google.com/", strangeWidth, strangeHeight);
|
||||
EXPECT_EQ(matrix.width(), strangeWidth);
|
||||
EXPECT_EQ(matrix.height(), strangeHeight);
|
||||
|
||||
int overflowSize = 0x1000000;
|
||||
EXPECT_THROW(writer.encode(L"http://www.google.com/", overflowSize, overflowSize), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(QRWriterTest, RegressionTest)
|
||||
{
|
||||
DoTest(L"http://www.google.com/", ErrorCorrectionLevel::Medium, 99,
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
" \n"
|
||||
);
|
||||
}
|
||||
4
src/qrcode/cpp_port/test/mod.rs
Normal file
4
src/qrcode/cpp_port/test/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod QRModeTest;
|
||||
mod QRVersionTest;
|
||||
|
||||
mod QRFormatInformationTest;
|
||||
Reference in New Issue
Block a user