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 000000000..19eb919a9 --- /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 000000000..da41bae8d --- /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 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 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 include = Arrays.asList("age", "name"); + Mockito.when(writeHolder.includeColumnFieldNames()).thenReturn(include); + + FieldCache fieldCache = ClassUtils.declaredFields(SimpleEntity.class, writeHolder); + Map 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 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> 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 000000000..8f8e69cd5 --- /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> 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> 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 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> 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 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> cellDataMap = new HashMap<>(); + cellDataMap.put(0, new ReadCellData<>(CellDataTypeEnum.EMPTY)); + + Map result = ConverterUtils.convertToStringMap(cellDataMap, context); + + Assertions.assertNull(result.get(0)); + Mockito.verify(stringConverter, Mockito.never()).convertToJavaData(Mockito.any()); + } + + @Test + void test_convertToStringMap_noConverter() { + Map> 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 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 000000000..43460cfc2 --- /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> tl = (ThreadLocal>) threadLocalField.get(null); + + Map 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 000000000..7c4817a5c --- /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 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 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 000000000..87a602035 --- /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 000000000..3c0133d03 --- /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 threadLocal = (ThreadLocal) 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 000000000..c4d6cb934 --- /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 000000000..a182856b8 --- /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 000000000..5a1f59f37 --- /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 000000000..9ed8181c6 --- /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 000000000..f0d9cb236 --- /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 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 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 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 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 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 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 000000000..737c5f164 --- /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)); + } +}