moving aroudn test cases for integration

This commit is contained in:
Henry Schimke
2022-08-31 13:32:56 -05:00
parent bafd0663a4
commit aae5684127
79 changed files with 0 additions and 516 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

BIN
java_test/.DS_Store vendored Normal file

Binary file not shown.

BIN
java_test/java/.DS_Store vendored Normal file

Binary file not shown.

BIN
java_test/java/com/.DS_Store vendored Normal file

Binary file not shown.

BIN
java_test/java/com/google/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/.DS_Store vendored Normal file

Binary file not shown.

BIN
src/common/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -1,357 +0,0 @@
/*
* 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.common;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.BufferedImageLuminanceSource;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.Reader;
import com.google.zxing.ReaderException;
import com.google.zxing.RXingResult;
import com.google.zxing.RXingResultMetadataType;
import org.junit.Assert;
import org.junit.Test;
import javax.imageio.ImageIO;
import java.awt.Graphics;
import java.awt.geom.AffineTransform;
import java.awt.geom.RectangularShape;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
/**
* @author Sean Owen
* @author dswitkin@google.com (Daniel Switkin)
*/
public abstract class AbstractBlackBoxTestCase extends Assert {
private static final Logger log = Logger.getLogger(AbstractBlackBoxTestCase.class.getSimpleName());
private final Path testBase;
private final Reader barcodeReader;
private final BarcodeFormat expectedFormat;
private final List<TestRXingResult> testRXingResults;
private final EnumMap<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);
public static Path buildTestBase(String testBasePathSuffix) {
// A little workaround to prevent aggravation in my IDE
Path testBase = Paths.get(testBasePathSuffix);
if (!Files.exists(testBase)) {
// try starting with 'core' since the test base is often given as the project root
testBase = Paths.get("core").resolve(testBasePathSuffix);
}
return testBase;
}
protected AbstractBlackBoxTestCase(String testBasePathSuffix,
Reader barcodeReader,
BarcodeFormat expectedFormat) {
this.testBase = buildTestBase(testBasePathSuffix);
this.barcodeReader = barcodeReader;
this.expectedFormat = expectedFormat;
testRXingResults = new ArrayList<>();
System.setProperty("java.util.logging.SimpleFormatter.format", "%4$s: %5$s%6$s%n");
}
protected final Path getTestBase() {
return testBase;
}
protected final void addTest(int mustPassCount, int tryHarderCount, float rotation) {
addTest(mustPassCount, tryHarderCount, 0, 0, rotation);
}
protected void addHint(DecodeHintType hint) {
hints.put(hint, Boolean.TRUE);
}
/**
* Adds a new test for the current directory of images.
*
* @param mustPassCount The number of images which must decode for the test to pass.
* @param tryHarderCount The number of images which must pass using the try harder flag.
* @param maxMisreads Maximum number of images which can fail due to successfully reading the wrong contents
* @param maxTryHarderMisreads Maximum number of images which can fail due to successfully
* reading the wrong contents using the try harder flag
* @param rotation The rotation in degrees clockwise to use for this test.
*/
protected final void addTest(int mustPassCount,
int tryHarderCount,
int maxMisreads,
int maxTryHarderMisreads,
float rotation) {
testRXingResults.add(new TestRXingResult(mustPassCount, tryHarderCount, maxMisreads, maxTryHarderMisreads, rotation));
}
protected final List<Path> getImageFiles() throws IOException {
assertTrue("Please download and install test images, and run from the 'core' directory", Files.exists(testBase));
List<Path> paths = new ArrayList<>();
try (DirectoryStream<Path> pathIt = Files.newDirectoryStream(testBase, "*.{jpg,jpeg,gif,png,JPG,JPEG,GIF,PNG}")) {
for (Path path : pathIt) {
paths.add(path);
}
}
return paths;
}
final Reader getReader() {
return barcodeReader;
}
@Test
public void testBlackBox() throws IOException {
assertFalse(testRXingResults.isEmpty());
List<Path> imageFiles = getImageFiles();
int testCount = testRXingResults.size();
int[] passedCounts = new int[testCount];
int[] misreadCounts = new int[testCount];
int[] tryHarderCounts = new int[testCount];
int[] tryHarderMisreadCounts = new int[testCount];
for (Path testImage : imageFiles) {
log.info(String.format("Starting %s", testImage));
BufferedImage image = ImageIO.read(testImage.toFile());
String testImageFileName = testImage.getFileName().toString();
String fileBaseName = testImageFileName.substring(0, testImageFileName.indexOf('.'));
Path expectedTextFile = testBase.resolve(fileBaseName + ".txt");
String expectedText;
if (Files.exists(expectedTextFile)) {
expectedText = readFileAsString(expectedTextFile, StandardCharsets.UTF_8);
} else {
expectedTextFile = testBase.resolve(fileBaseName + ".bin");
assertTrue(Files.exists(expectedTextFile));
expectedText = readFileAsString(expectedTextFile, StandardCharsets.ISO_8859_1);
}
Path expectedMetadataFile = testBase.resolve(fileBaseName + ".metadata.txt");
Properties expectedMetadata = new Properties();
if (Files.exists(expectedMetadataFile)) {
try (BufferedReader reader = Files.newBufferedReader(expectedMetadataFile, StandardCharsets.UTF_8)) {
expectedMetadata.load(reader);
}
}
for (int x = 0; x < testCount; x++) {
float rotation = testRXingResults.get(x).getRotation();
BufferedImage rotatedImage = rotateImage(image, rotation);
LuminanceSource source = new BufferedImageLuminanceSource(rotatedImage);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
if (decode(bitmap, rotation, expectedText, expectedMetadata, false)) {
passedCounts[x]++;
} else {
misreadCounts[x]++;
}
} catch (ReaderException ignored) {
log.fine(String.format("could not read at rotation %f", rotation));
}
try {
if (decode(bitmap, rotation, expectedText, expectedMetadata, true)) {
tryHarderCounts[x]++;
} else {
tryHarderMisreadCounts[x]++;
}
} catch (ReaderException ignored) {
log.fine(String.format("could not read at rotation %f w/TH", rotation));
}
}
}
// Print the results of all tests first
int totalFound = 0;
int totalMustPass = 0;
int totalMisread = 0;
int totalMaxMisread = 0;
for (int x = 0; x < testRXingResults.size(); x++) {
TestRXingResult testRXingResult = testRXingResults.get(x);
log.info(String.format("Rotation %d degrees:", (int) testRXingResult.getRotation()));
log.info(String.format(" %d of %d images passed (%d required)",
passedCounts[x], imageFiles.size(), testRXingResult.getMustPassCount()));
int failed = imageFiles.size() - passedCounts[x];
log.info(String.format(" %d failed due to misreads, %d not detected",
misreadCounts[x], failed - misreadCounts[x]));
log.info(String.format(" %d of %d images passed with try harder (%d required)",
tryHarderCounts[x], imageFiles.size(), testRXingResult.getTryHarderCount()));
failed = imageFiles.size() - tryHarderCounts[x];
log.info(String.format(" %d failed due to misreads, %d not detected",
tryHarderMisreadCounts[x], failed - tryHarderMisreadCounts[x]));
totalFound += passedCounts[x] + tryHarderCounts[x];
totalMustPass += testRXingResult.getMustPassCount() + testRXingResult.getTryHarderCount();
totalMisread += misreadCounts[x] + tryHarderMisreadCounts[x];
totalMaxMisread += testRXingResult.getMaxMisreads() + testRXingResult.getMaxTryHarderMisreads();
}
int totalTests = imageFiles.size() * testCount * 2;
log.info(String.format("Decoded %d images out of %d (%d%%, %d required)",
totalFound, totalTests, totalFound * 100 / totalTests, totalMustPass));
if (totalFound > totalMustPass) {
log.warning(String.format("+++ Test too lax by %d images", totalFound - totalMustPass));
} else if (totalFound < totalMustPass) {
log.warning(String.format("--- Test failed by %d images", totalMustPass - totalFound));
}
if (totalMisread < totalMaxMisread) {
log.warning(String.format("+++ Test expects too many misreads by %d images", totalMaxMisread - totalMisread));
} else if (totalMisread > totalMaxMisread) {
log.warning(String.format("--- Test had too many misreads by %d images", totalMisread - totalMaxMisread));
}
// Then run through again and assert if any failed
for (int x = 0; x < testCount; x++) {
TestRXingResult testRXingResult = testRXingResults.get(x);
String label = "Rotation " + testRXingResult.getRotation() + " degrees: Too many images failed";
assertTrue(label,
passedCounts[x] >= testRXingResult.getMustPassCount());
assertTrue("Try harder, " + label,
tryHarderCounts[x] >= testRXingResult.getTryHarderCount());
label = "Rotation " + testRXingResult.getRotation() + " degrees: Too many images misread";
assertTrue(label,
misreadCounts[x] <= testRXingResult.getMaxMisreads());
assertTrue("Try harder, " + label,
tryHarderMisreadCounts[x] <= testRXingResult.getMaxTryHarderMisreads());
}
}
private boolean decode(BinaryBitmap source,
float rotation,
String expectedText,
Map<?,?> expectedMetadata,
boolean tryHarder) throws ReaderException {
String suffix = String.format(" (%srotation: %d)", tryHarder ? "try harder, " : "", (int) rotation);
Map<DecodeHintType,Object> hints = this.hints.clone();
if (tryHarder) {
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
}
// Try in 'pure' mode mostly to exercise PURE_BARCODE code paths for exceptions;
// not expected to pass, generally
RXingResult result = null;
try {
Map<DecodeHintType,Object> pureHints = new EnumMap<>(hints);
pureHints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);
result = barcodeReader.decode(source, pureHints);
} catch (ReaderException re) {
// continue
}
if (result == null) {
result = barcodeReader.decode(source, hints);
}
if (expectedFormat != result.getBarcodeFormat()) {
log.info(String.format("Format mismatch: expected '%s' but got '%s'%s",
expectedFormat, result.getBarcodeFormat(), suffix));
return false;
}
String resultText = result.getText();
if (!expectedText.equals(resultText)) {
log.info(String.format("Content mismatch: expected '%s' but got '%s'%s",
expectedText, resultText, suffix));
return false;
}
Map<RXingResultMetadataType,?> resultMetadata = result.getRXingResultMetadata();
for (Map.Entry<?,?> metadatum : expectedMetadata.entrySet()) {
RXingResultMetadataType key = RXingResultMetadataType.valueOf(metadatum.getKey().toString());
Object expectedValue = metadatum.getValue();
Object actualValue = resultMetadata == null ? null : resultMetadata.get(key);
if (!expectedValue.equals(actualValue)) {
log.info(String.format("Metadata mismatch for key '%s': expected '%s' but got '%s'",
key, expectedValue, actualValue));
return false;
}
}
return true;
}
protected static String readFileAsString(Path file, Charset charset) throws IOException {
String stringContents = new String(Files.readAllBytes(file), charset);
if (stringContents.endsWith("\n")) {
log.info("String contents of file " + file + " end with a newline. " +
"This may not be intended and cause a test failure");
}
return stringContents;
}
protected static BufferedImage rotateImage(BufferedImage original, float degrees) {
if (degrees == 0.0f) {
return original;
}
switch (original.getType()) {
case BufferedImage.TYPE_BYTE_INDEXED:
case BufferedImage.TYPE_BYTE_BINARY:
BufferedImage argb = new BufferedImage(original.getWidth(),
original.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics g = argb.createGraphics();
g.drawImage(original, 0, 0, null);
g.dispose();
original = argb;
break;
}
double radians = Math.toRadians(degrees);
// Transform simply to find out the new bounding box (don't actually run the image through it)
AffineTransform at = new AffineTransform();
at.rotate(radians, original.getWidth() / 2.0, original.getHeight() / 2.0);
BufferedImageOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
RectangularShape r = op.getBounds2D(original);
int width = (int) Math.ceil(r.getWidth());
int height = (int) Math.ceil(r.getHeight());
// Real transform, now that we know the size of the new image and how to translate after we rotate
// to keep it centered
at = new AffineTransform();
at.rotate(radians, width / 2.0, height / 2.0);
at.translate((width - original.getWidth()) / 2.0,
(height - original.getHeight()) / 2.0);
op = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
return op.filter(original, new BufferedImage(width, height, original.getType()));
}
}

View File

@@ -1,159 +0,0 @@
/*
* 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.common;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.BufferedImageLuminanceSource;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.RXingResult;
import org.junit.Test;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
/**
* This abstract class looks for negative results, i.e. it only allows a certain number of false
* positives in images which should not decode. This helps ensure that we are not too lenient.
*
* @author dswitkin@google.com (Daniel Switkin)
*/
public abstract class AbstractNegativeBlackBoxTestCase extends AbstractBlackBoxTestCase {
private static final Logger log = Logger.getLogger(AbstractNegativeBlackBoxTestCase.class.getSimpleName());
private final List<TestRXingResult> testRXingResults;
private static final class TestRXingResult {
private final int falsePositivesAllowed;
private final float rotation;
TestRXingResult(int falsePositivesAllowed, float rotation) {
this.falsePositivesAllowed = falsePositivesAllowed;
this.rotation = rotation;
}
int getFalsePositivesAllowed() {
return falsePositivesAllowed;
}
float getRotation() {
return rotation;
}
}
// Use the multiformat reader to evaluate all decoders in the system.
protected AbstractNegativeBlackBoxTestCase(String testBasePathSuffix) {
super(testBasePathSuffix, new MultiFormatReader(), null);
testRXingResults = new ArrayList<>();
}
protected final void addTest(int falsePositivesAllowed, float rotation) {
testRXingResults.add(new TestRXingResult(falsePositivesAllowed, rotation));
}
@Override
@Test
public void testBlackBox() throws IOException {
assertFalse(testRXingResults.isEmpty());
List<Path> imageFiles = getImageFiles();
int[] falsePositives = new int[testRXingResults.size()];
for (Path testImage : imageFiles) {
log.info(String.format("Starting %s", testImage));
BufferedImage image = ImageIO.read(testImage.toFile());
if (image == null) {
throw new IOException("Could not read image: " + testImage);
}
for (int x = 0; x < testRXingResults.size(); x++) {
TestRXingResult testRXingResult = testRXingResults.get(x);
if (!checkForFalsePositives(image, testRXingResult.getRotation())) {
falsePositives[x]++;
}
}
}
int totalFalsePositives = 0;
int totalAllowed = 0;
for (int x = 0; x < testRXingResults.size(); x++) {
TestRXingResult testRXingResult = testRXingResults.get(x);
totalFalsePositives += falsePositives[x];
totalAllowed += testRXingResult.getFalsePositivesAllowed();
}
if (totalFalsePositives < totalAllowed) {
log.warning(String.format("+++ Test too lax by %d images", totalAllowed - totalFalsePositives));
} else if (totalFalsePositives > totalAllowed) {
log.warning(String.format("--- Test failed by %d images", totalFalsePositives - totalAllowed));
}
for (int x = 0; x < testRXingResults.size(); x++) {
TestRXingResult testRXingResult = testRXingResults.get(x);
log.info(String.format("Rotation %d degrees: %d of %d images were false positives (%d allowed)",
(int) testRXingResult.getRotation(), falsePositives[x], imageFiles.size(),
testRXingResult.getFalsePositivesAllowed()));
assertTrue("Rotation " + testRXingResult.getRotation() + " degrees: Too many false positives found",
falsePositives[x] <= testRXingResult.getFalsePositivesAllowed());
}
}
/**
* Make sure ZXing does NOT find a barcode in the image.
*
* @param image The image to test
* @param rotationInDegrees The amount of rotation to apply
* @return true if nothing found, false if a non-existent barcode was detected
*/
private boolean checkForFalsePositives(BufferedImage image, float rotationInDegrees) {
BufferedImage rotatedImage = rotateImage(image, rotationInDegrees);
LuminanceSource source = new BufferedImageLuminanceSource(rotatedImage);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
RXingResult result;
try {
result = getReader().decode(bitmap);
log.info(String.format("Found false positive: '%s' with format '%s' (rotation: %d)",
result.getText(), result.getBarcodeFormat(), (int) rotationInDegrees));
return false;
} catch (ReaderException re) {
// continue
}
// Try "try harder" getMode
Map<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
try {
result = getReader().decode(bitmap, hints);
log.info(String.format("Try harder found false positive: '%s' with format '%s' (rotation: %d)",
result.getText(), result.getBarcodeFormat(), (int) rotationInDegrees));
return false;
} catch (ReaderException re) {
// continue
}
return true;
}
}

BIN
tests/.DS_Store vendored Normal file

Binary file not shown.