Unify handling of EC level between encoder and decoder
[zxing.git] / core / test / src / com / google / zxing / qrcode / encoder / EncoderTestCase.java
1 /*
2  * Copyright 2008 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.qrcode.encoder;
18
19 import com.google.zxing.common.ByteArray;
20 import com.google.zxing.WriterException;
21 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
22 import junit.framework.TestCase;
23
24 /**
25  * @author satorux@google.com (Satoru Takabayashi) - creator
26  * @author mysen@google.com (Chris Mysen) - ported from C++
27  */
28 public final class EncoderTestCase extends TestCase {
29
30   public void testGetAlphanumericCode() throws WriterException {
31     // The first ten code points are numbers.
32     for (int i = 0; i < 10; ++i) {
33       assertEquals(i, Encoder.getAlphanumericCode('0' + i));
34     }
35
36     // The next 26 code points are capital alphabet letters.
37     for (int i = 10; i < 36; ++i) {
38       assertEquals(i, Encoder.getAlphanumericCode('A' + i - 10));
39     }
40
41     // Others are symbol letters
42     assertEquals(36, Encoder.getAlphanumericCode(' '));
43     assertEquals(37, Encoder.getAlphanumericCode('$'));
44     assertEquals(38, Encoder.getAlphanumericCode('%'));
45     assertEquals(39, Encoder.getAlphanumericCode('*'));
46     assertEquals(40, Encoder.getAlphanumericCode('+'));
47     assertEquals(41, Encoder.getAlphanumericCode('-'));
48     assertEquals(42, Encoder.getAlphanumericCode('.'));
49     assertEquals(43, Encoder.getAlphanumericCode('/'));
50     assertEquals(44, Encoder.getAlphanumericCode(':'));
51
52     // Should return -1 for other letters;
53     assertEquals(-1, Encoder.getAlphanumericCode('a'));
54     assertEquals(-1, Encoder.getAlphanumericCode('#'));
55     assertEquals(-1, Encoder.getAlphanumericCode('\0'));
56   }
57
58   public void testChooseMode() throws WriterException {
59     // Numeric mode.
60     assertEquals(QRCode.MODE_NUMERIC, Encoder.chooseMode(new ByteArray("0")));
61     assertEquals(QRCode.MODE_NUMERIC, Encoder.chooseMode(new ByteArray("0123456789")));
62     // Alphanumeric mode.
63     assertEquals(QRCode.MODE_ALPHANUMERIC, Encoder.chooseMode(new ByteArray("A")));
64     assertEquals(QRCode.MODE_ALPHANUMERIC,
65         Encoder.chooseMode(new ByteArray("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")));
66     // 8-bit byte mode.
67     assertEquals(QRCode.MODE_8BIT_BYTE, Encoder.chooseMode(new ByteArray("a")));
68     assertEquals(QRCode.MODE_8BIT_BYTE, Encoder.chooseMode(new ByteArray("#")));
69     assertEquals(QRCode.MODE_8BIT_BYTE, Encoder.chooseMode(new ByteArray("")));
70     // Kanji mode.  We used to use MODE_KANJI for these, but we stopped
71     // doing that as we cannot distinguish Shift_JIS from other encodings
72     // from data bytes alone.  See also comments in qrcode_encoder.h.
73
74     // AIUE in Hiragana in Shift_JIS
75     byte[] dat1 = {0x8,0xa,0x8,0xa,0x8,0xa,0x8,(byte)0xa6};
76     assertEquals(QRCode.MODE_8BIT_BYTE, Encoder.chooseMode(new ByteArray(dat1)));
77
78     // Nihon in Kanji in Shift_JIS.
79     byte[] dat2 = {0x9,0xf,0x9,0x7b};
80     assertEquals(QRCode.MODE_8BIT_BYTE, Encoder.chooseMode(new ByteArray(dat2)));
81
82     // Sou-Utsu-Byou in Kanji in Shift_JIS.
83     byte[] dat3 = {0xe,0x4,0x9,0x5,0x9,0x61};
84     assertEquals(QRCode.MODE_8BIT_BYTE, Encoder.chooseMode(new ByteArray(dat3)));
85   }
86
87   public void testEncode() throws WriterException {
88     QRCode qrCode = new QRCode();
89     Encoder.encode(new ByteArray("ABCDEF"), ErrorCorrectionLevel.H, qrCode);
90     // The following is a valid QR Code that can be read by cell phones.
91     String expected =
92       "<<\n" +
93       " mode: ALPHANUMERIC\n" +
94       " ecLevel: H\n" +
95       " version: 1\n" +
96       " matrixWidth: 21\n" +
97       " maskPattern: 0\n" +
98       " numTotalBytes: 26\n" +
99       " numDataBytes: 9\n" +
100       " numECBytes: 17\n" +
101       " numRSBlocks: 1\n" +
102       " matrix:\n" +
103       " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" +
104       " 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n" +
105       " 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n" +
106       " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n" +
107       " 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n" +
108       " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n" +
109       " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
110       " 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n" +
111       " 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n" +
112       " 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n" +
113       " 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n" +
114       " 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n" +
115       " 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n" +
116       " 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n" +
117       " 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n" +
118       " 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n" +
119       " 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n" +
120       " 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n" +
121       " 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n" +
122       " 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n" +
123       " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n" +
124       ">>\n";
125     assertEquals(expected, qrCode.toString());
126   }
127
128   public void testAppendModeInfo() throws WriterException {
129     BitVector bits = new BitVector();
130     Encoder.appendModeInfo(QRCode.MODE_NUMERIC, bits);
131     assertEquals("0001", bits.toString());
132   }
133
134   public void testAppendLengthInfo() throws WriterException {
135     {
136       BitVector bits = new BitVector();
137       Encoder.appendLengthInfo(1,  // 1 letter (1/1).
138                                                   1,  // version 1.
139                                                   QRCode.MODE_NUMERIC,
140                                                   bits);
141       assertEquals("0000000001", bits.toString());  // 10 bits.
142     }
143     {
144       BitVector bits = new BitVector();
145       Encoder.appendLengthInfo(2,  // 2 letters (2/1).
146                                                   10,  // version 10.
147                                                   QRCode.MODE_ALPHANUMERIC,
148                                                   bits);
149       assertEquals("00000000010", bits.toString());  // 11 bits.
150     }
151     {
152       BitVector bits = new BitVector();
153       Encoder.appendLengthInfo(255,  // 255 letter (255/1).
154                                                   27,  // version 27.
155                                                   QRCode.MODE_8BIT_BYTE,
156                                                   bits);
157       assertEquals("0000000011111111", bits.toString());  // 16 bits.
158     }
159     {
160       BitVector bits = new BitVector();
161       Encoder.appendLengthInfo(1024,  // 512 letters (1024/2).
162                                                   40,  // version 40.
163                                                   QRCode.MODE_KANJI,
164                                                   bits);
165       assertEquals("001000000000", bits.toString());  // 12 bits.
166     }
167   }
168
169   public void testAppendBytes() throws WriterException {
170     {
171       // Should use appendNumericBytes.
172       // 1 = 01 = 0001 in 4 bits.
173       BitVector bits = new BitVector();
174       Encoder.appendBytes(new ByteArray("1"), QRCode.MODE_NUMERIC, bits);
175       assertEquals("0001" , bits.toString());
176       // 'A' cannot be encoded in MODE_NUMERIC.
177       try {
178         Encoder.appendBytes(new ByteArray("A"), QRCode.MODE_NUMERIC, bits);
179         fail("Should have thrown exception");
180       } catch (WriterException we) {
181         // good
182       }
183     }
184     {
185       // Should use appendAlphanumericBytes.
186       // A = 10 = 0xa = 001010 in 6 bits
187       BitVector bits = new BitVector();
188       Encoder.appendBytes(new ByteArray("A"), QRCode.MODE_ALPHANUMERIC, bits);
189       assertEquals("001010" , bits.toString());
190       // Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
191       try {
192         Encoder.appendBytes(new ByteArray("a"), QRCode.MODE_ALPHANUMERIC, bits);
193       } catch (WriterException we) {
194         // good
195       }
196     }
197     {
198       // Should use append8BitBytes.
199       // 0x61, 0x62, 0x63
200       BitVector bits = new BitVector();
201       Encoder.appendBytes(new ByteArray("abc"), QRCode.MODE_8BIT_BYTE, bits);
202       assertEquals("01100001" + "01100010" + "01100011", bits.toString());
203       // Anything can be encoded in QRCode.MODE_8BIT_BYTE.
204       byte[] bytes = {0x00};
205       Encoder.appendBytes(new ByteArray(bytes), QRCode.MODE_8BIT_BYTE, bits);
206     }
207     {
208       // Should use appendKanjiBytes.
209       // 0x93, 0x5f
210       BitVector bits = new BitVector();
211       byte[] bytes = {(byte)0x93,0x5f};
212       Encoder.appendBytes(new ByteArray(bytes), QRCode.MODE_KANJI, bits);
213       assertEquals("0110110011111", bits.toString());
214       // ASCII characters can not be encoded in QRCode.MODE_KANJI.
215
216       try {
217         Encoder.appendBytes(new ByteArray("a"), QRCode.MODE_KANJI, bits);
218       } catch (WriterException we) {
219         // good
220       }
221     }
222   }
223
224   public void testInit() {
225     // TODO: should be implemented.
226   }
227
228   public void testTerminateBits() throws WriterException {
229     {
230       BitVector v = new BitVector();
231       Encoder.terminateBits(0, v);
232       assertEquals("", v.toString());
233     }
234     {
235       BitVector v = new BitVector();
236       Encoder.terminateBits(1, v);
237       assertEquals("00000000", v.toString());
238     }
239     {
240       BitVector v = new BitVector();
241       v.appendBits(0, 3);  // Append 000
242       Encoder.terminateBits(1, v);
243       assertEquals("00000000", v.toString());
244     }
245     {
246       BitVector v = new BitVector();
247       v.appendBits(0, 5);  // Append 00000
248       Encoder.terminateBits(1, v);
249       assertEquals("00000000", v.toString());
250     }
251     {
252       BitVector v = new BitVector();
253       v.appendBits(0, 8);  // Append 00000000
254       Encoder.terminateBits(1, v);
255       assertEquals("00000000", v.toString());
256     }
257     {
258       BitVector v = new BitVector();
259       Encoder.terminateBits(2, v);
260       assertEquals("0000000011101100", v.toString());
261     }
262     {
263       BitVector v = new BitVector();
264       v.appendBits(0, 1);  // Append 0
265       Encoder.terminateBits(3, v);
266       assertEquals("000000001110110000010001", v.toString());
267     }
268   }
269
270   public void testGetNumDataBytesAndNumECBytesForBlockID() throws WriterException {
271     int[] numDataBytes = new int[1];
272     int[] numEcBytes = new int[1];
273     // Version 1-H.
274     Encoder.getNumDataBytesAndNumECBytesForBlockID(26, 9, 1, 0, numDataBytes, numEcBytes);
275     assertEquals(9, numDataBytes[0]);
276     assertEquals(17, numEcBytes[0]);
277
278     // Version 3-H.  2 blocks.
279     Encoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 0, numDataBytes, numEcBytes);
280     assertEquals(13, numDataBytes[0]);
281     assertEquals(22, numEcBytes[0]);
282     Encoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 1, numDataBytes, numEcBytes);
283     assertEquals(13, numDataBytes[0]);
284     assertEquals(22, numEcBytes[0]);
285
286     // Version 7-H. (4 + 1) blocks.
287     Encoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 0, numDataBytes, numEcBytes);
288     assertEquals(13, numDataBytes[0]);
289     assertEquals(26, numEcBytes[0]);
290     Encoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 4, numDataBytes, numEcBytes);
291     assertEquals(14, numDataBytes[0]);
292     assertEquals(26, numEcBytes[0]);
293
294     // Version 40-H. (20 + 61) blocks.
295     Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 0, numDataBytes, numEcBytes);
296     assertEquals(15, numDataBytes[0]);
297     assertEquals(30, numEcBytes[0]);
298     Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 20, numDataBytes, numEcBytes);
299     assertEquals(16, numDataBytes[0]);
300     assertEquals(30, numEcBytes[0]);
301     Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 80, numDataBytes, numEcBytes);
302     assertEquals(16, numDataBytes[0]);
303     assertEquals(30, numEcBytes[0]);
304   }
305
306   public void testInterleaveWithECBytes() throws WriterException {
307     {
308       final byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
309       BitVector in = new BitVector();
310       for (byte dataByte: dataBytes) {
311         in.appendBits(dataByte, 8);
312       }
313       BitVector out = new BitVector();
314       Encoder.interleaveWithECBytes(in, 26, 9, 1, out);
315       final byte[] expected = {
316           // Data bytes.
317           32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236,
318           // Error correction bytes.
319           42, (byte)159, 74, (byte)221, (byte)244, (byte)169, (byte)239, (byte)150, (byte)138, 70,
320           (byte)237, 85, (byte)224, 96, 74, (byte)219, 61,
321       };
322       assertEquals(expected.length, out.sizeInBytes());
323       final byte[] outArray = out.getArray();
324       // Can't use Arrays.equals(), because outArray may be longer than out.sizeInBytes()
325       for (int x = 0; x < expected.length; x++) {
326         assertEquals(expected[x], outArray[x]);
327       }
328     }
329     // Numbers are from http://www.swetake.com/qr/qr8.html
330     {
331       final byte[] dataBytes = {
332           67, 70, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166, (byte)182,
333           (byte)198, (byte)214, (byte)230, (byte)247, 7, 23, 39, 55, 71, 87, 103, 119, (byte)135,
334           (byte)151, (byte)166, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166,
335           (byte)182, (byte)198, (byte)214, (byte)230, (byte)247, 7, 23, 39, 55, 71, 87, 103, 119,
336           (byte)135, (byte)151, (byte)160, (byte)236, 17, (byte)236, 17, (byte)236, 17, (byte)236,
337           17
338       };
339       BitVector in = new BitVector();
340       for (byte dataByte: dataBytes) {
341         in.appendBits(dataByte, 8);
342       }
343       BitVector out = new BitVector();
344       Encoder.interleaveWithECBytes(in, 134, 62, 4, out);
345       final byte[] expected = {
346           // Data bytes.
347           67, (byte)230, 54, 55, 70, (byte)247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39,
348           118, 119, 70, 55, (byte)134, (byte)135, 86, 71, (byte)150, (byte)151, 102, 87, (byte)166,
349           (byte)160, 118, 103, (byte)182, (byte)236, (byte)134, 119, (byte)198, 17, (byte)150,
350           (byte)135, (byte)214, (byte)236, (byte)166, (byte)151, (byte)230, 17, (byte)182,
351           (byte)166, (byte)247, (byte)236, (byte)198, 22, 7, 17, (byte)214, 38, 23, (byte)236, 39,
352           17,
353           // Error correction bytes.
354           (byte)175, (byte)155, (byte)245, (byte)236, 80, (byte)146, 56, 74, (byte)155, (byte)165,
355           (byte)133, (byte)142, 64, (byte)183, (byte)132, 13, (byte)178, 54, (byte)132, 108, 45,
356           113, 53, 50, (byte)214, 98, (byte)193, (byte)152, (byte)233, (byte)147, 50, 71, 65,
357           (byte)190, 82, 51, (byte)209, (byte)199, (byte)171, 54, 12, 112, 57, 113, (byte)155, 117,
358           (byte)211, (byte)164, 117, 30, (byte)158, (byte)225, 31, (byte)190, (byte)242, 38,
359           (byte)140, 61, (byte)179, (byte)154, (byte)214, (byte)138, (byte)147, 87, 27, 96, 77, 47,
360           (byte)187, 49, (byte)156, (byte)214,
361       };
362       assertEquals(expected.length, out.sizeInBytes());
363       final byte[] outArray = out.getArray();
364       for (int x = 0; x < expected.length; x++) {
365         assertEquals(expected[x], outArray[x]);
366       }
367     }
368   }
369
370   public void testAppendNumericBytes() throws WriterException {
371     {
372       // 1 = 01 = 0001 in 4 bits.
373       BitVector bits = new BitVector();
374       Encoder.appendNumericBytes(new ByteArray("1"), bits);
375       assertEquals("0001" , bits.toString());
376     }
377     {
378       // 12 = 0xc = 0001100 in 7 bits.
379       BitVector bits = new BitVector();
380       Encoder.appendNumericBytes(new ByteArray("12"), bits);
381       assertEquals("0001100" , bits.toString());
382     }
383     {
384       // 123 = 0x7b = 0001111011 in 10 bits.
385       BitVector bits = new BitVector();
386       Encoder.appendNumericBytes(new ByteArray("123"), bits);
387       assertEquals("0001111011" , bits.toString());
388     }
389     {
390       // 1234 = "123" + "4" = 0001111011 + 0100
391       BitVector bits = new BitVector();
392       Encoder.appendNumericBytes(new ByteArray("1234"), bits);
393       assertEquals("0001111011" + "0100" , bits.toString());
394     }
395     {
396       // Empty.
397       BitVector bits = new BitVector();
398       Encoder.appendNumericBytes(new ByteArray(""), bits);
399       assertEquals("" , bits.toString());
400     }
401     {
402       // Invalid data.
403       BitVector bits = new BitVector();
404       try {
405         Encoder.appendNumericBytes(new ByteArray("abc"), bits);
406       } catch (WriterException we) {
407         // good
408       }
409     }
410   }
411
412   public void testAppendAlphanumericBytes() throws WriterException {
413     {
414       // A = 10 = 0xa = 001010 in 6 bits
415       BitVector bits = new BitVector();
416       Encoder.appendAlphanumericBytes(new ByteArray("A"), bits);
417       assertEquals("001010" , bits.toString());
418     }
419     {
420       // AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
421       BitVector bits = new BitVector();
422       Encoder.appendAlphanumericBytes(new ByteArray("AB"), bits);
423       assertEquals("00111001101", bits.toString());
424     }
425     {
426       // ABC = "AB" + "C" = 00111001101 + 001100
427       BitVector bits = new BitVector();
428       Encoder.appendAlphanumericBytes(new ByteArray("ABC"), bits);
429       assertEquals("00111001101" + "001100" , bits.toString());
430     }
431     {
432       // Empty.
433       BitVector bits = new BitVector();
434       Encoder.appendAlphanumericBytes(new ByteArray(""), bits);
435       assertEquals("" , bits.toString());
436     }
437     {
438       // Invalid data.
439       BitVector bits = new BitVector();
440       try {
441         Encoder.appendAlphanumericBytes(new ByteArray("abc"), bits);
442       } catch (WriterException we) {
443         // good
444       }
445     }
446   }
447
448   public void testAppend8BitBytes() throws WriterException {
449     {
450       // 0x61, 0x62, 0x63
451       BitVector bits = new BitVector();
452       Encoder.append8BitBytes(new ByteArray("abc"), bits);
453       assertEquals("01100001" + "01100010" + "01100011", bits.toString());
454     }
455     {
456       // Empty.
457       BitVector bits = new BitVector();
458       Encoder.append8BitBytes(new ByteArray(""), bits);
459       assertEquals("", bits.toString());
460     }
461   }
462
463   // Numbers are from page 21 of JISX0510:2004
464   public void testAppendKanjiBytes() throws WriterException {
465     {
466       BitVector bits = new BitVector();
467       byte[] dat1 = {(byte)0x93,0x5f};
468       Encoder.appendKanjiBytes(new ByteArray(dat1), bits);
469       assertEquals("0110110011111", bits.toString());
470       byte[] dat2 = {(byte)0xe4,(byte)0xaa};
471       Encoder.appendKanjiBytes(new ByteArray(dat2), bits);
472       assertEquals("0110110011111" + "1101010101010", bits.toString());
473     }
474   }
475
476   // JAVAPORT: Uncomment and fix up with new Reed Solomon objects
477 //  static boolean ComparePoly(final int[] expected, final int size, final GF_Poly poly) {
478 //    if (size != poly.degree() + 1) {
479 //      return false;
480 //    }
481 //    for (int i = 0; i < size; ++i) {
482 //      // "expected" is ordered in a reverse order.  We reverse the coeff
483 //      // index for comparison.
484 //      final int coeff = GaloisField.GetField(8).Log(
485 //          poly.coeff(size - i - 1));
486 //      if (expected[i] != coeff) {
487 //        Debug.LOG_ERROR("values don't match at " + i + ": " +
488 //            expected[i] + " vs. " + coeff);
489 //        return false;
490 //      }
491 //    }
492 //    return true;
493 //  }
494 //
495 //  // Numbers are from Appendix A of JISX0510 2004 (p.59).
496 //  public void testGetECPoly() {
497 //    {
498 //      final GF_Poly poly = Encoder.GetECPoly(7);
499 //      final int[] expected = {0, 87, 229, 146, 149, 238, 102, 21};
500 //      assertTrue(ComparePoly(expected, expected.length, poly));
501 //    }
502 //    {
503 //      final GF_Poly poly = Encoder.GetECPoly(17);
504 //      final int[] expected = {
505 //          0, 43, 139, 206, 78, 43, 239, 123, 206, 214, 147, 24, 99, 150,
506 //          39, 243, 163, 136
507 //      };
508 //      assertTrue(ComparePoly(expected, expected.length, poly));
509 //    }
510 //    {
511 //      final GF_Poly poly = Encoder.GetECPoly(34);
512 //      final int[] expected = {
513 //          0, 111, 77, 146, 94, 26, 21, 108, 19,
514 //          105, 94, 113, 193, 86, 140, 163, 125,
515 //          58,
516 //          158, 229, 239, 218, 103, 56, 70, 114,
517 //          61, 183, 129, 167, 13, 98, 62, 129, 51
518 //      };
519 //      assertTrue(ComparePoly(expected, expected.length, poly));
520 //    }
521 //    {
522 //      final GF_Poly poly = Encoder.GetECPoly(68);
523 //      final int[] expected = {
524 //          0, 247, 159, 223, 33, 224, 93, 77, 70,
525 //          90, 160, 32, 254, 43, 150, 84, 101,
526 //          190,
527 //          205, 133, 52, 60, 202, 165, 220, 203,
528 //          151, 93, 84, 15, 84, 253, 173, 160,
529 //          89, 227, 52, 199, 97, 95, 231, 52,
530 //          177, 41, 125, 137, 241, 166, 225, 118,
531 //          2, 54,
532 //          32, 82, 215, 175, 198, 43, 238, 235,
533 //          27, 101, 184, 127, 3, 5, 8, 163, 238
534 //      };
535 //      assertTrue(ComparePoly(expected, expected.length, poly));
536 //    }
537 //  }
538
539   // Numbers are from http://www.swetake.com/qr/qr3.html and
540   // http://www.swetake.com/qr/qr9.html
541   public void testGenerateECBytes() {
542     {
543       final byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
544       ByteArray ecBytes = Encoder.generateECBytes(new ByteArray(dataBytes), 17);
545       final int[] expected = {
546           42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61
547       };
548       assertEquals(expected.length, ecBytes.size());
549       for (int x = 0; x < expected.length; x++) {
550         assertEquals(expected[x], ecBytes.at(x));
551       }
552     }
553     {
554       final byte[] dataBytes = {67, 70, 22, 38, 54, 70, 86, 102, 118,
555           (byte)134, (byte)150, (byte)166, (byte)182, (byte)198, (byte)214};
556       ByteArray ecBytes = Encoder.generateECBytes(new ByteArray(dataBytes), 18);
557       final int[] expected = {
558           175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187
559       };
560       assertEquals(expected.length, ecBytes.size());
561       for (int x = 0; x < expected.length; x++) {
562         assertEquals(expected[x], ecBytes.at(x));
563       }
564     }
565     {
566       // High-order zero cofficient case.
567       final byte[] dataBytes = {32, 49, (byte)205, 69, 42, 20, 0, (byte)236, 17};
568       ByteArray ecBytes = Encoder.generateECBytes(new ByteArray(dataBytes), 17);
569       final int[] expected = {
570           0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213
571       };
572       assertEquals(expected.length, ecBytes.size());
573       for (int x = 0; x < expected.length; x++) {
574         assertEquals(expected[x], ecBytes.at(x));
575       }
576     }
577   }
578
579   public void testIsValidKanji() {
580     assertTrue(Encoder.isValidKanji(0x82, 0xa0));  // Hiragana "A".
581     assertTrue(Encoder.isValidKanji(0x93, 0xfa));  // Nichi in Kanji.
582     assertTrue(Encoder.isValidKanji(0x8a, 0xbf));  // Kan in Kanji.
583     assertTrue(Encoder.isValidKanji(0xe7, 0x4e));  // Sou in Kanji.
584     assertTrue(Encoder.isValidKanji(0xea, 0xa2));  // Haruka in Kanji.
585
586     assertFalse(Encoder.isValidKanji('0', '1'));
587     assertFalse(Encoder.isValidKanji(0x82, 0x7f));
588     assertFalse(Encoder.isValidKanji(0xa0, 0xa0));
589   }
590
591   public void testIsValidKanjiSequence() {
592     // AIUEO in Katakana
593     byte[] dat1 = {
594         (byte)0x83, 0x41, (byte)0x83, 0x43, (byte)0x83, 0x45, (byte)0x83, 0x47, (byte)0x83, 0x49
595     };
596     assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat1)));
597     // 012345 in multi-byte letters.
598     byte[] dat2 = {
599         (byte)0x82, 0x4f, (byte)0x82, 0x50, (byte)0x82, 0x51, (byte)0x82, 0x52, (byte)0x82, 0x53,
600         (byte)0x82, 0x54
601     };
602     assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat2)));
603     // Yoroshiku in Kanji.
604     byte[] dat3 = {
605         (byte)0x96, (byte)0xe9, (byte)0x98, 0x49, (byte)0x8e, (byte)0x80, (byte)0x8b, (byte)0xea
606     };
607     assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat3)));
608     assertFalse(Encoder.isValidKanjiSequence(new ByteArray("0123")));
609     assertFalse(Encoder.isValidKanjiSequence(new ByteArray("ABC")));
610   }
611
612   public void testBugInBitVectorNumBytes() throws WriterException {
613     // There was a bug in BitVector.sizeInBytes() that caused it to return a
614     // smaller-by-one value (ex. 1465 instead of 1466) if the number of bits
615     // in the vector is not 8-bit aligned.  In QRCodeEncoder::InitQRCode(),
616     // BitVector::sizeInBytes() is used for finding the smallest QR Code
617     // version that can fit the given data.  Hence there were corner cases
618     // where we chose a wrong QR Code version that cannot fit the given
619     // data.  Note that the issue did not occur with MODE_8BIT_BYTE, as the
620     // bits in the bit vector are always 8-bit aligned.
621     //
622     // Before the bug was fixed, the following test didn't pass, because:
623     //
624     // - MODE_NUMERIC is chosen as all bytes in the data are '0'
625     // - The 3518-byte numeric data needs 1466 bytes
626     //   - 3518 / 3 * 10 + 7 = 11727 bits = 1465.875 bytes
627     //   - 3 numeric bytes are encoded in 10 bits, hence the first
628     //     3516 bytes are encoded in 3516 / 3 * 10 = 11720 bits.
629     //   - 2 numeric bytes can be encoded in 7 bits, hence the last
630     //     2 bytes are encoded in 7 bits.
631     // - The version 27 QR Code with the EC level L has 1468 bytes for data.
632     //   - 1828 - 360 = 1468
633     // - In InitQRCode(), 3 bytes are reserved for a header.  Hence 1465 bytes
634     //   (1468 -3) are left for data.
635     // - Because of the bug in BitVector::sizeInBytes(), InitQRCode() determines
636     //   the given data can fit in 1465 bytes, despite it needs 1466 bytes.
637     // - Hence QRCodeEncoder.encode() failed and returned false.
638     //   - To be precise, it needs 11727 + 4 (getMode info) + 14 (length info) =
639     //     11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468
640     //     bytes).
641     final int arraySize = 3518;
642     byte[] dataBytes = new byte[arraySize];
643     for (int x = 0; x < arraySize; x++) {
644       dataBytes[x] = '0';
645     }
646     QRCode qrCode = new QRCode();
647     Encoder.encode(new ByteArray(dataBytes), ErrorCorrectionLevel.L, qrCode);
648   }
649 }