PagesConfigTest.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.tika.parser.pages;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.ParseRecord;
import org.apache.tika.parser.inference.InputKind;
import org.apache.tika.renderer.ImageType;
import org.apache.tika.renderer.RenderSettings;
public class PagesConfigTest {
@Test
public void testDefaultsAreComplete() {
PagesConfig d = PagesConfig.defaults();
assertEquals(TextPolicy.AUTO, d.getText());
assertEquals(300, d.getRender().getDpi());
assertEquals(-1, d.getOcr().getMaxPages());
assertEquals(10, d.getOcr().getAuto().getTotalCharsPerPage());
assertEquals(List.of(InputKind.TEXT), d.getInference());
assertFalse(d.getEmit().getEnabled());
assertTrue(d.emitsSameImage());
}
@Test
public void testLayersFoldPerField() throws Exception {
PagesConfig deployment = new PagesConfig();
RenderSettings render = new RenderSettings();
render.setDpi(200);
deployment.setRender(render);
deployment.setText(TextPolicy.EXTRACT);
PagesConfig parser = new PagesConfig();
PagesConfig.Emit emit = new PagesConfig.Emit();
emit.setEnabled(true);
emit.setMaxPages(1);
RenderSettings emitted = new RenderSettings();
emitted.setImageType(ImageType.RGB);
emit.setRender(emitted);
parser.setEmit(emit);
PagesConfig request = new PagesConfig();
PagesConfig.Emit requestEmit = new PagesConfig.Emit();
RenderSettings requestEmitted = new RenderSettings();
requestEmitted.setMaxWidth(256);
requestEmit.setRender(requestEmitted);
request.setEmit(requestEmit);
ParseContext context = new ParseContext();
context.set(PagesConfig.class, deployment);
PagesConfig effective = PagesConfig.resolve(context, parser, request);
assertEquals(TextPolicy.EXTRACT, effective.getText());
assertEquals(200, effective.getRender().getDpi());
assertTrue(effective.getEmit().getEnabled());
assertEquals(1, effective.getEmit().getMaxPages());
RenderSettings out = effective.emittedRender();
// nested overlays accumulate: the parser's imageType and the request's box both hold
assertEquals(ImageType.RGB, out.getImageType());
assertEquals(256, out.getMaxWidth());
assertEquals(200, out.getDpi());
assertFalse(effective.emitsSameImage());
// the layers are untouched
assertNull(parser.getText());
assertNull(request.getRender());
assertEquals(TextPolicy.EXTRACT, deployment.getText());
}
@Test
public void testNoContextAndNoOverlaysIsDefaults() throws Exception {
PagesConfig effective = PagesConfig.resolve(new ParseContext());
assertEquals(TextPolicy.AUTO, effective.getText());
assertEquals(300, effective.getRender().getDpi());
PagesConfig withNull = PagesConfig.resolve(null, (PagesConfig) null);
assertEquals(TextPolicy.AUTO, withNull.getText());
}
@Test
public void testEmitApplies() {
PagesConfig.Emit emit = PagesConfig.Emit.defaults();
ParseContext context = new ParseContext();
Metadata top = new Metadata();
assertFalse(emit.applies(top, context));
emit.setEnabled(true);
assertTrue(emit.applies(top, context));
assertTrue(emit.applies(top, null), "no context is the top level");
emit.setResourceTypes(Set.of("THUMBNAIL"));
assertFalse(emit.applies(top, context));
Metadata thumbnail = new Metadata();
thumbnail.set(TikaCoreProperties.EMBEDDED_RESOURCE_TYPE, "THUMBNAIL");
assertTrue(emit.applies(thumbnail, context));
assertTrue(emit.withinBudget(50));
emit.setMaxPages(1);
assertTrue(emit.withinBudget(1));
assertFalse(emit.withinBudget(2));
}
/** maxDepth reads the extractor's embedding depth: 0 is the top-level document only. */
@Test
public void testEmitMaxDepth() {
PagesConfig.Emit emit = PagesConfig.Emit.defaults();
emit.setEnabled(true);
ParseContext context = new ParseContext();
ParseRecord record = ParseRecord.newInstance(context);
context.set(ParseRecord.class, record);
Metadata attachment = new Metadata();
record.enterEmbedded();
assertTrue(emit.applies(attachment, context), "-1 is any depth");
emit.setMaxDepth(0);
assertFalse(emit.applies(attachment, context), "an attachment is depth 1");
record.exitEmbedded();
assertTrue(emit.applies(new Metadata(), context), "the top-level document is depth 0");
emit.setMaxDepth(1);
record.enterEmbedded();
assertTrue(emit.applies(attachment, context));
record.enterEmbedded();
assertFalse(emit.applies(attachment, context), "depth 2");
assertThrows(IllegalArgumentException.class, () -> emit.setMaxDepth(-2));
}
/** An overlay applied to a config never shares objects with the config it came from. */
@Test
public void testOverlayIsCopied() {
PagesConfig mine = new PagesConfig();
mine.ocr().auto().setTotalCharsPerPage(5);
mine.emit().render().setDpi(20);
PagesConfig applied = new PagesConfig().over(mine);
mine.ocr().auto().setTotalCharsPerPage(99);
mine.emit().render().setDpi(99);
assertEquals(5, applied.getOcr().getAuto().getTotalCharsPerPage());
assertEquals(20, applied.getEmit().getRender().getDpi());
}
@Test
public void testValidation() {
PagesConfig config = new PagesConfig();
assertThrows(IllegalArgumentException.class,
() -> config.setInference(List.of(InputKind.IMAGES)));
PagesConfig.Emit emit = new PagesConfig.Emit();
assertThrows(IllegalArgumentException.class, () -> emit.setResourceTypes(Set.of("THUMB")));
assertThrows(IllegalArgumentException.class, () -> emit.setMaxPages(0));
PagesConfig.Ocr ocr = new PagesConfig.Ocr();
assertThrows(IllegalArgumentException.class, () -> ocr.setMaxPages(-3));
}
private static ParseContext requestFor(String componentName, PagesConfig operatorTop) {
ParseContext context = new ParseContext();
// the parser's block came over the wire
context.setJsonConfig(componentName, "{}", false);
context.set(PagesConfig.OperatorPages.class, new PagesConfig.OperatorPages(operatorTop));
return context;
}
@Test
public void testRequestMayNotRaiseRenderLimits() throws Exception {
PagesConfig request = new PagesConfig();
request.render().setDpi(1200);
request.render().setMaxImagePixels((long) RenderSettings.NO_LIMIT);
request.emit().render().setDpi(2400);
PagesConfig pages = PagesConfig.resolve(requestFor("x-parser", null), "x-parser",
null, request);
assertEquals(300, pages.getRender().getDpi());
assertEquals(100_000_000L, pages.getRender().getMaxImagePixels());
assertEquals(300, pages.emittedRender().getDpi());
}
@Test
public void testOperatorLayersAreTheCeiling() throws Exception {
PagesConfig operatorTop = new PagesConfig();
operatorTop.render().setDpi(150);
// this parser's operator overlay allows more than the top-level block
PagesConfig operatorOverlay = new PagesConfig();
operatorOverlay.render().setDpi(600);
PagesConfig request = new PagesConfig();
request.render().setDpi(1200);
PagesConfig pages = PagesConfig.resolve(requestFor("x-parser", operatorTop), "x-parser",
operatorOverlay, request);
assertEquals(600, pages.getRender().getDpi());
request.render().setDpi(96);
pages = PagesConfig.resolve(requestFor("x-parser", operatorTop), "x-parser",
operatorOverlay, request);
assertEquals(96, pages.getRender().getDpi());
}
@Test
public void testNoClampOutsideTheWorker() throws Exception {
ParseContext context = new ParseContext();
context.setJsonConfig("x-parser", "{}", false);
PagesConfig request = new PagesConfig();
request.render().setDpi(1200);
assertEquals(1200, PagesConfig.resolve(context, "x-parser", null, request)
.getRender().getDpi());
}
}