暂存提交
This commit is contained in:
+52
@@ -0,0 +1,52 @@
|
||||
package com.baiyue.integration.service.ocr;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class ImageCropperTest {
|
||||
@TempDir
|
||||
Path tempDirectory;
|
||||
|
||||
@Test
|
||||
void cropsConfiguredBottomCenterRegion() throws Exception {
|
||||
Path source = createImage();
|
||||
Path target = tempDirectory.resolve("cropped/result.jpg");
|
||||
|
||||
new ImageCropper().cropBottomCenter(source, target, 0.5, 0.25, 10_000);
|
||||
|
||||
BufferedImage cropped = ImageIO.read(target.toFile());
|
||||
assertThat(cropped.getWidth()).isEqualTo(50);
|
||||
assertThat(cropped.getHeight()).isEqualTo(40);
|
||||
assertThat(new Color(cropped.getRGB(10, 10))).isEqualTo(Color.BLACK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsImageOverPixelLimit() throws Exception {
|
||||
Path source = createImage();
|
||||
assertThatThrownBy(() -> new ImageCropper()
|
||||
.cropBottomCenter(source, tempDirectory.resolve("result.jpg"), 0.5, 0.25, 100))
|
||||
.hasMessageContaining("像素超过");
|
||||
}
|
||||
|
||||
private Path createImage() throws Exception {
|
||||
BufferedImage image = new BufferedImage(100, 80, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.fillRect(0, 0, 100, 40);
|
||||
graphics.setColor(Color.BLACK);
|
||||
graphics.fillRect(0, 40, 100, 40);
|
||||
graphics.dispose();
|
||||
Path source = tempDirectory.resolve("source.png");
|
||||
ImageIO.write(image, "png", source.toFile());
|
||||
return source;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.baiyue.integration.service.ocr;
|
||||
|
||||
import com.baiyue.integration.dto.ocr.OcrCandidate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class WeightCandidateSelectorTest {
|
||||
private final WeightCandidateSelector selector = new WeightCandidateSelector();
|
||||
|
||||
@Test
|
||||
void selectsLargestNumericCandidateAndNormalizesDecimalSeparator() {
|
||||
List<OcrCandidate> candidates = List.of(
|
||||
new OcrCandidate("10:38", 0.99, 10, 10, 40, 10),
|
||||
new OcrCandidate(" 12,35 ", 0.97, 20, 30, 120, 60),
|
||||
new OcrCandidate("29", 0.99, 160, 10, 20, 10),
|
||||
new OcrCandidate("kg", 0.99, 150, 70, 30, 15));
|
||||
|
||||
WeightCandidateSelector.SelectedWeight selected = selector.select(candidates).orElseThrow();
|
||||
|
||||
assertThat(selected.weight()).isEqualByComparingTo("12.35");
|
||||
assertThat(selected.confidence()).isEqualTo(0.97);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsNonNumericCandidates() {
|
||||
assertThat(selector.select(List.of(
|
||||
new OcrCandidate("kg", 0.99, 0, 0, 20, 10),
|
||||
new OcrCandidate("10:38", 0.99, 0, 0, 20, 10)))).isEmpty();
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.baiyue.integration.service.ocr;
|
||||
|
||||
import com.baiyue.integration.config.IntegrationProperties;
|
||||
import com.baiyue.integration.dto.ocr.OcrCandidate;
|
||||
import com.baiyue.integration.dto.ocr.WeightOcrBatchRequest;
|
||||
import com.baiyue.integration.dto.ocr.WeightOcrImageResult.Status;
|
||||
import com.baiyue.integration.provider.ocr.BaiduMeterClient;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class WeightOcrBatchServiceTest {
|
||||
@TempDir
|
||||
Path tempDirectory;
|
||||
|
||||
@Test
|
||||
void completesBatchAndWritesArtifactsWithoutCallingRealProvider() throws Exception {
|
||||
Path inputRoot = Files.createDirectories(tempDirectory.resolve("input"));
|
||||
Path outputRoot = tempDirectory.resolve("output");
|
||||
Path batchInput = Files.createDirectories(inputRoot.resolve("batch-a"));
|
||||
BufferedImage image = new BufferedImage(100, 80, BufferedImage.TYPE_INT_RGB);
|
||||
for (int y = 0; y < image.getHeight(); y++) {
|
||||
for (int x = 0; x < image.getWidth(); x++) {
|
||||
image.setRGB(x, y, Color.BLACK.getRGB());
|
||||
}
|
||||
}
|
||||
ImageIO.write(image, "png", batchInput.resolve("weight.png").toFile());
|
||||
|
||||
IntegrationProperties properties = properties(inputRoot, outputRoot);
|
||||
BaiduMeterClient client = mock(BaiduMeterClient.class);
|
||||
when(client.recognize(any())).thenReturn(new BaiduMeterClient.MeterResponse(
|
||||
"{\"words_result\":[]}",
|
||||
List.of(new OcrCandidate("12.35", 0.98, 10, 10, 80, 30))));
|
||||
ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
|
||||
WeightOcrBatchService service = new WeightOcrBatchService(
|
||||
properties, new WeightOcrStoragePolicy(properties), new ImageCropper(), client,
|
||||
new WeightCandidateSelector(), objectMapper);
|
||||
|
||||
var result = service.recognize(new WeightOcrBatchRequest("batch-a", null, null, null, false));
|
||||
|
||||
assertThat(result.total()).isEqualTo(1);
|
||||
assertThat(result.recognized()).isEqualTo(1);
|
||||
assertThat(result.results().get(0).status()).isEqualTo(Status.RECOGNIZED);
|
||||
Path batchOutput = outputRoot.resolve(result.outputDirectory());
|
||||
assertThat(batchOutput.resolve("cropped/weight.jpg")).isRegularFile();
|
||||
assertThat(batchOutput.resolve("raw/weight.json")).isRegularFile();
|
||||
assertThat(batchOutput.resolve("batch-results.json")).isRegularFile();
|
||||
}
|
||||
|
||||
private IntegrationProperties properties(Path inputRoot, Path outputRoot) {
|
||||
IntegrationProperties.BaiduOcr baidu = new IntegrationProperties.BaiduOcr(
|
||||
true, "key", "secret", URI.create("https://example.com/token"),
|
||||
URI.create("https://example.com/meter"), Duration.ofSeconds(1), Duration.ofSeconds(1),
|
||||
inputRoot, outputRoot, DataSize.ofMegabytes(3), 40_000_000L,
|
||||
50, Duration.ZERO, 0);
|
||||
return new IntegrationProperties(baidu, null);
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package com.baiyue.integration.service.ocr;
|
||||
|
||||
import com.baiyue.common.core.api.ResultCode;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.integration.config.IntegrationProperties;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class WeightOcrStoragePolicyTest {
|
||||
@TempDir
|
||||
Path tempDirectory;
|
||||
|
||||
@Test
|
||||
void resolvesDirectoriesInsideConfiguredRoots() throws Exception {
|
||||
Path input = Files.createDirectories(tempDirectory.resolve("input/batch-a"));
|
||||
Path outputRoot = tempDirectory.resolve("output");
|
||||
WeightOcrStoragePolicy policy = new WeightOcrStoragePolicy(properties(input.getParent(), outputRoot));
|
||||
|
||||
WeightOcrStoragePolicy.BatchPaths paths = policy.resolve("batch-a", null, "batch-id");
|
||||
|
||||
assertThat(paths.inputDirectory()).isEqualTo(input.toRealPath());
|
||||
assertThat(paths.outputDirectory()).isEqualTo(outputRoot.resolve("batch-id").toRealPath());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInputAndOutputOutsideConfiguredRoots() throws Exception {
|
||||
Path inputRoot = Files.createDirectories(tempDirectory.resolve("input"));
|
||||
Path outputRoot = tempDirectory.resolve("output");
|
||||
Path outside = Files.createDirectories(tempDirectory.resolve("outside"));
|
||||
WeightOcrStoragePolicy policy = new WeightOcrStoragePolicy(properties(inputRoot, outputRoot));
|
||||
|
||||
assertThatThrownBy(() -> policy.resolve(outside.toString(), null, "batch-id"))
|
||||
.isInstanceOfSatisfying(BizException.class,
|
||||
exception -> assertThat(exception.getResultCode()).isEqualTo(ResultCode.FORBIDDEN));
|
||||
assertThatThrownBy(() -> policy.resolve(".", "../outside", "batch-id"))
|
||||
.isInstanceOfSatisfying(BizException.class,
|
||||
exception -> assertThat(exception.getResultCode()).isEqualTo(ResultCode.FORBIDDEN));
|
||||
}
|
||||
|
||||
private IntegrationProperties properties(Path inputRoot, Path outputRoot) {
|
||||
IntegrationProperties.BaiduOcr baidu = new IntegrationProperties.BaiduOcr(
|
||||
true, "key", "secret", URI.create("https://example.com/token"),
|
||||
URI.create("https://example.com/meter"), Duration.ofSeconds(1), Duration.ofSeconds(1),
|
||||
inputRoot, outputRoot, DataSize.ofMegabytes(3), 40_000_000L,
|
||||
50, Duration.ZERO, 0);
|
||||
return new IntegrationProperties(baidu, null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user