Bug 68778: Verify "ignoreMissingFontSystem" for SheetUtil.getDefaultCharWidthAsFloat()

This functionality saw some regressions at times and thus
should be verified via unit-tests. 

We can simulate failures in the low-level font-system by 
mocking the FontRenderContext and triggering exceptions
from there.

This hopefully now verifies behavior of 
SheetUtil.getDefaultCharWidthAsFloat() both with 
"ignoreMissingFontSystem" enabled and disabled.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1916297 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Dominik Stadler 2024-03-14 13:20:47 +00:00
parent 08436ddf7f
commit f4af02bb24
2 changed files with 185 additions and 2 deletions

View File

@ -96,13 +96,13 @@ public class SheetUtil {
/** /**
* drawing context to measure text * drawing context to measure text
*/ */
private static final FontRenderContext fontRenderContext = new FontRenderContext(null, true, true); private static FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
/** /**
* A system property which can be enabled to not fail when the * A system property which can be enabled to not fail when the
* font-system is not available on the current machine * font-system is not available on the current machine
*/ */
private static final boolean ignoreMissingFontSystem = private static boolean ignoreMissingFontSystem =
Boolean.parseBoolean(System.getProperty("org.apache.poi.ss.ignoreMissingFontSystem")); Boolean.parseBoolean(System.getProperty("org.apache.poi.ss.ignoreMissingFontSystem"));
/** /**
@ -490,4 +490,21 @@ public class SheetUtil {
// live within any merged regions // live within any merged regions
return null; return null;
} }
// Getters/Setters are available to allow in-depth testing
protected static boolean isIgnoreMissingFontSystem() {
return ignoreMissingFontSystem;
}
protected static void setIgnoreMissingFontSystem(boolean value) {
ignoreMissingFontSystem = value;
}
protected static FontRenderContext getFontRenderContext() {
return fontRenderContext;
}
protected static void setFontRenderContext(FontRenderContext fontRenderContext) {
SheetUtil.fontRenderContext = fontRenderContext;
}
} }

View File

@ -19,10 +19,14 @@ package org.apache.poi.ss.util;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull; 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 static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import java.awt.font.FontRenderContext;
import java.io.IOException; import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@ -31,13 +35,16 @@ import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.ExceptionUtil;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.stubbing.Answer;
/** /**
* Tests SheetUtil. * Tests SheetUtil.
* *
* @see org.apache.poi.ss.util.SheetUtil * @see org.apache.poi.ss.util.SheetUtil
*/ */
@SuppressWarnings("deprecation")
final class TestSheetUtil { final class TestSheetUtil {
@Test @Test
void testCellWithMerges() throws Exception { void testCellWithMerges() throws Exception {
@ -220,4 +227,163 @@ final class TestSheetUtil {
assertEquals(-1.0, SheetUtil.getColumnWidth(sheet, 0, true, 1, 2), 0.01, "Not having any width for rows with all empty cells"); assertEquals(-1.0, SheetUtil.getColumnWidth(sheet, 0, true, 1, 2), 0.01, "Not having any width for rows with all empty cells");
} }
} }
@Test
void testIsFatal() {
assertFalse(ExceptionUtil.isFatal(new RuntimeException()),
"RuntimeException should not be regarded as 'fatal'");
assertTrue(ExceptionUtil.isFatal(new LinkageError()),
"LinkageError should not be regarded as 'fatal'");
assertTrue(ExceptionUtil.isFatal(new UnsatisfiedLinkError()),
"UnsatisfiedLinkError should not be regarded as 'fatal'");
}
@Test
void testGetCharWidthWithFonts() throws IOException {
// verify that normal call returns a useful value
// (may fail if font-system is missing, but then many other tests fail as well)
try (Workbook wb = new HSSFWorkbook()) {
final float width = SheetUtil.getDefaultCharWidthAsFloat(wb);
assertTrue(width > 0,
"Should get some useful char width, but had: " + width);
}
}
@Test
void testGetCharWidthWithInvalidFont() throws IOException {
// verify that a call with an unknown font-name returns a useful value
// (likely the font-system falls back to a default font here)
// (may fail if font-system is missing, but then many other tests fail as well)
try (Workbook wb = new HSSFWorkbook()) {
wb.getFontAt(0).setFontName("invalid font");
final float width = SheetUtil.getDefaultCharWidthAsFloat(wb);
assertTrue(width > 0,
"Should get some useful char width, but had: " + width);
}
}
@Test
void testGetCharWidthWithIgnoreEnabled() throws IOException {
boolean previous = SheetUtil.isIgnoreMissingFontSystem();
SheetUtil.setIgnoreMissingFontSystem(true);
// just verify that enabling the setting "ignoreMissingFontSystem"
// does not cause unexpected results
try (Workbook wb = new HSSFWorkbook()) {
final float width = SheetUtil.getDefaultCharWidthAsFloat(wb);
assertTrue(width > 0,
"Should get some useful char width, but had: " + width);
} finally {
// restore value
SheetUtil.setIgnoreMissingFontSystem(previous);
}
}
@Test
void testGetCharWidthWithMockedException() throws IOException {
FontRenderContext prevCtx = SheetUtil.getFontRenderContext();
final FontRenderContext ctx = mock(FontRenderContext.class, (Answer<Object>) invocation -> {
// simulate an exception in some of the calls to java.awt packages
throw new IllegalArgumentException("Test runtime exception");
});
SheetUtil.setFontRenderContext(ctx);
boolean previous = SheetUtil.isIgnoreMissingFontSystem();
SheetUtil.setIgnoreMissingFontSystem(false);
// verify that a RuntimeException in the font-system is
// thrown when "ignoreMissingFontSystem" is disabled
try (Workbook wb = new HSSFWorkbook()) {
assertThrows(IllegalArgumentException.class,
() -> SheetUtil.getDefaultCharWidthAsFloat(wb),
"Should get an exception because ignoreMissingFontSystem = false");
} finally {
// restore values
SheetUtil.setFontRenderContext(prevCtx);
SheetUtil.setIgnoreMissingFontSystem(previous);
}
}
@Test
void testGetCharWidthWithMockedUnsatisfiedLinkError() throws IOException {
FontRenderContext prevCtx = SheetUtil.getFontRenderContext();
final FontRenderContext ctx = mock(FontRenderContext.class, (Answer<Object>) invocation -> {
// simulate an exception in some of the calls to java.awt packages
throw new UnsatisfiedLinkError("Test runtime exception");
});
SheetUtil.setFontRenderContext(ctx);
boolean previous = SheetUtil.isIgnoreMissingFontSystem();
SheetUtil.setIgnoreMissingFontSystem(false);
// verify that a UnsatisfiedLinkError in the font-system is
// thrown when "ignoreMissingFontSystem" is disabled
try (Workbook wb = new HSSFWorkbook()) {
assertThrows(UnsatisfiedLinkError.class,
() -> SheetUtil.getDefaultCharWidthAsFloat(wb),
"Should get an exception because ignoreMissingFontSystem = false");
} finally {
// restore values
SheetUtil.setFontRenderContext(prevCtx);
SheetUtil.setIgnoreMissingFontSystem(previous);
}
}
@Test
void testGetCharWidthWithMockedExceptionAndIgnore() throws IOException {
FontRenderContext prevCtx = SheetUtil.getFontRenderContext();
final FontRenderContext ctx = mock(FontRenderContext.class, (Answer<Object>) invocation -> {
// simulate an exception in some of the calls to java.awt packages
throw new IllegalArgumentException("Test runtime exception");
});
SheetUtil.setFontRenderContext(ctx);
boolean previous = SheetUtil.isIgnoreMissingFontSystem();
SheetUtil.setIgnoreMissingFontSystem(true);
// verify that a RuntimeException in the font-system is
// ignored when "ignoreMissingFontSystem" is enabled
try (Workbook wb = new HSSFWorkbook()) {
final float width = SheetUtil.getDefaultCharWidthAsFloat(wb);
assertEquals(SheetUtil.DEFAULT_CHAR_WIDTH, width,
"Should get default char width because ignoreMissingFontSystem = true, but had: " + width);
} finally {
// restore values
SheetUtil.setFontRenderContext(prevCtx);
SheetUtil.setIgnoreMissingFontSystem(previous);
}
}
@Test
void testGetCharWidthWithMockedUnsatisfiedLinkErrorAndIgnore() throws IOException {
FontRenderContext prevCtx = SheetUtil.getFontRenderContext();
final FontRenderContext ctx = mock(FontRenderContext.class, (Answer<Object>) invocation -> {
// simulate an exception in some of the calls to java.awt packages
throw new UnsatisfiedLinkError("Test runtime exception");
});
SheetUtil.setFontRenderContext(ctx);
boolean previous = SheetUtil.isIgnoreMissingFontSystem();
SheetUtil.setIgnoreMissingFontSystem(true);
// verify that a UnsatisfiedLinkError in the font-system is
// ignored when "ignoreMissingFontSystem" is enabled
try (Workbook wb = new HSSFWorkbook()) {
final float width = SheetUtil.getDefaultCharWidthAsFloat(wb);
assertEquals(SheetUtil.DEFAULT_CHAR_WIDTH, width,
"Should get default char width because ignoreMissingFontSystem = true, but had: " + width);
} finally {
// restore values
SheetUtil.setFontRenderContext(prevCtx);
SheetUtil.setIgnoreMissingFontSystem(previous);
}
}
} }