From f4af02bb24abdfbd39e8a19e2114fadb6f6ef2fa Mon Sep 17 00:00:00 2001 From: Dominik Stadler Date: Thu, 14 Mar 2024 13:20:47 +0000 Subject: [PATCH] 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 --- .../org/apache/poi/ss/util/SheetUtil.java | 21 ++- .../org/apache/poi/ss/util/TestSheetUtil.java | 166 ++++++++++++++++++ 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/poi/src/main/java/org/apache/poi/ss/util/SheetUtil.java b/poi/src/main/java/org/apache/poi/ss/util/SheetUtil.java index cc5abe81b1..f90d229895 100644 --- a/poi/src/main/java/org/apache/poi/ss/util/SheetUtil.java +++ b/poi/src/main/java/org/apache/poi/ss/util/SheetUtil.java @@ -96,13 +96,13 @@ public class SheetUtil { /** * 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 * 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")); /** @@ -490,4 +490,21 @@ public class SheetUtil { // live within any merged regions 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; + } } diff --git a/poi/src/test/java/org/apache/poi/ss/util/TestSheetUtil.java b/poi/src/test/java/org/apache/poi/ss/util/TestSheetUtil.java index b63460596c..4836b345fa 100644 --- a/poi/src/test/java/org/apache/poi/ss/util/TestSheetUtil.java +++ b/poi/src/test/java/org/apache/poi/ss/util/TestSheetUtil.java @@ -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.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; 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.mockito.Mockito.mock; +import java.awt.font.FontRenderContext; import java.io.IOException; 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.Sheet; import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.util.ExceptionUtil; import org.junit.jupiter.api.Test; +import org.mockito.stubbing.Answer; /** * Tests SheetUtil. * * @see org.apache.poi.ss.util.SheetUtil */ +@SuppressWarnings("deprecation") final class TestSheetUtil { @Test 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"); } } + + @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) 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) 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) 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) 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); + } + } } -- 2.39.5