2 * Copyright 2008 ZXing authors
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.google.zxing.qrcode.encoder;
19 import com.google.zxing.WriterException;
20 import com.google.zxing.common.ByteArray;
21 import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
22 import com.google.zxing.qrcode.decoder.Mode;
23 import junit.framework.TestCase;
26 * @author satorux@google.com (Satoru Takabayashi) - creator
27 * @author mysen@google.com (Chris Mysen) - ported from C++
29 public final class EncoderTestCase extends TestCase {
31 public void testGetAlphanumericCode() throws WriterException {
32 // The first ten code points are numbers.
33 for (int i = 0; i < 10; ++i) {
34 assertEquals(i, Encoder.getAlphanumericCode('0' + i));
37 // The next 26 code points are capital alphabet letters.
38 for (int i = 10; i < 36; ++i) {
39 assertEquals(i, Encoder.getAlphanumericCode('A' + i - 10));
42 // Others are symbol letters
43 assertEquals(36, Encoder.getAlphanumericCode(' '));
44 assertEquals(37, Encoder.getAlphanumericCode('$'));
45 assertEquals(38, Encoder.getAlphanumericCode('%'));
46 assertEquals(39, Encoder.getAlphanumericCode('*'));
47 assertEquals(40, Encoder.getAlphanumericCode('+'));
48 assertEquals(41, Encoder.getAlphanumericCode('-'));
49 assertEquals(42, Encoder.getAlphanumericCode('.'));
50 assertEquals(43, Encoder.getAlphanumericCode('/'));
51 assertEquals(44, Encoder.getAlphanumericCode(':'));
53 // Should return -1 for other letters;
54 assertEquals(-1, Encoder.getAlphanumericCode('a'));
55 assertEquals(-1, Encoder.getAlphanumericCode('#'));
56 assertEquals(-1, Encoder.getAlphanumericCode('\0'));
59 public void testChooseMode() throws WriterException {
61 assertEquals(Mode.NUMERIC, Encoder.chooseMode(new ByteArray("0")));
62 assertEquals(Mode.NUMERIC, Encoder.chooseMode(new ByteArray("0123456789")));
64 assertEquals(Mode.ALPHANUMERIC, Encoder.chooseMode(new ByteArray("A")));
65 assertEquals(Mode.ALPHANUMERIC,
66 Encoder.chooseMode(new ByteArray("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")));
68 assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray("a")));
69 assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray("#")));
70 assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray("")));
71 // Kanji mode. We used to use MODE_KANJI for these, but we stopped
72 // doing that as we cannot distinguish Shift_JIS from other encodings
73 // from data bytes alone. See also comments in qrcode_encoder.h.
75 // AIUE in Hiragana in Shift_JIS
76 byte[] dat1 = {0x8,0xa,0x8,0xa,0x8,0xa,0x8,(byte)0xa6};
77 assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray(dat1)));
79 // Nihon in Kanji in Shift_JIS.
80 byte[] dat2 = {0x9,0xf,0x9,0x7b};
81 assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray(dat2)));
83 // Sou-Utsu-Byou in Kanji in Shift_JIS.
84 byte[] dat3 = {0xe,0x4,0x9,0x5,0x9,0x61};
85 assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray(dat3)));
88 public void testEncode() throws WriterException {
89 QRCode qrCode = new QRCode();
90 Encoder.encode(new ByteArray("ABCDEF"), ErrorCorrectionLevel.H, qrCode);
91 // The following is a valid QR Code that can be read by cell phones.
94 " mode: ALPHANUMERIC\n" +
97 " matrixWidth: 21\n" +
99 " numTotalBytes: 26\n" +
100 " numDataBytes: 9\n" +
101 " numECBytes: 17\n" +
102 " numRSBlocks: 1\n" +
104 " 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" +
105 " 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n" +
106 " 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n" +
107 " 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n" +
108 " 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n" +
109 " 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n" +
110 " 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
111 " 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n" +
112 " 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n" +
113 " 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n" +
114 " 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n" +
115 " 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n" +
116 " 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n" +
117 " 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n" +
118 " 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n" +
119 " 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n" +
120 " 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n" +
121 " 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n" +
122 " 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n" +
123 " 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n" +
124 " 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n" +
126 assertEquals(expected, qrCode.toString());
129 public void testAppendModeInfo() throws WriterException {
130 BitVector bits = new BitVector();
131 Encoder.appendModeInfo(Mode.NUMERIC, bits);
132 assertEquals("0001", bits.toString());
135 public void testAppendLengthInfo() throws WriterException {
137 BitVector bits = new BitVector();
138 Encoder.appendLengthInfo(1, // 1 letter (1/1).
142 assertEquals("0000000001", bits.toString()); // 10 bits.
145 BitVector bits = new BitVector();
146 Encoder.appendLengthInfo(2, // 2 letters (2/1).
150 assertEquals("00000000010", bits.toString()); // 11 bits.
153 BitVector bits = new BitVector();
154 Encoder.appendLengthInfo(255, // 255 letter (255/1).
158 assertEquals("0000000011111111", bits.toString()); // 16 bits.
161 BitVector bits = new BitVector();
162 Encoder.appendLengthInfo(1024, // 512 letters (1024/2).
166 assertEquals("001000000000", bits.toString()); // 12 bits.
170 public void testAppendBytes() throws WriterException {
172 // Should use appendNumericBytes.
173 // 1 = 01 = 0001 in 4 bits.
174 BitVector bits = new BitVector();
175 Encoder.appendBytes(new ByteArray("1"), Mode.NUMERIC, bits);
176 assertEquals("0001" , bits.toString());
177 // 'A' cannot be encoded in MODE_NUMERIC.
179 Encoder.appendBytes(new ByteArray("A"), Mode.NUMERIC, bits);
180 fail("Should have thrown exception");
181 } catch (WriterException we) {
186 // Should use appendAlphanumericBytes.
187 // A = 10 = 0xa = 001010 in 6 bits
188 BitVector bits = new BitVector();
189 Encoder.appendBytes(new ByteArray("A"), Mode.ALPHANUMERIC, bits);
190 assertEquals("001010" , bits.toString());
191 // Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
193 Encoder.appendBytes(new ByteArray("a"), Mode.ALPHANUMERIC, bits);
194 } catch (WriterException we) {
199 // Should use append8BitBytes.
201 BitVector bits = new BitVector();
202 Encoder.appendBytes(new ByteArray("abc"), Mode.BYTE, bits);
203 assertEquals("01100001" + "01100010" + "01100011", bits.toString());
204 // Anything can be encoded in QRCode.MODE_8BIT_BYTE.
205 byte[] bytes = {0x00};
206 Encoder.appendBytes(new ByteArray(bytes), Mode.BYTE, bits);
209 // Should use appendKanjiBytes.
211 BitVector bits = new BitVector();
212 byte[] bytes = {(byte)0x93,0x5f};
213 Encoder.appendBytes(new ByteArray(bytes), Mode.KANJI, bits);
214 assertEquals("0110110011111", bits.toString());
215 // ASCII characters can not be encoded in QRCode.MODE_KANJI.
218 Encoder.appendBytes(new ByteArray("a"), Mode.KANJI, bits);
219 } catch (WriterException we) {
225 public void testInit() {
226 // TODO: should be implemented.
229 public void testTerminateBits() throws WriterException {
231 BitVector v = new BitVector();
232 Encoder.terminateBits(0, v);
233 assertEquals("", v.toString());
236 BitVector v = new BitVector();
237 Encoder.terminateBits(1, v);
238 assertEquals("00000000", v.toString());
241 BitVector v = new BitVector();
242 v.appendBits(0, 3); // Append 000
243 Encoder.terminateBits(1, v);
244 assertEquals("00000000", v.toString());
247 BitVector v = new BitVector();
248 v.appendBits(0, 5); // Append 00000
249 Encoder.terminateBits(1, v);
250 assertEquals("00000000", v.toString());
253 BitVector v = new BitVector();
254 v.appendBits(0, 8); // Append 00000000
255 Encoder.terminateBits(1, v);
256 assertEquals("00000000", v.toString());
259 BitVector v = new BitVector();
260 Encoder.terminateBits(2, v);
261 assertEquals("0000000011101100", v.toString());
264 BitVector v = new BitVector();
265 v.appendBits(0, 1); // Append 0
266 Encoder.terminateBits(3, v);
267 assertEquals("000000001110110000010001", v.toString());
271 public void testGetNumDataBytesAndNumECBytesForBlockID() throws WriterException {
272 int[] numDataBytes = new int[1];
273 int[] numEcBytes = new int[1];
275 Encoder.getNumDataBytesAndNumECBytesForBlockID(26, 9, 1, 0, numDataBytes, numEcBytes);
276 assertEquals(9, numDataBytes[0]);
277 assertEquals(17, numEcBytes[0]);
279 // Version 3-H. 2 blocks.
280 Encoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 0, numDataBytes, numEcBytes);
281 assertEquals(13, numDataBytes[0]);
282 assertEquals(22, numEcBytes[0]);
283 Encoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 1, numDataBytes, numEcBytes);
284 assertEquals(13, numDataBytes[0]);
285 assertEquals(22, numEcBytes[0]);
287 // Version 7-H. (4 + 1) blocks.
288 Encoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 0, numDataBytes, numEcBytes);
289 assertEquals(13, numDataBytes[0]);
290 assertEquals(26, numEcBytes[0]);
291 Encoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 4, numDataBytes, numEcBytes);
292 assertEquals(14, numDataBytes[0]);
293 assertEquals(26, numEcBytes[0]);
295 // Version 40-H. (20 + 61) blocks.
296 Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 0, numDataBytes, numEcBytes);
297 assertEquals(15, numDataBytes[0]);
298 assertEquals(30, numEcBytes[0]);
299 Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 20, numDataBytes, numEcBytes);
300 assertEquals(16, numDataBytes[0]);
301 assertEquals(30, numEcBytes[0]);
302 Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 80, numDataBytes, numEcBytes);
303 assertEquals(16, numDataBytes[0]);
304 assertEquals(30, numEcBytes[0]);
307 public void testInterleaveWithECBytes() throws WriterException {
309 final byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
310 BitVector in = new BitVector();
311 for (byte dataByte: dataBytes) {
312 in.appendBits(dataByte, 8);
314 BitVector out = new BitVector();
315 Encoder.interleaveWithECBytes(in, 26, 9, 1, out);
316 final byte[] expected = {
318 32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236,
319 // Error correction bytes.
320 42, (byte)159, 74, (byte)221, (byte)244, (byte)169, (byte)239, (byte)150, (byte)138, 70,
321 (byte)237, 85, (byte)224, 96, 74, (byte)219, 61,
323 assertEquals(expected.length, out.sizeInBytes());
324 final byte[] outArray = out.getArray();
325 // Can't use Arrays.equals(), because outArray may be longer than out.sizeInBytes()
326 for (int x = 0; x < expected.length; x++) {
327 assertEquals(expected[x], outArray[x]);
330 // Numbers are from http://www.swetake.com/qr/qr8.html
332 final byte[] dataBytes = {
333 67, 70, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166, (byte)182,
334 (byte)198, (byte)214, (byte)230, (byte)247, 7, 23, 39, 55, 71, 87, 103, 119, (byte)135,
335 (byte)151, (byte)166, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166,
336 (byte)182, (byte)198, (byte)214, (byte)230, (byte)247, 7, 23, 39, 55, 71, 87, 103, 119,
337 (byte)135, (byte)151, (byte)160, (byte)236, 17, (byte)236, 17, (byte)236, 17, (byte)236,
340 BitVector in = new BitVector();
341 for (byte dataByte: dataBytes) {
342 in.appendBits(dataByte, 8);
344 BitVector out = new BitVector();
345 Encoder.interleaveWithECBytes(in, 134, 62, 4, out);
346 final byte[] expected = {
348 67, (byte)230, 54, 55, 70, (byte)247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39,
349 118, 119, 70, 55, (byte)134, (byte)135, 86, 71, (byte)150, (byte)151, 102, 87, (byte)166,
350 (byte)160, 118, 103, (byte)182, (byte)236, (byte)134, 119, (byte)198, 17, (byte)150,
351 (byte)135, (byte)214, (byte)236, (byte)166, (byte)151, (byte)230, 17, (byte)182,
352 (byte)166, (byte)247, (byte)236, (byte)198, 22, 7, 17, (byte)214, 38, 23, (byte)236, 39,
354 // Error correction bytes.
355 (byte)175, (byte)155, (byte)245, (byte)236, 80, (byte)146, 56, 74, (byte)155, (byte)165,
356 (byte)133, (byte)142, 64, (byte)183, (byte)132, 13, (byte)178, 54, (byte)132, 108, 45,
357 113, 53, 50, (byte)214, 98, (byte)193, (byte)152, (byte)233, (byte)147, 50, 71, 65,
358 (byte)190, 82, 51, (byte)209, (byte)199, (byte)171, 54, 12, 112, 57, 113, (byte)155, 117,
359 (byte)211, (byte)164, 117, 30, (byte)158, (byte)225, 31, (byte)190, (byte)242, 38,
360 (byte)140, 61, (byte)179, (byte)154, (byte)214, (byte)138, (byte)147, 87, 27, 96, 77, 47,
361 (byte)187, 49, (byte)156, (byte)214,
363 assertEquals(expected.length, out.sizeInBytes());
364 final byte[] outArray = out.getArray();
365 for (int x = 0; x < expected.length; x++) {
366 assertEquals(expected[x], outArray[x]);
371 public void testAppendNumericBytes() throws WriterException {
373 // 1 = 01 = 0001 in 4 bits.
374 BitVector bits = new BitVector();
375 Encoder.appendNumericBytes(new ByteArray("1"), bits);
376 assertEquals("0001" , bits.toString());
379 // 12 = 0xc = 0001100 in 7 bits.
380 BitVector bits = new BitVector();
381 Encoder.appendNumericBytes(new ByteArray("12"), bits);
382 assertEquals("0001100" , bits.toString());
385 // 123 = 0x7b = 0001111011 in 10 bits.
386 BitVector bits = new BitVector();
387 Encoder.appendNumericBytes(new ByteArray("123"), bits);
388 assertEquals("0001111011" , bits.toString());
391 // 1234 = "123" + "4" = 0001111011 + 0100
392 BitVector bits = new BitVector();
393 Encoder.appendNumericBytes(new ByteArray("1234"), bits);
394 assertEquals("0001111011" + "0100" , bits.toString());
398 BitVector bits = new BitVector();
399 Encoder.appendNumericBytes(new ByteArray(""), bits);
400 assertEquals("" , bits.toString());
404 BitVector bits = new BitVector();
406 Encoder.appendNumericBytes(new ByteArray("abc"), bits);
407 } catch (WriterException we) {
413 public void testAppendAlphanumericBytes() throws WriterException {
415 // A = 10 = 0xa = 001010 in 6 bits
416 BitVector bits = new BitVector();
417 Encoder.appendAlphanumericBytes(new ByteArray("A"), bits);
418 assertEquals("001010" , bits.toString());
421 // AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
422 BitVector bits = new BitVector();
423 Encoder.appendAlphanumericBytes(new ByteArray("AB"), bits);
424 assertEquals("00111001101", bits.toString());
427 // ABC = "AB" + "C" = 00111001101 + 001100
428 BitVector bits = new BitVector();
429 Encoder.appendAlphanumericBytes(new ByteArray("ABC"), bits);
430 assertEquals("00111001101" + "001100" , bits.toString());
434 BitVector bits = new BitVector();
435 Encoder.appendAlphanumericBytes(new ByteArray(""), bits);
436 assertEquals("" , bits.toString());
440 BitVector bits = new BitVector();
442 Encoder.appendAlphanumericBytes(new ByteArray("abc"), bits);
443 } catch (WriterException we) {
449 public void testAppend8BitBytes() throws WriterException {
452 BitVector bits = new BitVector();
453 Encoder.append8BitBytes(new ByteArray("abc"), bits);
454 assertEquals("01100001" + "01100010" + "01100011", bits.toString());
458 BitVector bits = new BitVector();
459 Encoder.append8BitBytes(new ByteArray(""), bits);
460 assertEquals("", bits.toString());
464 // Numbers are from page 21 of JISX0510:2004
465 public void testAppendKanjiBytes() throws WriterException {
467 BitVector bits = new BitVector();
468 byte[] dat1 = {(byte)0x93,0x5f};
469 Encoder.appendKanjiBytes(new ByteArray(dat1), bits);
470 assertEquals("0110110011111", bits.toString());
471 byte[] dat2 = {(byte)0xe4,(byte)0xaa};
472 Encoder.appendKanjiBytes(new ByteArray(dat2), bits);
473 assertEquals("0110110011111" + "1101010101010", bits.toString());
477 // JAVAPORT: Uncomment and fix up with new Reed Solomon objects
478 // static boolean ComparePoly(final int[] expected, final int size, final GF_Poly poly) {
479 // if (size != poly.degree() + 1) {
482 // for (int i = 0; i < size; ++i) {
483 // // "expected" is ordered in a reverse order. We reverse the coeff
484 // // index for comparison.
485 // final int coeff = GaloisField.GetField(8).Log(
486 // poly.coeff(size - i - 1));
487 // if (expected[i] != coeff) {
488 // Debug.LOG_ERROR("values don't match at " + i + ": " +
489 // expected[i] + " vs. " + coeff);
496 // // Numbers are from Appendix A of JISX0510 2004 (p.59).
497 // public void testGetECPoly() {
499 // final GF_Poly poly = Encoder.GetECPoly(7);
500 // final int[] expected = {0, 87, 229, 146, 149, 238, 102, 21};
501 // assertTrue(ComparePoly(expected, expected.length, poly));
504 // final GF_Poly poly = Encoder.GetECPoly(17);
505 // final int[] expected = {
506 // 0, 43, 139, 206, 78, 43, 239, 123, 206, 214, 147, 24, 99, 150,
509 // assertTrue(ComparePoly(expected, expected.length, poly));
512 // final GF_Poly poly = Encoder.GetECPoly(34);
513 // final int[] expected = {
514 // 0, 111, 77, 146, 94, 26, 21, 108, 19,
515 // 105, 94, 113, 193, 86, 140, 163, 125,
517 // 158, 229, 239, 218, 103, 56, 70, 114,
518 // 61, 183, 129, 167, 13, 98, 62, 129, 51
520 // assertTrue(ComparePoly(expected, expected.length, poly));
523 // final GF_Poly poly = Encoder.GetECPoly(68);
524 // final int[] expected = {
525 // 0, 247, 159, 223, 33, 224, 93, 77, 70,
526 // 90, 160, 32, 254, 43, 150, 84, 101,
528 // 205, 133, 52, 60, 202, 165, 220, 203,
529 // 151, 93, 84, 15, 84, 253, 173, 160,
530 // 89, 227, 52, 199, 97, 95, 231, 52,
531 // 177, 41, 125, 137, 241, 166, 225, 118,
533 // 32, 82, 215, 175, 198, 43, 238, 235,
534 // 27, 101, 184, 127, 3, 5, 8, 163, 238
536 // assertTrue(ComparePoly(expected, expected.length, poly));
540 // Numbers are from http://www.swetake.com/qr/qr3.html and
541 // http://www.swetake.com/qr/qr9.html
542 public void testGenerateECBytes() {
544 final byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
545 ByteArray ecBytes = Encoder.generateECBytes(new ByteArray(dataBytes), 17);
546 final int[] expected = {
547 42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61
549 assertEquals(expected.length, ecBytes.size());
550 for (int x = 0; x < expected.length; x++) {
551 assertEquals(expected[x], ecBytes.at(x));
555 final byte[] dataBytes = {67, 70, 22, 38, 54, 70, 86, 102, 118,
556 (byte)134, (byte)150, (byte)166, (byte)182, (byte)198, (byte)214};
557 ByteArray ecBytes = Encoder.generateECBytes(new ByteArray(dataBytes), 18);
558 final int[] expected = {
559 175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187
561 assertEquals(expected.length, ecBytes.size());
562 for (int x = 0; x < expected.length; x++) {
563 assertEquals(expected[x], ecBytes.at(x));
567 // High-order zero cofficient case.
568 final byte[] dataBytes = {32, 49, (byte)205, 69, 42, 20, 0, (byte)236, 17};
569 ByteArray ecBytes = Encoder.generateECBytes(new ByteArray(dataBytes), 17);
570 final int[] expected = {
571 0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213
573 assertEquals(expected.length, ecBytes.size());
574 for (int x = 0; x < expected.length; x++) {
575 assertEquals(expected[x], ecBytes.at(x));
580 public void testIsValidKanji() {
581 assertTrue(Encoder.isValidKanji(0x82, 0xa0)); // Hiragana "A".
582 assertTrue(Encoder.isValidKanji(0x93, 0xfa)); // Nichi in Kanji.
583 assertTrue(Encoder.isValidKanji(0x8a, 0xbf)); // Kan in Kanji.
584 assertTrue(Encoder.isValidKanji(0xe7, 0x4e)); // Sou in Kanji.
585 assertTrue(Encoder.isValidKanji(0xea, 0xa2)); // Haruka in Kanji.
587 assertFalse(Encoder.isValidKanji('0', '1'));
588 assertFalse(Encoder.isValidKanji(0x82, 0x7f));
589 assertFalse(Encoder.isValidKanji(0xa0, 0xa0));
592 public void testIsValidKanjiSequence() {
595 (byte)0x83, 0x41, (byte)0x83, 0x43, (byte)0x83, 0x45, (byte)0x83, 0x47, (byte)0x83, 0x49
597 assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat1)));
598 // 012345 in multi-byte letters.
600 (byte)0x82, 0x4f, (byte)0x82, 0x50, (byte)0x82, 0x51, (byte)0x82, 0x52, (byte)0x82, 0x53,
603 assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat2)));
604 // Yoroshiku in Kanji.
606 (byte)0x96, (byte)0xe9, (byte)0x98, 0x49, (byte)0x8e, (byte)0x80, (byte)0x8b, (byte)0xea
608 assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat3)));
609 assertFalse(Encoder.isValidKanjiSequence(new ByteArray("0123")));
610 assertFalse(Encoder.isValidKanjiSequence(new ByteArray("ABC")));
613 public void testBugInBitVectorNumBytes() throws WriterException {
614 // There was a bug in BitVector.sizeInBytes() that caused it to return a
615 // smaller-by-one value (ex. 1465 instead of 1466) if the number of bits
616 // in the vector is not 8-bit aligned. In QRCodeEncoder::InitQRCode(),
617 // BitVector::sizeInBytes() is used for finding the smallest QR Code
618 // version that can fit the given data. Hence there were corner cases
619 // where we chose a wrong QR Code version that cannot fit the given
620 // data. Note that the issue did not occur with MODE_8BIT_BYTE, as the
621 // bits in the bit vector are always 8-bit aligned.
623 // Before the bug was fixed, the following test didn't pass, because:
625 // - MODE_NUMERIC is chosen as all bytes in the data are '0'
626 // - The 3518-byte numeric data needs 1466 bytes
627 // - 3518 / 3 * 10 + 7 = 11727 bits = 1465.875 bytes
628 // - 3 numeric bytes are encoded in 10 bits, hence the first
629 // 3516 bytes are encoded in 3516 / 3 * 10 = 11720 bits.
630 // - 2 numeric bytes can be encoded in 7 bits, hence the last
631 // 2 bytes are encoded in 7 bits.
632 // - The version 27 QR Code with the EC level L has 1468 bytes for data.
633 // - 1828 - 360 = 1468
634 // - In InitQRCode(), 3 bytes are reserved for a header. Hence 1465 bytes
635 // (1468 -3) are left for data.
636 // - Because of the bug in BitVector::sizeInBytes(), InitQRCode() determines
637 // the given data can fit in 1465 bytes, despite it needs 1466 bytes.
638 // - Hence QRCodeEncoder.encode() failed and returned false.
639 // - To be precise, it needs 11727 + 4 (getMode info) + 14 (length info) =
640 // 11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468
642 final int arraySize = 3518;
643 byte[] dataBytes = new byte[arraySize];
644 for (int x = 0; x < arraySize; x++) {
647 QRCode qrCode = new QRCode();
648 Encoder.encode(new ByteArray(dataBytes), ErrorCorrectionLevel.L, qrCode);