MatrixUtilTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. <?php
  2. declare(strict_types = 1);
  3. namespace BaconQrCodeTest\Encoder;
  4. use BaconQrCode\Common\BitArray;
  5. use BaconQrCode\Common\ErrorCorrectionLevel;
  6. use BaconQrCode\Common\Version;
  7. use BaconQrCode\Encoder\ByteMatrix;
  8. use BaconQrCode\Encoder\MatrixUtil;
  9. use PHPUnit\Framework\TestCase;
  10. use ReflectionClass;
  11. use ReflectionMethod;
  12. class MatrixUtilTest extends TestCase
  13. {
  14. /**
  15. * @var ReflectionMethod[]
  16. */
  17. protected $methods = [];
  18. public function setUp() : void
  19. {
  20. // Hack to be able to test protected methods
  21. $reflection = new ReflectionClass(MatrixUtil::class);
  22. foreach ($reflection->getMethods(ReflectionMethod::IS_STATIC) as $method) {
  23. $method->setAccessible(true);
  24. $this->methods[$method->getName()] = $method;
  25. }
  26. }
  27. public function testToString() : void
  28. {
  29. $matrix = new ByteMatrix(3, 3);
  30. $matrix->set(0, 0, 0);
  31. $matrix->set(1, 0, 1);
  32. $matrix->set(2, 0, 0);
  33. $matrix->set(0, 1, 1);
  34. $matrix->set(1, 1, 0);
  35. $matrix->set(2, 1, 1);
  36. $matrix->set(0, 2, -1);
  37. $matrix->set(1, 2, -1);
  38. $matrix->set(2, 2, -1);
  39. $expected = " 0 1 0\n 1 0 1\n \n";
  40. $this->assertSame($expected, (string) $matrix);
  41. }
  42. public function testClearMatrix() : void
  43. {
  44. $matrix = new ByteMatrix(2, 2);
  45. MatrixUtil::clearMatrix($matrix);
  46. $this->assertSame(-1, $matrix->get(0, 0));
  47. $this->assertSame(-1, $matrix->get(1, 0));
  48. $this->assertSame(-1, $matrix->get(0, 1));
  49. $this->assertSame(-1, $matrix->get(1, 1));
  50. }
  51. public function testEmbedBasicPatterns1() : void
  52. {
  53. $matrix = new ByteMatrix(21, 21);
  54. MatrixUtil::clearMatrix($matrix);
  55. $this->methods['embedBasicPatterns']->invoke(
  56. null,
  57. Version::getVersionForNumber(1),
  58. $matrix
  59. );
  60. $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n"
  61. . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n"
  62. . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
  63. . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
  64. . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
  65. . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n"
  66. . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
  67. . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  68. . " 1 \n"
  69. . " 0 \n"
  70. . " 1 \n"
  71. . " 0 \n"
  72. . " 1 \n"
  73. . " 0 0 0 0 0 0 0 0 1 \n"
  74. . " 1 1 1 1 1 1 1 0 \n"
  75. . " 1 0 0 0 0 0 1 0 \n"
  76. . " 1 0 1 1 1 0 1 0 \n"
  77. . " 1 0 1 1 1 0 1 0 \n"
  78. . " 1 0 1 1 1 0 1 0 \n"
  79. . " 1 0 0 0 0 0 1 0 \n"
  80. . " 1 1 1 1 1 1 1 0 \n";
  81. $this->assertSame($expected, (string) $matrix);
  82. }
  83. public function testEmbedBasicPatterns2() : void
  84. {
  85. $matrix = new ByteMatrix(25, 25);
  86. MatrixUtil::clearMatrix($matrix);
  87. $this->methods['embedBasicPatterns']->invoke(
  88. null,
  89. Version::getVersionForNumber(2),
  90. $matrix
  91. );
  92. $expected = " 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n"
  93. . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n"
  94. . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
  95. . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
  96. . " 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n"
  97. . " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n"
  98. . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
  99. . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  100. . " 1 \n"
  101. . " 0 \n"
  102. . " 1 \n"
  103. . " 0 \n"
  104. . " 1 \n"
  105. . " 0 \n"
  106. . " 1 \n"
  107. . " 0 \n"
  108. . " 1 1 1 1 1 1 \n"
  109. . " 0 0 0 0 0 0 0 0 1 1 0 0 0 1 \n"
  110. . " 1 1 1 1 1 1 1 0 1 0 1 0 1 \n"
  111. . " 1 0 0 0 0 0 1 0 1 0 0 0 1 \n"
  112. . " 1 0 1 1 1 0 1 0 1 1 1 1 1 \n"
  113. . " 1 0 1 1 1 0 1 0 \n"
  114. . " 1 0 1 1 1 0 1 0 \n"
  115. . " 1 0 0 0 0 0 1 0 \n"
  116. . " 1 1 1 1 1 1 1 0 \n";
  117. $this->assertSame($expected, (string) $matrix);
  118. }
  119. public function testEmbedTypeInfo() : void
  120. {
  121. $matrix = new ByteMatrix(21, 21);
  122. MatrixUtil::clearMatrix($matrix);
  123. $this->methods['embedTypeInfo']->invoke(
  124. null,
  125. ErrorCorrectionLevel::M(),
  126. 5,
  127. $matrix
  128. );
  129. $expected = " 0 \n"
  130. . " 1 \n"
  131. . " 1 \n"
  132. . " 1 \n"
  133. . " 0 \n"
  134. . " 0 \n"
  135. . " \n"
  136. . " 1 \n"
  137. . " 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0\n"
  138. . " \n"
  139. . " \n"
  140. . " \n"
  141. . " \n"
  142. . " \n"
  143. . " 0 \n"
  144. . " 0 \n"
  145. . " 0 \n"
  146. . " 0 \n"
  147. . " 0 \n"
  148. . " 0 \n"
  149. . " 1 \n";
  150. $this->assertSame($expected, (string) $matrix);
  151. }
  152. public function testEmbedVersionInfo() : void
  153. {
  154. $matrix = new ByteMatrix(21, 21);
  155. MatrixUtil::clearMatrix($matrix);
  156. $this->methods['maybeEmbedVersionInfo']->invoke(
  157. null,
  158. Version::getVersionForNumber(7),
  159. $matrix
  160. );
  161. $expected = " 0 0 1 \n"
  162. . " 0 1 0 \n"
  163. . " 0 1 0 \n"
  164. . " 0 1 1 \n"
  165. . " 1 1 1 \n"
  166. . " 0 0 0 \n"
  167. . " \n"
  168. . " \n"
  169. . " \n"
  170. . " \n"
  171. . " 0 0 0 0 1 0 \n"
  172. . " 0 1 1 1 1 0 \n"
  173. . " 1 0 0 1 1 0 \n"
  174. . " \n"
  175. . " \n"
  176. . " \n"
  177. . " \n"
  178. . " \n"
  179. . " \n"
  180. . " \n"
  181. . " \n";
  182. $this->assertSame($expected, (string) $matrix);
  183. }
  184. public function testEmbedDataBits() : void
  185. {
  186. $matrix = new ByteMatrix(21, 21);
  187. MatrixUtil::clearMatrix($matrix);
  188. $this->methods['embedBasicPatterns']->invoke(
  189. null,
  190. Version::getVersionForNumber(1),
  191. $matrix
  192. );
  193. $bits = new BitArray();
  194. $this->methods['embedDataBits']->invoke(
  195. null,
  196. $bits,
  197. -1,
  198. $matrix
  199. );
  200. $expected = " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n"
  201. . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n"
  202. . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n"
  203. . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n"
  204. . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n"
  205. . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n"
  206. . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
  207. . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  208. . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  209. . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  210. . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  211. . " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  212. . " 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  213. . " 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n"
  214. . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  215. . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  216. . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  217. . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  218. . " 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  219. . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  220. . " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
  221. $this->assertSame($expected, (string) $matrix);
  222. }
  223. public function testBuildMatrix() : void
  224. {
  225. $bytes = [
  226. 32, 65, 205, 69, 41, 220, 46, 128, 236, 42, 159, 74, 221, 244, 169,
  227. 239, 150, 138, 70, 237, 85, 224, 96, 74, 219 , 61
  228. ];
  229. $bits = new BitArray();
  230. foreach ($bytes as $byte) {
  231. $bits->appendBits($byte, 8);
  232. }
  233. $matrix = new ByteMatrix(21, 21);
  234. MatrixUtil::buildMatrix(
  235. $bits,
  236. ErrorCorrectionLevel::H(),
  237. Version::getVersionForNumber(1),
  238. 3,
  239. $matrix
  240. );
  241. $expected = " 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n"
  242. . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n"
  243. . " 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n"
  244. . " 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n"
  245. . " 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n"
  246. . " 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n"
  247. . " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n"
  248. . " 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n"
  249. . " 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n"
  250. . " 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n"
  251. . " 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n"
  252. . " 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n"
  253. . " 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n"
  254. . " 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n"
  255. . " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n"
  256. . " 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n"
  257. . " 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n"
  258. . " 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n"
  259. . " 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n"
  260. . " 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n"
  261. . " 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n";
  262. $this->assertSame($expected, (string) $matrix);
  263. }
  264. public function testFindMsbSet() : void
  265. {
  266. $this->assertSame(0, $this->methods['findMsbSet']->invoke(null, 0));
  267. $this->assertSame(1, $this->methods['findMsbSet']->invoke(null, 1));
  268. $this->assertSame(8, $this->methods['findMsbSet']->invoke(null, 0x80));
  269. $this->assertSame(32, $this->methods['findMsbSet']->invoke(null, 0x80000000));
  270. }
  271. public function testCalculateBchCode() : void
  272. {
  273. // Encoding of type information.
  274. // From Appendix C in JISX0510:2004 (p 65)
  275. $this->assertSame(0xdc, $this->methods['calculateBchCode']->invoke(null, 5, 0x537));
  276. // From http://www.swetake.com/qr/qr6.html
  277. $this->assertSame(0x1c2, $this->methods['calculateBchCode']->invoke(null, 0x13, 0x537));
  278. // From http://www.swetake.com/qr/qr11.html
  279. $this->assertSame(0x214, $this->methods['calculateBchCode']->invoke(null, 0x1b, 0x537));
  280. // Encoding of version information.
  281. // From Appendix D in JISX0510:2004 (p 68)
  282. $this->assertSame(0xc94, $this->methods['calculateBchCode']->invoke(null, 7, 0x1f25));
  283. $this->assertSame(0x5bc, $this->methods['calculateBchCode']->invoke(null, 8, 0x1f25));
  284. $this->assertSame(0xa99, $this->methods['calculateBchCode']->invoke(null, 9, 0x1f25));
  285. $this->assertSame(0x4d3, $this->methods['calculateBchCode']->invoke(null, 10, 0x1f25));
  286. $this->assertSame(0x9a6, $this->methods['calculateBchCode']->invoke(null, 20, 0x1f25));
  287. $this->assertSame(0xd75, $this->methods['calculateBchCode']->invoke(null, 30, 0x1f25));
  288. $this->assertSame(0xc69, $this->methods['calculateBchCode']->invoke(null, 40, 0x1f25));
  289. }
  290. public function testMakeVersionInfoBits() : void
  291. {
  292. // From Appendix D in JISX0510:2004 (p 68)
  293. $bits = new BitArray();
  294. $this->methods['makeVersionInfoBits']->invoke(null, Version::getVersionForNumber(7), $bits);
  295. $this->assertSame(' ...XXXXX ..X..X.X ..', (string) $bits);
  296. }
  297. public function testMakeTypeInfoBits() : void
  298. {
  299. // From Appendix D in JISX0510:2004 (p 68)
  300. $bits = new BitArray();
  301. $this->methods['makeTypeInfoBits']->invoke(null, ErrorCorrectionLevel::M(), 5, $bits);
  302. $this->assertSame(' X......X X..XXX.', (string) $bits);
  303. }
  304. }