AZEncoderTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Copyright 2017 Huy Cuong Nguyen
  3. * Copyright 2013 ZXing authors
  4. */
  5. // SPDX-License-Identifier: Apache-2.0
  6. #include "aztec/AZEncoder.h"
  7. #include "BitArray.h"
  8. #include "BitArrayUtility.h"
  9. #include "BitMatrixIO.h"
  10. #include "gtest/gtest.h"
  11. #include <algorithm>
  12. #include <stdexcept>
  13. namespace ZXing {
  14. namespace Aztec {
  15. void GenerateModeMessage(bool compact, int layers, int messageSizeInWords, BitArray& modeMessage);
  16. void StuffBits(const BitArray& bits, int wordSize, BitArray& out);
  17. }
  18. }
  19. using namespace ZXing;
  20. namespace {
  21. void TestEncode(const std::string& data, bool compact, int layers, const BitMatrix& expected) {
  22. Aztec::EncodeResult aztec = Aztec::Encoder::Encode(data, 33, Aztec::Encoder::DEFAULT_AZTEC_LAYERS);
  23. EXPECT_EQ(aztec.compact, compact) << "Unexpected symbol format (compact)";
  24. EXPECT_EQ(aztec.layers, layers) << "Unexpected nr. of layers";
  25. EXPECT_EQ(aztec.matrix, expected) << "encode() failed";
  26. }
  27. std::string StripSpaces(std::string str) {
  28. #ifdef __cpp_lib_erase_if
  29. std::erase_if(str, isspace);
  30. #else
  31. str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
  32. #endif
  33. return str;
  34. }
  35. void TestModeMessage(bool compact, int layers, int words, const std::string& expected) {
  36. BitArray bits;
  37. Aztec::GenerateModeMessage(compact, layers, words, bits);
  38. auto expectedBits = Utility::ParseBitArray(StripSpaces(expected));
  39. EXPECT_EQ(bits, expectedBits) << "generateModeMessage() failed";
  40. }
  41. void TestStuffBits(int wordSize, const std::string& bits, const std::string& expected) {
  42. BitArray in = Utility::ParseBitArray(StripSpaces(bits));
  43. BitArray expectedBits = Utility::ParseBitArray(StripSpaces(expected));
  44. BitArray stuffed;
  45. Aztec::StuffBits(in, wordSize, stuffed);
  46. EXPECT_EQ(stuffed, expectedBits) << "stuffBits() failed for input string: " + bits;
  47. }
  48. }
  49. TEST(AZEncoderTest, GenerateModeMessage)
  50. {
  51. TestModeMessage(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X");
  52. TestModeMessage(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX..");
  53. TestModeMessage(false, 21, 660, "X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX");
  54. TestModeMessage(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX");
  55. }
  56. TEST(AZEncoderTest, StuffBits)
  57. {
  58. TestStuffBits(5, ".X.X. X.X.X .X.X.",
  59. ".X.X. X.X.X .X.X.");
  60. TestStuffBits(5, ".X.X. ..... .X.X",
  61. ".X.X. ....X ..X.X");
  62. TestStuffBits(3, "XX. ... ... ..X XXX .X. ..",
  63. "XX. ..X ..X ..X ..X .XX XX. .X. ..X");
  64. TestStuffBits(6, ".X.X.. ...... ..X.XX",
  65. ".X.X.. .....X. ..X.XX XXXX.");
  66. TestStuffBits(6, ".X.X.. ...... ...... ..X.X.",
  67. ".X.X.. .....X .....X ....X. X.XXXX");
  68. TestStuffBits(6, ".X.X.. XXXXXX ...... ..X.XX",
  69. ".X.X.. XXXXX. X..... ...X.X XXXXX.");
  70. TestStuffBits(6,
  71. "...... ..XXXX X..XX. .X.... .X.X.X .....X .X.... ...X.X .....X ....XX ..X... ....X. X..XXX X.XX.X",
  72. ".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX");
  73. }
  74. TEST(AZEncoderTest, Encode1)
  75. {
  76. TestEncode(
  77. "This is an example Aztec symbol for Wikipedia.",
  78. true, 3, ParseBitMatrix(
  79. "X X X X X X X X \n"
  80. "X X X X X X X X X X \n"
  81. "X X X X X X X X X X X \n"
  82. "X X X X X X X X X X X \n"
  83. " X X X X X X X X X X X \n"
  84. " X X X X X X X X X X X X X \n"
  85. " X X X X X X X X X X X X \n"
  86. "X X X X X X X X X X X X X X X X \n"
  87. "X X X X X X X X X X X \n"
  88. "X X X X X X X X X X X X X X X X \n"
  89. "X X X X X X X X X X \n"
  90. "X X X X X X X X X X \n"
  91. " X X X X X X X X X X \n"
  92. " X X X X X X X X X X X X X X X X X X \n"
  93. " X X X X X X X X X X X X \n"
  94. " X X X X X X X X X X X X X X X X \n"
  95. " X X X X X X X X X X X \n"
  96. " X X X X X X X X \n"
  97. " X X X X X X X X X X X X X X X X \n"
  98. " X X X X X X X X X X X X \n"
  99. " X X X \n"
  100. " X X X X X X X X X X \n"
  101. " X X X X X X X X X X \n"
  102. , 'X', true)
  103. );
  104. }
  105. TEST(AZEncoderTest, Encode2)
  106. {
  107. TestEncode(
  108. "Aztec Code is a public domain 2D matrix barcode symbology"
  109. " of nominally square symbols built on a square grid with a "
  110. "distinctive square bullseye pattern at their center.",
  111. false, 6, ParseBitMatrix(
  112. " X X X X X X X X X X X X X X X \n"
  113. " X X X X X X X X X X X X X X X \n"
  114. " X X X X X X X X X X X X X X X X X X X \n"
  115. "X X X X X X X X X X X X X X \n"
  116. "X X X X X X X X X X X X X X X X X X X X X \n"
  117. " X X X X X X X X X X X X X X X X \n"
  118. "X X X X X X X X X X X X X X X X X X X X \n"
  119. " X X X X X X X X X X X X X X X X X X X X X X \n"
  120. "X X X X 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"
  121. " X X X X X X X X X X X X X X X X X X X X \n"
  122. " X X X X X X X X X X X X X X X X X X X X \n"
  123. " X X X X X X X X X X X X X X X X X X X X X X X \n"
  124. "X X X X X X X X X X X X X X X X X X X X X \n"
  125. " X X X X X X X X X X X X X X X \n"
  126. " X X X 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"
  127. " X X X X X X X X X X X \n"
  128. " X 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"
  129. " X X X X X X X X X X X X X X X \n"
  130. "X X 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"
  131. "X X X X X X X X X X X X X X X X X X X X \n"
  132. "X X X X X X X X X X X X X X X X X X X X X \n"
  133. " X X X X X X X X X X X X \n"
  134. " X X X X X X X X X X X X X X X X X X X X X X X \n"
  135. "X X X X X X X X X X X X X X X X X \n"
  136. " X X X 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"
  137. " X X X X X X X X X X X X X X X X \n"
  138. " X X X 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"
  139. " X X X X X X X X X X X X X X X X X \n"
  140. "X X X X X X X X X X X X X X X X X \n"
  141. "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"
  142. " X X X X X X X X X X X X X X X X X X X X \n"
  143. "X X X X X X X X X X X X X X X \n"
  144. " X 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"
  145. " X X X X X X X X X X X X X X X X X \n"
  146. "X X X X X X X X X X X X X X X X X X \n"
  147. "X X X X X X X X X X X X X X X X X X X X X X X \n"
  148. "X X X X X X X X X X X X X X X X X X X X X \n"
  149. "X X X X X X X X X X X X X X X X \n"
  150. "X X X X X X X X X X X X X X X X X X X X X \n"
  151. " X X X X X X X X X X X X X X X X \n"
  152. "X X X X X X X X X X X X X \n"
  153. , 'X', true)
  154. );
  155. }
  156. TEST(AZEncoderTest, UserSpecifiedLayers)
  157. {
  158. std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  159. Aztec::EncodeResult aztec;
  160. aztec = Aztec::Encoder::Encode(alphabet, 25, -2);
  161. EXPECT_EQ(aztec.layers, 2);
  162. EXPECT_TRUE(aztec.compact);
  163. aztec = Aztec::Encoder::Encode(alphabet, 25, 32);
  164. EXPECT_EQ(aztec.layers, 32);
  165. EXPECT_FALSE(aztec.compact);
  166. EXPECT_THROW({Aztec::Encoder::Encode(alphabet, 25, 33);}, std::invalid_argument );
  167. EXPECT_THROW({Aztec::Encoder::Encode(alphabet, 25, -1);}, std::invalid_argument );
  168. }
  169. TEST(AZEncoderTest, BorderCompact4Case)
  170. {
  171. // Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
  172. // be error correction
  173. std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  174. // encodes as 26 * 5 * 4 = 520 bits of data
  175. std::string alphabet4 = alphabet + alphabet + alphabet + alphabet;
  176. EXPECT_THROW({Aztec::Encoder::Encode(alphabet4, 0, -4);}, std::invalid_argument );
  177. // If we just try to encode it normally, it will go to a non-compact 4 layer
  178. auto aztec = Aztec::Encoder::Encode(alphabet4, 0, Aztec::Encoder::DEFAULT_AZTEC_LAYERS);
  179. EXPECT_FALSE(aztec.compact);
  180. EXPECT_EQ(aztec.layers, 4);
  181. // But shortening the string to 100 bytes (500 bits of data), compact works fine, even if we
  182. // include more error checking.
  183. aztec = Aztec::Encoder::Encode(alphabet4.substr(0, 100), 10, Aztec::Encoder::DEFAULT_AZTEC_LAYERS);
  184. EXPECT_TRUE(aztec.compact);
  185. EXPECT_EQ(aztec.layers, 4);
  186. }
  187. TEST(AZEncoderTest, Rune)
  188. {
  189. {
  190. Aztec::EncodeResult aztec = Aztec::Encoder::Encode("\x19", 0, Aztec::Encoder::AZTEC_RUNE_LAYERS);
  191. EXPECT_EQ(aztec.layers, 0);
  192. EXPECT_EQ(aztec.matrix, ParseBitMatrix(
  193. "X X X X X X X \n"
  194. "X X X X X X X X X X X \n"
  195. " X X X \n"
  196. " X X X X X X X X \n"
  197. " X X X X \n"
  198. "X X X X X X X \n"
  199. "X X X X X X \n"
  200. "X X X X X X X X \n"
  201. "X X X X \n"
  202. " X X X X X X X X X X \n"
  203. " X X \n"
  204. ));
  205. }
  206. {
  207. Aztec::EncodeResult aztec = Aztec::Encoder::Encode("\xFF", 0, Aztec::Encoder::AZTEC_RUNE_LAYERS);
  208. EXPECT_EQ(aztec.layers, 0);
  209. EXPECT_EQ(aztec.matrix, ParseBitMatrix(
  210. "X X X X X X \n"
  211. "X X X X X X X X X X X \n"
  212. " X X X \n"
  213. "X X X X X X X X X \n"
  214. "X X X X X X \n"
  215. " X X X X X X \n"
  216. " X X X X \n"
  217. "X X X X X X X X X \n"
  218. "X X X \n"
  219. " X X X X X X X X X X \n"
  220. " X X X X X \n"
  221. ));
  222. }
  223. {
  224. Aztec::EncodeResult aztec = Aztec::Encoder::Encode("\x44", 0, Aztec::Encoder::AZTEC_RUNE_LAYERS);
  225. std::cout << ToString(aztec.matrix, 'X', ' ', true);
  226. }
  227. }