This is an automated email from the ASF dual-hosted git repository.
delei pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fesod.git
The following commit(s) were added to refs/heads/main by this push:
new 50404dec test: add unit tests for utils (#821)
50404dec is described below
commit 50404dec010cddb1e6af4cdd4ffa34a1c2bff1dc
Author: Bengbengbalabalabeng
<[email protected]>
AuthorDate: Sun Feb 8 12:21:24 2026 +0800
test: add unit tests for utils (#821)
---
.../apache/fesod/sheet/util/BeanMapUtilsTest.java | 95 +++++
.../apache/fesod/sheet/util/ClassUtilsTest.java | 350 +++++++++++++++++
.../fesod/sheet/util/ConverterUtilsTest.java | 275 +++++++++++++
.../org/apache/fesod/sheet/util/DateUtilsTest.java | 370 ++++++++++++++++++
.../apache/fesod/sheet/util/FieldUtilsTest.java | 242 ++++++++++++
.../org/apache/fesod/sheet/util/FileUtilsTest.java | 308 +++++++++++++++
.../sheet/util/NumberDataFormatterUtilsTest.java | 110 ++++++
.../apache/fesod/sheet/util/NumberUtilsTest.java | 270 +++++++++++++
.../apache/fesod/sheet/util/ParameterUtilTest.java | 166 ++++++++
.../org/apache/fesod/sheet/util/PoiUtilsTest.java | 81 ++++
.../apache/fesod/sheet/util/SheetUtilsTest.java | 180 +++++++++
.../apache/fesod/sheet/util/WorkBookUtilTest.java | 381 ++++++++++++++++++
.../fesod/sheet/util/WriteHandlerUtilsTest.java | 424 +++++++++++++++++++++
13 files changed, 3252 insertions(+)
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/BeanMapUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/BeanMapUtilsTest.java
new file mode 100644
index 00000000..19eb919a
--- /dev/null
+++
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/BeanMapUtilsTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.fesod.sheet.util;
+
+import org.apache.fesod.shaded.cglib.beans.BeanMap;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link BeanMapUtils}
+ */
+class BeanMapUtilsTest {
+
+ public static class TestUser {
+ private String name;
+ private int age;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+ }
+
+ @Test
+ void test_create_Functionality() {
+ TestUser user = new TestUser();
+ user.setName("Fesod");
+ user.setAge(18);
+
+ BeanMap beanMap = BeanMapUtils.create(user);
+
+ Assertions.assertNotNull(beanMap);
+ Assertions.assertEquals("Fesod", beanMap.get("name"));
+ Assertions.assertEquals(18, beanMap.get("age"));
+ beanMap.put("name", "Fesod");
+ Assertions.assertEquals("Fesod", user.getName());
+ }
+
+ @Test
+ void test_create_NamingPolicy() {
+ TestUser user = new TestUser();
+ BeanMap beanMap = BeanMapUtils.create(user);
+
+ String generatedClassName = beanMap.getClass().getName();
+
+ Assertions.assertTrue(generatedClassName.contains("ByFesodCGLIB"));
+ }
+
+ @Test
+ void test_NamingPolicy_tag() {
+ BeanMapUtils.FesodSheetNamingPolicy policy =
BeanMapUtils.FesodSheetNamingPolicy.INSTANCE;
+
+ Assertions.assertDoesNotThrow(() -> {
+ java.lang.reflect.Method getTagMethod =
policy.getClass().getDeclaredMethod("getTag");
+ getTagMethod.setAccessible(true);
+ String tag = (String) getTagMethod.invoke(policy);
+ Assertions.assertEquals("ByFesodCGLIB", tag);
+ });
+ }
+
+ @Test
+ void test_create_null() {
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ BeanMapUtils.create(null);
+ });
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/ClassUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/ClassUtilsTest.java
new file mode 100644
index 00000000..da41bae8
--- /dev/null
+++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/ClassUtilsTest.java
@@ -0,0 +1,350 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.apache.fesod.shaded.cglib.beans.BeanMap;
+import org.apache.fesod.sheet.annotation.ExcelIgnore;
+import org.apache.fesod.sheet.annotation.ExcelProperty;
+import org.apache.fesod.sheet.annotation.format.DateTimeFormat;
+import org.apache.fesod.sheet.annotation.format.NumberFormat;
+import org.apache.fesod.sheet.converters.Converter;
+import org.apache.fesod.sheet.converters.string.StringStringConverter;
+import org.apache.fesod.sheet.enums.CacheLocationEnum;
+import org.apache.fesod.sheet.metadata.FieldCache;
+import org.apache.fesod.sheet.metadata.FieldWrapper;
+import org.apache.fesod.sheet.metadata.GlobalConfiguration;
+import org.apache.fesod.sheet.metadata.property.DateTimeFormatProperty;
+import org.apache.fesod.sheet.metadata.property.ExcelContentProperty;
+import org.apache.fesod.sheet.metadata.property.FontProperty;
+import org.apache.fesod.sheet.metadata.property.NumberFormatProperty;
+import org.apache.fesod.sheet.metadata.property.StyleProperty;
+import org.apache.fesod.sheet.write.metadata.holder.WriteHolder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+/**
+ * Tests {@link ClassUtils}
+ */
+@ExtendWith(MockitoExtension.class)
+class ClassUtilsTest {
+
+ @Mock
+ private WriteHolder writeHolder;
+
+ @Mock
+ private GlobalConfiguration globalConfiguration;
+
+ @BeforeEach
+ void setUp() {
+
Mockito.lenient().when(writeHolder.globalConfiguration()).thenReturn(globalConfiguration);
+ }
+
+ @AfterEach
+ void tearDown() {
+ ClassUtils.removeThreadLocalCache();
+ ClassUtils.FIELD_CACHE.clear();
+ ClassUtils.CONTENT_CACHE.clear();
+ ClassUtils.CLASS_CONTENT_CACHE.clear();
+ }
+
+ private static class SimpleEntity {
+ @ExcelProperty("Name")
+ private String name;
+
+ @ExcelProperty(value = "Age", order = 1)
+ private Integer age;
+ }
+
+ private static class ComplexEntity {
+ @ExcelProperty(index = 0)
+ private String id;
+
+ @ExcelProperty(index = 2)
+ private String name;
+
+ @ExcelProperty(order = 10)
+ private String email;
+
+ @ExcelIgnore
+ private String ignoredField;
+
+ private String noAnnotationField;
+ }
+
+ private static class FormatEntity {
+ @DateTimeFormat("yyyy-MM-dd")
+ private Date date;
+
+ @NumberFormat("#.00")
+ private Double money;
+
+ @ExcelProperty(converter = StringStringConverter.class)
+ private String customConvert;
+ }
+
+ @Test
+ void test_declaredFields_cache_memory() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.MEMORY);
+
+ FieldCache cache1 = ClassUtils.declaredFields(SimpleEntity.class,
writeHolder);
+ Assertions.assertNotNull(cache1);
+
+ Assertions.assertFalse(ClassUtils.FIELD_CACHE.isEmpty());
+
+ FieldCache cache2 = ClassUtils.declaredFields(SimpleEntity.class,
writeHolder);
+ Assertions.assertSame(cache1, cache2);
+ }
+
+ @Test
+ void test_declaredFields_cache_ThreadLocal() throws NoSuchFieldException,
IllegalAccessException {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.THREAD_LOCAL);
+
+ FieldCache cache1 = ClassUtils.declaredFields(SimpleEntity.class,
writeHolder);
+ Assertions.assertNotNull(cache1);
+
+ Assertions.assertTrue(ClassUtils.FIELD_CACHE.isEmpty());
+
+ FieldCache cache2 = ClassUtils.declaredFields(SimpleEntity.class,
writeHolder);
+ Assertions.assertSame(cache1, cache2);
+ }
+
+ @Test
+ void test_declaredFields_non_cache() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.NONE);
+
+ FieldCache cache1 = ClassUtils.declaredFields(SimpleEntity.class,
writeHolder);
+ FieldCache cache2 = ClassUtils.declaredFields(SimpleEntity.class,
writeHolder);
+
+ Assertions.assertNotSame(cache1, cache2);
+ Assertions.assertTrue(ClassUtils.FIELD_CACHE.isEmpty());
+ }
+
+ @Test
+ void test_declaredFields_ordering() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.NONE);
+
+ FieldCache fieldCache = ClassUtils.declaredFields(ComplexEntity.class,
writeHolder);
+ Map<Integer, FieldWrapper> sortedMap = fieldCache.getSortedFieldMap();
+
+ Assertions.assertTrue(sortedMap.containsKey(0));
+ Assertions.assertEquals("id", sortedMap.get(0).getFieldName());
+
+ Assertions.assertTrue(sortedMap.containsKey(2));
+ Assertions.assertEquals("name", sortedMap.get(2).getFieldName());
+
+ Assertions.assertTrue(sortedMap.containsKey(1));
+ Assertions.assertEquals("email", sortedMap.get(1).getFieldName());
+
+ Assertions.assertTrue(sortedMap.containsKey(3));
+ Assertions.assertEquals("noAnnotationField",
sortedMap.get(3).getFieldName());
+ }
+
+ @Test
+ void test_declaredFields_ignore() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.NONE);
+
+ FieldCache fieldCache = ClassUtils.declaredFields(ComplexEntity.class,
writeHolder);
+
+ boolean containsIgnored =
+ fieldCache.getSortedFieldMap().values().stream().anyMatch(f ->
"ignoredField".equals(f.getFieldName()));
+
+ Assertions.assertFalse(containsIgnored);
+ }
+
+ @Test
+ void test_declaredFields_WriteHolder_exclude() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.NONE);
+
+
Mockito.when(writeHolder.excludeColumnFieldNames()).thenReturn(Collections.singleton("name"));
+ Mockito.when(writeHolder.ignore(Mockito.anyString(),
Mockito.anyInt())).thenReturn(false);
+ Mockito.when(writeHolder.ignore(Mockito.eq("name"),
Mockito.anyInt())).thenReturn(true);
+
+ FieldCache fieldCache = ClassUtils.declaredFields(SimpleEntity.class,
writeHolder);
+
+ Map<Integer, FieldWrapper> map = fieldCache.getSortedFieldMap();
+
+ boolean hasName = map.values().stream().anyMatch(f ->
"name".equals(f.getFieldName()));
+ Assertions.assertFalse(hasName);
+
+ boolean hasAge = map.values().stream().anyMatch(f ->
"age".equals(f.getFieldName()));
+ Assertions.assertTrue(hasAge);
+ }
+
+ @Test
+ void test_declaredFields_resort() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.NONE);
+
+ Mockito.when(writeHolder.orderByIncludeColumn()).thenReturn(true);
+ List<String> include = Arrays.asList("age", "name");
+
Mockito.when(writeHolder.includeColumnFieldNames()).thenReturn(include);
+
+ FieldCache fieldCache = ClassUtils.declaredFields(SimpleEntity.class,
writeHolder);
+ Map<Integer, FieldWrapper> map = fieldCache.getSortedFieldMap();
+
+ Assertions.assertEquals("age", map.get(0).getFieldName());
+ Assertions.assertEquals("name", map.get(1).getFieldName());
+ }
+
+ @Test
+ void test_declaredFields_resort_byIndex() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.NONE);
+ Mockito.when(writeHolder.orderByIncludeColumn()).thenReturn(true);
+ Mockito.when(writeHolder.includeColumnFieldNames()).thenReturn(null);
+
Mockito.when(writeHolder.includeColumnIndexes()).thenReturn(Arrays.asList(2,
0));
+ Mockito.when(writeHolder.ignore(Mockito.anyString(),
Mockito.anyInt())).thenReturn(false);
+
+ FieldCache fieldCache = ClassUtils.declaredFields(ComplexEntity.class,
writeHolder);
+ Map<Integer, FieldWrapper> sortedMap = fieldCache.getSortedFieldMap();
+
+ Assertions.assertEquals(2, sortedMap.size());
+
+ Assertions.assertTrue(sortedMap.containsKey(0));
+ Assertions.assertEquals("name", sortedMap.get(0).getFieldName());
+
+ Assertions.assertTrue(sortedMap.containsKey(1));
+ Assertions.assertEquals("id", sortedMap.get(1).getFieldName());
+ }
+
+ @Test
+ void test_declaredExcelContentProperty() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.NONE);
+
+ ExcelContentProperty property =
+ ClassUtils.declaredExcelContentProperty(null,
FormatEntity.class, "date", writeHolder);
+
+ Assertions.assertNotNull(property);
+ Assertions.assertNotNull(property.getDateTimeFormatProperty());
+ Assertions.assertEquals(
+ "yyyy-MM-dd",
property.getDateTimeFormatProperty().getFormat());
+ }
+
+ @Test
+ void test_declaredExcelContentProperty_cache_memory() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.MEMORY);
+
+ ExcelContentProperty property =
+ ClassUtils.declaredExcelContentProperty(null,
FormatEntity.class, "date", writeHolder);
+
+ Assertions.assertNotNull(property);
+ Assertions.assertNotNull(property.getDateTimeFormatProperty());
+ Assertions.assertEquals(
+ "yyyy-MM-dd",
property.getDateTimeFormatProperty().getFormat());
+ }
+
+ @Test
+ void test_declaredExcelContentProperty_cache_ThreadLocal() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.THREAD_LOCAL);
+
+ ExcelContentProperty property =
+ ClassUtils.declaredExcelContentProperty(null,
FormatEntity.class, "date", writeHolder);
+
+ Assertions.assertNotNull(property);
+ Assertions.assertNotNull(property.getDateTimeFormatProperty());
+ Assertions.assertEquals(
+ "yyyy-MM-dd",
property.getDateTimeFormatProperty().getFormat());
+ }
+
+ @Test
+ void test_declaredExcelContentProperty_BeanMap() {
+ BeanMap beanMapMocked = Mockito.mock(BeanMap.class);
+ FormatEntity beanMocked = Mockito.mock(FormatEntity.class);
+
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.NONE);
+ Mockito.when(beanMapMocked.getBean()).thenReturn(beanMocked);
+
+ ExcelContentProperty property =
+ ClassUtils.declaredExcelContentProperty(beanMapMocked,
FormatEntity.class, "date", writeHolder);
+
+ Assertions.assertNotNull(property);
+ Assertions.assertNotNull(property.getDateTimeFormatProperty());
+ Assertions.assertEquals(
+ "yyyy-MM-dd",
property.getDateTimeFormatProperty().getFormat());
+ }
+
+ @Test
+ void test_declaredExcelContentProperty_converter() {
+
Mockito.when(globalConfiguration.getFiledCacheLocation()).thenReturn(CacheLocationEnum.NONE);
+
+ ExcelContentProperty property =
+ ClassUtils.declaredExcelContentProperty(null,
FormatEntity.class, "customConvert", writeHolder);
+
+ Assertions.assertNotNull(property);
+ Assertions.assertNotNull(property.getConverter());
+ Assertions.assertInstanceOf(StringStringConverter.class,
property.getConverter());
+ }
+
+ @Test
+ void test_combineExcelContentProperty() throws NoSuchFieldException {
+ Field field = SimpleEntity.class.getDeclaredField("name");
+ Converter converter = Mockito.mock(Converter.class);
+ DateTimeFormatProperty dateTimeFormatProperty =
Mockito.mock(DateTimeFormatProperty.class);
+ NumberFormatProperty numberFormatProperty =
Mockito.mock(NumberFormatProperty.class);
+ StyleProperty styleProperty = Mockito.mock(StyleProperty.class);
+ FontProperty fontProperty = Mockito.mock(FontProperty.class);
+
+ ExcelContentProperty propertyMocked =
Mockito.mock(ExcelContentProperty.class);
+ Mockito.when(propertyMocked.getField()).thenReturn(field);
+ Mockito.when(propertyMocked.getConverter()).thenReturn(converter);
+
Mockito.when(propertyMocked.getDateTimeFormatProperty()).thenReturn(dateTimeFormatProperty);
+
Mockito.when(propertyMocked.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+
Mockito.when(propertyMocked.getContentStyleProperty()).thenReturn(styleProperty);
+
Mockito.when(propertyMocked.getContentFontProperty()).thenReturn(fontProperty);
+
+ ExcelContentProperty combine = new ExcelContentProperty();
+
+ ClassUtils.combineExcelContentProperty(combine, propertyMocked);
+
+ Assertions.assertEquals(field, combine.getField());
+ Assertions.assertEquals(converter, combine.getConverter());
+ Assertions.assertEquals(dateTimeFormatProperty,
combine.getDateTimeFormatProperty());
+ Assertions.assertEquals(numberFormatProperty,
combine.getNumberFormatProperty());
+ Assertions.assertEquals(styleProperty,
combine.getContentStyleProperty());
+ Assertions.assertEquals(fontProperty,
combine.getContentFontProperty());
+ }
+
+ interface InterfaceA {}
+
+ interface InterfaceB extends InterfaceA {}
+
+ static class ClassImpl implements InterfaceB {}
+
+ @Test
+ void test_getAllInterfaces() {
+ List<Class<?>> interfaces =
ClassUtils.getAllInterfaces(ClassImpl.class);
+
+ Assertions.assertNull(ClassUtils.getAllInterfaces(null));
+ Assertions.assertNotNull(interfaces);
+ Assertions.assertTrue(interfaces.contains(InterfaceB.class));
+ Assertions.assertTrue(interfaces.contains(InterfaceA.class));
+ Assertions.assertEquals(InterfaceB.class, interfaces.get(0));
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/ConverterUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/ConverterUtilsTest.java
new file mode 100644
index 00000000..8f8e69cd
--- /dev/null
+++
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/ConverterUtilsTest.java
@@ -0,0 +1,275 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import org.apache.fesod.sheet.context.AnalysisContext;
+import org.apache.fesod.sheet.converters.Converter;
+import org.apache.fesod.sheet.converters.ConverterKeyBuild;
+import org.apache.fesod.sheet.converters.NullableObjectConverter;
+import org.apache.fesod.sheet.enums.CellDataTypeEnum;
+import org.apache.fesod.sheet.exception.ExcelDataConvertException;
+import org.apache.fesod.sheet.metadata.data.ReadCellData;
+import org.apache.fesod.sheet.metadata.property.ExcelContentProperty;
+import org.apache.fesod.sheet.read.metadata.holder.ReadRowHolder;
+import org.apache.fesod.sheet.read.metadata.holder.ReadSheetHolder;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+/**
+ * Tests {@link ConverterUtils}
+ */
+@ExtendWith(MockitoExtension.class)
+class ConverterUtilsTest {
+
+ @Mock
+ private AnalysisContext context;
+
+ @Mock
+ private ReadSheetHolder readSheetHolder;
+
+ @Mock
+ private ReadRowHolder readRowHolder;
+
+ @Mock
+ private Converter stringConverter;
+
+ @Mock
+ private Converter integerConverter;
+
+ private Map<ConverterKeyBuild.ConverterKey, Converter<?>> converterMap;
+
+ @BeforeEach
+ void setUp() {
+ converterMap = new HashMap<>();
+
+
Mockito.lenient().when(context.readSheetHolder()).thenReturn(readSheetHolder);
+
Mockito.lenient().when(context.readRowHolder()).thenReturn(readRowHolder);
+
Mockito.lenient().when(readSheetHolder.converterMap()).thenReturn(converterMap);
+ Mockito.lenient().when(readRowHolder.getRowIndex()).thenReturn(1);
+ }
+
+ @Test
+ void test_convertToStringMap_normal() throws Exception {
+ // {0: "A", 1: "B"}
+ Map<Integer, ReadCellData<?>> cellDataMap = new TreeMap<>();
+ cellDataMap.put(0, new ReadCellData<>("A"));
+ cellDataMap.put(1, new ReadCellData<>("B"));
+
+ ConverterKeyBuild.ConverterKey key =
ConverterKeyBuild.buildKey(String.class, CellDataTypeEnum.STRING);
+ converterMap.put(key, stringConverter);
+
Mockito.when(stringConverter.convertToJavaData(Mockito.any())).thenReturn("A",
"B");
+
+ Map<Integer, String> result =
ConverterUtils.convertToStringMap(cellDataMap, context);
+
+ Assertions.assertEquals(2, result.size());
+ Assertions.assertEquals("A", result.get(0));
+ Assertions.assertEquals("B", result.get(1));
+ }
+
+ @Test
+ void test_convertToStringMap_withGap() throws Exception {
+ // {0: "A", 2: "C"}
+ Map<Integer, ReadCellData<?>> cellDataMap = new TreeMap<>();
+ cellDataMap.put(0, new ReadCellData<>("A"));
+ cellDataMap.put(2, new ReadCellData<>("C"));
+
+ ConverterKeyBuild.ConverterKey key =
ConverterKeyBuild.buildKey(String.class, CellDataTypeEnum.STRING);
+ converterMap.put(key, stringConverter);
+
Mockito.when(stringConverter.convertToJavaData(Mockito.any())).thenReturn("A",
"C");
+
+ Map<Integer, String> result =
ConverterUtils.convertToStringMap(cellDataMap, context);
+
+ // 0->A, 1->null, 2->C
+ Assertions.assertEquals(3, result.size());
+ Assertions.assertEquals("A", result.get(0));
+ Assertions.assertNull(result.get(1));
+ Assertions.assertEquals("C", result.get(2));
+ }
+
+ @Test
+ void test_convertToStringMap_emptyCell() throws Exception {
+ Map<Integer, ReadCellData<?>> cellDataMap = new HashMap<>();
+ cellDataMap.put(0, new ReadCellData<>(CellDataTypeEnum.EMPTY));
+
+ Map<Integer, String> result =
ConverterUtils.convertToStringMap(cellDataMap, context);
+
+ Assertions.assertNull(result.get(0));
+ Mockito.verify(stringConverter,
Mockito.never()).convertToJavaData(Mockito.any());
+ }
+
+ @Test
+ void test_convertToStringMap_noConverter() {
+ Map<Integer, ReadCellData<?>> cellDataMap = new HashMap<>();
+ cellDataMap.put(0, new ReadCellData<>(CellDataTypeEnum.BOOLEAN));
+
+ Assertions.assertThrows(ExcelDataConvertException.class, () -> {
+ ConverterUtils.convertToStringMap(cellDataMap, context);
+ });
+ }
+
+ class DemoData {
+ private String stringField;
+ private ReadCellData<Integer> cellDataIntField;
+ private ReadCellData rawCellDataField;
+ }
+
+ @Test
+ void test_convertToJavaData_simpleConversion() throws Exception {
+ ReadCellData<?> cellData = new ReadCellData<>(new BigDecimal("123"));
+
+ ConverterKeyBuild.ConverterKey key =
ConverterKeyBuild.buildKey(Integer.class, CellDataTypeEnum.NUMBER);
+ converterMap.put(key, integerConverter);
+
Mockito.when(integerConverter.convertToJavaData(Mockito.any())).thenReturn(123);
+
+ Object result = ConverterUtils.convertToJavaObject(
+ cellData, null, Integer.class, null, null, converterMap,
context, 1, 0);
+
+ Assertions.assertEquals(123, result);
+ }
+
+ @Test
+ void test_convertToJavaData() throws Exception {
+ ReadCellData<?> cellData = new ReadCellData<>("123");
+
+ ConverterKeyBuild.ConverterKey key =
ConverterKeyBuild.buildKey(String.class, CellDataTypeEnum.STRING);
+ converterMap.put(key, stringConverter);
+
Mockito.when(stringConverter.convertToJavaData(Mockito.any())).thenReturn("123");
+
+ Object result1 =
+ ConverterUtils.convertToJavaObject(cellData, null, null, null,
null, converterMap, context, 1, 0);
+
+ Field field = DemoData.class.getDeclaredField("stringField");
+ Object result2 =
+ ConverterUtils.convertToJavaObject(cellData, field, null,
null, null, converterMap, context, 1, 0);
+
+ Assertions.assertEquals("123", result1);
+ Assertions.assertEquals("123", result2);
+ }
+
+ @Test
+ void test_ReadCellData_generic_inference() throws Exception,
NoSuchFieldException {
+ ReadCellData<?> cellData = new ReadCellData<>(new BigDecimal("100"));
+ Field field = DemoData.class.getDeclaredField("cellDataIntField");
+
+ ConverterKeyBuild.ConverterKey key =
ConverterKeyBuild.buildKey(Integer.class, CellDataTypeEnum.NUMBER);
+ converterMap.put(key, integerConverter);
+
Mockito.when(integerConverter.convertToJavaData(Mockito.any())).thenReturn(100);
+
+ Object result = ConverterUtils.convertToJavaObject(
+ cellData, field, ReadCellData.class, null, null, converterMap,
context, 1, 0);
+
+ Assertions.assertInstanceOf(ReadCellData.class, result);
+ ReadCellData<?> resultData = (ReadCellData<?>) result;
+ Assertions.assertEquals(100, resultData.getData());
+ }
+
+ @Test
+ void test_ReadCellData_raw_defaultString() throws Exception,
NoSuchFieldException {
+ ReadCellData<?> cellData = new ReadCellData<>("test");
+ Field field = DemoData.class.getDeclaredField("rawCellDataField");
+
+ ConverterKeyBuild.ConverterKey key =
ConverterKeyBuild.buildKey(String.class, CellDataTypeEnum.STRING);
+ converterMap.put(key, stringConverter);
+
Mockito.when(stringConverter.convertToJavaData(Mockito.any())).thenReturn("test");
+
+ Object result = ConverterUtils.convertToJavaObject(
+ cellData, field, ReadCellData.class, null, null, converterMap,
context, 1, 0);
+
+ Assertions.assertTrue(result instanceof ReadCellData);
+ Mockito.verify(stringConverter).convertToJavaData(Mockito.any());
+ }
+
+ @Test
+ void test_Priority_ContentProperty() throws Exception {
+ ReadCellData<?> cellData = new ReadCellData<>("test");
+
+ Converter globalConverter = Mockito.mock(Converter.class);
+ Converter customConverter = Mockito.mock(Converter.class);
+ converterMap.put(ConverterKeyBuild.buildKey(String.class,
CellDataTypeEnum.STRING), globalConverter);
+
+ ExcelContentProperty property =
Mockito.mock(ExcelContentProperty.class);
+ Mockito.when(property.getConverter()).thenReturn(customConverter);
+
Mockito.when(customConverter.convertToJavaData(Mockito.any())).thenReturn("Custom");
+
+ Object result = ConverterUtils.convertToJavaObject(
+ cellData, null, String.class, null, property, converterMap,
context, 1, 0);
+
+ Assertions.assertEquals("Custom", result);
+ Mockito.verify(customConverter).convertToJavaData(Mockito.any());
+ Mockito.verify(globalConverter,
Mockito.never()).convertToJavaData(Mockito.any());
+ }
+
+ @Test
+ void test_EmptyCell_NormalConverter() throws Exception,
NoSuchFieldException {
+ ReadCellData<?> cellData = new ReadCellData<>(CellDataTypeEnum.EMPTY);
+ ExcelContentProperty property =
Mockito.mock(ExcelContentProperty.class);
+ Mockito.when(property.getConverter()).thenReturn(stringConverter);
+
+ Object result = ConverterUtils.convertToJavaObject(
+ cellData, null, String.class, null, property, converterMap,
context, 1, 0);
+
+ Assertions.assertNull(result);
+ Mockito.verify(stringConverter,
Mockito.never()).convertToJavaData(Mockito.any());
+ }
+
+ @Test
+ void test_EmptyCell_NullableConverter() throws Exception {
+ ReadCellData<?> cellData = new ReadCellData<>(CellDataTypeEnum.EMPTY);
+ ExcelContentProperty property =
Mockito.mock(ExcelContentProperty.class);
+
+ Converter nullableConverter =
+ Mockito.mock(Converter.class,
Mockito.withSettings().extraInterfaces(NullableObjectConverter.class));
+ Mockito.when(property.getConverter()).thenReturn(nullableConverter);
+
Mockito.when(nullableConverter.convertToJavaData(Mockito.any())).thenReturn("HandledNull");
+
+ Object result = ConverterUtils.convertToJavaObject(
+ cellData, null, String.class, null, property, converterMap,
context, 1, 0);
+
+ Assertions.assertEquals("HandledNull", result);
+ Mockito.verify(nullableConverter).convertToJavaData(Mockito.any());
+ }
+
+ @Test
+ void test_exception_wrapping() throws Exception {
+ ReadCellData<?> cellData = new ReadCellData<>("ErrorData");
+ ConverterKeyBuild.ConverterKey key =
ConverterKeyBuild.buildKey(String.class, CellDataTypeEnum.STRING);
+ converterMap.put(key, stringConverter);
+
+
Mockito.when(stringConverter.convertToJavaData(Mockito.any())).thenThrow(new
RuntimeException("Inner error"));
+
+ ExcelDataConvertException ex =
Assertions.assertThrows(ExcelDataConvertException.class, () -> {
+ ConverterUtils.convertToJavaObject(cellData, null, String.class,
null, null, converterMap, context, 99, 88);
+ });
+
+ Assertions.assertEquals(99, ex.getRowIndex());
+ Assertions.assertEquals(88, ex.getColumnIndex());
+ Assertions.assertTrue(ex.getMessage().contains("Convert data"));
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java
new file mode 100644
index 00000000..43460cfc
--- /dev/null
+++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/DateUtilsTest.java
@@ -0,0 +1,370 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+/**
+ * Tests {@link DateUtils}
+ */
+class DateUtilsTest {
+
+ @AfterEach
+ void tearDown() {
+ DateUtils.removeThreadLocalCache();
+ }
+
+ @Test
+ void test_switchDateFormat() {
+ Assertions.assertEquals(DateUtils.DATE_FORMAT_19,
DateUtils.switchDateFormat("2026-01-01 12:00:00"));
+ Assertions.assertEquals(
+ DateUtils.DATE_FORMAT_19_FORWARD_SLASH,
DateUtils.switchDateFormat("2026/01/01 12:00:00"));
+
+ Assertions.assertEquals(DateUtils.DATE_FORMAT_16,
DateUtils.switchDateFormat("2026-01-01 12:00"));
+ Assertions.assertEquals(DateUtils.DATE_FORMAT_16_FORWARD_SLASH,
DateUtils.switchDateFormat("2026/01/01 12:00"));
+
+ Assertions.assertEquals(DateUtils.DATE_FORMAT_17,
DateUtils.switchDateFormat("20260101 12:00:00"));
+ Assertions.assertEquals(DateUtils.DATE_FORMAT_14,
DateUtils.switchDateFormat("20260101120000"));
+ Assertions.assertEquals(DateUtils.DATE_FORMAT_10,
DateUtils.switchDateFormat("2026-01-01"));
+
+ Assertions.assertThrows(
+ IllegalArgumentException.class, () ->
DateUtils.switchDateFormat("invalid_datestring_length"));
+ }
+
+ @Test
+ void test_parseDate() throws ParseException {
+ String dateStr = "2026-10-01 12:30:45";
+ Date date1 = DateUtils.parseDate(dateStr);
+
+ Calendar cal1 = Calendar.getInstance();
+ cal1.setTime(date1);
+ Assertions.assertEquals(2026, cal1.get(Calendar.YEAR));
+ Assertions.assertEquals(Calendar.OCTOBER, cal1.get(Calendar.MONTH));
+ Assertions.assertEquals(30, cal1.get(Calendar.MINUTE));
+
+ Date date2 = DateUtils.parseDate(dateStr, "");
+
+ Calendar cal2 = Calendar.getInstance();
+ cal2.setTime(date2);
+ Assertions.assertEquals(2026, cal2.get(Calendar.YEAR));
+ Assertions.assertEquals(Calendar.OCTOBER, cal2.get(Calendar.MONTH));
+ Assertions.assertEquals(30, cal2.get(Calendar.MINUTE));
+ }
+
+ @Test
+ void test_parseLocalDateTime() {
+ String dateStr = "2026-10-01 12:30:45";
+ String format = "yyyy-MM-dd HH:mm:ss";
+ LocalDateTime usResult = DateUtils.parseLocalDateTime(dateStr, format,
Locale.US);
+
+ Assertions.assertEquals(2026, usResult.getYear());
+ Assertions.assertEquals(10, usResult.getMonthValue());
+ Assertions.assertEquals(1, usResult.getDayOfMonth());
+ Assertions.assertEquals(12, usResult.getHour());
+ Assertions.assertEquals(30, usResult.getMinute());
+ Assertions.assertEquals(45, usResult.getSecond());
+
+ LocalDateTime result = DateUtils.parseLocalDateTime(dateStr, format,
null);
+
+ Assertions.assertEquals(2026, result.getYear());
+ Assertions.assertEquals(10, result.getMonthValue());
+ Assertions.assertEquals(1, result.getDayOfMonth());
+ Assertions.assertEquals(12, result.getHour());
+ Assertions.assertEquals(30, result.getMinute());
+ Assertions.assertEquals(45, result.getSecond());
+
+ LocalDateTime autoDetectFormatResult =
DateUtils.parseLocalDateTime(dateStr, "", null);
+
+ Assertions.assertEquals(2026, autoDetectFormatResult.getYear());
+ Assertions.assertEquals(10, autoDetectFormatResult.getMonthValue());
+ Assertions.assertEquals(1, autoDetectFormatResult.getDayOfMonth());
+ Assertions.assertEquals(12, autoDetectFormatResult.getHour());
+ Assertions.assertEquals(30, autoDetectFormatResult.getMinute());
+ Assertions.assertEquals(45, autoDetectFormatResult.getSecond());
+ }
+
+ @Test
+ void test_parseLocalDate() {
+ String dateStr = "2026-10-01";
+ String format = "yyyy-MM-dd";
+ LocalDate usResult = DateUtils.parseLocalDate(dateStr, format,
Locale.US);
+
+ Assertions.assertEquals(2026, usResult.getYear());
+ Assertions.assertEquals(10, usResult.getMonthValue());
+ Assertions.assertEquals(1, usResult.getDayOfMonth());
+
+ LocalDate result = DateUtils.parseLocalDate(dateStr, format, null);
+
+ Assertions.assertEquals(2026, result.getYear());
+ Assertions.assertEquals(10, result.getMonthValue());
+ Assertions.assertEquals(1, result.getDayOfMonth());
+
+ LocalDate autoDetectFormatResult = DateUtils.parseLocalDate(dateStr,
"", null);
+
+ Assertions.assertEquals(2026, autoDetectFormatResult.getYear());
+ Assertions.assertEquals(10, autoDetectFormatResult.getMonthValue());
+ Assertions.assertEquals(1, autoDetectFormatResult.getDayOfMonth());
+ }
+
+ @Test
+ void test_format_default() {
+ Date now = new Date();
+ String result = DateUtils.format(now);
+ Assertions.assertNotNull(result);
+ // yyyy-MM-dd HH:mm:ss
+ Assertions.assertEquals(19, result.length());
+
+ Assertions.assertNull(DateUtils.format(null));
+ }
+
+ @Test
+ void test_format_LocalDateTime() {
+ LocalDateTime ldt = LocalDateTime.of(2026, 10, 1, 12, 0, 0);
+ String format = "dd-MMM-yyyy";
+
+ String usResult = DateUtils.format(ldt, format, Locale.US);
+ Assertions.assertEquals("01-Oct-2026", usResult);
+
+ String cnResult = DateUtils.format(ldt, format,
Locale.SIMPLIFIED_CHINESE);
+ Assertions.assertNotNull(cnResult);
+
+ Assertions.assertNull(DateUtils.format((LocalDateTime) null, format,
Locale.US));
+
+ String defaultUSResult = DateUtils.format(ldt, "", Locale.US);
+ Assertions.assertEquals("2026-10-01 12:00:00", defaultUSResult);
+ }
+
+ @Test
+ void test_format_LocalDate() {
+ LocalDate ld = LocalDate.of(2026, 10, 1);
+ String format = "dd-MMM-yyyy";
+
+ String usResult = DateUtils.format(ld, format, Locale.US);
+ Assertions.assertEquals("01-Oct-2026", usResult);
+
+ String cnResult = DateUtils.format(ld, format,
Locale.SIMPLIFIED_CHINESE);
+ Assertions.assertNotNull(cnResult);
+
+ Assertions.assertNull(DateUtils.format((LocalDate) null, format,
Locale.US));
+
+ String defaultUSResult = DateUtils.format(ld, "", Locale.US);
+ Assertions.assertEquals("2026-10-01", defaultUSResult);
+
+ String defaultFormatResult = DateUtils.format(ld, "", null);
+ Assertions.assertEquals("2026-10-01", defaultFormatResult);
+
+ String defaultFormatResult2 = DateUtils.format(ld, "");
+ Assertions.assertEquals("2026-10-01", defaultFormatResult2);
+ }
+
+ @Test
+ void test_format_BigDecimal() {
+ // 43831 = 2020-01-01
+ BigDecimal excelDate = new BigDecimal("43831.5");
+
+ String result = DateUtils.format(excelDate, false,
DateUtils.DATE_FORMAT_19);
+ Assertions.assertNotNull(result);
+ Assertions.assertTrue(result.contains("2020-01-01"));
+
+ Assertions.assertNull(DateUtils.format(null, false,
DateUtils.DATE_FORMAT_19));
+ }
+
+ @ParameterizedTest
+ @CsvSource({
+ "1.0, 1900-01-01 00:00:00",
+ "32.0, 1900-02-01 00:00:00",
+ "61.0, 1900-03-01 00:00:00",
+ "43831.5, 2020-01-01 12:00:00"
+ })
+ void test_getJavaDate_1900(double excelValue, String expectedStr) throws
ParseException {
+ Date date = DateUtils.getJavaDate(excelValue, false);
+
+ SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.DATE_FORMAT_19);
+ sdf.setTimeZone(TimeZone.getDefault());
+
+ Assertions.assertEquals(expectedStr, sdf.format(date));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"0.0, 1904-01-01 00:00:00", "1.0, 1904-01-02 00:00:00",
"42369.5, 2020-01-01 12:00:00"})
+ void test_getJavaDate_1904(double excelValue, String expectedStr) {
+ Date date = DateUtils.getJavaDate(excelValue, true);
+
+ SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.DATE_FORMAT_19);
+ sdf.setTimeZone(TimeZone.getDefault());
+
+ Assertions.assertEquals(expectedStr, sdf.format(date));
+ }
+
+ @ParameterizedTest
+ @CsvSource({
+ "1.0, 1900-01-01 00:00:00",
+ "32.0, 1900-02-01 00:00:00",
+ "61.0, 1900-03-01 00:00:00",
+ "43831.5, 2020-01-01 12:00:00"
+ })
+ void test_getLocalDateTime_1900(double excelValue, String expectedStr) {
+ LocalDateTime date = DateUtils.getLocalDateTime(excelValue, false);
+ String formatted = date.atZone(TimeZone.getDefault().toZoneId())
+ .format(DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_19));
+
+ Assertions.assertEquals(expectedStr, formatted);
+ }
+
+ @ParameterizedTest
+ @CsvSource({"0.0, 1904-01-01 00:00:00", "1.0, 1904-01-02 00:00:00",
"42369.5, 2020-01-01 12:00:00"})
+ void test_getLocalDateTime_1904(double excelValue, String expectedStr) {
+ LocalDateTime date = DateUtils.getLocalDateTime(excelValue, true);
+
+ String formatted = date.atZone(TimeZone.getDefault().toZoneId())
+ .format(DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_19));
+
+ Assertions.assertEquals(expectedStr, formatted);
+ }
+
+ @ParameterizedTest
+ @CsvSource({"1.0, 1900-01-01", "32.0, 1900-02-01", "61.0, 1900-03-01",
"43831.5, 2020-01-01"})
+ void test_getLocalDate_1900(double excelValue, String expectedStr) {
+ LocalDate date = DateUtils.getLocalDate(excelValue, false);
+ Assertions.assertNotNull(date);
+
+ String formatted =
date.format(DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_10));
+ Assertions.assertEquals(expectedStr, formatted);
+ }
+
+ @ParameterizedTest
+ @CsvSource({"0.0, 1904-01-01", "1.0, 1904-01-02", "42369.5, 2020-01-01"})
+ void test_getLocalDate_1904(double excelValue, String expectedStr) {
+ LocalDate date = DateUtils.getLocalDate(excelValue, true);
+ Assertions.assertNotNull(date);
+
+ String formatted =
date.format(DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_10));
+ Assertions.assertEquals(expectedStr, formatted);
+ }
+
+ @Test
+ void test_isValidExcelDate() {
+ Assertions.assertTrue(DateUtils.isValidExcelDate(0.0));
+ Assertions.assertTrue(DateUtils.isValidExcelDate(100.0));
+ Assertions.assertFalse(DateUtils.isValidExcelDate(-1.0));
+ }
+
+ @Test
+ void test_getJavaCalendar_rounding() {
+ double base = 44000.0;
+ double halfDay = 0.5;
+
+ Calendar cal = DateUtils.getJavaCalendar(base + halfDay, false, null,
true);
+ Assertions.assertNotNull(cal);
+ Assertions.assertEquals(12, cal.get(Calendar.HOUR_OF_DAY));
+ Assertions.assertEquals(0, cal.get(Calendar.SECOND));
+ Assertions.assertEquals(0, cal.get(Calendar.MILLISECOND));
+ }
+
+ @ParameterizedTest
+ @ValueSource(shorts = {0x0e, 0x0f, 0x16, 0x2d, 0x2f})
+ void test_isADateFormat_internal(short formatId) {
+ Assertions.assertTrue(DateUtils.isADateFormat(formatId, null));
+ Assertions.assertTrue(DateUtils.isADateFormat(formatId, "General"));
+ }
+
+ @ParameterizedTest
+ @ValueSource(
+ strings = {
+ "yyyy-mm-dd",
+ "mm/dd/yy",
+ "hh:mm:ss",
+ "yyyy年mm月dd日",
+ "[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy",
+ "[DBNum1]yyyy年mm月dd日",
+ "yyyy/mm/dd;@",
+ "[h]:mm:ss",
+ "mm:ss.0",
+ "yyyy-MM-dd HH:mm:ss"
+ })
+ void test_isADateFormat_true(String formatString) {
+ Assertions.assertTrue(DateUtils.isADateFormat((short) 100,
formatString));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"General", "0.00", "#", "#,##0", "0%", "@", "_-*
#,##0_-", ""})
+ void test_isADateFormat_false(String formatString) {
+ Assertions.assertFalse(DateUtils.isADateFormat((short) 100,
formatString));
+
+ Assertions.assertFalse(DateUtils.isADateFormat(null, formatString));
+ }
+
+ @Test
+ void test_isADateFormat_Cache() throws NoSuchFieldException,
IllegalAccessException {
+ short formatId = 200;
+ String formatStr = "yyyy-MM-dd";
+
+ boolean res1 = DateUtils.isADateFormat(formatId, formatStr);
+ Assertions.assertTrue(res1);
+
+ Field threadLocalField =
DateUtils.class.getDeclaredField("DATE_THREAD_LOCAL");
+ threadLocalField.setAccessible(true);
+ ThreadLocal<Map<Short, Boolean>> tl = (ThreadLocal<Map<Short,
Boolean>>) threadLocalField.get(null);
+
+ Map<Short, Boolean> cache = tl.get();
+ Assertions.assertNotNull(cache);
+ Assertions.assertTrue(cache.containsKey(formatId));
+ Assertions.assertTrue(cache.get(formatId));
+
+ boolean res2 = DateUtils.isADateFormat(formatId, formatStr);
+ Assertions.assertTrue(res2);
+ }
+
+ @Test
+ void test_removeThreadLocalCache() throws NoSuchFieldException,
IllegalAccessException {
+ DateUtils.format(new Date(), "yyyy-MM-dd");
+ DateUtils.isADateFormat((short) 100, "yyyy-MM-dd");
+
+ Field f1 = DateUtils.class.getDeclaredField("DATE_THREAD_LOCAL");
+ Field f2 =
DateUtils.class.getDeclaredField("DATE_FORMAT_THREAD_LOCAL");
+ f1.setAccessible(true);
+ f2.setAccessible(true);
+
+ Assertions.assertNotNull(((ThreadLocal<?>) f1.get(null)).get());
+ Assertions.assertNotNull(((ThreadLocal<?>) f2.get(null)).get());
+
+ DateUtils.removeThreadLocalCache();
+
+ Assertions.assertNull(((ThreadLocal<?>) f1.get(null)).get());
+ Assertions.assertNull(((ThreadLocal<?>) f2.get(null)).get());
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/FieldUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/FieldUtilsTest.java
new file mode 100644
index 00000000..7c4817a5
--- /dev/null
+++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/FieldUtilsTest.java
@@ -0,0 +1,242 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+import org.apache.fesod.shaded.cglib.beans.BeanMap;
+import org.apache.fesod.sheet.metadata.NullObject;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Mockito;
+
+/**
+ * Tests {@link FieldUtils}
+ */
+class FieldUtilsTest {
+
+ @Test
+ void test_getFieldClass_normalValue() {
+ Class<?> clazz = FieldUtils.getFieldClass(null, "any", "StringValue");
+
+ Assertions.assertEquals(String.class, clazz);
+ }
+
+ @Test
+ void test_getFieldClass_nullValue() {
+ Class<?> clazz = FieldUtils.getFieldClass(null, "any", null);
+
+ Assertions.assertEquals(NullObject.class, clazz);
+ }
+
+ @Test
+ void test_getFieldClass_BeanMap() {
+ BeanMap mockBeanMap = Mockito.mock(BeanMap.class);
+
Mockito.when(mockBeanMap.getPropertyType("name")).thenReturn(Integer.class);
+
+ Class<?> clazz = FieldUtils.getFieldClass(mockBeanMap, "name", "123");
+
+ Assertions.assertEquals(Integer.class, clazz);
+ }
+
+ @Test
+ void test_getFieldClass_BeanMap_fallback() {
+ BeanMap mockBeanMap = Mockito.mock(BeanMap.class);
+ Mockito.when(mockBeanMap.getPropertyType("unknown")).thenReturn(null);
+
+ Class<?> clazz = FieldUtils.getFieldClass(mockBeanMap, "unknown",
"Value");
+
+ Assertions.assertEquals(String.class, clazz);
+ }
+
+ @Test
+ void test_getFieldClass_normalMap() {
+ Map<String, Object> map = new HashMap<>();
+ Class<?> clazz = FieldUtils.getFieldClass(map, "any", 100L);
+
+ Assertions.assertEquals(Long.class, clazz);
+ }
+
+ @Test
+ void test_resolveCglibFieldName_nullField() {
+ Assertions.assertNull(FieldUtils.resolveCglibFieldName(null));
+ }
+
+ @ParameterizedTest
+ @MethodSource("cglibNameProvider")
+ void test_resolveCglibFieldName_resolveLogic(String fieldName, String
expected) throws NoSuchFieldException {
+ Field field = FieldNameFixture.class.getDeclaredField(fieldName);
+
+ String result = FieldUtils.resolveCglibFieldName(field);
+ Assertions.assertEquals(expected, result);
+ }
+
+ static class FieldNameFixture {
+ private String a;
+ private String A;
+ private String ab;
+ private String AB;
+ private String string1;
+ private String STRING5;
+ private String String2;
+ private String sTring3;
+ private String aBc;
+ }
+
+ static Stream<Arguments> cglibNameProvider() {
+ return Stream.of(
+ Arguments.of("a", "a"),
+ Arguments.of("A", "A"),
+ // lower, lower
+ Arguments.of("ab", "ab"),
+ // Upper, Upper
+ Arguments.of("AB", "AB"),
+ // s(l), t(l) -> keep
+ Arguments.of("string1", "string1"),
+ // S(U), T(U) -> keep
+ Arguments.of("STRING5", "STRING5"),
+ // String2 -> string2
+ Arguments.of("String2", "string2"),
+ // sTring3 -> STring3
+ Arguments.of("sTring3", "STring3"),
+ // aBc -> a(l), B(U) -> A(U) + Bc -> ABc
+ Arguments.of("aBc", "ABc"));
+ }
+
+ @Test
+ void test_getField_nullClass() {
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
FieldUtils.getField(null, "any", true));
+ }
+
+ interface InterfaceA {
+ String interfaceField = "I_A";
+ }
+
+ interface InterfaceB {
+ String interfaceField = "I_B";
+ }
+
+ static class Parent {
+ public String parentPublic;
+ protected String parentProtected;
+ private String parentPrivate;
+ }
+
+ static class Child extends Parent implements InterfaceA {
+ public String childPublic;
+ private String childPrivate;
+ }
+
+ static class AmbiguousChild implements InterfaceA, InterfaceB {}
+
+ @Test
+ void test_getField_blankName() {
+ Assertions.assertThrows(IllegalArgumentException.class, () ->
FieldUtils.getField(Child.class, " ", true));
+ }
+
+ @Test
+ void test_getField_self_public() {
+ Field field = FieldUtils.getField(Child.class, "childPublic", false);
+ Assertions.assertNotNull(field);
+ Assertions.assertEquals("childPublic", field.getName());
+ }
+
+ @Test
+ void test_getField_self_private_force() {
+ Field field = FieldUtils.getField(Child.class, "childPrivate", true);
+ Assertions.assertNotNull(field);
+ Assertions.assertTrue(field.isAccessible());
+ }
+
+ @Test
+ void test_getField_self_private_noForce() {
+ Field field = FieldUtils.getField(Child.class, "childPrivate", false);
+
+ Assertions.assertNull(field);
+ }
+
+ @Test
+ void test_getField_super_public() {
+ Field field = FieldUtils.getField(Child.class, "parentPublic", false);
+ Assertions.assertNotNull(field);
+ Assertions.assertEquals(Parent.class, field.getDeclaringClass());
+ }
+
+ @Test
+ void test_getField_super_private_force() {
+ Field field = FieldUtils.getField(Child.class, "parentPrivate", true);
+
+ Assertions.assertNotNull(field);
+ Assertions.assertEquals("parentPrivate", field.getName());
+ Assertions.assertEquals(Parent.class, field.getDeclaringClass());
+ }
+
+ @Test
+ void test_getField_interface_field() {
+ Field field = FieldUtils.getField(Child.class, "interfaceField",
false);
+ Assertions.assertNotNull(field);
+ Assertions.assertEquals(InterfaceA.class, field.getDeclaringClass());
+ }
+
+ @Test
+ void test_getField_notFound() {
+ Field field = FieldUtils.getField(Child.class, "notExists", true);
+ Assertions.assertNull(field);
+ }
+
+ @Test
+ void test_getField_ambiguous_interface() {
+ try {
+ FieldUtils.getField(AmbiguousChild.class, "interfaceField", true);
+ } catch (IllegalArgumentException e) {
+ Assertions.assertTrue(e.getMessage().contains("ambiguous"));
+ } catch (NoClassDefFoundError e) {
+ }
+ }
+
+ public static class PublicTarget {
+ public String publicField;
+ }
+
+ static class PackagePrivateTarget {
+ public String publicField;
+ }
+
+ @Test
+ void test_getField_publicClass_publicField() {
+ Field field = FieldUtils.getField(PublicTarget.class, "publicField");
+
+ Assertions.assertNotNull(field);
+ Assertions.assertFalse(field.isAccessible());
+ }
+
+ @Test
+ void test_getField_packagePrivateClass_publicField() {
+ Field field = FieldUtils.getField(PackagePrivateTarget.class,
"publicField");
+
+ Assertions.assertNotNull(field);
+ Assertions.assertTrue(field.isAccessible());
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/FileUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/FileUtilsTest.java
new file mode 100644
index 00000000..87a60203
--- /dev/null
+++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/FileUtilsTest.java
@@ -0,0 +1,308 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.UUID;
+import org.apache.fesod.sheet.exception.ExcelAnalysisException;
+import org.apache.fesod.sheet.exception.ExcelCommonException;
+import org.apache.poi.util.TempFile;
+import org.apache.poi.util.TempFileCreationStrategy;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import org.mockito.Mockito;
+
+/**
+ * Tests {@link FileUtils}
+ */
+class FileUtilsTest {
+
+ @TempDir
+ Path tempDir;
+
+ private String originalTempPrefix;
+ private String originalPoiFilesPath;
+ private String originalCachePath;
+
+ @BeforeEach
+ void setUp() {
+ originalTempPrefix = FileUtils.getTempFilePrefix();
+ originalPoiFilesPath = FileUtils.getPoiFilesPath();
+ originalCachePath = FileUtils.getCachePath();
+ }
+
+ @AfterEach
+ void tearDown() {
+ FileUtils.setTempFilePrefix(originalTempPrefix);
+ FileUtils.setPoiFilesPath(originalPoiFilesPath);
+ FileUtils.setCachePath(originalCachePath);
+ }
+
+ @Test
+ void test_ReadWrite_loop() throws IOException {
+ String content = "Hello, this is a test string.";
+ File targetFile = tempDir.resolve("test_rw.txt").toFile();
+ ByteArrayInputStream inputStream = new
ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
+
+ FileUtils.writeToFile(targetFile, inputStream);
+
+ Assertions.assertTrue(targetFile.exists());
+ Assertions.assertTrue(targetFile.length() > 0);
+
+ byte[] readBytes = FileUtils.readFileToByteArray(targetFile);
+ String readContent = new String(readBytes, StandardCharsets.UTF_8);
+
+ Assertions.assertEquals(content, readContent);
+ }
+
+ @Test
+ void test_writeToFile_exception() {
+ InputStream badStream = new ByteArrayInputStream("test".getBytes());
+ try {
+ badStream.close();
+ } catch (IOException ignored) {
+ }
+
+ File directoryAsFile = tempDir.resolve("subdir").toFile();
+ directoryAsFile.mkdir();
+
+ InputStream validStream = new ByteArrayInputStream("test".getBytes());
+
+ Assertions.assertThrows(ExcelAnalysisException.class, () -> {
+ FileUtils.writeToFile(directoryAsFile, validStream);
+ });
+ }
+
+ @Test
+ void test_finally_inputStream_shouldClose() throws IOException {
+ File file = tempDir.resolve("close_test.txt").toFile();
+ InputStream mockInputStream = Mockito.mock(InputStream.class);
+ Mockito.when(mockInputStream.read(Mockito.any(), Mockito.anyInt(),
Mockito.anyInt()))
+ .thenReturn(-1);
+
+ FileUtils.writeToFile(file, mockInputStream, true);
+
+ Mockito.verify(mockInputStream).close();
+ }
+
+ @Test
+ void test_finally_inputStream_shouldNotClose() throws IOException {
+ File file = tempDir.resolve("noclose_test.txt").toFile();
+ InputStream mockInputStream = Mockito.mock(InputStream.class);
+ Mockito.when(mockInputStream.read(Mockito.any(), Mockito.anyInt(),
Mockito.anyInt()))
+ .thenReturn(-1);
+
+ FileUtils.writeToFile(file, mockInputStream, false);
+
+ Mockito.verify(mockInputStream, Mockito.never()).close();
+ }
+
+ @Test
+ void test_finally_inputStream_closeException() throws IOException {
+ File file = tempDir.resolve("ex_test.txt").toFile();
+ InputStream mockInputStream = Mockito.mock(InputStream.class);
+ Mockito.when(mockInputStream.read(Mockito.any(), Mockito.anyInt(),
Mockito.anyInt()))
+ .thenReturn(-1);
+
+ Mockito.doThrow(new IOException("Close
failed")).when(mockInputStream).close();
+
+ Assertions.assertThrows(ExcelAnalysisException.class, () -> {
+ FileUtils.writeToFile(file, mockInputStream, true);
+ });
+ }
+
+ @Test
+ void test_openInputStream_notFound() {
+ File nonExistentFile =
tempDir.resolve(UUID.randomUUID().toString()).toFile();
+
+ Assertions.assertThrows(FileNotFoundException.class, () -> {
+ FileUtils.openInputStream(nonExistentFile);
+ });
+ }
+
+ @Test
+ void test_openInputStream_isDirectory() {
+ File dir = tempDir.resolve("test_dir").toFile();
+ dir.mkdirs();
+
+ IOException ex = Assertions.assertThrows(IOException.class, () -> {
+ FileUtils.openInputStream(dir);
+ });
+ Assertions.assertTrue(ex.getMessage().contains("exists but is a
directory"));
+ }
+
+ @Test
+ void test_openInputStream_noRead() {
+ File fileMocked = Mockito.mock(File.class);
+
+ Mockito.when(fileMocked.exists()).thenReturn(true);
+ Mockito.when(fileMocked.isDirectory()).thenReturn(false);
+ Mockito.when(fileMocked.canRead()).thenReturn(false);
+ Mockito.when(fileMocked.toString()).thenReturn("/path/to/locked_file");
+
+ Assertions.assertThrows(IOException.class, () -> {
+ FileUtils.openInputStream(fileMocked);
+ });
+ }
+
+ @Test
+ void test_createDirectory() {
+ File nestedDir = tempDir.resolve("a/b/c").toFile();
+
+ File result = FileUtils.createDirectory(nestedDir);
+
+ Assertions.assertTrue(result.exists());
+ Assertions.assertTrue(result.isDirectory());
+ }
+
+ @Test
+ void test_createDirectory_exception() {
+ File dirMocked = Mockito.mock(File.class);
+
+ Mockito.when(dirMocked.exists()).thenReturn(false);
+ Mockito.when(dirMocked.mkdirs()).thenReturn(false);
+ Mockito.when(dirMocked.toString()).thenReturn("/path/to/locked_file");
+
+ Assertions.assertThrows(ExcelCommonException.class, () -> {
+ FileUtils.createDirectory(dirMocked);
+ });
+ }
+
+ @Test
+ void test_createTmpFile() {
+ String fileName = "my_temp.xlsx";
+ File tmpFile = FileUtils.createTmpFile(fileName);
+
+ Assertions.assertNotNull(tmpFile);
+ Assertions.assertFalse(tmpFile.exists());
+ Assertions.assertEquals(fileName, tmpFile.getName());
+
+ Assertions.assertTrue(tmpFile.getParentFile().exists());
+ }
+
+ @Test
+ void test_createCacheTmpFile() {
+ File cacheDir = FileUtils.createCacheTmpFile();
+
+ Assertions.assertNotNull(cacheDir);
+ Assertions.assertTrue(cacheDir.exists());
+ Assertions.assertTrue(cacheDir.isDirectory());
+
Assertions.assertTrue(cacheDir.getAbsolutePath().contains(FileUtils.EX_CACHE));
+ }
+
+ @Test
+ void test_delete_recursive() throws IOException {
+ // root/
+ // - file1.txt
+ // - sub/
+ // - file2.txt
+ File root = tempDir.resolve("root").toFile();
+ File sub = new File(root, "sub");
+ FileUtils.createDirectory(sub);
+
+ File file1 = new File(root, "file1.txt");
+ File file2 = new File(sub, "file2.txt");
+
+ Files.write(file1.toPath(), "content".getBytes());
+ Files.write(file2.toPath(), "content".getBytes());
+
+ Assertions.assertTrue(file1.exists());
+ Assertions.assertTrue(file2.exists());
+
+ FileUtils.delete(root);
+
+ Assertions.assertFalse(root.exists());
+ Assertions.assertFalse(file1.exists());
+ Assertions.assertFalse(sub.exists());
+ Assertions.assertFalse(file2.exists());
+ }
+
+ @Test
+ void test_delete_singleFile() throws IOException {
+ File file = tempDir.resolve("single.txt").toFile();
+ file.createNewFile();
+
+ FileUtils.delete(file);
+
+ Assertions.assertFalse(file.exists());
+ }
+
+ @Test
+ void test_delete_directory() {
+ File root = tempDir.resolve("root").toFile();
+ FileUtils.createDirectory(root);
+
+ Assertions.assertTrue(root.exists());
+
+ FileUtils.delete(root);
+
+ Assertions.assertFalse(root.exists());
+ }
+
+ @Test
+ void test_GetterSetter() {
+ String originalPrefix = FileUtils.getTempFilePrefix();
+ String newPrefix = tempDir.toString() + File.separator;
+
+ try {
+ FileUtils.setTempFilePrefix(newPrefix);
+ Assertions.assertEquals(newPrefix, FileUtils.getTempFilePrefix());
+
+ FileUtils.setCachePath(newPrefix + "cache");
+ Assertions.assertEquals(newPrefix + "cache",
FileUtils.getCachePath());
+
+ FileUtils.setPoiFilesPath(newPrefix + "poi");
+ Assertions.assertEquals(newPrefix + "poi",
FileUtils.getPoiFilesPath());
+ } finally {
+ FileUtils.setTempFilePrefix(originalPrefix);
+ }
+ }
+
+ @Test
+ void test_createPoiFilesDirectory() throws NoSuchFieldException,
IllegalAccessException {
+ Field strategyField = TempFile.class.getDeclaredField("strategy");
+ strategyField.setAccessible(true);
+
+ TempFileCreationStrategy originalStrategy = (TempFileCreationStrategy)
strategyField.get(null);
+
+ try {
+ FileUtils.createPoiFilesDirectory();
+
+ TempFileCreationStrategy newStrategy = (TempFileCreationStrategy)
strategyField.get(null);
+
+ Assertions.assertNotNull(newStrategy);
+ Assertions.assertEquals(FesodTempFileCreationStrategy.class,
newStrategy.getClass());
+ Assertions.assertNotSame(originalStrategy, newStrategy);
+ } finally {
+ TempFile.setTempFileCreationStrategy(originalStrategy);
+ }
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/NumberDataFormatterUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/NumberDataFormatterUtilsTest.java
new file mode 100644
index 00000000..3c0133d0
--- /dev/null
+++
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/NumberDataFormatterUtilsTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.util.Locale;
+import org.apache.fesod.sheet.metadata.GlobalConfiguration;
+import org.apache.fesod.sheet.metadata.format.DataFormatter;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+/**
+ * Tests {@link NumberDataFormatterUtils}
+ */
+@ExtendWith(MockitoExtension.class)
+class NumberDataFormatterUtilsTest {
+
+ @Mock
+ private GlobalConfiguration globalConfiguration;
+
+ @AfterEach
+ void tearDown() {
+ NumberDataFormatterUtils.removeThreadLocalCache();
+ }
+
+ @Test
+ void test_format_withConfig_Locale() {
+ // Setup
+
Mockito.when(globalConfiguration.getLocale()).thenReturn(Locale.GERMANY);
+
Mockito.when(globalConfiguration.getUse1904windowing()).thenReturn(false);
+
Mockito.when(globalConfiguration.getUseScientificFormat()).thenReturn(false);
+
+ BigDecimal data = new BigDecimal("1234.56");
+ String formatString = "0.00";
+
+ // Execute
+ String result = NumberDataFormatterUtils.format(data, null,
formatString, globalConfiguration);
+
+ // Verify
+ Assertions.assertEquals("1234,56", result);
+ }
+
+ @Test
+ void test_format_nullConfig() {
+ BigDecimal data = new BigDecimal("1234.56");
+ String formatString = "0.00";
+
+ String result = NumberDataFormatterUtils.format(data, null,
formatString, null);
+
+ Assertions.assertNotNull(result);
+ Assertions.assertTrue(result.contains("1234"));
+ }
+
+ @Test
+ void test_format_scientific() {
+ // 1.23E4 -> 12300
+ BigDecimal data = new BigDecimal("1.23E+4");
+ String formatString = "0";
+
+ String result = NumberDataFormatterUtils.format(data, null,
formatString, false, Locale.US, false);
+
+ Assertions.assertEquals("12300", result);
+ }
+
+ @Test
+ void test_ThreadLocal_Cache_And_Remove() throws NoSuchFieldException,
IllegalAccessException {
+ Field field =
NumberDataFormatterUtils.class.getDeclaredField("DATA_FORMATTER_THREAD_LOCAL");
+ field.setAccessible(true);
+
+ @SuppressWarnings("unchecked")
+ ThreadLocal<DataFormatter> threadLocal = (ThreadLocal<DataFormatter>)
field.get(null);
+
+ Assertions.assertNull(threadLocal.get());
+
+ NumberDataFormatterUtils.format(new BigDecimal("1"), null, "0", false,
Locale.US, false);
+
+ DataFormatter cachedFormatter = threadLocal.get();
+ Assertions.assertNotNull(cachedFormatter);
+
+ NumberDataFormatterUtils.format(new BigDecimal("2"), null, "0", false,
Locale.US, false);
+ Assertions.assertSame(cachedFormatter, threadLocal.get());
+
+ NumberDataFormatterUtils.removeThreadLocalCache();
+
+ Assertions.assertNull(threadLocal.get());
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/NumberUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/NumberUtilsTest.java
new file mode 100644
index 00000000..c4d6cb93
--- /dev/null
+++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/NumberUtilsTest.java
@@ -0,0 +1,270 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.ParseException;
+import org.apache.fesod.sheet.metadata.data.WriteCellData;
+import org.apache.fesod.sheet.metadata.property.ExcelContentProperty;
+import org.apache.fesod.sheet.metadata.property.NumberFormatProperty;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+/**
+ * Tests {@link NumberUtils}
+ */
+@ExtendWith(MockitoExtension.class)
+class NumberUtilsTest {
+
+ @Mock
+ private ExcelContentProperty contentProperty;
+
+ @Mock
+ private NumberFormatProperty numberFormatProperty;
+
+ @Test
+ void test_format_noFormat_BigDecimal() {
+ BigDecimal bigDecimal = new BigDecimal("0.0000001");
+
+ String result = NumberUtils.format(bigDecimal, null);
+
+ Assertions.assertEquals("0.0000001", result);
+ }
+
+ @Test
+ void test_format_noFormat_Integer() {
+ Integer num = 123;
+ String result = NumberUtils.format(num, null);
+
+ Assertions.assertEquals("123", result);
+ }
+
+ @Test
+ void test_format_withFormat() {
+ // Setup
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("#.00");
+
Mockito.when(numberFormatProperty.getRoundingMode()).thenReturn(RoundingMode.UP);
+
+ // 123.451 -> UP -> 123.46
+ String result = NumberUtils.format(123.451, contentProperty);
+
+ Assertions.assertEquals("123.46", result);
+ }
+
+ @Test
+ void test_formatToCellDataString() {
+ Integer num = 100;
+ WriteCellData<?> data = NumberUtils.formatToCellDataString(num, null);
+
+ Assertions.assertEquals("100", data.getStringValue());
+ }
+
+ @Test
+ void test_formatToCellData_withFormat() {
+ // Setup
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("#,##0.00");
+
+ // Execute
+ WriteCellData<?> data = NumberUtils.formatToCellData(1234.56,
contentProperty);
+
+ // Verify Value
+ Assertions.assertEquals(0, new
BigDecimal("1234.56").compareTo(data.getNumberValue()));
+ Assertions.assertNotNull(data.getWriteCellStyle());
+ Assertions.assertNotNull(data.getWriteCellStyle().getDataFormatData());
+ Assertions.assertEquals(
+ "#,##0.00",
data.getWriteCellStyle().getDataFormatData().getFormat());
+ }
+
+ @Test
+ void test_formatToCellData_noFormat() {
+ WriteCellData<?> data = NumberUtils.formatToCellData(99, null);
+
+ Assertions.assertEquals(0, new
BigDecimal("99").compareTo(data.getNumberValue()));
+ Assertions.assertNull(data.getWriteCellStyle());
+ }
+
+ @Test
+ void test_parseInteger_noFormat() throws ParseException {
+ Integer result = NumberUtils.parseInteger("100", null);
+ Assertions.assertEquals(100, result);
+ }
+
+ @Test
+ void test_parseInteger_withFormat() throws ParseException {
+ // Setup
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("#");
+
Mockito.when(numberFormatProperty.getRoundingMode()).thenReturn(RoundingMode.HALF_UP);
+
+ // Execute
+ Integer result = NumberUtils.parseInteger("99", contentProperty);
+
+ // Verify
+ Assertions.assertEquals(99, result);
+ }
+
+ @Test
+ void test_parseBigDecimal_noFormat() throws ParseException {
+ BigDecimal result = NumberUtils.parseBigDecimal("123.456789", null);
+ Assertions.assertEquals(new BigDecimal("123.456789"), result);
+ }
+
+ @Test
+ void test_parseBigDecimal_withFormat() throws ParseException {
+ // Setup
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("#,##0.00");
+
Mockito.when(numberFormatProperty.getRoundingMode()).thenReturn(RoundingMode.HALF_UP);
+
+ // Execute: "1,234.56" -> 1234.56
+ BigDecimal result = NumberUtils.parseBigDecimal("1,234.56",
contentProperty);
+
+ // Verify
+ Assertions.assertEquals(0, new
BigDecimal("1234.56").compareTo(result));
+ }
+
+ @Test
+ void test_parseFloat_noFormat() throws ParseException {
+ Float result = NumberUtils.parseFloat("12.34", null);
+ Assertions.assertEquals(12.34f, result, 0.0001f);
+ }
+
+ @Test
+ void test_parseFloat_withFormat() throws ParseException {
+ // Setup
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("#.00");
+
Mockito.when(numberFormatProperty.getRoundingMode()).thenReturn(RoundingMode.HALF_UP);
+
+ // Execute
+ Float result = NumberUtils.parseFloat("12.34", contentProperty);
+
+ // Verify
+ Assertions.assertEquals(12.34f, result, 0.0001f);
+ }
+
+ @Test
+ void test_parseDouble_noFormat() throws ParseException {
+ Double result = NumberUtils.parseDouble("123.456", null);
+ Assertions.assertEquals(123.456, result, 0.000001);
+ }
+
+ @Test
+ void test_parseDouble_withFormat() throws ParseException {
+ // Setup
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ // 12.34% -> 0.1234
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("0.00%");
+
Mockito.when(numberFormatProperty.getRoundingMode()).thenReturn(RoundingMode.HALF_UP);
+
+ // Execute
+ Double result = NumberUtils.parseDouble("12.34%", contentProperty);
+
+ // Verify
+ Assertions.assertEquals(0.1234, result, 0.000001);
+ }
+
+ @Test
+ void test_parseLong_noFormat() throws ParseException {
+ Long result = NumberUtils.parseLong("123456789", null);
+
+ Assertions.assertEquals(123456789L, result);
+ }
+
+ @Test
+ void test_parseLong_withFormat() throws ParseException {
+ // Setup
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("#,###");
+
Mockito.when(numberFormatProperty.getRoundingMode()).thenReturn(RoundingMode.HALF_UP);
+
+ // Execute: "1,234" -> 1234L
+ Long result = NumberUtils.parseLong("1,234", contentProperty);
+
+ // Verify
+ Assertions.assertEquals(1234L, result);
+ }
+
+ @Test
+ void test_parseByte_noFormat() throws ParseException {
+ Byte result = NumberUtils.parseByte("127", null);
+ Assertions.assertEquals((byte) 127, result);
+ }
+
+ @Test
+ void test_parseByte_withFormat() throws ParseException {
+ // Setup
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("#");
+
Mockito.when(numberFormatProperty.getRoundingMode()).thenReturn(RoundingMode.HALF_UP);
+
+ // Execute
+ Byte result = NumberUtils.parseByte("100", contentProperty);
+
+ // Verify
+ Assertions.assertEquals((byte) 100, result);
+ }
+
+ @Test
+ void test_parseShort_withFormat() throws ParseException {
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("#");
+
Mockito.when(numberFormatProperty.getRoundingMode()).thenReturn(RoundingMode.UP);
+
+ Short resultSimple = NumberUtils.parseShort("123", contentProperty);
+ Assertions.assertEquals((short) 123, resultSimple);
+ }
+
+ @Test
+ void test_parseShort_noFormat() throws ParseException {
+ Short resultNullProp = NumberUtils.parseShort("123", null);
+ Assertions.assertEquals((short) 123, resultNullProp);
+
+ Mockito.reset(contentProperty);
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(null);
+
+ Short resultNullFormat = NumberUtils.parseShort("456",
contentProperty);
+ Assertions.assertEquals((short) 456, resultNullFormat);
+
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn(null);
+
+ Short resultEmptyFormat = NumberUtils.parseShort("789",
contentProperty);
+ Assertions.assertEquals((short) 789, resultEmptyFormat);
+ }
+
+ @Test
+ void test_parse_Error() {
+
Mockito.when(contentProperty.getNumberFormatProperty()).thenReturn(numberFormatProperty);
+ Mockito.when(numberFormatProperty.getFormat()).thenReturn("#");
+
Mockito.when(numberFormatProperty.getRoundingMode()).thenReturn(RoundingMode.UP);
+
+ Assertions.assertThrows(ParseException.class, () -> {
+ NumberUtils.parseInteger("not_a_number", contentProperty);
+ });
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/ParameterUtilTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/ParameterUtilTest.java
new file mode 100644
index 00000000..a182856b
--- /dev/null
+++
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/ParameterUtilTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.fesod.sheet.util;
+
+import org.apache.fesod.sheet.context.AnalysisContext;
+import org.apache.fesod.sheet.context.WriteContext;
+import org.apache.fesod.sheet.metadata.GlobalConfiguration;
+import org.apache.fesod.sheet.read.metadata.ReadSheet;
+import org.apache.fesod.sheet.read.metadata.holder.ReadWorkbookHolder;
+import org.apache.fesod.sheet.write.metadata.WriteSheet;
+import org.apache.fesod.sheet.write.metadata.holder.WriteWorkbookHolder;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+/**
+ * Tests {@link ParameterUtil}
+ */
+@ExtendWith(MockitoExtension.class)
+class ParameterUtilTest {
+
+ @Mock
+ private AnalysisContext analysisContext;
+
+ @Mock
+ private ReadWorkbookHolder readWorkbookHolder;
+
+ @Mock
+ private WriteContext writeContext;
+
+ @Mock
+ private WriteWorkbookHolder writeWorkbookHolder;
+
+ @Mock
+ private GlobalConfiguration globalConfiguration;
+
+ @Mock
+ private ReadSheet readSheet;
+
+ @Mock
+ private WriteSheet writeSheet;
+
+ @BeforeEach
+ void setUp() {
+
Mockito.lenient().when(analysisContext.readWorkbookHolder()).thenReturn(readWorkbookHolder);
+
Mockito.lenient().when(readWorkbookHolder.getGlobalConfiguration()).thenReturn(globalConfiguration);
+
+
Mockito.lenient().when(writeContext.writeWorkbookHolder()).thenReturn(writeWorkbookHolder);
+
Mockito.lenient().when(writeWorkbookHolder.getGlobalConfiguration()).thenReturn(globalConfiguration);
+ }
+
+ @Test
+ void test_AutoTrim_LocalTrue() {
+ Mockito.when(readSheet.getAutoTrim()).thenReturn(true);
+
+ Assertions.assertTrue(ParameterUtil.getAutoTrimFlag(readSheet,
analysisContext));
+ }
+
+ @Test
+ void test_AutoTrim_LocalNull_GlobalTrue() {
+ Mockito.when(readSheet.getAutoTrim()).thenReturn(null);
+ Mockito.when(globalConfiguration.getAutoTrim()).thenReturn(true);
+
+ Assertions.assertTrue(ParameterUtil.getAutoTrimFlag(readSheet,
analysisContext));
+ }
+
+ @Test
+ void test_AutoTrim_LocalNull_GlobalFalse() {
+ Mockito.when(readSheet.getAutoTrim()).thenReturn(null);
+ Mockito.when(globalConfiguration.getAutoTrim()).thenReturn(false);
+
+ Assertions.assertFalse(ParameterUtil.getAutoTrimFlag(readSheet,
analysisContext));
+ }
+
+ @Test
+ void test_AutoTrim_LocalFalse_Override_Global() {
+ Mockito.when(readSheet.getAutoTrim()).thenReturn(false);
+
Mockito.lenient().when(globalConfiguration.getAutoTrim()).thenReturn(true);
+
+ Assertions.assertFalse(ParameterUtil.getAutoTrimFlag(readSheet,
analysisContext));
+ }
+
+ @Test
+ void test_AutoStrip_LocalTrue() {
+ Mockito.when(readSheet.getAutoStrip()).thenReturn(true);
+
+ Assertions.assertTrue(ParameterUtil.getAutoStripFlag(readSheet,
analysisContext));
+ }
+
+ @Test
+ void test_AutoStrip_LocalNull_GlobalTrue() {
+ Mockito.when(readSheet.getAutoStrip()).thenReturn(null);
+ Mockito.when(globalConfiguration.getAutoStrip()).thenReturn(true);
+
+ Assertions.assertTrue(ParameterUtil.getAutoStripFlag(readSheet,
analysisContext));
+ }
+
+ @Test
+ void test_AutoStrip_AllFalse() {
+ Mockito.when(readSheet.getAutoStrip()).thenReturn(false);
+ Mockito.when(globalConfiguration.getAutoStrip()).thenReturn(false);
+
+ Assertions.assertFalse(ParameterUtil.getAutoStripFlag(readSheet,
analysisContext));
+ }
+
+ @Test
+ void test_AutoStrip_LocalFalse_Cannot_Override_Global() {
+ Mockito.when(readSheet.getAutoStrip()).thenReturn(false);
+ Mockito.when(globalConfiguration.getAutoStrip()).thenReturn(true);
+
+ Assertions.assertTrue(ParameterUtil.getAutoStripFlag(readSheet,
analysisContext));
+ }
+
+ @Test
+ void test_AutoTrim() {
+ Mockito.when(writeSheet.getAutoTrim()).thenReturn(null);
+ Mockito.when(globalConfiguration.getAutoTrim()).thenReturn(true);
+
+ Assertions.assertTrue(ParameterUtil.getAutoTrimFlag(writeSheet,
writeContext));
+ }
+
+ @Test
+ void test_AutoTrim_Override() {
+ Mockito.when(writeSheet.getAutoTrim()).thenReturn(false);
+
Mockito.lenient().when(globalConfiguration.getAutoTrim()).thenReturn(true);
+
+ Assertions.assertFalse(ParameterUtil.getAutoTrimFlag(writeSheet,
writeContext));
+ }
+
+ @Test
+ void test_AutoStrip_Fallback() {
+ Mockito.when(writeSheet.getAutoStrip()).thenReturn(null);
+ Mockito.when(globalConfiguration.getAutoStrip()).thenReturn(true);
+
+ Assertions.assertTrue(ParameterUtil.getAutoStripFlag(writeSheet,
writeContext));
+ }
+
+ @Test
+ void test_AutoStrip_CannotOverride() {
+ Mockito.when(writeSheet.getAutoStrip()).thenReturn(false);
+ Mockito.when(globalConfiguration.getAutoStrip()).thenReturn(true);
+
+ Assertions.assertTrue(ParameterUtil.getAutoStripFlag(writeSheet,
writeContext));
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/PoiUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/PoiUtilsTest.java
new file mode 100644
index 00000000..5a1f59f3
--- /dev/null
+++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/PoiUtilsTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.io.IOException;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+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.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link PoiUtils}
+ */
+class PoiUtilsTest {
+
+ @Test
+ void test_customHeight_XSSF_true() throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) {
+ Sheet sheet = wb.createSheet();
+ Row row = sheet.createRow(0);
+
+ if (row instanceof XSSFRow) {
+ ((XSSFRow) row).getCTRow().setCustomHeight(true);
+ }
+
+ Assertions.assertTrue(PoiUtils.customHeight(row));
+ }
+ }
+
+ @Test
+ void test_customHeight_XSSF_false() throws IOException {
+ try (Workbook wb = new XSSFWorkbook()) {
+ Sheet sheet = wb.createSheet();
+ Row row = sheet.createRow(0);
+
+ Assertions.assertFalse(PoiUtils.customHeight(row));
+ }
+ }
+
+ @Test
+ void test_customHeight_HSSF_false() throws IOException {
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ Sheet sheet = wb.createSheet();
+ Row row = sheet.createRow(0);
+
+ Assertions.assertFalse(PoiUtils.customHeight(row));
+ }
+ }
+
+ @Test
+ void test_customHeight_unsupportedType_false() throws IOException {
+ try (Workbook wb = new SXSSFWorkbook()) {
+ Sheet sheet = wb.createSheet();
+ Row row = sheet.createRow(0);
+
+ Assertions.assertFalse(PoiUtils.customHeight(row));
+ }
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/SheetUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/SheetUtilsTest.java
new file mode 100644
index 00000000..9ed8181c
--- /dev/null
+++ b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/SheetUtilsTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.util.Collections;
+import org.apache.fesod.sheet.context.AnalysisContext;
+import org.apache.fesod.sheet.metadata.GlobalConfiguration;
+import org.apache.fesod.sheet.read.metadata.ReadSheet;
+import org.apache.fesod.sheet.read.metadata.holder.ReadWorkbookHolder;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+/**
+ * Tests {@link SheetUtils}
+ */
+@ExtendWith(MockitoExtension.class)
+class SheetUtilsTest {
+
+ @Mock
+ private AnalysisContext analysisContext;
+
+ @Mock
+ private ReadWorkbookHolder readWorkbookHolder;
+
+ @Mock
+ private GlobalConfiguration globalConfiguration;
+
+ @Mock
+ private ReadSheet actualSheet;
+
+ @Mock
+ private ReadSheet paramSheet;
+
+ @BeforeEach
+ void setUp() {
+
Mockito.lenient().when(analysisContext.readWorkbookHolder()).thenReturn(readWorkbookHolder);
+
Mockito.lenient().when(readWorkbookHolder.getGlobalConfiguration()).thenReturn(globalConfiguration);
+ }
+
+ @Test
+ void test_match_withIgnoreHiddenSheet() {
+ // Setup
+
Mockito.when(readWorkbookHolder.getIgnoreHiddenSheet()).thenReturn(true);
+ Mockito.when(actualSheet.isHidden()).thenReturn(true);
+
+ // Execute
+ ReadSheet result = SheetUtils.match(actualSheet, analysisContext);
+
+ Assertions.assertNull(result);
+ }
+
+ @Test
+ void test_match_withReadAll() {
+ // Setup
+
Mockito.when(readWorkbookHolder.getIgnoreHiddenSheet()).thenReturn(false);
+ Mockito.when(readWorkbookHolder.getReadAll()).thenReturn(true);
+
+ // Execute
+ ReadSheet result = SheetUtils.match(actualSheet, analysisContext);
+
+ Assertions.assertEquals(actualSheet, result);
+ }
+
+ @Test
+ void test_match_withParameterSheetDataList_empty() {
+ // Setup
+
Mockito.when(readWorkbookHolder.getIgnoreHiddenSheet()).thenReturn(false);
+
Mockito.when(readWorkbookHolder.getParameterSheetDataList()).thenReturn(Collections.emptyList());
+
+ // Execute
+ ReadSheet result = SheetUtils.match(actualSheet, analysisContext);
+
+ Assertions.assertNull(result);
+ }
+
+ @Test
+ void test_match_ByName_FromSheet_RealObject() {
+ // Setup
+
Mockito.when(readWorkbookHolder.getIgnoreHiddenSheet()).thenReturn(false);
+ ReadSheet realParamSheet = new ReadSheet();
+
+ Mockito.when(readWorkbookHolder.getParameterSheetDataList())
+ .thenReturn(Collections.singletonList(realParamSheet));
+
+ Mockito.when(actualSheet.getSheetNo()).thenReturn(0);
+
+ // Execute
+ ReadSheet result = SheetUtils.match(actualSheet, analysisContext);
+
+ // Verify
+ Assertions.assertEquals(actualSheet, result);
+ Assertions.assertEquals(0, realParamSheet.getSheetNo());
+ Mockito.verify(actualSheet).copyBasicParameter(realParamSheet);
+ }
+
+ @Test
+ void test_match_ByName_AutoStrip_FromSheet() {
+ // Setup
+
Mockito.when(readWorkbookHolder.getIgnoreHiddenSheet()).thenReturn(false);
+
Mockito.when(readWorkbookHolder.getParameterSheetDataList()).thenReturn(Collections.singletonList(paramSheet));
+ Mockito.when(paramSheet.getSheetNo()).thenReturn(99);
+ Mockito.when(actualSheet.getSheetNo()).thenReturn(100);
+ Mockito.when(paramSheet.getSheetName()).thenReturn(" SheetA ");
+ Mockito.when(actualSheet.getSheetName()).thenReturn("SheetA");
+
+ Mockito.when(paramSheet.getAutoStrip()).thenReturn(true);
+
+ // Execute
+ ReadSheet result = SheetUtils.match(actualSheet, analysisContext);
+
+ // verify
+ Assertions.assertEquals(actualSheet, result);
+ Mockito.verify(actualSheet).copyBasicParameter(paramSheet);
+ }
+
+ @Test
+ void test_match_ByName_AutoTrim_FromSheet() {
+ // Setup
+
Mockito.when(readWorkbookHolder.getIgnoreHiddenSheet()).thenReturn(false);
+
Mockito.when(readWorkbookHolder.getParameterSheetDataList()).thenReturn(Collections.singletonList(paramSheet));
+
+ Mockito.when(paramSheet.getSheetNo()).thenReturn(99);
+ Mockito.when(actualSheet.getSheetNo()).thenReturn(100);
+ Mockito.when(paramSheet.getSheetName()).thenReturn(" SheetA ");
+ Mockito.when(actualSheet.getSheetName()).thenReturn("SheetA");
+
+ Mockito.when(paramSheet.getAutoStrip()).thenReturn(false);
+ Mockito.when(globalConfiguration.getAutoStrip()).thenReturn(false);
+ Mockito.when(paramSheet.getAutoTrim()).thenReturn(true);
+
+ // Execute
+ ReadSheet result = SheetUtils.match(actualSheet, analysisContext);
+
+ // verify
+ Assertions.assertEquals(actualSheet, result);
+ }
+
+ @Test
+ void test_match_ByName_GlobalConfig() {
+ // Setup
+
Mockito.when(readWorkbookHolder.getIgnoreHiddenSheet()).thenReturn(false);
+
Mockito.when(readWorkbookHolder.getParameterSheetDataList()).thenReturn(Collections.singletonList(paramSheet));
+
+ Mockito.when(paramSheet.getSheetNo()).thenReturn(99);
+ Mockito.when(actualSheet.getSheetNo()).thenReturn(100);
+ Mockito.when(paramSheet.getSheetName()).thenReturn(" SheetA ");
+ Mockito.when(actualSheet.getSheetName()).thenReturn("SheetA");
+
+ Mockito.when(paramSheet.getAutoStrip()).thenReturn(null);
+ Mockito.when(globalConfiguration.getAutoStrip()).thenReturn(true);
+
+ // Execute
+ ReadSheet result = SheetUtils.match(actualSheet, analysisContext);
+
+ // verify
+ Assertions.assertEquals(actualSheet, result);
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/WorkBookUtilTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/WorkBookUtilTest.java
new file mode 100644
index 00000000..f0d9cb23
--- /dev/null
+++
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/WorkBookUtilTest.java
@@ -0,0 +1,381 @@
+/*
+ * 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.fesod.sheet.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Locale;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.fesod.sheet.metadata.GlobalConfiguration;
+import org.apache.fesod.sheet.metadata.data.DataFormatData;
+import org.apache.fesod.sheet.metadata.data.WriteCellData;
+import org.apache.fesod.sheet.support.ExcelTypeEnum;
+import org.apache.fesod.sheet.write.metadata.WriteWorkbook;
+import org.apache.fesod.sheet.write.metadata.holder.WriteWorkbookHolder;
+import org.apache.fesod.sheet.write.metadata.style.WriteCellStyle;
+import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+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.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
+
+/**
+ * Tests {@link WorkBookUtil}
+ */
+@ExtendWith(MockitoExtension.class)
+class WorkBookUtilTest {
+
+ @Mock
+ private WriteWorkbookHolder writeWorkbookHolder;
+
+ @Mock
+ private GlobalConfiguration globalConfiguration;
+
+ @Mock
+ private WriteWorkbook writeWorkbook;
+
+ @AfterEach
+ void tearDown() {
+ Biff8EncryptionKey.setCurrentUserPassword(null);
+ }
+
+ @Test
+ void test_createWorkBook_XLSX_SXSSF() throws IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.XLSX);
+
Mockito.when(writeWorkbookHolder.getTempTemplateInputStream()).thenReturn(null);
+ Mockito.when(writeWorkbookHolder.getInMemory()).thenReturn(false);
+
Mockito.when(writeWorkbookHolder.getGlobalConfiguration()).thenReturn(globalConfiguration);
+
Mockito.when(globalConfiguration.getUse1904windowing()).thenReturn(null);
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+ // Verify
+ ArgumentCaptor<Workbook> workbookCaptor =
ArgumentCaptor.forClass(Workbook.class);
+
Mockito.verify(writeWorkbookHolder).setWorkbook(workbookCaptor.capture());
+ Assertions.assertInstanceOf(SXSSFWorkbook.class,
workbookCaptor.getValue());
+
Mockito.verify(writeWorkbookHolder).setCachedWorkbook(Mockito.any(Workbook.class));
+ }
+
+ @Test
+ void test_createWorkBook_XLSX_SXSSF_use1904windowing() throws IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.XLSX);
+
Mockito.when(writeWorkbookHolder.getTempTemplateInputStream()).thenReturn(null);
+ Mockito.when(writeWorkbookHolder.getInMemory()).thenReturn(false);
+
Mockito.when(writeWorkbookHolder.getGlobalConfiguration()).thenReturn(globalConfiguration);
+
Mockito.when(globalConfiguration.getUse1904windowing()).thenReturn(true);
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+ // Verify
+ ArgumentCaptor<Workbook> workbookCaptor =
ArgumentCaptor.forClass(Workbook.class);
+
Mockito.verify(writeWorkbookHolder).setWorkbook(workbookCaptor.capture());
+
+ Assertions.assertInstanceOf(SXSSFWorkbook.class,
workbookCaptor.getValue());
+
+ SXSSFWorkbook sxssfWorkbook = (SXSSFWorkbook)
workbookCaptor.getValue();
+ CTWorkbook ctWorkbook =
sxssfWorkbook.getXSSFWorkbook().getCTWorkbook();
+ Assertions.assertTrue(ctWorkbook.getWorkbookPr().getDate1904());
+
Mockito.verify(writeWorkbookHolder).setCachedWorkbook(Mockito.any(Workbook.class));
+ }
+
+ @Test
+ void test_createWorkBook_XLSX_SXSSF_withTemplate() throws IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.XLSX);
+
Mockito.when(writeWorkbookHolder.getTempTemplateInputStream()).thenReturn(createXLSX());
+ Mockito.when(writeWorkbookHolder.getInMemory()).thenReturn(false);
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+ // Verify
+
Mockito.verify(writeWorkbookHolder).setCachedWorkbook(Mockito.any(XSSFWorkbook.class));
+ ArgumentCaptor<Workbook> workbookCaptor =
ArgumentCaptor.forClass(Workbook.class);
+
Mockito.verify(writeWorkbookHolder).setWorkbook(workbookCaptor.capture());
+ Assertions.assertInstanceOf(SXSSFWorkbook.class,
workbookCaptor.getValue());
+ }
+
+ @Test
+ void test_createWorkBook_XLSX_SXSSF_withTemplate_inMemory() throws
IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.XLSX);
+
Mockito.when(writeWorkbookHolder.getTempTemplateInputStream()).thenReturn(createXLSX());
+ Mockito.when(writeWorkbookHolder.getInMemory()).thenReturn(true);
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+ // Verify
+
Mockito.verify(writeWorkbookHolder).setCachedWorkbook(Mockito.any(XSSFWorkbook.class));
+
Mockito.verify(writeWorkbookHolder).setWorkbook(Mockito.any(XSSFWorkbook.class));
+ }
+
+ private ByteArrayInputStream createXLSX() throws IOException {
+ try (XSSFWorkbook workbook = new XSSFWorkbook();
+ ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ workbook.createSheet("Template");
+ workbook.write(out);
+ return new ByteArrayInputStream(out.toByteArray());
+ }
+ }
+
+ @Test
+ void test_createWorkBook_XLSX_XSSF() throws IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.XLSX);
+
Mockito.when(writeWorkbookHolder.getTempTemplateInputStream()).thenReturn(null);
+ Mockito.when(writeWorkbookHolder.getInMemory()).thenReturn(true);
+
Mockito.when(writeWorkbookHolder.getGlobalConfiguration()).thenReturn(globalConfiguration);
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+ // Verify
+ ArgumentCaptor<Workbook> workbookCaptor =
ArgumentCaptor.forClass(Workbook.class);
+
Mockito.verify(writeWorkbookHolder).setWorkbook(workbookCaptor.capture());
+
+ Assertions.assertInstanceOf(XSSFWorkbook.class,
workbookCaptor.getValue());
+ }
+
+ @Test
+ void test_createWorkBook_XLS() throws IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.XLS);
+
Mockito.when(writeWorkbookHolder.getTempTemplateInputStream()).thenReturn(null);
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+ // Verify
+
Mockito.verify(writeWorkbookHolder).setCachedWorkbook(Mockito.any(HSSFWorkbook.class));
+ ArgumentCaptor<Workbook> workbookCaptor =
ArgumentCaptor.forClass(Workbook.class);
+
Mockito.verify(writeWorkbookHolder).setWorkbook(workbookCaptor.capture());
+
+ Assertions.assertInstanceOf(HSSFWorkbook.class,
workbookCaptor.getValue());
+ }
+
+ @Test
+ void test_createWorkBook_XLS_withTemplate() throws IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.XLS);
+
Mockito.when(writeWorkbookHolder.getTempTemplateInputStream()).thenReturn(createXLS());
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+ // Verify
+
Mockito.verify(writeWorkbookHolder).setCachedWorkbook(Mockito.any(HSSFWorkbook.class));
+ ArgumentCaptor<Workbook> workbookCaptor =
ArgumentCaptor.forClass(Workbook.class);
+
Mockito.verify(writeWorkbookHolder).setWorkbook(workbookCaptor.capture());
+
+ Assertions.assertInstanceOf(HSSFWorkbook.class,
workbookCaptor.getValue());
+ }
+
+ private ByteArrayInputStream createXLS() throws IOException {
+ try (HSSFWorkbook workbook = new HSSFWorkbook();
+ ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+ workbook.createSheet("Template");
+ workbook.write(out);
+ return new ByteArrayInputStream(out.toByteArray());
+ }
+ }
+
+ @Test
+ void test_createWorkBook_XLS_Password() throws IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.XLS);
+
Mockito.when(writeWorkbookHolder.getTempTemplateInputStream()).thenReturn(null);
+ Mockito.when(writeWorkbookHolder.getPassword()).thenReturn("123456");
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+ // Verify
+
Mockito.verify(writeWorkbookHolder).setWorkbook(Mockito.any(HSSFWorkbook.class));
+ }
+
+ @Test
+ void test_createWorkBook_CSV() throws IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.CSV);
+ Mockito.when(writeWorkbookHolder.getOutputStream()).thenReturn(new
ByteArrayOutputStream());
+
Mockito.when(writeWorkbookHolder.getCharset()).thenReturn(StandardCharsets.UTF_8);
+
Mockito.when(writeWorkbookHolder.getWriteWorkbook()).thenReturn(writeWorkbook);
+
+
Mockito.when(writeWorkbookHolder.getGlobalConfiguration()).thenReturn(globalConfiguration);
+
Mockito.when(globalConfiguration.getLocale()).thenReturn(Locale.SIMPLIFIED_CHINESE);
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+ // Verify
+
Mockito.verify(writeWorkbookHolder).setWorkbook(Mockito.any(Workbook.class));
+ }
+
+ @Test
+ void test_createWorkBook_CSV_withFormat() throws IOException {
+ // Setup
+
Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(ExcelTypeEnum.CSV);
+ Mockito.when(writeWorkbookHolder.getOutputStream()).thenReturn(new
ByteArrayOutputStream());
+
Mockito.when(writeWorkbookHolder.getCharset()).thenReturn(StandardCharsets.UTF_8);
+
Mockito.when(writeWorkbookHolder.getWriteWorkbook()).thenReturn(writeWorkbook);
+
Mockito.when(writeWorkbook.getCsvFormat()).thenReturn(CSVFormat.DEFAULT);
+
+
Mockito.when(writeWorkbookHolder.getGlobalConfiguration()).thenReturn(globalConfiguration);
+
Mockito.when(globalConfiguration.getLocale()).thenReturn(Locale.SIMPLIFIED_CHINESE);
+
+ // Execute
+ WorkBookUtil.createWorkBook(writeWorkbookHolder);
+
+
Mockito.verify(writeWorkbookHolder).setWorkbook(Mockito.any(Workbook.class));
+ }
+
+ @Test
+ void test_createWorkBook_UnknownType() {
+ Mockito.when(writeWorkbookHolder.getExcelType()).thenReturn(null);
+
+ Assertions.assertThrows(NullPointerException.class, () ->
WorkBookUtil.createWorkBook(writeWorkbookHolder));
+ }
+
+ @Test
+ void test_createSheet() {
+ Workbook workbook = Mockito.mock(Workbook.class);
+ String sheetName = "TestSheet";
+
+ WorkBookUtil.createSheet(workbook, sheetName);
+
+ Mockito.verify(workbook).createSheet(sheetName);
+ }
+
+ @Test
+ void test_createRow() {
+ Sheet sheet = Mockito.mock(Sheet.class);
+
+ WorkBookUtil.createRow(sheet, 1);
+
+ Mockito.verify(sheet).createRow(1);
+ }
+
+ @Test
+ void test_createCell_basic() {
+ Row row = Mockito.mock(Row.class);
+
+ WorkBookUtil.createCell(row, 2);
+
+ Mockito.verify(row).createCell(2);
+ }
+
+ @Test
+ void test_createCell_withStyle() {
+ Row row = Mockito.mock(Row.class);
+ Cell cell = Mockito.mock(Cell.class);
+ CellStyle style = Mockito.mock(CellStyle.class);
+ Mockito.when(row.createCell(Mockito.anyInt())).thenReturn(cell);
+
+ WorkBookUtil.createCell(row, 2, style);
+
+ Mockito.verify(row).createCell(2);
+ Mockito.verify(cell).setCellStyle(style);
+ }
+
+ @Test
+ void test_createCell_withValue() {
+ Row row = Mockito.mock(Row.class);
+ Cell cell = Mockito.mock(Cell.class);
+ CellStyle style = Mockito.mock(CellStyle.class);
+ Mockito.when(row.createCell(Mockito.anyInt())).thenReturn(cell);
+
+ WorkBookUtil.createCell(row, 2, style, "Hello");
+
+ Mockito.verify(cell).setCellStyle(style);
+ Mockito.verify(cell).setCellValue("Hello");
+ }
+
+ @Test
+ void test_createCell_stringOnly() {
+ Row row = Mockito.mock(Row.class);
+ Cell cell = Mockito.mock(Cell.class);
+ Mockito.when(row.createCell(Mockito.anyInt())).thenReturn(cell);
+
+ WorkBookUtil.createCell(row, 2, "World");
+
+ Mockito.verify(cell).setCellValue("World");
+ }
+
+ @Test
+ void test_fillDataFormat_allNull() {
+ WriteCellData<?> cellData = new WriteCellData<>();
+ String format = null;
+ String defaultFormat = "yyyy-MM-dd";
+
+ WorkBookUtil.fillDataFormat(cellData, format, defaultFormat);
+
+ Assertions.assertNotNull(cellData.getWriteCellStyle());
+
Assertions.assertNotNull(cellData.getWriteCellStyle().getDataFormatData());
+ Assertions.assertEquals(
+ defaultFormat,
cellData.getWriteCellStyle().getDataFormatData().getFormat());
+ }
+
+ @Test
+ void test_fillDataFormat_withFormat() {
+ WriteCellData<?> cellData = new WriteCellData<>();
+ String format = "#.00";
+ String defaultFormat = "General";
+
+ WorkBookUtil.fillDataFormat(cellData, format, defaultFormat);
+
+ Assertions.assertEquals(
+ format,
cellData.getWriteCellStyle().getDataFormatData().getFormat());
+ }
+
+ @Test
+ void test_fillDataFormat_existingFormat() {
+ WriteCellData<?> cellData = new WriteCellData<>();
+ WriteCellStyle writeCellStyle = new WriteCellStyle();
+ DataFormatData dataFormatData = new DataFormatData();
+ dataFormatData.setFormat("Existing");
+ writeCellStyle.setDataFormatData(dataFormatData);
+ cellData.setWriteCellStyle(writeCellStyle);
+
+ WorkBookUtil.fillDataFormat(cellData, "NewFormat", "Default");
+
+ Assertions.assertEquals(
+ "Existing",
cellData.getWriteCellStyle().getDataFormatData().getFormat());
+ }
+}
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/WriteHandlerUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/WriteHandlerUtilsTest.java
new file mode 100644
index 00000000..737c5f16
--- /dev/null
+++
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/WriteHandlerUtilsTest.java
@@ -0,0 +1,424 @@
+/*
+ * 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.fesod.sheet.util;
+
+import org.apache.fesod.sheet.context.WriteContext;
+import org.apache.fesod.sheet.metadata.Head;
+import org.apache.fesod.sheet.metadata.property.ExcelContentProperty;
+import org.apache.fesod.sheet.write.handler.chain.CellHandlerExecutionChain;
+import org.apache.fesod.sheet.write.handler.chain.RowHandlerExecutionChain;
+import org.apache.fesod.sheet.write.handler.chain.SheetHandlerExecutionChain;
+import
org.apache.fesod.sheet.write.handler.chain.WorkbookHandlerExecutionChain;
+import org.apache.fesod.sheet.write.handler.context.CellWriteHandlerContext;
+import org.apache.fesod.sheet.write.handler.context.RowWriteHandlerContext;
+import org.apache.fesod.sheet.write.handler.context.SheetWriteHandlerContext;
+import
org.apache.fesod.sheet.write.handler.context.WorkbookWriteHandlerContext;
+import org.apache.fesod.sheet.write.metadata.holder.AbstractWriteHolder;
+import org.apache.fesod.sheet.write.metadata.holder.WriteSheetHolder;
+import org.apache.fesod.sheet.write.metadata.holder.WriteTableHolder;
+import org.apache.fesod.sheet.write.metadata.holder.WriteWorkbookHolder;
+import org.apache.poi.ss.usermodel.Row;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+/**
+ * Tests {@link WriteHandlerUtilsTest}
+ */
+@ExtendWith(MockitoExtension.class)
+class WriteHandlerUtilsTest {
+
+ @Mock
+ private WriteContext writeContext;
+
+ @Mock
+ private WriteWorkbookHolder writeWorkbookHolder;
+
+ @Mock
+ private WriteSheetHolder writeSheetHolder;
+
+ @Mock
+ private WriteTableHolder writeTableHolder;
+
+ @Mock
+ private AbstractWriteHolder abstractWriteHolder;
+
+ @Mock
+ private WorkbookHandlerExecutionChain workbookChain;
+
+ @Mock
+ private SheetHandlerExecutionChain sheetChain;
+
+ @Mock
+ private RowHandlerExecutionChain rowChain;
+
+ @Mock
+ private CellHandlerExecutionChain cellChain;
+
+ @BeforeEach
+ void setUp() {
+
Mockito.lenient().when(writeContext.writeWorkbookHolder()).thenReturn(writeWorkbookHolder);
+
Mockito.lenient().when(writeContext.writeSheetHolder()).thenReturn(writeSheetHolder);
+
Mockito.lenient().when(writeContext.writeTableHolder()).thenReturn(writeTableHolder);
+
Mockito.lenient().when(writeContext.currentWriteHolder()).thenReturn(abstractWriteHolder);
+ }
+
+ @Test
+ void test_createWorkbookWriteHandlerContext_success() {
+ Assertions.assertDoesNotThrow(() -> {
+ WorkbookWriteHandlerContext context =
WriteHandlerUtils.createWorkbookWriteHandlerContext(writeContext);
+ Assertions.assertNotNull(context);
+ Assertions.assertEquals(writeContext, context.getWriteContext());
+
+
Mockito.verify(writeWorkbookHolder).setWorkbookWriteHandlerContext(context);
+ });
+ }
+
+ @Test
+ void test_beforeWorkbookCreate_runOwn_false() {
+ WorkbookWriteHandlerContext context =
Mockito.mock(WorkbookWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getWorkbookHandlerExecutionChain()).thenReturn(workbookChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeWorkbookCreate(context));
+ Mockito.verify(workbookChain).beforeWorkbookCreate(context);
+ }
+
+ @Test
+ void test_beforeWorkbookCreate_runOwn_true() {
+ WorkbookWriteHandlerContext context =
Mockito.mock(WorkbookWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getOwnWorkbookHandlerExecutionChain()).thenReturn(workbookChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeWorkbookCreate(context, true));
+
+ Mockito.verify(workbookChain).beforeWorkbookCreate(context);
+ Mockito.verify(abstractWriteHolder,
Mockito.never()).getWorkbookHandlerExecutionChain();
+ }
+
+ @Test
+ void test_beforeWorkbookCreate_chain_null() {
+ WorkbookWriteHandlerContext context =
Mockito.mock(WorkbookWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getWorkbookHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeWorkbookCreate(context));
+ }
+
+ @Test
+ void test_afterWorkbookCreate_runOwn_false() {
+ WorkbookWriteHandlerContext context =
Mockito.mock(WorkbookWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getWorkbookHandlerExecutionChain()).thenReturn(workbookChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterWorkbookCreate(context));
+ Mockito.verify(workbookChain).afterWorkbookCreate(context);
+ }
+
+ @Test
+ void test_afterWorkbookCreate_runOwn_true() {
+ WorkbookWriteHandlerContext context =
Mockito.mock(WorkbookWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getOwnWorkbookHandlerExecutionChain()).thenReturn(workbookChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterWorkbookCreate(context, true));
+ Mockito.verify(workbookChain).afterWorkbookCreate(context);
+ Mockito.verify(abstractWriteHolder,
Mockito.never()).getWorkbookHandlerExecutionChain();
+ }
+
+ @Test
+ void test_afterWorkbookCreate_chain_null() {
+ WorkbookWriteHandlerContext context =
Mockito.mock(WorkbookWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getWorkbookHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterWorkbookCreate(context));
+ }
+
+ @Test
+ void test_afterWorkbookDispose_execution() {
+ WorkbookWriteHandlerContext context =
Mockito.mock(WorkbookWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getWorkbookHandlerExecutionChain()).thenReturn(workbookChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterWorkbookDispose(context));
+ Mockito.verify(workbookChain).afterWorkbookDispose(context);
+ }
+
+ @Test
+ void test_afterWorkbookDispose_chain_null() {
+ WorkbookWriteHandlerContext context =
Mockito.mock(WorkbookWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getWorkbookHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterWorkbookDispose(context));
+ }
+
+ @Test
+ void test_createSheetWriteHandlerContext_fields_populated() {
+ Assertions.assertDoesNotThrow(() -> {
+ SheetWriteHandlerContext context =
WriteHandlerUtils.createSheetWriteHandlerContext(writeContext);
+ Assertions.assertNotNull(context);
+ Assertions.assertEquals(writeSheetHolder,
context.getWriteSheetHolder());
+ });
+ }
+
+ @Test
+ void test_beforeSheetCreate_runOwn_false() {
+ SheetWriteHandlerContext context =
Mockito.mock(SheetWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getSheetHandlerExecutionChain()).thenReturn(sheetChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeSheetCreate(context));
+
+ Mockito.verify(sheetChain).beforeSheetCreate(context);
+ }
+
+ @Test
+ void test_beforeSheetCreate_runOwn_true() {
+ SheetWriteHandlerContext context =
Mockito.mock(SheetWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getOwnSheetHandlerExecutionChain()).thenReturn(sheetChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeSheetCreate(context, true));
+ Mockito.verify(sheetChain).beforeSheetCreate(context);
+ Mockito.verify(abstractWriteHolder,
Mockito.never()).getSheetHandlerExecutionChain();
+ }
+
+ @Test
+ void test_beforeSheetCreate_chain_null() {
+ SheetWriteHandlerContext context =
Mockito.mock(SheetWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getSheetHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeSheetCreate(context));
+ }
+
+ @Test
+ void test_afterSheetCreate_runOwn_false() {
+ SheetWriteHandlerContext context =
Mockito.mock(SheetWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getSheetHandlerExecutionChain()).thenReturn(sheetChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterSheetCreate(context));
+ Mockito.verify(sheetChain).afterSheetCreate(context);
+ }
+
+ @Test
+ void test_afterSheetCreate_runOwn_true() {
+ SheetWriteHandlerContext context =
Mockito.mock(SheetWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getOwnSheetHandlerExecutionChain()).thenReturn(sheetChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterSheetCreate(context, true));
+ Mockito.verify(sheetChain).afterSheetCreate(context);
+ Mockito.verify(abstractWriteHolder,
Mockito.never()).getSheetHandlerExecutionChain();
+ }
+
+ @Test
+ void test_afterSheetCreate_chain_null() {
+ SheetWriteHandlerContext context =
Mockito.mock(SheetWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getSheetHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterSheetCreate(context));
+ }
+
+ @Test
+ void test_afterSheetDispose_execution() {
+
Mockito.when(abstractWriteHolder.getSheetHandlerExecutionChain()).thenReturn(sheetChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterSheetDispose(writeContext));
+
Mockito.verify(sheetChain).afterSheetDispose(ArgumentMatchers.any(SheetWriteHandlerContext.class));
+ }
+
+ @Test
+ void test_afterSheetDispose_chain_null() {
+
Mockito.when(abstractWriteHolder.getSheetHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterSheetDispose(writeContext));
+ }
+
+ @Test
+ void test_createRowWriteHandlerContext_args_mapping() {
+ Assertions.assertDoesNotThrow(() -> {
+ RowWriteHandlerContext context =
WriteHandlerUtils.createRowWriteHandlerContext(writeContext, 10, 5, true);
+ Assertions.assertEquals(10, context.getRowIndex());
+ Assertions.assertEquals(5, context.getRelativeRowIndex());
+ Assertions.assertTrue(context.getHead());
+ });
+ }
+
+ @Test
+ void test_beforeRowCreate_execution() {
+ RowWriteHandlerContext context =
Mockito.mock(RowWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getRowHandlerExecutionChain()).thenReturn(rowChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeRowCreate(context));
+ Mockito.verify(rowChain).beforeRowCreate(context);
+ }
+
+ @Test
+ void test_beforeRowCreate_chain_null() {
+ RowWriteHandlerContext context =
Mockito.mock(RowWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getRowHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeRowCreate(context));
+ }
+
+ @Test
+ void test_afterRowCreate_execution() {
+ RowWriteHandlerContext context =
Mockito.mock(RowWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getRowHandlerExecutionChain()).thenReturn(rowChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterRowCreate(context));
+ Mockito.verify(rowChain).afterRowCreate(context);
+ }
+
+ @Test
+ void test_afterRowCreate_chain_null() {
+ RowWriteHandlerContext context =
Mockito.mock(RowWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getRowHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterRowCreate(context));
+ }
+
+ @Test
+ void test_afterRowDispose_execution() {
+ RowWriteHandlerContext context =
Mockito.mock(RowWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getRowHandlerExecutionChain()).thenReturn(rowChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterRowDispose(context));
+ Mockito.verify(rowChain).afterRowDispose(context);
+ }
+
+ @Test
+ void test_afterRowDispose_chain_null() {
+ RowWriteHandlerContext context =
Mockito.mock(RowWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getRowHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterRowDispose(context));
+ }
+
+ @Test
+ void test_createCellWriteHandlerContext_full_args() {
+ Row row = Mockito.mock(Row.class);
+ Head head = Mockito.mock(Head.class);
+ ExcelContentProperty property =
Mockito.mock(ExcelContentProperty.class);
+
+ Assertions.assertDoesNotThrow(() -> {
+ CellWriteHandlerContext context =
+
WriteHandlerUtils.createCellWriteHandlerContext(writeContext, row, 1, head, 2,
0, false, property);
+
+ Assertions.assertEquals(row, context.getRow());
+ Assertions.assertEquals(1, context.getRowIndex());
+ Assertions.assertEquals(head, context.getHeadData());
+ Assertions.assertEquals(2, context.getColumnIndex());
+ Assertions.assertEquals(property,
context.getExcelContentProperty());
+ });
+ }
+
+ @Test
+ void test_beforeCellCreate_execution() {
+ CellWriteHandlerContext context =
Mockito.mock(CellWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getCellHandlerExecutionChain()).thenReturn(cellChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeCellCreate(context));
+ Mockito.verify(cellChain).beforeCellCreate(context);
+ }
+
+ @Test
+ void test_beforeCellCreate_chain_null() {
+ CellWriteHandlerContext context =
Mockito.mock(CellWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getCellHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.beforeCellCreate(context));
+ }
+
+ @Test
+ void test_afterCellCreate_execution() {
+ CellWriteHandlerContext context =
Mockito.mock(CellWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getCellHandlerExecutionChain()).thenReturn(cellChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterCellCreate(context));
+ Mockito.verify(cellChain).afterCellCreate(context);
+ }
+
+ @Test
+ void test_afterCellCreate_chain_null() {
+ CellWriteHandlerContext context =
Mockito.mock(CellWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getCellHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterCellCreate(context));
+ }
+
+ @Test
+ void test_afterCellDataConverted_execution() {
+ CellWriteHandlerContext context =
Mockito.mock(CellWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getCellHandlerExecutionChain()).thenReturn(cellChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterCellDataConverted(context));
+ Mockito.verify(cellChain).afterCellDataConverted(context);
+ }
+
+ @Test
+ void test_afterCellDataConverted_chain_null() {
+ CellWriteHandlerContext context =
Mockito.mock(CellWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getCellHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterCellDataConverted(context));
+ }
+
+ @Test
+ void test_afterCellDispose_execution() {
+ CellWriteHandlerContext context =
Mockito.mock(CellWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getCellHandlerExecutionChain()).thenReturn(cellChain);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterCellDispose(context));
+ Mockito.verify(cellChain).afterCellDispose(context);
+ }
+
+ @Test
+ void test_afterCellDispose_chain_null() {
+ CellWriteHandlerContext context =
Mockito.mock(CellWriteHandlerContext.class);
+ Mockito.when(context.getWriteContext()).thenReturn(writeContext);
+
Mockito.when(abstractWriteHolder.getCellHandlerExecutionChain()).thenReturn(null);
+
+ Assertions.assertDoesNotThrow(() ->
WriteHandlerUtils.afterCellDispose(context));
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]