AZDecoderTest.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * Copyright 2017 Huy Cuong Nguyen
  3. * Copyright 2014 ZXing authors
  4. */
  5. // SPDX-License-Identifier: Apache-2.0
  6. #include "aztec/AZDecoder.h"
  7. #include "BitArray.h"
  8. #include "BitMatrixIO.h"
  9. #include "DecoderResult.h"
  10. #include "aztec/AZDetectorResult.h"
  11. #include "gtest/gtest.h"
  12. #include <string_view>
  13. #include <utility>
  14. namespace ZXing::Aztec {
  15. DecoderResult Decode(const BitArray& bits);
  16. }
  17. using namespace ZXing;
  18. // Shorthand to call Decode()
  19. static DecoderResult parse(BitMatrix&& bits, bool compact, int nbDatablocks, int nbLayers)
  20. {
  21. return Aztec::Decode({{std::move(bits), {}}, compact, nbDatablocks, nbLayers, false /*readerInit*/, false /*isMirrored*/, 0 /*runeValue*/});
  22. }
  23. TEST(AZDecoderTest, AztecResult)
  24. {
  25. auto bits = ParseBitMatrix(
  26. "X X X X X X X X X X X X X X \n"
  27. "X X X X X X X X X X X X X X X \n"
  28. " X X X X X X X X X X X X \n"
  29. " X X X X X X X X X X \n"
  30. " X X X X X X X X \n"
  31. " X X X X X X X X X X X X X X X X X X \n"
  32. " X X X X X X X X X \n"
  33. " X X X X X X X X X X X X X X X X X \n"
  34. " X X X X X X X X X \n"
  35. " X X X X X X X X X X X X X X X X \n"
  36. " X X X X X X X X X X X X \n"
  37. " X X X X X X X X X X X \n"
  38. " X X X X X X X X X X X X \n"
  39. " X X X X X X X X X X X X X X X X X \n"
  40. "X X X X X X X X X X X \n"
  41. " X X X X X X X X X X X X X X \n"
  42. " X X X X X X X X \n"
  43. " X X X X X X X X X X X X X X X X X X X \n"
  44. "X X X X X X X X X \n"
  45. "X X X X X X X X X X X X X X X \n"
  46. "X X X X X X X X X X X X \n"
  47. "X X X X X X X X X X X X X X \n"
  48. " X X X X X X X X X X X X X \n"
  49. , 'X', true);
  50. DecoderResult result = parse(std::move(bits), false, 30, 2);
  51. EXPECT_EQ(result.isValid(), true);
  52. EXPECT_EQ(result.text(), L"88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT");
  53. EXPECT_EQ(result.symbologyIdentifier(), "]z0");
  54. }
  55. TEST(AZDecoderTest, DecodeTooManyErrors)
  56. {
  57. auto bits = ParseBitMatrix(
  58. "X X . X . . . X X . . . X . . X X X . X . X X X X X . \n"
  59. "X X . . X X . . . . . X X . . . X X . . . X . X . . X \n"
  60. "X . . . X X . . X X X . X X . X X X X . X X . . X . . \n"
  61. ". . . . X . X X . . X X . X X . X . X X X X . X . . X \n"
  62. "X X X . . X X X X X . . . . . X X . . . X . X . X . X \n"
  63. "X X . . . . . . . . X . . . X . X X X . X . . X . . . \n"
  64. "X X . . X . . . . . X X . . . . . X . . . . X . . X X \n"
  65. ". . . X . X . X . . . . . X X X X X X . . . . . . X X \n"
  66. "X . . . X . X X X X X X . . X X X . X . X X X X X X . \n"
  67. "X . . X X X . X X X X X X X X X X X X X . . . X . X X \n"
  68. ". . . . X X . . . X . . . . . . . X X . . . X X . X . \n"
  69. ". . . X X X . . X X . X X X X X . X . . X . . . . . . \n"
  70. "X . . . . X . X . X . X . . . X . X . X X . X X . X X \n"
  71. "X . X . . X . X . X . X . X . X . X . . . . . X . X X \n"
  72. "X . X X X . . X . X . X . . . X . X . X X X . . . X X \n"
  73. "X X X X X X X X . X . X X X X X . X . X . X . X X X . \n"
  74. ". . . . . . . X . X . . . . . . . X X X X . . . X X X \n"
  75. "X X . . X . . X . X X X X X X X X X X X X X . . X . X \n"
  76. "X X X . X X X X . . X X X X . . X . . . . X . . X X X \n"
  77. ". . . . X . X X X . . . . X X X X . . X X X X . . . . \n"
  78. ". . X . . X . X . . . X . X X . X X . X . . . X . X . \n"
  79. "X X . . X . . X X X X X X X . . X . X X X X X X X . . \n"
  80. "X . 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 X . X X X X . . X X . \n"
  83. "X X X X . . . X . . X X X . X X . . X . . . . X X X . \n"
  84. "X X . X . X . . . X . X . . . . X X . X . . X X . . . \n"
  85. , 'X', true);
  86. DecoderResult result = parse(std::move(bits), true, 16, 4);
  87. EXPECT_EQ(result.error(), Error::Checksum);
  88. }
  89. TEST(AZDecoderTest, DecodeTooManyErrors2)
  90. {
  91. auto bits = ParseBitMatrix(
  92. ". 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 . X . X X \n"
  94. ". . . . 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 . . . . . X . \n"
  96. "X X . X . . X . X X . . . . . X X . . . . . X . . . X \n"
  97. "X . . X . . . . . . X . . . X . X X X X X X X . . . X \n"
  98. "X . . X X . . X . . X X . . . . . X . . . . . X X X . \n"
  99. ". . X X X X . X . . . . . X X X X X X . . . . . . X X \n"
  100. "X . . . X . X X X X X X . . X X X . X . X X X X X X . \n"
  101. "X . . X X X . X X X X X X X X X X X X X . . . X . X X \n"
  102. ". . . . X X . . . X . . . . . . . X X . . . X X . X . \n"
  103. ". . . X X X . . X X . X X X X X . X . . X . . . . . . \n"
  104. "X . . . . X . X . X . X . . . X . X . X X . X X . X X \n"
  105. "X . X . . X . X . X . X . X . X . X . . . . . X . X X \n"
  106. "X . X X X . . X . X . X . . . X . X . X X X . . . X X \n"
  107. "X X X X X X X X . X . X X X X X . X . X . X . X X X . \n"
  108. ". . . . . . . X . X . . . . . . . X X X X . . . X X X \n"
  109. "X X . . X . . X . X X X X X X X X X X X X X . . X . X \n"
  110. "X X X . X X X X . . X X X X . . X . . . . X . . X X X \n"
  111. ". . X X X X X . X . . . . X X X X . . X X X . X . X . \n"
  112. ". . 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 . X . . \n"
  114. ". 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 . \n"
  116. "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 . \n"
  118. "X X . . . X X . . X . X . . . . X X . X . . X . X . X \n"
  119. , 'X', true);
  120. DecoderResult result = parse(std::move(bits), true, 16, 4);
  121. EXPECT_EQ(result.error(), Error::Checksum);
  122. }
  123. // Helper taking bit string to call GetEncodedData()
  124. static DecoderResult getData(std::string_view bitStr)
  125. {
  126. BitArray bits;
  127. for (auto b : bitStr)
  128. bits.appendBit(b == '1');
  129. return Aztec::Decode(bits);
  130. }
  131. TEST(AZDecoderTest, SymbologyIdentifier)
  132. {
  133. {
  134. // Plain
  135. auto data = getData("00010");
  136. EXPECT_EQ(data.symbologyIdentifier(), "]z0");
  137. EXPECT_EQ(data.text(), L"A");
  138. }
  139. {
  140. // GS1 ("PS FLGN(0) DL (20)01")
  141. auto data = getData("0000000000000111100100001000100011");
  142. EXPECT_EQ(data.symbologyIdentifier(), "]z1");
  143. EXPECT_EQ(data.text(), L"2001");
  144. }
  145. {
  146. // AIM ("A PS FLGN(0) B")
  147. auto data = getData("00010000000000000000011");
  148. EXPECT_EQ(data.symbologyIdentifier(), "]z2");
  149. EXPECT_EQ(data.text(), L"AB");
  150. }
  151. {
  152. // AIM ("DL 99 UL PS FLGN(0) B")
  153. auto data = getData("11110101110111110000000000000000011");
  154. EXPECT_EQ(data.symbologyIdentifier(), "]z2");
  155. EXPECT_EQ(data.text(), L"99B");
  156. }
  157. {
  158. // Structured Append ("UL ML A D A")
  159. auto data = getData("1110111101000100010100010");
  160. EXPECT_EQ(data.symbologyIdentifier(), "]z6");
  161. EXPECT_EQ(data.text(), L"A");
  162. EXPECT_EQ(data.structuredAppend().index, 0);
  163. EXPECT_EQ(data.structuredAppend().count, 4);
  164. }
  165. {
  166. // Structured Append with GS1 ("UL ML A D PS FLGN(0) DL (20)01")
  167. auto data = getData("111011110100010001010000000000000111100100001000100011");
  168. EXPECT_EQ(data.symbologyIdentifier(), "]z7");
  169. EXPECT_EQ(data.text(), L"2001");
  170. EXPECT_EQ(data.structuredAppend().index, 0);
  171. EXPECT_EQ(data.structuredAppend().count, 4);
  172. }
  173. {
  174. // Structured Append with AIM ("UL ML A D A PS FLGN(0) B")
  175. auto data = getData("1110111101000100010100010000000000000000011");
  176. EXPECT_EQ(data.symbologyIdentifier(), "]z8");
  177. EXPECT_EQ(data.text(), L"AB");
  178. EXPECT_EQ(data.structuredAppend().index, 0);
  179. EXPECT_EQ(data.structuredAppend().count, 4);
  180. }
  181. {
  182. // Plain with FNC1 not in first/second position ("A B PS FLGN(0) C")
  183. auto data = getData("0001000011000000000000000100");
  184. EXPECT_EQ(data.symbologyIdentifier(), "]z0");
  185. EXPECT_EQ(data.text(), L"AB\u001DC"); // "AB<GS>C"
  186. }
  187. {
  188. // Plain with FNC1 not in first/second position ("A B C PS FLGN(0) D")
  189. auto data = getData("000100001100100000000000000000101");
  190. EXPECT_EQ(data.symbologyIdentifier(), "]z0");
  191. EXPECT_EQ(data.text(), L"ABC\u001DD"); // "ABC<GS>D"
  192. }
  193. {
  194. // Plain with FNC1 not in first/second position ("DL 1 UL PS FLGN(0) A")
  195. auto data = getData("1111000111110000000000000000010");
  196. EXPECT_EQ(data.symbologyIdentifier(), "]z0");
  197. EXPECT_EQ(data.text(), L"1\u001DA"); // "1<GS>D"
  198. }
  199. }
  200. // Helper taking 5-bit word array to call GetEncodedData()
  201. static DecoderResult getData(const ByteArray& bytes)
  202. {
  203. BitArray bits; // 5-bit words (assuming no digits/binary)
  204. for (auto b : bytes)
  205. bits.appendBits(b, 5);
  206. return Aztec::Decode(bits);
  207. }
  208. // Shorthand to return Structured Append given 5-bit word array
  209. static StructuredAppendInfo sai(const ByteArray& bytes)
  210. {
  211. return getData(bytes).structuredAppend();
  212. }
  213. // Shorthand to return string result given 5-bit word array
  214. static std::wstring text(const ByteArray& bytes)
  215. {
  216. return getData(bytes).text();
  217. }
  218. TEST(AZDecoderTest, StructuredAppend)
  219. {
  220. // Null
  221. EXPECT_EQ(sai({2}).index, -1);
  222. EXPECT_EQ(sai({2}).count, -1);
  223. EXPECT_TRUE(sai({2}).id.empty());
  224. EXPECT_EQ(text({2}), L"A");
  225. // Example from ISO/IEC 24778:2008 Section 8
  226. EXPECT_EQ(sai({29, 29, 2, 5, 2}).index, 0); // AD
  227. EXPECT_EQ(sai({29, 29, 2, 5, 2}).count, 4);
  228. EXPECT_TRUE(sai({29, 29, 2, 5, 2}).id.empty());
  229. EXPECT_EQ(text({29, 29, 2, 5, 2}), L"A");
  230. EXPECT_EQ(sai({29, 29, 3, 5, 2}).index, 1); // BD
  231. EXPECT_EQ(sai({29, 29, 3, 5, 2}).count, 4);
  232. EXPECT_TRUE(sai({29, 29, 3, 5, 2}).id.empty());
  233. EXPECT_EQ(text({29, 29, 3, 5, 2}), L"A");
  234. EXPECT_EQ(sai({29, 29, 4, 5, 2}).index, 2); // CD
  235. EXPECT_EQ(sai({29, 29, 4, 5, 2}).count, 4);
  236. EXPECT_TRUE(sai({29, 29, 4, 5, 2}).id.empty());
  237. EXPECT_EQ(text({29, 29, 4, 5, 2}), L"A");
  238. EXPECT_EQ(sai({29, 29, 5, 5, 2}).index, 3); // DD
  239. EXPECT_EQ(sai({29, 29, 5, 5, 2}).count, 4);
  240. EXPECT_TRUE(sai({29, 29, 5, 5, 2}).id.empty());
  241. EXPECT_EQ(text({29, 29, 5, 5, 2}), L"A");
  242. // Sequencing field
  243. EXPECT_EQ(sai({29, 29, 2, 27, 2}).index, 0); // AZ
  244. EXPECT_EQ(sai({29, 29, 2, 27, 2}).count, 26);
  245. EXPECT_EQ(sai({29, 29, 14, 27, 2}).index, 12); // MZ
  246. EXPECT_EQ(sai({29, 29, 14, 27, 2}).count, 26);
  247. EXPECT_EQ(sai({29, 29, 27, 27, 2}).index, 25); // ZZ
  248. EXPECT_EQ(sai({29, 29, 27, 27, 2}).count, 26);
  249. // Id
  250. EXPECT_EQ(sai({29, 29, 1, 10, 5, 1, 2, 5, 2}).id, "ID");
  251. EXPECT_EQ(text({29, 29, 1, 10, 5, 1, 2, 5, 2}), L"A");
  252. // Invalid sequencing
  253. EXPECT_EQ(sai({29, 29, 2, 2, 2}).index, 0); // AA
  254. EXPECT_EQ(sai({29, 29, 2, 2, 2}).count, 0); // Count 1 so set to 0
  255. EXPECT_EQ(text({29, 29, 2, 2, 2}), L"A");
  256. EXPECT_EQ(sai({29, 29, 6, 5, 2}).index, 4); // ED
  257. EXPECT_EQ(sai({29, 29, 6, 5, 2}).count, 0); // Count 4 <= index 4 so set to 0
  258. EXPECT_EQ(text({29, 29, 6, 5, 2}), L"A");
  259. EXPECT_EQ(sai({29, 29, 1, 5, 2}).index, -1); // Index < 'A'
  260. EXPECT_EQ(sai({29, 29, 1, 5, 2}).count, -1);
  261. EXPECT_EQ(text({29, 29, 1, 5, 2}), L" DA"); // Bad sequencing left in result
  262. EXPECT_EQ(sai({29, 29, 28, 5, 2}).index, -1); // Index > 'Z' (LL)
  263. EXPECT_EQ(sai({29, 29, 28, 5, 2}).count, -1);
  264. EXPECT_EQ(text({29, 29, 28, 5, 2}), L"da");
  265. EXPECT_EQ(sai({29, 29, 2, 1, 2}).index, -1); // Count < 'A'
  266. EXPECT_EQ(sai({29, 29, 2, 1, 2}).count, -1);
  267. EXPECT_EQ(text({29, 29, 2, 1, 2}), L"A A");
  268. EXPECT_EQ(sai({29, 29, 2, 28, 2}).index, -1); // Count > 'Z'
  269. EXPECT_EQ(sai({29, 29, 2, 28, 2}).count, -1);
  270. EXPECT_EQ(text({29, 29, 2, 28, 2}), L"Aa");
  271. EXPECT_EQ(sai({29, 29, 2, 5}).index, -1); // Sequencing but no data
  272. EXPECT_EQ(sai({29, 29, 2, 5}).count, -1);
  273. EXPECT_EQ(text({29, 29, 2, 5}), L"AD");
  274. // Invalid Ids
  275. {
  276. auto data = getData({29, 29, 1, 10, 5, 2, 5, 2}); // No terminating space
  277. EXPECT_TRUE(data.structuredAppend().id.empty());
  278. EXPECT_EQ(data.structuredAppend().index, -1); // Not recognized as sequence
  279. EXPECT_EQ(data.structuredAppend().count, -1);
  280. EXPECT_EQ(data.text(), L" IDADA"); // Bad ID and sequencing left in result
  281. }
  282. {
  283. auto data = getData({29, 29, 1, 1, 2, 5, 2}); // Blank
  284. EXPECT_TRUE(data.structuredAppend().id.empty());
  285. EXPECT_EQ(data.structuredAppend().index, 0); // Recognized as sequence
  286. EXPECT_EQ(data.structuredAppend().count, 4);
  287. EXPECT_EQ(data.text(), L"A");
  288. }
  289. {
  290. auto data = getData({29, 29, 1, 10, 1, 5, 1, 2, 5, 2}); // Space in "I D"
  291. EXPECT_TRUE(data.structuredAppend().id.empty());
  292. EXPECT_EQ(data.structuredAppend().index, -1); // Not recognized as sequence as sequence count invalid (space)
  293. EXPECT_EQ(data.structuredAppend().count, -1);
  294. EXPECT_EQ(data.text(), L" I D ADA"); // Bad ID and sequencing left in result
  295. }
  296. {
  297. auto data = getData({29, 29, 1, 10, 1, 2, 5, 1, 2, 5, 2}); // "I AD" (happens to have valid sequencing at end)
  298. EXPECT_EQ(data.structuredAppend().id, "I");
  299. EXPECT_EQ(data.structuredAppend().index, 0);
  300. EXPECT_EQ(data.structuredAppend().count, 4);
  301. EXPECT_EQ(data.text(), L" ADA"); // Trailing space and "real" sequencing left in result
  302. }
  303. }