housekeeping for tests for qrcode and aztec

This commit is contained in:
Henry Schimke
2022-09-30 15:57:01 -05:00
parent 438ae9f588
commit 5436b8d9f3
14 changed files with 1 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.Writer;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.junit.Assert;
import org.junit.Test;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.EnumMap;
import java.util.Map;
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author dswitkin@google.com (Daniel Switkin) - ported and expanded from C++
*/
public final class QRCodeWriterTestCase extends Assert {
private static final Path BASE_IMAGE_PATH = Paths.get("src/test/resources/golden/qrcode/");
private static BufferedImage loadImage(String fileName) throws IOException {
Path file = BASE_IMAGE_PATH.resolve(fileName);
if (!Files.exists(file)) {
// try starting with 'core' since the test base is often given as the project root
file = Paths.get("core/").resolve(BASE_IMAGE_PATH).resolve(fileName);
}
assertTrue("Please download and install test images, and run from the 'core' directory", Files.exists(file));
return ImageIO.read(file.toFile());
}
// In case the golden images are not monochromatic, convert the RGB values to greyscale.
private static BitMatrix createMatrixFromImage(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
int[] pixels = new int[width * height];
image.getRGB(0, 0, width, height, pixels, 0, width);
BitMatrix matrix = new BitMatrix(width, height);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = pixels[y * width + x];
int luminance = (306 * ((pixel >> 16) & 0xFF) +
601 * ((pixel >> 8) & 0xFF) +
117 * (pixel & 0xFF)) >> 10;
if (luminance <= 0x7F) {
matrix.set(x, y);
}
}
}
return matrix;
}
@Test
public void testQRCodeWriter() throws WriterException {
// The QR should be multiplied up to fit, with extra padding if necessary
int bigEnough = 256;
Writer writer = new QRCodeWriter();
BitMatrix matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, bigEnough,
bigEnough, null);
assertNotNull(matrix);
assertEquals(bigEnough, matrix.getWidth());
assertEquals(bigEnough, matrix.getHeight());
// The QR will not fit in this size, so the matrix should come back bigger
int tooSmall = 20;
matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, tooSmall,
tooSmall, null);
assertNotNull(matrix);
assertTrue(tooSmall < matrix.getWidth());
assertTrue(tooSmall < matrix.getHeight());
// We should also be able to handle non-square requests by padding them
int strangeWidth = 500;
int strangeHeight = 100;
matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, strangeWidth,
strangeHeight, null);
assertNotNull(matrix);
assertEquals(strangeWidth, matrix.getWidth());
assertEquals(strangeHeight, matrix.getHeight());
}
private static void compareToGoldenFile(String contents,
ErrorCorrectionLevel ecLevel,
int resolution,
String fileName) throws WriterException, IOException {
BufferedImage image = loadImage(fileName);
assertNotNull(image);
BitMatrix goldenRXingResult = createMatrixFromImage(image);
assertNotNull(goldenRXingResult);
Map<EncodeHintType,Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.ERROR_CORRECTION, ecLevel);
Writer writer = new QRCodeWriter();
BitMatrix generatedRXingResult = writer.encode(contents, BarcodeFormat.QR_CODE, resolution,
resolution, hints);
assertEquals(resolution, generatedRXingResult.getWidth());
assertEquals(resolution, generatedRXingResult.getHeight());
assertEquals(goldenRXingResult, generatedRXingResult);
}
// Golden images are generated with "qrcode_sample.cc". The images are checked with both eye balls
// and cell phones. We expect pixel-perfect results, because the error correction level is known,
// and the pixel dimensions matches exactly.
@Test
public void testRegressionTest() throws Exception {
compareToGoldenFile("http://www.google.com/", ErrorCorrectionLevel.M, 99,
"renderer-test-01.png");
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.decoder;
import com.google.zxing.common.BitMatrix;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Sean Owen
*/
public final class DataMaskTestCase extends Assert {
@Test
public void testMask0() {
testMaskAcrossDimensions(0, (i, j) -> (i + j) % 2 == 0);
}
@Test
public void testMask1() {
testMaskAcrossDimensions(1, (i, j) -> i % 2 == 0);
}
@Test
public void testMask2() {
testMaskAcrossDimensions(2, (i, j) -> j % 3 == 0);
}
@Test
public void testMask3() {
testMaskAcrossDimensions(3, (i, j) -> (i + j) % 3 == 0);
}
@Test
public void testMask4() {
testMaskAcrossDimensions(4, (i, j) -> (i / 2 + j / 3) % 2 == 0);
}
@Test
public void testMask5() {
testMaskAcrossDimensions(5, (i, j) -> (i * j) % 2 + (i * j) % 3 == 0);
}
@Test
public void testMask6() {
testMaskAcrossDimensions(6, (i, j) -> ((i * j) % 2 + (i * j) % 3) % 2 == 0);
}
@Test
public void testMask7() {
testMaskAcrossDimensions(7, (i, j) -> ((i + j) % 2 + (i * j) % 3) % 2 == 0);
}
private static void testMaskAcrossDimensions(int reference, MaskCondition condition) {
DataMask mask = DataMask.values()[reference];
for (int version = 1; version <= 40; version++) {
int dimension = 17 + 4 * version;
testMask(mask, dimension, condition);
}
}
private static void testMask(DataMask mask, int dimension, MaskCondition condition) {
BitMatrix bits = new BitMatrix(dimension);
mask.unmaskBitMatrix(bits, dimension);
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
assertEquals(
"(" + i + ',' + j + ')',
condition.isMasked(i, j),
bits.get(j, i));
}
}
}
@FunctionalInterface
private interface MaskCondition {
boolean isMasked(int i, int j);
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.decoder;
import com.google.zxing.common.BitSourceBuilder;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests {@link DecodedBitStreamParser}.
*
* @author Sean Owen
*/
public final class DecodedBitStreamParserTestCase extends Assert {
@Test
public void testSimpleByteMode() throws Exception {
BitSourceBuilder builder = new BitSourceBuilder();
builder.write(0x04, 4); // Byte mode
builder.write(0x03, 8); // 3 bytes
builder.write(0xF1, 8);
builder.write(0xF2, 8);
builder.write(0xF3, 8);
String result = DecodedBitStreamParser.decode(builder.toByteArray(),
Version.getVersionForNumber(1), null, null).getText();
assertEquals("\u00f1\u00f2\u00f3", result);
}
@Test
public void testSimpleSJIS() throws Exception {
BitSourceBuilder builder = new BitSourceBuilder();
builder.write(0x04, 4); // Byte mode
builder.write(0x04, 8); // 4 bytes
builder.write(0xA1, 8);
builder.write(0xA2, 8);
builder.write(0xA3, 8);
builder.write(0xD0, 8);
String result = DecodedBitStreamParser.decode(builder.toByteArray(),
Version.getVersionForNumber(1), null, null).getText();
assertEquals("\uff61\uff62\uff63\uff90", result);
}
@Test
public void testECI() throws Exception {
BitSourceBuilder builder = new BitSourceBuilder();
builder.write(0x07, 4); // ECI mode
builder.write(0x02, 8); // ECI 2 = CP437 encoding
builder.write(0x04, 4); // Byte mode
builder.write(0x03, 8); // 3 bytes
builder.write(0xA1, 8);
builder.write(0xA2, 8);
builder.write(0xA3, 8);
String result = DecodedBitStreamParser.decode(builder.toByteArray(),
Version.getVersionForNumber(1), null, null).getText();
assertEquals("\u00ed\u00f3\u00fa", result);
}
@Test
public void testHanzi() throws Exception {
BitSourceBuilder builder = new BitSourceBuilder();
builder.write(0x0D, 4); // Hanzi mode
builder.write(0x01, 4); // Subset 1 = GB2312 encoding
builder.write(0x01, 8); // 1 characters
builder.write(0x03C1, 13);
String result = DecodedBitStreamParser.decode(builder.toByteArray(),
Version.getVersionForNumber(1), null, null).getText();
assertEquals("\u963f", result);
}
@Test
public void testHanziLevel1() throws Exception {
BitSourceBuilder builder = new BitSourceBuilder();
builder.write(0x0D, 4); // Hanzi mode
builder.write(0x01, 4); // Subset 1 = GB2312 encoding
builder.write(0x01, 8); // 1 characters
// A5A2 (U+30A2) => A5A2 - A1A1 = 401, 4*60 + 01 = 0181
builder.write(0x0181, 13);
String result = DecodedBitStreamParser.decode(builder.toByteArray(),
Version.getVersionForNumber(1), null, null).getText();
assertEquals("\u30a2", result);
}
// TODO definitely need more tests here
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.decoder;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Sean Owen
*/
public final class ErrorCorrectionLevelTestCase extends Assert {
@Test
public void testForBits() {
assertSame(ErrorCorrectionLevel.M, ErrorCorrectionLevel.forBits(0));
assertSame(ErrorCorrectionLevel.L, ErrorCorrectionLevel.forBits(1));
assertSame(ErrorCorrectionLevel.H, ErrorCorrectionLevel.forBits(2));
assertSame(ErrorCorrectionLevel.Q, ErrorCorrectionLevel.forBits(3));
}
@Test(expected = IllegalArgumentException.class)
public void testBadECLevel() {
ErrorCorrectionLevel.forBits(4);
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.decoder;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Sean Owen
*/
public final class FormatInformationTestCase extends Assert {
private static final int MASKED_TEST_FORMAT_INFO = 0x2BED;
private static final int UNMASKED_TEST_FORMAT_INFO = MASKED_TEST_FORMAT_INFO ^ 0x5412;
@Test
public void testBitsDiffering() {
assertEquals(0, FormatInformation.numBitsDiffering(1, 1));
assertEquals(1, FormatInformation.numBitsDiffering(0, 2));
assertEquals(2, FormatInformation.numBitsDiffering(1, 2));
assertEquals(32, FormatInformation.numBitsDiffering(-1, 0));
}
@Test
public void testDecode() {
// Normal case
FormatInformation expected =
FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
assertNotNull(expected);
assertEquals((byte) 0x07, expected.getDataMask());
assertSame(ErrorCorrectionLevel.Q, expected.getErrorCorrectionLevel());
// where the code forgot the mask!
assertEquals(expected,
FormatInformation.decodeFormatInformation(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO));
}
@Test
public void testDecodeWithBitDifference() {
FormatInformation expected =
FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
// 1,2,3,4 bits difference
assertEquals(expected, FormatInformation.decodeFormatInformation(
MASKED_TEST_FORMAT_INFO ^ 0x01, MASKED_TEST_FORMAT_INFO ^ 0x01));
assertEquals(expected, FormatInformation.decodeFormatInformation(
MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x03));
assertEquals(expected, FormatInformation.decodeFormatInformation(
MASKED_TEST_FORMAT_INFO ^ 0x07, MASKED_TEST_FORMAT_INFO ^ 0x07));
assertNull(FormatInformation.decodeFormatInformation(
MASKED_TEST_FORMAT_INFO ^ 0x0F, MASKED_TEST_FORMAT_INFO ^ 0x0F));
}
@Test
public void testDecodeWithMisread() {
FormatInformation expected =
FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO);
assertEquals(expected, FormatInformation.decodeFormatInformation(
MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x0F));
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.decoder;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Sean Owen
*/
public final class ModeTestCase extends Assert {
@Test
public void testForBits() {
assertSame(Mode.TERMINATOR, Mode.forBits(0x00));
assertSame(Mode.NUMERIC, Mode.forBits(0x01));
assertSame(Mode.ALPHANUMERIC, Mode.forBits(0x02));
assertSame(Mode.BYTE, Mode.forBits(0x04));
assertSame(Mode.KANJI, Mode.forBits(0x08));
}
@Test(expected = IllegalArgumentException.class)
public void testBadMode() {
Mode.forBits(0x10);
}
@Test
public void testCharacterCount() {
// Spot check a few values
assertEquals(10, Mode.NUMERIC.getCharacterCountBits(Version.getVersionForNumber(5)));
assertEquals(12, Mode.NUMERIC.getCharacterCountBits(Version.getVersionForNumber(26)));
assertEquals(14, Mode.NUMERIC.getCharacterCountBits(Version.getVersionForNumber(40)));
assertEquals(9, Mode.ALPHANUMERIC.getCharacterCountBits(Version.getVersionForNumber(6)));
assertEquals(8, Mode.BYTE.getCharacterCountBits(Version.getVersionForNumber(7)));
assertEquals(8, Mode.KANJI.getCharacterCountBits(Version.getVersionForNumber(8)));
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.decoder;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Sean Owen
*/
public final class VersionTestCase extends Assert {
@Test(expected = IllegalArgumentException.class)
public void testBadVersion() {
Version.getVersionForNumber(0);
}
@Test
public void testVersionForNumber() {
for (int i = 1; i <= 40; i++) {
checkVersion(Version.getVersionForNumber(i), i, 4 * i + 17);
}
}
private static void checkVersion(Version version, int number, int dimension) {
assertNotNull(version);
assertEquals(number, version.getVersionNumber());
assertNotNull(version.getAlignmentPatternCenters());
if (number > 1) {
assertTrue(version.getAlignmentPatternCenters().length > 0);
}
assertEquals(dimension, version.getDimensionForVersion());
assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel.H));
assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel.L));
assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel.M));
assertNotNull(version.getECBlocksForLevel(ErrorCorrectionLevel.Q));
assertNotNull(version.buildFunctionPattern());
}
@Test
public void testGetProvisionalVersionForDimension() throws Exception {
for (int i = 1; i <= 40; i++) {
assertEquals(i, Version.getProvisionalVersionForDimension(4 * i + 17).getVersionNumber());
}
}
@Test
public void testDecodeVersionInformation() {
// Spot check
doTestVersion(7, 0x07C94);
doTestVersion(12, 0x0C762);
doTestVersion(17, 0x1145D);
doTestVersion(22, 0x168C9);
doTestVersion(27, 0x1B08E);
doTestVersion(32, 0x209D5);
}
private static void doTestVersion(int expectedVersion, int mask) {
Version version = Version.decodeVersionInformation(mask);
assertNotNull(version);
assertEquals(expectedVersion, version.getVersionNumber());
}
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.BitArray;
import org.junit.Assert;
import org.junit.Test;
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author dswitkin@google.com (Daniel Switkin) - ported from C++
*/
public final class BitVectorTestCase extends Assert {
private static long getUnsignedInt(BitArray v) {
long result = 0L;
for (int i = 0, offset = 0; i < 32; i++) {
if (v.get(offset + i)) {
result |= 1L << (31 - i);
}
}
return result;
}
@Test
public void testAppendBit() {
BitArray v = new BitArray();
assertEquals(0, v.getSizeInBytes());
// 1
v.appendBit(true);
assertEquals(1, v.getSize());
assertEquals(0x80000000L, getUnsignedInt(v));
// 10
v.appendBit(false);
assertEquals(2, v.getSize());
assertEquals(0x80000000L, getUnsignedInt(v));
// 101
v.appendBit(true);
assertEquals(3, v.getSize());
assertEquals(0xa0000000L, getUnsignedInt(v));
// 1010
v.appendBit(false);
assertEquals(4, v.getSize());
assertEquals(0xa0000000L, getUnsignedInt(v));
// 10101
v.appendBit(true);
assertEquals(5, v.getSize());
assertEquals(0xa8000000L, getUnsignedInt(v));
// 101010
v.appendBit(false);
assertEquals(6, v.getSize());
assertEquals(0xa8000000L, getUnsignedInt(v));
// 1010101
v.appendBit(true);
assertEquals(7, v.getSize());
assertEquals(0xaa000000L, getUnsignedInt(v));
// 10101010
v.appendBit(false);
assertEquals(8, v.getSize());
assertEquals(0xaa000000L, getUnsignedInt(v));
// 10101010 1
v.appendBit(true);
assertEquals(9, v.getSize());
assertEquals(0xaa800000L, getUnsignedInt(v));
// 10101010 10
v.appendBit(false);
assertEquals(10, v.getSize());
assertEquals(0xaa800000L, getUnsignedInt(v));
}
@Test
public void testAppendBits() {
BitArray v = new BitArray();
v.appendBits(0x1, 1);
assertEquals(1, v.getSize());
assertEquals(0x80000000L, getUnsignedInt(v));
v = new BitArray();
v.appendBits(0xff, 8);
assertEquals(8, v.getSize());
assertEquals(0xff000000L, getUnsignedInt(v));
v = new BitArray();
v.appendBits(0xff7, 12);
assertEquals(12, v.getSize());
assertEquals(0xff700000L, getUnsignedInt(v));
}
@Test
public void testNumBytes() {
BitArray v = new BitArray();
assertEquals(0, v.getSizeInBytes());
v.appendBit(false);
// 1 bit was added in the vector, so 1 byte should be consumed.
assertEquals(1, v.getSizeInBytes());
v.appendBits(0, 7);
assertEquals(1, v.getSizeInBytes());
v.appendBits(0, 8);
assertEquals(2, v.getSizeInBytes());
v.appendBits(0, 1);
// We now have 17 bits, so 3 bytes should be consumed.
assertEquals(3, v.getSizeInBytes());
}
@Test
public void testAppendBitVector() {
BitArray v1 = new BitArray();
v1.appendBits(0xbe, 8);
BitArray v2 = new BitArray();
v2.appendBits(0xef, 8);
v1.appendBitArray(v2);
// beef = 1011 1110 1110 1111
assertEquals(" X.XXXXX. XXX.XXXX", v1.toString());
}
@Test
public void testXOR() {
BitArray v1 = new BitArray();
v1.appendBits(0x5555aaaa, 32);
BitArray v2 = new BitArray();
v2.appendBits(0xaaaa5555, 32);
v1.xor(v2);
assertEquals(0xffffffffL, getUnsignedInt(v1));
}
@Test
public void testXOR2() {
BitArray v1 = new BitArray();
v1.appendBits(0x2a, 7); // 010 1010
BitArray v2 = new BitArray();
v2.appendBits(0x55, 7); // 101 0101
v1.xor(v2);
assertEquals(0xfe000000L, getUnsignedInt(v1)); // 1111 1110
}
@Test
public void testAt() {
BitArray v = new BitArray();
v.appendBits(0xdead, 16); // 1101 1110 1010 1101
assertTrue(v.get(0));
assertTrue(v.get(1));
assertFalse(v.get(2));
assertTrue(v.get(3));
assertTrue(v.get(4));
assertTrue(v.get(5));
assertTrue(v.get(6));
assertFalse(v.get(7));
assertTrue(v.get(8));
assertFalse(v.get(9));
assertTrue(v.get(10));
assertFalse(v.get(11));
assertTrue(v.get(12));
assertTrue(v.get(13));
assertFalse(v.get(14));
assertTrue(v.get(15));
}
@Test
public void testToString() {
BitArray v = new BitArray();
v.appendBits(0xdead, 16); // 1101 1110 1010 1101
assertEquals(" XX.XXXX. X.X.XX.X", v.toString());
}
}

View File

@@ -0,0 +1,987 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.encoder;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitArray;
import com.google.zxing.common.StringUtils;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Mode;
import com.google.zxing.qrcode.decoder.Version;
import org.junit.Assert;
import org.junit.Test;
import java.util.EnumMap;
import java.util.Map;
import java.nio.charset.Charset;
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author mysen@google.com (Chris Mysen) - ported from C++
*/
public final class EncoderTestCase extends Assert {
@Test
public void testGetAlphanumericCode() {
// The first ten code points are numbers.
for (int i = 0; i < 10; ++i) {
assertEquals(i, Encoder.getAlphanumericCode('0' + i));
}
// The next 26 code points are capital alphabet letters.
for (int i = 10; i < 36; ++i) {
assertEquals(i, Encoder.getAlphanumericCode('A' + i - 10));
}
// Others are symbol letters
assertEquals(36, Encoder.getAlphanumericCode(' '));
assertEquals(37, Encoder.getAlphanumericCode('$'));
assertEquals(38, Encoder.getAlphanumericCode('%'));
assertEquals(39, Encoder.getAlphanumericCode('*'));
assertEquals(40, Encoder.getAlphanumericCode('+'));
assertEquals(41, Encoder.getAlphanumericCode('-'));
assertEquals(42, Encoder.getAlphanumericCode('.'));
assertEquals(43, Encoder.getAlphanumericCode('/'));
assertEquals(44, Encoder.getAlphanumericCode(':'));
// Should return -1 for other letters;
assertEquals(-1, Encoder.getAlphanumericCode('a'));
assertEquals(-1, Encoder.getAlphanumericCode('#'));
assertEquals(-1, Encoder.getAlphanumericCode('\0'));
}
@Test
public void testChooseMode() {
// Numeric mode.
assertSame(Mode.NUMERIC, Encoder.chooseMode("0"));
assertSame(Mode.NUMERIC, Encoder.chooseMode("0123456789"));
// Alphanumeric mode.
assertSame(Mode.ALPHANUMERIC, Encoder.chooseMode("A"));
assertSame(Mode.ALPHANUMERIC,
Encoder.chooseMode("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"));
// 8-bit byte mode.
assertSame(Mode.BYTE, Encoder.chooseMode("a"));
assertSame(Mode.BYTE, Encoder.chooseMode("#"));
assertSame(Mode.BYTE, Encoder.chooseMode(""));
// Kanji mode. We used to use MODE_KANJI for these, but we stopped
// doing that as we cannot distinguish Shift_JIS from other encodings
// from data bytes alone. See also comments in qrcode_encoder.h.
// AIUE in Hiragana in Shift_JIS
assertSame(Mode.BYTE,
Encoder.chooseMode(shiftJISString(bytes(0x8, 0xa, 0x8, 0xa, 0x8, 0xa, 0x8, 0xa6))));
// Nihon in Kanji in Shift_JIS.
assertSame(Mode.BYTE, Encoder.chooseMode(shiftJISString(bytes(0x9, 0xf, 0x9, 0x7b))));
// Sou-Utsu-Byou in Kanji in Shift_JIS.
assertSame(Mode.BYTE, Encoder.chooseMode(shiftJISString(bytes(0xe, 0x4, 0x9, 0x5, 0x9, 0x61))));
}
@Test
public void testEncode() throws WriterException {
QRCode qrCode = Encoder.encode("ABCDEF", ErrorCorrectionLevel.H);
String expected = "<<\n" +
" mode: ALPHANUMERIC\n" +
" ecLevel: H\n" +
" version: 1\n" +
" maskPattern: 0\n" +
" matrix:\n" +
" 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n" +
" 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n" +
" 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n" +
" 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n" +
" 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n" +
" 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n" +
" 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n" +
" 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n" +
" 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n" +
" 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n" +
" 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n" +
">>\n";
assertEquals(expected, qrCode.toString());
}
@Test
public void testEncodeWithVersion() throws WriterException {
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.QR_VERSION, 7);
QRCode qrCode = Encoder.encode("ABCDEF", ErrorCorrectionLevel.H, hints);
assertTrue(qrCode.toString().contains(" version: 7\n"));
}
@Test(expected = WriterException.class)
public void testEncodeWithVersionTooSmall() throws WriterException {
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.QR_VERSION, 3);
Encoder.encode("THISMESSAGEISTOOLONGFORAQRCODEVERSION3", ErrorCorrectionLevel.H, hints);
}
@Test
public void testSimpleUTF8ECI() throws WriterException {
Map<EncodeHintType,Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, "UTF8");
QRCode qrCode = Encoder.encode("hello", ErrorCorrectionLevel.H, hints);
String expected = "<<\n" +
" mode: BYTE\n" +
" ecLevel: H\n" +
" version: 1\n" +
" maskPattern: 3\n" +
" matrix:\n" +
" 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 0 1 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n" +
" 0 0 1 1 0 0 1 1 1 1 0 0 0 1 1 0 1 0 0 0 0\n" +
" 0 0 1 1 1 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 0\n" +
" 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 1 1 1\n" +
" 1 1 0 0 1 0 0 1 1 0 0 1 1 1 1 0 1 0 1 1 0\n" +
" 0 0 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 0 1 0 0\n" +
" 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 0 1 0 0\n" +
" 1 0 0 0 0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0\n" +
" 1 0 1 1 1 0 1 0 1 1 1 0 1 0 0 0 1 1 0 0 0\n" +
" 1 0 1 1 1 0 1 0 1 1 0 0 0 1 0 0 1 0 0 0 0\n" +
" 1 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 1 0 1 1 0\n" +
" 1 1 1 1 1 1 1 0 0 1 0 1 1 1 0 1 1 0 0 0 0\n" +
">>\n";
assertEquals(expected, qrCode.toString());
}
@Test
public void testEncodeKanjiMode() throws WriterException {
Map<EncodeHintType,Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, "Shift_JIS");
// Nihon in Kanji
QRCode qrCode = Encoder.encode("\u65e5\u672c", ErrorCorrectionLevel.M, hints);
String expected = "<<\n" +
" mode: KANJI\n" +
" ecLevel: M\n" +
" version: 1\n" +
" maskPattern: 4\n" +
" matrix:\n" +
" 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 0 1 0 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 1 0 1 1 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 0 0 0 1 0 1 1 1 0 0 0 1 1 1 1 1 1 0 0 1\n" +
" 0 1 1 0 0 1 0 1 1 0 1 0 1 1 1 0 0 0 1 0 1\n" +
" 1 1 1 1 0 1 1 1 0 0 1 0 1 1 0 0 0 0 1 1 1\n" +
" 1 0 1 0 1 1 0 0 0 0 1 1 1 0 0 1 0 0 1 1 0\n" +
" 0 0 1 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 1 1\n" +
" 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 1 0 1 0 0 0\n" +
" 1 1 1 1 1 1 1 0 1 1 0 1 0 0 1 1 1 1 1 1 0\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 1 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 0 1 1 1 0 0 0 1 1 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 0 1 1 0 0 0 1 0 0 0\n" +
" 1 0 0 0 0 0 1 0 0 0 1 1 1 0 0 1 0 1 0 0 0\n" +
" 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 0 1 1 0\n" +
">>\n";
assertEquals(expected, qrCode.toString());
}
@Test
public void testEncodeShiftjisNumeric() throws WriterException {
Map<EncodeHintType,Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, "Shift_JIS");
QRCode qrCode = Encoder.encode("0123", ErrorCorrectionLevel.M, hints);
String expected = "<<\n" +
" mode: NUMERIC\n" +
" ecLevel: M\n" +
" version: 1\n" +
" maskPattern: 0\n" +
" matrix:\n" +
" 1 1 1 1 1 1 1 0 0 0 0 0 1 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 1 1 0 1 0 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 0 1 0 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0\n" +
" 1 0 1 0 1 0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0\n" +
" 0 0 0 0 0 0 0 1 1 0 1 1 0 1 0 1 0 1 0 1 0\n" +
" 0 1 0 1 0 1 1 1 1 0 0 1 0 1 1 1 0 1 0 1 0\n" +
" 0 1 1 1 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 1 0\n" +
" 0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 1 0 1\n" +
" 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 1 1 0\n" +
" 1 1 1 1 1 1 1 0 0 1 0 0 1 0 0 0 1 0 0 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 1 0 0\n" +
" 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 0 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 1 1 0 1 0 1 0 1 1 0 1 1 1 0 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 0 1 1 1 1 0 1 1 1 0 0 0\n" +
" 1 1 1 1 1 1 1 0 1 0 1 1 0 1 1 1 0 1 1 0 1\n" +
">>\n";
assertEquals(expected, qrCode.toString());
}
@Test
public void testEncodeGS1WithStringTypeHint() throws WriterException {
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.GS1_FORMAT, "true");
QRCode qrCode = Encoder.encode("100001%11171218", ErrorCorrectionLevel.H, hints);
verifyGS1EncodedData(qrCode);
}
@Test
public void testEncodeGS1WithBooleanTypeHint() throws WriterException {
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.GS1_FORMAT, true);
QRCode qrCode = Encoder.encode("100001%11171218", ErrorCorrectionLevel.H, hints);
verifyGS1EncodedData(qrCode);
}
@Test
public void testDoesNotEncodeGS1WhenBooleanTypeHintExplicitlyFalse() throws WriterException {
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.GS1_FORMAT, false);
QRCode qrCode = Encoder.encode("ABCDEF", ErrorCorrectionLevel.H, hints);
verifyNotGS1EncodedData(qrCode);
}
@Test
public void testDoesNotEncodeGS1WhenStringTypeHintExplicitlyFalse() throws WriterException {
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.GS1_FORMAT, "false");
QRCode qrCode = Encoder.encode("ABCDEF", ErrorCorrectionLevel.H, hints);
verifyNotGS1EncodedData(qrCode);
}
@Test
public void testGS1ModeHeaderWithECI() throws WriterException {
Map<EncodeHintType,Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, "UTF8");
hints.put(EncodeHintType.GS1_FORMAT, true);
QRCode qrCode = Encoder.encode("hello", ErrorCorrectionLevel.H, hints);
String expected = "<<\n" +
" mode: BYTE\n" +
" ecLevel: H\n" +
" version: 1\n" +
" maskPattern: 6\n" +
" matrix:\n" +
" 1 1 1 1 1 1 1 0 0 0 1 1 0 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 1 1 0 0 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 1 0 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 0 1 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 1 0 1 0 0 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0\n" +
" 0 0 0 1 1 0 1 1 0 1 0 0 0 0 0 0 0 1 1 0 0\n" +
" 0 1 0 1 1 0 0 1 0 1 1 1 1 1 1 0 1 1 1 0 1\n" +
" 0 1 1 1 1 0 1 0 0 1 0 1 0 1 1 1 0 0 1 0 1\n" +
" 1 1 1 1 1 0 0 1 0 0 0 1 1 0 0 1 0 0 1 0 0\n" +
" 1 0 0 1 0 0 1 1 0 1 1 0 1 0 1 0 0 1 0 0 1\n" +
" 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 0 0\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 1 1 1 0 0\n" +
" 1 0 1 1 1 0 1 0 1 1 0 1 1 0 0 0 1 1 0 0 0\n" +
" 1 0 1 1 1 0 1 0 1 0 1 1 1 1 1 0 0 0 1 1 0\n" +
" 1 0 1 1 1 0 1 0 0 0 1 0 0 1 0 0 1 0 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 1 0 0\n" +
" 1 1 1 1 1 1 1 0 0 1 0 1 0 0 1 0 0 0 0 0 0\n" +
">>\n";
assertEquals(expected, qrCode.toString());
}
@Test
public void testAppendModeInfo() {
BitArray bits = new BitArray();
Encoder.appendModeInfo(Mode.NUMERIC, bits);
assertEquals(" ...X", bits.toString());
}
@Test
public void testAppendLengthInfo() throws WriterException {
BitArray bits = new BitArray();
Encoder.appendLengthInfo(1, // 1 letter (1/1).
Version.getVersionForNumber(1),
Mode.NUMERIC,
bits);
assertEquals(" ........ .X", bits.toString()); // 10 bits.
bits = new BitArray();
Encoder.appendLengthInfo(2, // 2 letters (2/1).
Version.getVersionForNumber(10),
Mode.ALPHANUMERIC,
bits);
assertEquals(" ........ .X.", bits.toString()); // 11 bits.
bits = new BitArray();
Encoder.appendLengthInfo(255, // 255 letter (255/1).
Version.getVersionForNumber(27),
Mode.BYTE,
bits);
assertEquals(" ........ XXXXXXXX", bits.toString()); // 16 bits.
bits = new BitArray();
Encoder.appendLengthInfo(512, // 512 letters (1024/2).
Version.getVersionForNumber(40),
Mode.KANJI,
bits);
assertEquals(" ..X..... ....", bits.toString()); // 12 bits.
}
@Test
public void testAppendBytes() throws WriterException {
// Should use appendNumericBytes.
// 1 = 01 = 0001 in 4 bits.
BitArray bits = new BitArray();
Encoder.appendBytes("1", Mode.NUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals(" ...X" , bits.toString());
// Should use appendAlphanumericBytes.
// A = 10 = 0xa = 001010 in 6 bits
bits = new BitArray();
Encoder.appendBytes("A", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals(" ..X.X." , bits.toString());
// Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
try {
Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
} catch (WriterException we) {
// good
}
// Should use append8BitBytes.
// 0x61, 0x62, 0x63
bits = new BitArray();
Encoder.appendBytes("abc", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals(" .XX....X .XX...X. .XX...XX", bits.toString());
// Anything can be encoded in QRCode.MODE_8BIT_BYTE.
Encoder.appendBytes("\0", Mode.BYTE, bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
// Should use appendKanjiBytes.
// 0x93, 0x5f
bits = new BitArray();
Encoder.appendBytes(shiftJISString(bytes(0x93, 0x5f)), Mode.KANJI, bits,
Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals(" .XX.XX.. XXXXX", bits.toString());
}
@Test
public void testTerminateBits() throws WriterException {
BitArray v = new BitArray();
Encoder.terminateBits(0, v);
assertEquals("", v.toString());
v = new BitArray();
Encoder.terminateBits(1, v);
assertEquals(" ........", v.toString());
v = new BitArray();
v.appendBits(0, 3); // Append 000
Encoder.terminateBits(1, v);
assertEquals(" ........", v.toString());
v = new BitArray();
v.appendBits(0, 5); // Append 00000
Encoder.terminateBits(1, v);
assertEquals(" ........", v.toString());
v = new BitArray();
v.appendBits(0, 8); // Append 00000000
Encoder.terminateBits(1, v);
assertEquals(" ........", v.toString());
v = new BitArray();
Encoder.terminateBits(2, v);
assertEquals(" ........ XXX.XX..", v.toString());
v = new BitArray();
v.appendBits(0, 1); // Append 0
Encoder.terminateBits(3, v);
assertEquals(" ........ XXX.XX.. ...X...X", v.toString());
}
@Test
public void testGetNumDataBytesAndNumECBytesForBlockID() throws WriterException {
int[] numDataBytes = new int[1];
int[] numEcBytes = new int[1];
// Version 1-H.
Encoder.getNumDataBytesAndNumECBytesForBlockID(26, 9, 1, 0, numDataBytes, numEcBytes);
assertEquals(9, numDataBytes[0]);
assertEquals(17, numEcBytes[0]);
// Version 3-H. 2 blocks.
Encoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 0, numDataBytes, numEcBytes);
assertEquals(13, numDataBytes[0]);
assertEquals(22, numEcBytes[0]);
Encoder.getNumDataBytesAndNumECBytesForBlockID(70, 26, 2, 1, numDataBytes, numEcBytes);
assertEquals(13, numDataBytes[0]);
assertEquals(22, numEcBytes[0]);
// Version 7-H. (4 + 1) blocks.
Encoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 0, numDataBytes, numEcBytes);
assertEquals(13, numDataBytes[0]);
assertEquals(26, numEcBytes[0]);
Encoder.getNumDataBytesAndNumECBytesForBlockID(196, 66, 5, 4, numDataBytes, numEcBytes);
assertEquals(14, numDataBytes[0]);
assertEquals(26, numEcBytes[0]);
// Version 40-H. (20 + 61) blocks.
Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 0, numDataBytes, numEcBytes);
assertEquals(15, numDataBytes[0]);
assertEquals(30, numEcBytes[0]);
Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 20, numDataBytes, numEcBytes);
assertEquals(16, numDataBytes[0]);
assertEquals(30, numEcBytes[0]);
Encoder.getNumDataBytesAndNumECBytesForBlockID(3706, 1276, 81, 80, numDataBytes, numEcBytes);
assertEquals(16, numDataBytes[0]);
assertEquals(30, numEcBytes[0]);
}
@Test
public void testInterleaveWithECBytes() throws WriterException {
byte[] dataBytes = bytes(32, 65, 205, 69, 41, 220, 46, 128, 236);
BitArray in = new BitArray();
for (byte dataByte: dataBytes) {
in.appendBits(dataByte, 8);
}
BitArray out = Encoder.interleaveWithECBytes(in, 26, 9, 1);
byte[] expected = bytes(
// Data bytes.
32, 65, 205, 69, 41, 220, 46, 128, 236,
// Error correction bytes.
42, 159, 74, 221, 244, 169, 239, 150, 138, 70,
237, 85, 224, 96, 74, 219, 61
);
assertEquals(expected.length, out.getSizeInBytes());
byte[] outArray = new byte[expected.length];
out.toBytes(0, outArray, 0, expected.length);
// Can't use Arrays.equals(), because outArray may be longer than out.sizeInBytes()
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], outArray[x]);
}
// Numbers are from http://www.swetake.com/qr/qr8.html
dataBytes = bytes(
67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182,
198, 214, 230, 247, 7, 23, 39, 55, 71, 87, 103, 119, 135,
151, 166, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166,
182, 198, 214, 230, 247, 7, 23, 39, 55, 71, 87, 103, 119,
135, 151, 160, 236, 17, 236, 17, 236, 17, 236,
17
);
in = new BitArray();
for (byte dataByte: dataBytes) {
in.appendBits(dataByte, 8);
}
out = Encoder.interleaveWithECBytes(in, 134, 62, 4);
expected = bytes(
// Data bytes.
67, 230, 54, 55, 70, 247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39,
118, 119, 70, 55, 134, 135, 86, 71, 150, 151, 102, 87, 166,
160, 118, 103, 182, 236, 134, 119, 198, 17, 150,
135, 214, 236, 166, 151, 230, 17, 182,
166, 247, 236, 198, 22, 7, 17, 214, 38, 23, 236, 39,
17,
// Error correction bytes.
175, 155, 245, 236, 80, 146, 56, 74, 155, 165,
133, 142, 64, 183, 132, 13, 178, 54, 132, 108, 45,
113, 53, 50, 214, 98, 193, 152, 233, 147, 50, 71, 65,
190, 82, 51, 209, 199, 171, 54, 12, 112, 57, 113, 155, 117,
211, 164, 117, 30, 158, 225, 31, 190, 242, 38,
140, 61, 179, 154, 214, 138, 147, 87, 27, 96, 77, 47,
187, 49, 156, 214
);
assertEquals(expected.length, out.getSizeInBytes());
outArray = new byte[expected.length];
out.toBytes(0, outArray, 0, expected.length);
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], outArray[x]);
}
}
private static byte[] bytes(int... ints) {
byte[] bytes = new byte[ints.length];
for (int i = 0; i < ints.length; i++) {
bytes[i] = (byte) ints[i];
}
return bytes;
}
@Test
public void testAppendNumericBytes() {
// 1 = 01 = 0001 in 4 bits.
BitArray bits = new BitArray();
Encoder.appendNumericBytes("1", bits);
assertEquals(" ...X" , bits.toString());
// 12 = 0xc = 0001100 in 7 bits.
bits = new BitArray();
Encoder.appendNumericBytes("12", bits);
assertEquals(" ...XX.." , bits.toString());
// 123 = 0x7b = 0001111011 in 10 bits.
bits = new BitArray();
Encoder.appendNumericBytes("123", bits);
assertEquals(" ...XXXX. XX" , bits.toString());
// 1234 = "123" + "4" = 0001111011 + 0100
bits = new BitArray();
Encoder.appendNumericBytes("1234", bits);
assertEquals(" ...XXXX. XX.X.." , bits.toString());
// Empty.
bits = new BitArray();
Encoder.appendNumericBytes("", bits);
assertEquals("" , bits.toString());
}
@Test
public void testAppendAlphanumericBytes() throws WriterException {
// A = 10 = 0xa = 001010 in 6 bits
BitArray bits = new BitArray();
Encoder.appendAlphanumericBytes("A", bits);
assertEquals(" ..X.X." , bits.toString());
// AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
bits = new BitArray();
Encoder.appendAlphanumericBytes("AB", bits);
assertEquals(" ..XXX..X X.X", bits.toString());
// ABC = "AB" + "C" = 00111001101 + 001100
bits = new BitArray();
Encoder.appendAlphanumericBytes("ABC", bits);
assertEquals(" ..XXX..X X.X..XX. ." , bits.toString());
// Empty.
bits = new BitArray();
Encoder.appendAlphanumericBytes("", bits);
assertEquals("" , bits.toString());
// Invalid data.
try {
Encoder.appendAlphanumericBytes("abc", new BitArray());
} catch (WriterException we) {
// good
}
}
@Test
public void testAppend8BitBytes() {
// 0x61, 0x62, 0x63
BitArray bits = new BitArray();
Encoder.append8BitBytes("abc", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals(" .XX....X .XX...X. .XX...XX", bits.toString());
// Empty.
bits = new BitArray();
Encoder.append8BitBytes("", bits, Encoder.DEFAULT_BYTE_MODE_ENCODING);
assertEquals("", bits.toString());
}
// Numbers are from page 21 of JISX0510:2004
@Test
public void testAppendKanjiBytes() throws WriterException {
BitArray bits = new BitArray();
Encoder.appendKanjiBytes(shiftJISString(bytes(0x93, 0x5f)), bits);
assertEquals(" .XX.XX.. XXXXX", bits.toString());
Encoder.appendKanjiBytes(shiftJISString(bytes(0xe4, 0xaa)), bits);
assertEquals(" .XX.XX.. XXXXXXX. X.X.X.X. X.", bits.toString());
}
// Numbers are from http://www.swetake.com/qr/qr3.html and
// http://www.swetake.com/qr/qr9.html
@Test
public void testGenerateECBytes() {
byte[] dataBytes = bytes(32, 65, 205, 69, 41, 220, 46, 128, 236);
byte[] ecBytes = Encoder.generateECBytes(dataBytes, 17);
int[] expected = {
42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61
};
assertEquals(expected.length, ecBytes.length);
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], ecBytes[x] & 0xFF);
}
dataBytes = bytes(67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214);
ecBytes = Encoder.generateECBytes(dataBytes, 18);
expected = new int[] {
175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187
};
assertEquals(expected.length, ecBytes.length);
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], ecBytes[x] & 0xFF);
}
// High-order zero coefficient case.
dataBytes = bytes(32, 49, 205, 69, 42, 20, 0, 236, 17);
ecBytes = Encoder.generateECBytes(dataBytes, 17);
expected = new int[] {
0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213
};
assertEquals(expected.length, ecBytes.length);
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], ecBytes[x] & 0xFF);
}
}
@Test
public void testBugInBitVectorNumBytes() throws WriterException {
// There was a bug in BitVector.sizeInBytes() that caused it to return a
// smaller-by-one value (ex. 1465 instead of 1466) if the number of bits
// in the vector is not 8-bit aligned. In QRCodeEncoder::InitQRCode(),
// BitVector::sizeInBytes() is used for finding the smallest QR Code
// version that can fit the given data. Hence there were corner cases
// where we chose a wrong QR Code version that cannot fit the given
// data. Note that the issue did not occur with MODE_8BIT_BYTE, as the
// bits in the bit vector are always 8-bit aligned.
//
// Before the bug was fixed, the following test didn't pass, because:
//
// - MODE_NUMERIC is chosen as all bytes in the data are '0'
// - The 3518-byte numeric data needs 1466 bytes
// - 3518 / 3 * 10 + 7 = 11727 bits = 1465.875 bytes
// - 3 numeric bytes are encoded in 10 bits, hence the first
// 3516 bytes are encoded in 3516 / 3 * 10 = 11720 bits.
// - 2 numeric bytes can be encoded in 7 bits, hence the last
// 2 bytes are encoded in 7 bits.
// - The version 27 QR Code with the EC level L has 1468 bytes for data.
// - 1828 - 360 = 1468
// - In InitQRCode(), 3 bytes are reserved for a header. Hence 1465 bytes
// (1468 -3) are left for data.
// - Because of the bug in BitVector::sizeInBytes(), InitQRCode() determines
// the given data can fit in 1465 bytes, despite it needs 1466 bytes.
// - Hence QRCodeEncoder.encode() failed and returned false.
// - To be precise, it needs 11727 + 4 (getMode info) + 14 (length info) =
// 11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468
// bytes).
StringBuilder builder = new StringBuilder(3518);
for (int x = 0; x < 3518; x++) {
builder.append('0');
}
Encoder.encode(builder.toString(), ErrorCorrectionLevel.L);
}
@Test
public void testMinimalEncoder1() throws Exception {
verifyMinimalEncoding("A", "ALPHANUMERIC(A)", null, false);
}
@Test
public void testMinimalEncoder2() throws Exception {
verifyMinimalEncoding("AB", "ALPHANUMERIC(AB)", null, false);
}
@Test
public void testMinimalEncoder3() throws Exception {
verifyMinimalEncoding("ABC", "ALPHANUMERIC(ABC)", null, false);
}
@Test
public void testMinimalEncoder4() throws Exception {
verifyMinimalEncoding("ABCD", "ALPHANUMERIC(ABCD)", null, false);
}
@Test
public void testMinimalEncoder5() throws Exception {
verifyMinimalEncoding("ABCDE", "ALPHANUMERIC(ABCDE)", null, false);
}
@Test
public void testMinimalEncoder6() throws Exception {
verifyMinimalEncoding("ABCDEF", "ALPHANUMERIC(ABCDEF)", null, false);
}
@Test
public void testMinimalEncoder7() throws Exception {
verifyMinimalEncoding("ABCDEFG", "ALPHANUMERIC(ABCDEFG)", null, false);
}
@Test
public void testMinimalEncoder8() throws Exception {
verifyMinimalEncoding("1", "NUMERIC(1)", null, false);
}
@Test
public void testMinimalEncoder9() throws Exception {
verifyMinimalEncoding("12", "NUMERIC(12)", null, false);
}
@Test
public void testMinimalEncoder10() throws Exception {
verifyMinimalEncoding("123", "NUMERIC(123)", null, false);
}
@Test
public void testMinimalEncoder11() throws Exception {
verifyMinimalEncoding("1234", "NUMERIC(1234)", null, false);
}
@Test
public void testMinimalEncoder12() throws Exception {
verifyMinimalEncoding("12345", "NUMERIC(12345)", null, false);
}
@Test
public void testMinimalEncoder13() throws Exception {
verifyMinimalEncoding("123456", "NUMERIC(123456)", null, false);
}
@Test
public void testMinimalEncoder14() throws Exception {
verifyMinimalEncoding("123A", "ALPHANUMERIC(123A)", null, false);
}
@Test
public void testMinimalEncoder15() throws Exception {
verifyMinimalEncoding("A1", "ALPHANUMERIC(A1)", null, false);
}
@Test
public void testMinimalEncoder16() throws Exception {
verifyMinimalEncoding("A12", "ALPHANUMERIC(A12)", null, false);
}
@Test
public void testMinimalEncoder17() throws Exception {
verifyMinimalEncoding("A123", "ALPHANUMERIC(A123)", null, false);
}
@Test
public void testMinimalEncoder18() throws Exception {
verifyMinimalEncoding("A1234", "ALPHANUMERIC(A1234)", null, false);
}
@Test
public void testMinimalEncoder19() throws Exception {
verifyMinimalEncoding("A12345", "ALPHANUMERIC(A12345)", null, false);
}
@Test
public void testMinimalEncoder20() throws Exception {
verifyMinimalEncoding("A123456", "ALPHANUMERIC(A123456)", null, false);
}
@Test
public void testMinimalEncoder21() throws Exception {
verifyMinimalEncoding("A1234567", "ALPHANUMERIC(A1234567)", null, false);
}
@Test
public void testMinimalEncoder22() throws Exception {
verifyMinimalEncoding("A12345678", "BYTE(A),NUMERIC(12345678)", null, false);
}
@Test
public void testMinimalEncoder23() throws Exception {
verifyMinimalEncoding("A123456789", "BYTE(A),NUMERIC(123456789)", null, false);
}
@Test
public void testMinimalEncoder24() throws Exception {
verifyMinimalEncoding("A1234567890", "ALPHANUMERIC(A1),NUMERIC(234567890)", null, false);
}
@Test
public void testMinimalEncoder25() throws Exception {
verifyMinimalEncoding("AB1", "ALPHANUMERIC(AB1)", null, false);
}
@Test
public void testMinimalEncoder26() throws Exception {
verifyMinimalEncoding("AB12", "ALPHANUMERIC(AB12)", null, false);
}
@Test
public void testMinimalEncoder27() throws Exception {
verifyMinimalEncoding("AB123", "ALPHANUMERIC(AB123)", null, false);
}
@Test
public void testMinimalEncoder28() throws Exception {
verifyMinimalEncoding("AB1234", "ALPHANUMERIC(AB1234)", null, false);
}
@Test
public void testMinimalEncoder29() throws Exception {
verifyMinimalEncoding("ABC1", "ALPHANUMERIC(ABC1)", null, false);
}
@Test
public void testMinimalEncoder30() throws Exception {
verifyMinimalEncoding("ABC12", "ALPHANUMERIC(ABC12)", null, false);
}
@Test
public void testMinimalEncoder31() throws Exception {
verifyMinimalEncoding("ABC1234", "ALPHANUMERIC(ABC1234)", null, false);
}
@Test
public void testMinimalEncoder32() throws Exception {
verifyMinimalEncoding("http://foo.com", "BYTE(http://foo.com)" +
"", null, false);
}
@Test
public void testMinimalEncoder33() throws Exception {
verifyMinimalEncoding("HTTP://FOO.COM", "ALPHANUMERIC(HTTP://FOO.COM" +
")", null, false);
}
@Test
public void testMinimalEncoder34() throws Exception {
verifyMinimalEncoding("1001114670010%01201220%107211220%140045003267781",
"NUMERIC(1001114670010),ALPHANUMERIC(%01201220%107211220%),NUMERIC(140045003267781)", null, false);
}
@Test
public void testMinimalEncoder35() throws Exception {
verifyMinimalEncoding("\u0150", "ECI(ISO-8859-2),BYTE(.)", null, false);
}
@Test
public void testMinimalEncoder36() throws Exception {
verifyMinimalEncoding("\u015C", "ECI(ISO-8859-3),BYTE(.)", null, false);
}
@Test
public void testMinimalEncoder37() throws Exception {
verifyMinimalEncoding("\u0150\u015C", "ECI(UTF-8),BYTE(..)", null, false);
}
@Test
public void testMinimalEncoder38() throws Exception {
verifyMinimalEncoding("\u0150\u0150\u015C\u015C", "ECI(ISO-8859-2),BYTE(." +
".),ECI(ISO-8859-3),BYTE(..)", null, false);
}
@Test
public void testMinimalEncoder39() throws Exception {
verifyMinimalEncoding("abcdef\u0150ghij", "ECI(ISO-8859-2),BYTE(abcde" +
"f.ghij)", null, false);
}
@Test
public void testMinimalEncoder40() throws Exception {
verifyMinimalEncoding("2938928329832983\u01502938928329832983\u015C2938928329832983",
"NUMERIC(2938928329832983),ECI(ISO-8859-2),BYTE(.),NUMERIC(2938928329832983),ECI(ISO-8" +
"859-3),BYTE(.),NUMERIC(2938928329832983)", null, false);
}
@Test
public void testMinimalEncoder41() throws Exception {
verifyMinimalEncoding("1001114670010%01201220%107211220%140045003267781", "FNC1_FIRST_POSITION(),NUMERIC(100111" +
"4670010),ALPHANUMERIC(%01201220%107211220%),NUMERIC(140045003267781)", null,
true);
}
@Test
public void testMinimalEncoder42() throws Exception {
// test halfwidth Katakana character (they are single byte encoded in Shift_JIS)
verifyMinimalEncoding("Katakana:\uFF66\uFF66\uFF66\uFF66\uFF66\uFF66", "ECI(Shift_JIS),BYTE(Katakana:......)", null
, false);
}
@Test
public void testMinimalEncoder43() throws Exception {
// The character \u30A2 encodes as double byte in Shift_JIS so KANJI is more compact in this case
verifyMinimalEncoding("Katakana:\u30A2\u30A2\u30A2\u30A2\u30A2\u30A2", "BYTE(Katakana:),KANJI(......)", null,
false);
}
@Test
public void testMinimalEncoder44() throws Exception {
// The character \u30A2 encodes as double byte in Shift_JIS but KANJI is not more compact in this case because
// KANJI is only more compact when it encodes pairs of characters. In the case of mixed text it can however be
// that Shift_JIS encoding is more compact as in this example
verifyMinimalEncoding("Katakana:\u30A2a\u30A2a\u30A2a\u30A2a\u30A2a\u30A2", "ECI(Shift_JIS),BYTE(Katakana:.a.a.a" +
".a.a.)", null, false);
}
static void verifyMinimalEncoding(String input, String expectedRXingResult, Charset priorityCharset, boolean isGS1)
throws Exception {
MinimalEncoder.RXingResultList result = MinimalEncoder.encode(input, null, priorityCharset, isGS1,
ErrorCorrectionLevel.L);
assertEquals(result.toString(), expectedRXingResult);
}
private static void verifyGS1EncodedData(QRCode qrCode) {
String expected = "<<\n" +
" mode: ALPHANUMERIC\n" +
" ecLevel: H\n" +
" version: 2\n" +
" maskPattern: 2\n" +
" matrix:\n" +
" 1 1 1 1 1 1 1 0 1 0 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 1 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 1 0 1 1 0 1 1 0 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 0 1 0 1 1 1 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 1 1 1 1 1 1 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 1\n" +
" 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" +
" 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0\n" +
" 0 0 1 1 1 0 1 0 1 1 1 1 0 1 1 0 1 1 1 1 0 0 1 1 1\n" +
" 0 0 0 1 1 1 0 1 0 0 1 0 0 1 0 0 1 1 1 0 0 1 0 0 1\n" +
" 1 0 1 1 0 0 1 0 1 1 0 0 0 0 1 0 1 1 1 0 0 1 0 0 1\n" +
" 0 0 1 1 0 1 0 1 1 1 1 0 0 1 1 1 1 0 0 0 1 1 0 1 1\n" +
" 0 0 1 0 0 0 1 0 0 0 1 1 0 1 0 0 0 1 0 1 1 1 0 1 0\n" +
" 1 1 1 0 1 1 0 1 0 0 0 0 0 0 0 1 1 0 1 1 0 1 0 0 0\n" +
" 1 0 1 0 1 0 1 1 0 1 0 1 0 1 1 0 0 0 0 0 1 1 0 0 1\n" +
" 1 0 0 1 0 1 0 1 0 0 0 1 1 1 1 0 1 0 1 0 0 1 0 0 1\n" +
" 1 0 1 0 0 1 1 1 0 1 1 0 0 1 0 0 1 1 1 1 1 1 0 0 0\n" +
" 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 0 1 0 0 0 1 0 0 1 0\n" +
" 1 1 1 1 1 1 1 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 1 1 1 1 1 0 1 1 0 0 0 1 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 1 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 1 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0\n" +
" 1 0 1 1 1 0 1 0 1 0 0 0 1 1 0 1 0 0 1 1 1 0 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 1 0 1 1 1 0 1 0 0 1 1 1 1 1\n" +
" 1 1 1 1 1 1 1 0 0 1 1 0 0 1 1 0 1 0 0 0 0 1 0 1 1\n" +
">>\n";
assertEquals(expected, qrCode.toString());
}
private static void verifyNotGS1EncodedData(QRCode qrCode) {
String expected = "<<\n" +
" mode: ALPHANUMERIC\n" +
" ecLevel: H\n" +
" version: 1\n" +
" maskPattern: 0\n" +
" matrix:\n" +
" 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0\n" +
" 0 0 1 0 1 1 1 0 1 1 0 0 1 1 0 0 0 1 0 0 1\n" +
" 1 0 1 1 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0\n" +
" 0 0 1 1 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 1 0\n" +
" 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 0 0 0 1 0\n" +
" 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0\n" +
" 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 1 0 1 0 0 0\n" +
" 1 1 1 1 1 1 1 0 0 0 1 0 1 0 1 1 0 0 0 0 1\n" +
" 1 0 0 0 0 0 1 0 1 1 1 1 0 1 0 1 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 0 1 1 0 1 0 1 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 0 1 1 1 1 0 1 0 1 0\n" +
" 1 0 1 1 1 0 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 1 0 1 1 0 1 0 0 0 1 1\n" +
" 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1\n" +
">>\n";
assertEquals(expected, qrCode.toString());
}
private static String shiftJISString(byte[] bytes) {
return new String(bytes, StringUtils.SHIFT_JIS_CHARSET);
}
}

View File

@@ -0,0 +1,279 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.encoder;
import org.junit.Assert;
import org.junit.Test;
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author mysen@google.com (Chris Mysen) - ported from C++
*/
public final class MaskUtilTestCase extends Assert {
@Test
public void testApplyMaskPenaltyRule1() {
ByteMatrix matrix = new ByteMatrix(4, 1);
matrix.set(0, 0, 0);
matrix.set(1, 0, 0);
matrix.set(2, 0, 0);
matrix.set(3, 0, 0);
assertEquals(0, MaskUtil.applyMaskPenaltyRule1(matrix));
// Horizontal.
matrix = new ByteMatrix(6, 1);
matrix.set(0, 0, 0);
matrix.set(1, 0, 0);
matrix.set(2, 0, 0);
matrix.set(3, 0, 0);
matrix.set(4, 0, 0);
matrix.set(5, 0, 1);
assertEquals(3, MaskUtil.applyMaskPenaltyRule1(matrix));
matrix.set(5, 0, 0);
assertEquals(4, MaskUtil.applyMaskPenaltyRule1(matrix));
// Vertical.
matrix = new ByteMatrix(1, 6);
matrix.set(0, 0, 0);
matrix.set(0, 1, 0);
matrix.set(0, 2, 0);
matrix.set(0, 3, 0);
matrix.set(0, 4, 0);
matrix.set(0, 5, 1);
assertEquals(3, MaskUtil.applyMaskPenaltyRule1(matrix));
matrix.set(0, 5, 0);
assertEquals(4, MaskUtil.applyMaskPenaltyRule1(matrix));
}
@Test
public void testApplyMaskPenaltyRule2() {
ByteMatrix matrix = new ByteMatrix(1, 1);
matrix.set(0, 0, 0);
assertEquals(0, MaskUtil.applyMaskPenaltyRule2(matrix));
matrix = new ByteMatrix(2, 2);
matrix.set(0, 0, 0);
matrix.set(1, 0, 0);
matrix.set(0, 1, 0);
matrix.set(1, 1, 1);
assertEquals(0, MaskUtil.applyMaskPenaltyRule2(matrix));
matrix = new ByteMatrix(2, 2);
matrix.set(0, 0, 0);
matrix.set(1, 0, 0);
matrix.set(0, 1, 0);
matrix.set(1, 1, 0);
assertEquals(3, MaskUtil.applyMaskPenaltyRule2(matrix));
matrix = new ByteMatrix(3, 3);
matrix.set(0, 0, 0);
matrix.set(1, 0, 0);
matrix.set(2, 0, 0);
matrix.set(0, 1, 0);
matrix.set(1, 1, 0);
matrix.set(2, 1, 0);
matrix.set(0, 2, 0);
matrix.set(1, 2, 0);
matrix.set(2, 2, 0);
// Four instances of 2x2 blocks.
assertEquals(3 * 4, MaskUtil.applyMaskPenaltyRule2(matrix));
}
@Test
public void testApplyMaskPenaltyRule3() {
// Horizontal 00001011101.
ByteMatrix matrix = new ByteMatrix(11, 1);
matrix.set(0, 0, 0);
matrix.set(1, 0, 0);
matrix.set(2, 0, 0);
matrix.set(3, 0, 0);
matrix.set(4, 0, 1);
matrix.set(5, 0, 0);
matrix.set(6, 0, 1);
matrix.set(7, 0, 1);
matrix.set(8, 0, 1);
matrix.set(9, 0, 0);
matrix.set(10, 0, 1);
assertEquals(40, MaskUtil.applyMaskPenaltyRule3(matrix));
// Horizontal 10111010000.
matrix = new ByteMatrix(11, 1);
matrix.set(0, 0, 1);
matrix.set(1, 0, 0);
matrix.set(2, 0, 1);
matrix.set(3, 0, 1);
matrix.set(4, 0, 1);
matrix.set(5, 0, 0);
matrix.set(6, 0, 1);
matrix.set(7, 0, 0);
matrix.set(8, 0, 0);
matrix.set(9, 0, 0);
matrix.set(10, 0, 0);
assertEquals(40, MaskUtil.applyMaskPenaltyRule3(matrix));
// Horizontal 1011101.
matrix = new ByteMatrix(7, 1);
matrix.set(0, 0, 1);
matrix.set(1, 0, 0);
matrix.set(2, 0, 1);
matrix.set(3, 0, 1);
matrix.set(4, 0, 1);
matrix.set(5, 0, 0);
matrix.set(6, 0, 1);
assertEquals(0, MaskUtil.applyMaskPenaltyRule3(matrix));
// Vertical 00001011101.
matrix = new ByteMatrix(1, 11);
matrix.set(0, 0, 0);
matrix.set(0, 1, 0);
matrix.set(0, 2, 0);
matrix.set(0, 3, 0);
matrix.set(0, 4, 1);
matrix.set(0, 5, 0);
matrix.set(0, 6, 1);
matrix.set(0, 7, 1);
matrix.set(0, 8, 1);
matrix.set(0, 9, 0);
matrix.set(0, 10, 1);
assertEquals(40, MaskUtil.applyMaskPenaltyRule3(matrix));
// Vertical 10111010000.
matrix = new ByteMatrix(1, 11);
matrix.set(0, 0, 1);
matrix.set(0, 1, 0);
matrix.set(0, 2, 1);
matrix.set(0, 3, 1);
matrix.set(0, 4, 1);
matrix.set(0, 5, 0);
matrix.set(0, 6, 1);
matrix.set(0, 7, 0);
matrix.set(0, 8, 0);
matrix.set(0, 9, 0);
matrix.set(0, 10, 0);
// Vertical 1011101.
matrix = new ByteMatrix(1, 7);
matrix.set(0, 0, 1);
matrix.set(0, 1, 0);
matrix.set(0, 2, 1);
matrix.set(0, 3, 1);
matrix.set(0, 4, 1);
matrix.set(0, 5, 0);
matrix.set(0, 6, 1);
assertEquals(0, MaskUtil.applyMaskPenaltyRule3(matrix));
}
@Test
public void testApplyMaskPenaltyRule4() {
// Dark cell ratio = 0%
ByteMatrix matrix = new ByteMatrix(1, 1);
matrix.set(0, 0, 0);
assertEquals(100, MaskUtil.applyMaskPenaltyRule4(matrix));
// Dark cell ratio = 5%
matrix = new ByteMatrix(2, 1);
matrix.set(0, 0, 0);
matrix.set(0, 0, 1);
assertEquals(0, MaskUtil.applyMaskPenaltyRule4(matrix));
// Dark cell ratio = 66.67%
matrix = new ByteMatrix(6, 1);
matrix.set(0, 0, 0);
matrix.set(1, 0, 1);
matrix.set(2, 0, 1);
matrix.set(3, 0, 1);
matrix.set(4, 0, 1);
matrix.set(5, 0, 0);
assertEquals(30, MaskUtil.applyMaskPenaltyRule4(matrix));
}
private static boolean testGetDataMaskBitInternal(int maskPattern, int[][] expected) {
for (int x = 0; x < 6; ++x) {
for (int y = 0; y < 6; ++y) {
if ((expected[y][x] == 1) != MaskUtil.getDataMaskBit(maskPattern, x, y)) {
return false;
}
}
}
return true;
}
// See mask patterns on the page 43 of JISX0510:2004.
@Test
public void testGetDataMaskBit() {
int[][] mask0 = {
{1, 0, 1, 0, 1, 0},
{0, 1, 0, 1, 0, 1},
{1, 0, 1, 0, 1, 0},
{0, 1, 0, 1, 0, 1},
{1, 0, 1, 0, 1, 0},
{0, 1, 0, 1, 0, 1},
};
assertTrue(testGetDataMaskBitInternal(0, mask0));
int[][] mask1 = {
{1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1},
{0, 0, 0, 0, 0, 0},
};
assertTrue(testGetDataMaskBitInternal(1, mask1));
int[][] mask2 = {
{1, 0, 0, 1, 0, 0},
{1, 0, 0, 1, 0, 0},
{1, 0, 0, 1, 0, 0},
{1, 0, 0, 1, 0, 0},
{1, 0, 0, 1, 0, 0},
{1, 0, 0, 1, 0, 0},
};
assertTrue(testGetDataMaskBitInternal(2, mask2));
int[][] mask3 = {
{1, 0, 0, 1, 0, 0},
{0, 0, 1, 0, 0, 1},
{0, 1, 0, 0, 1, 0},
{1, 0, 0, 1, 0, 0},
{0, 0, 1, 0, 0, 1},
{0, 1, 0, 0, 1, 0},
};
assertTrue(testGetDataMaskBitInternal(3, mask3));
int[][] mask4 = {
{1, 1, 1, 0, 0, 0},
{1, 1, 1, 0, 0, 0},
{0, 0, 0, 1, 1, 1},
{0, 0, 0, 1, 1, 1},
{1, 1, 1, 0, 0, 0},
{1, 1, 1, 0, 0, 0},
};
assertTrue(testGetDataMaskBitInternal(4, mask4));
int[][] mask5 = {
{1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0},
{1, 0, 0, 1, 0, 0},
{1, 0, 1, 0, 1, 0},
{1, 0, 0, 1, 0, 0},
{1, 0, 0, 0, 0, 0},
};
assertTrue(testGetDataMaskBitInternal(5, mask5));
int[][] mask6 = {
{1, 1, 1, 1, 1, 1},
{1, 1, 1, 0, 0, 0},
{1, 1, 0, 1, 1, 0},
{1, 0, 1, 0, 1, 0},
{1, 0, 1, 1, 0, 1},
{1, 0, 0, 0, 1, 1},
};
assertTrue(testGetDataMaskBitInternal(6, mask6));
int[][] mask7 = {
{1, 0, 1, 0, 1, 0},
{0, 0, 0, 1, 1, 1},
{1, 0, 0, 0, 1, 1},
{0, 1, 0, 1, 0, 1},
{1, 1, 1, 0, 0, 0},
{0, 1, 1, 1, 0, 0},
};
assertTrue(testGetDataMaskBitInternal(7, mask7));
}
}

View File

@@ -0,0 +1,311 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.encoder;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitArray;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Version;
import org.junit.Assert;
import org.junit.Test;
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author mysen@google.com (Chris Mysen) - ported from C++
*/
public final class MatrixUtilTestCase extends Assert {
@Test
public void testToString() {
ByteMatrix array = new ByteMatrix(3, 3);
array.set(0, 0, 0);
array.set(1, 0, 1);
array.set(2, 0, 0);
array.set(0, 1, 1);
array.set(1, 1, 0);
array.set(2, 1, 1);
array.set(0, 2, -1);
array.set(1, 2, -1);
array.set(2, 2, -1);
String expected = " 0 1 0\n" + " 1 0 1\n" + " \n";
assertEquals(expected, array.toString());
}
@Test
public void testClearMatrix() {
ByteMatrix matrix = new ByteMatrix(2, 2);
MatrixUtil.clearMatrix(matrix);
assertEquals(-1, matrix.get(0, 0));
assertEquals(-1, matrix.get(1, 0));
assertEquals(-1, matrix.get(0, 1));
assertEquals(-1, matrix.get(1, 1));
}
@Test
public void testEmbedBasicPatterns1() throws WriterException {
// Version 1.
ByteMatrix matrix = new ByteMatrix(21, 21);
MatrixUtil.clearMatrix(matrix);
MatrixUtil.embedBasicPatterns(Version.getVersionForNumber(1), matrix);
String expected =
" 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 \n" +
" 0 \n" +
" 1 \n" +
" 0 \n" +
" 1 \n" +
" 0 0 0 0 0 0 0 0 1 \n" +
" 1 1 1 1 1 1 1 0 \n" +
" 1 0 0 0 0 0 1 0 \n" +
" 1 0 1 1 1 0 1 0 \n" +
" 1 0 1 1 1 0 1 0 \n" +
" 1 0 1 1 1 0 1 0 \n" +
" 1 0 0 0 0 0 1 0 \n" +
" 1 1 1 1 1 1 1 0 \n";
assertEquals(expected, matrix.toString());
}
@Test
public void testEmbedBasicPatterns2() throws WriterException {
// Version 2. Position adjustment pattern should apppear at right
// bottom corner.
ByteMatrix matrix = new ByteMatrix(25, 25);
MatrixUtil.clearMatrix(matrix);
MatrixUtil.embedBasicPatterns(Version.getVersionForNumber(2), matrix);
String expected =
" 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1\n" +
" 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" +
" 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 \n" +
" 0 \n" +
" 1 \n" +
" 0 \n" +
" 1 \n" +
" 0 \n" +
" 1 \n" +
" 0 \n" +
" 1 1 1 1 1 1 \n" +
" 0 0 0 0 0 0 0 0 1 1 0 0 0 1 \n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 \n" +
" 1 0 0 0 0 0 1 0 1 0 0 0 1 \n" +
" 1 0 1 1 1 0 1 0 1 1 1 1 1 \n" +
" 1 0 1 1 1 0 1 0 \n" +
" 1 0 1 1 1 0 1 0 \n" +
" 1 0 0 0 0 0 1 0 \n" +
" 1 1 1 1 1 1 1 0 \n";
assertEquals(expected, matrix.toString());
}
@Test
public void testEmbedTypeInfo() throws WriterException {
// Type info bits = 100000011001110.
ByteMatrix matrix = new ByteMatrix(21, 21);
MatrixUtil.clearMatrix(matrix);
MatrixUtil.embedTypeInfo(ErrorCorrectionLevel.M, 5, matrix);
String expected =
" 0 \n" +
" 1 \n" +
" 1 \n" +
" 1 \n" +
" 0 \n" +
" 0 \n" +
" \n" +
" 1 \n" +
" 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0\n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" 0 \n" +
" 0 \n" +
" 0 \n" +
" 0 \n" +
" 0 \n" +
" 0 \n" +
" 1 \n";
assertEquals(expected, matrix.toString());
}
@Test
public void testEmbedVersionInfo() throws WriterException {
// Version info bits = 000111 110010 010100
// Actually, version 7 QR Code has 45x45 matrix but we use 21x21 here
// since 45x45 matrix is too big to depict.
ByteMatrix matrix = new ByteMatrix(21, 21);
MatrixUtil.clearMatrix(matrix);
MatrixUtil.maybeEmbedVersionInfo(Version.getVersionForNumber(7), matrix);
String expected =
" 0 0 1 \n" +
" 0 1 0 \n" +
" 0 1 0 \n" +
" 0 1 1 \n" +
" 1 1 1 \n" +
" 0 0 0 \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" 0 0 0 0 1 0 \n" +
" 0 1 1 1 1 0 \n" +
" 1 0 0 1 1 0 \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n" +
" \n";
assertEquals(expected, matrix.toString());
}
@Test
public void testEmbedDataBits() throws WriterException {
// Cells other than basic patterns should be filled with zero.
ByteMatrix matrix = new ByteMatrix(21, 21);
MatrixUtil.clearMatrix(matrix);
MatrixUtil.embedBasicPatterns(Version.getVersionForNumber(1), matrix);
BitArray bits = new BitArray();
MatrixUtil.embedDataBits(bits, -1, matrix);
String expected =
" 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 0 0 0 0 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" +
" 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
assertEquals(expected, matrix.toString());
}
@Test
public void testBuildMatrix() throws WriterException {
// From http://www.swetake.com/qr/qr7.html
char[] bytes = {32, 65, 205, 69, 41, 220, 46, 128, 236,
42, 159, 74, 221, 244, 169, 239, 150, 138,
70, 237, 85, 224, 96, 74, 219 , 61};
BitArray bits = new BitArray();
for (char c: bytes) {
bits.appendBits(c, 8);
}
ByteMatrix matrix = new ByteMatrix(21, 21);
MatrixUtil.buildMatrix(bits,
ErrorCorrectionLevel.H,
Version.getVersionForNumber(1), // Version 1
3, // Mask pattern 3
matrix);
String expected =
" 1 1 1 1 1 1 1 0 0 1 1 0 0 0 1 1 1 1 1 1 1\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1\n" +
" 1 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1\n" +
" 1 0 1 1 1 0 1 0 1 1 0 0 1 0 1 0 1 1 1 0 1\n" +
" 1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 0 1\n" +
" 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0\n" +
" 0 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1 0 0 0 0\n" +
" 1 0 1 0 1 0 0 0 0 0 1 1 1 0 0 1 0 1 1 1 0\n" +
" 1 1 1 1 0 1 1 0 1 0 1 1 1 0 0 1 1 1 0 1 0\n" +
" 1 0 1 0 1 1 0 1 1 1 0 0 1 1 1 0 0 1 0 1 0\n" +
" 0 0 1 0 0 1 1 1 0 0 0 0 0 0 1 0 1 1 1 1 1\n" +
" 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 1 0 1 1\n" +
" 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 0 1 0 1 1 0\n" +
" 1 0 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0\n" +
" 1 0 1 1 1 0 1 0 0 1 0 0 1 1 0 0 1 0 0 1 1\n" +
" 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 0 0 1 1 1 0\n" +
" 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n" +
" 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n";
assertEquals(expected, matrix.toString());
}
@Test
public void testFindMSBSet() {
assertEquals(0, MatrixUtil.findMSBSet(0));
assertEquals(1, MatrixUtil.findMSBSet(1));
assertEquals(8, MatrixUtil.findMSBSet(0x80));
assertEquals(32, MatrixUtil.findMSBSet(0x80000000));
}
@Test
public void testCalculateBCHCode() {
// Encoding of type information.
// From Appendix C in JISX0510:2004 (p 65)
assertEquals(0xdc, MatrixUtil.calculateBCHCode(5, 0x537));
// From http://www.swetake.com/qr/qr6.html
assertEquals(0x1c2, MatrixUtil.calculateBCHCode(0x13, 0x537));
// From http://www.swetake.com/qr/qr11.html
assertEquals(0x214, MatrixUtil.calculateBCHCode(0x1b, 0x537));
// Encoding of version information.
// From Appendix D in JISX0510:2004 (p 68)
assertEquals(0xc94, MatrixUtil.calculateBCHCode(7, 0x1f25));
assertEquals(0x5bc, MatrixUtil.calculateBCHCode(8, 0x1f25));
assertEquals(0xa99, MatrixUtil.calculateBCHCode(9, 0x1f25));
assertEquals(0x4d3, MatrixUtil.calculateBCHCode(10, 0x1f25));
assertEquals(0x9a6, MatrixUtil.calculateBCHCode(20, 0x1f25));
assertEquals(0xd75, MatrixUtil.calculateBCHCode(30, 0x1f25));
assertEquals(0xc69, MatrixUtil.calculateBCHCode(40, 0x1f25));
}
// We don't test a lot of cases in this function since we've already
// tested them in TEST(calculateBCHCode).
@Test
public void testMakeVersionInfoBits() throws WriterException {
// From Appendix D in JISX0510:2004 (p 68)
BitArray bits = new BitArray();
MatrixUtil.makeVersionInfoBits(Version.getVersionForNumber(7), bits);
assertEquals(" ...XXXXX ..X..X.X ..", bits.toString());
}
// We don't test a lot of cases in this function since we've already
// tested them in TEST(calculateBCHCode).
@Test
public void testMakeTypeInfoInfoBits() throws WriterException {
// From Appendix C in JISX0510:2004 (p 65)
BitArray bits = new BitArray();
MatrixUtil.makeTypeInfoBits(ErrorCorrectionLevel.M, 5, bits);
assertEquals(" X......X X..XXX.", bits.toString());
}
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.encoder;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Mode;
import com.google.zxing.qrcode.decoder.Version;
import org.junit.Assert;
import org.junit.Test;
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author mysen@google.com (Chris Mysen) - ported from C++
*/
public final class QRCodeTestCase extends Assert {
@Test
public void test() {
QRCode qrCode = new QRCode();
// First, test simple setters and getters.
// We use numbers of version 7-H.
qrCode.setMode(Mode.BYTE);
qrCode.setECLevel(ErrorCorrectionLevel.H);
qrCode.setVersion(Version.getVersionForNumber(7));
qrCode.setMaskPattern(3);
assertSame(Mode.BYTE, qrCode.getMode());
assertSame(ErrorCorrectionLevel.H, qrCode.getECLevel());
assertEquals(7, qrCode.getVersion().getVersionNumber());
assertEquals(3, qrCode.getMaskPattern());
// Prepare the matrix.
ByteMatrix matrix = new ByteMatrix(45, 45);
// Just set bogus zero/one values.
for (int y = 0; y < 45; ++y) {
for (int x = 0; x < 45; ++x) {
matrix.set(x, y, (y + x) % 2);
}
}
// Set the matrix.
qrCode.setMatrix(matrix);
assertSame(matrix, qrCode.getMatrix());
}
@Test
public void testToString1() {
QRCode qrCode = new QRCode();
String expected =
"<<\n" +
" mode: null\n" +
" ecLevel: null\n" +
" version: null\n" +
" maskPattern: -1\n" +
" matrix: null\n" +
">>\n";
assertEquals(expected, qrCode.toString());
}
@Test
public void testToString2() {
QRCode qrCode = new QRCode();
qrCode.setMode(Mode.BYTE);
qrCode.setECLevel(ErrorCorrectionLevel.H);
qrCode.setVersion(Version.getVersionForNumber(1));
qrCode.setMaskPattern(3);
ByteMatrix matrix = new ByteMatrix(21, 21);
for (int y = 0; y < 21; ++y) {
for (int x = 0; x < 21; ++x) {
matrix.set(x, y, (y + x) % 2);
}
}
qrCode.setMatrix(matrix);
String expected = "<<\n" +
" mode: BYTE\n" +
" ecLevel: H\n" +
" version: 1\n" +
" maskPattern: 3\n" +
" matrix:\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
" 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1\n" +
" 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0\n" +
">>\n";
assertEquals(expected, qrCode.toString());
}
@Test
public void testIsValidMaskPattern() {
assertFalse(QRCode.isValidMaskPattern(-1));
assertTrue(QRCode.isValidMaskPattern(0));
assertTrue(QRCode.isValidMaskPattern(7));
assertFalse(QRCode.isValidMaskPattern(8));
}
}

0
src/qrcode/mod.rs Normal file
View File