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