This is an automated email from the ASF dual-hosted git repository.

delei pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fesod.git


The following commit(s) were added to refs/heads/main by this push:
     new 1fb95727 test: add tests for EscapeHexCellWriteHandler (#1001)
1fb95727 is described below

commit 1fb95727b222f141b3ca30a19aa8a17a2a39803b
Author: Nikita Kuprins <[email protected]>
AuthorDate: Sat Aug 15 14:46:00 2026 +0300

    test: add tests for EscapeHexCellWriteHandler (#1001)
    
    * test: add tests for escape-hex-write-handler
    
    * fix: give the escape-hex round-trip its own class and tag
    
    * fix: read the round-trip csv as utf-8
    
    * fix: mock the cell instead of a real workbook
    
    * test: cover the non-SXSSF cell branch
    
    ---------
    
    Co-authored-by: ian zhang <[email protected]>
    Co-authored-by: DeleiGuo <[email protected]>
---
 .../EscapeHexCellWriteHandlerRoundTripTest.java    |  84 ++++++++++++++
 .../handler/EscapeHexCellWriteHandlerTest.java     | 124 +++++++++++++++++++++
 2 files changed, 208 insertions(+)

diff --git 
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/write/handler/EscapeHexCellWriteHandlerRoundTripTest.java
 
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/write/handler/EscapeHexCellWriteHandlerRoundTripTest.java
new file mode 100644
index 00000000..6227dca3
--- /dev/null
+++ 
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/write/handler/EscapeHexCellWriteHandlerRoundTripTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.write.handler;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.fesod.sheet.FesodSheet;
+import org.apache.fesod.sheet.testkit.Tags;
+import org.apache.fesod.sheet.testkit.base.AbstractExcelTest;
+import org.apache.fesod.sheet.testkit.enums.ExcelFormat;
+import org.apache.fesod.sheet.testkit.params.ExcelFormatSource;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.xssf.streaming.SXSSFCell;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.params.ParameterizedTest;
+
+@Tag(Tags.ROUND_TRIP)
+class EscapeHexCellWriteHandlerRoundTripTest extends AbstractExcelTest {
+
+    private File writeEscapedWorkbook(ExcelFormat format) throws IOException {
+        File file = createTempFile("escape-hex", format);
+        List<List<String>> rows = new ArrayList<>();
+        rows.add(Collections.singletonList("_xB9f0_ and _x1234_"));
+
+        FesodSheet.write(file)
+                .excelType(format.toExcelTypeEnum())
+                
.head(Collections.singletonList(Collections.singletonList("value")))
+                .registerWriteHandler(new EscapeHexCellWriteHandler())
+                .sheet("escape")
+                .doWrite(rows);
+        return file;
+    }
+
+    private String readBackFirstDataValue(File file, ExcelFormat format) 
throws IOException {
+        if (format == ExcelFormat.CSV) {
+            try (BufferedReader reader = 
Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
+                reader.readLine(); // header
+                return reader.readLine();
+            }
+        }
+        try (Workbook workbook = WorkbookFactory.create(file)) {
+            return 
workbook.getSheetAt(0).getRow(1).getCell(0).getStringCellValue();
+        }
+    }
+
+    /**
+     * Writes a file with the handler registered and reads it back: the caller 
must see the literal they typed.
+     *
+     * <p>All three formats expect the same value, for different reasons. On 
XLSX the handler escapes the sequence
+     * and POI's reader decodes that escape away again. On XLS and CSV the 
handler never fires, since it only
+     * touches {@link SXSSFCell}, so there was nothing to undo.
+     */
+    @ParameterizedTest(name = "[{index}] {0} round-trips the literal hex 
sequence")
+    @ExcelFormatSource
+    void 
registeredOnAWrite_keepsLiteralHexSequencesIntactAcrossFormats(ExcelFormat 
format) throws IOException {
+        File file = writeEscapedWorkbook(format);
+        Assertions.assertEquals("_xB9f0_ and _x1234_", 
readBackFirstDataValue(file, format));
+    }
+}
diff --git 
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/write/handler/EscapeHexCellWriteHandlerTest.java
 
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/write/handler/EscapeHexCellWriteHandlerTest.java
new file mode 100644
index 00000000..f751594e
--- /dev/null
+++ 
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/write/handler/EscapeHexCellWriteHandlerTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.write.handler;
+
+import org.apache.fesod.sheet.enums.CellDataTypeEnum;
+import org.apache.fesod.sheet.metadata.data.WriteCellData;
+import org.apache.fesod.sheet.testkit.Tags;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.xssf.streaming.SXSSFCell;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Tag;
+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;
+import org.mockito.Mockito;
+
+@Tag(Tags.UNIT)
+class EscapeHexCellWriteHandlerTest {
+
+    private final EscapeHexCellWriteHandler handler = new 
EscapeHexCellWriteHandler();
+
+    /**
+     * The handler only checks that the cell is an {@link SXSSFCell} and never 
reads from it, so a mock is all it
+     * needs.
+     */
+    private final SXSSFCell cell = Mockito.mock(SXSSFCell.class);
+
+    /**
+     * Runs the handler over a string cell and returns the value it left 
behind.
+     */
+    private String escape(String input) {
+        WriteCellData<?> cellData = new WriteCellData<>(input);
+        handler.afterCellDataConverted(null, null, cellData, cell, null, 0, 
Boolean.FALSE);
+        return cellData.getStringValue();
+    }
+
+    @ParameterizedTest(name = "[{index}] {0} -> {1}")
+    @CsvSource(
+            delimiter = '|',
+            value = {
+                "_xB9f0_|_x005F_xB9f0_",
+                "abc_x0041_|abc_x005F_x0041_",
+                "_x0041__x0042_|_x005F_x0041__x005F_x0042_",
+                "_xB9f0_ and _x1234_ and _xABCD_|_x005F_xB9f0_ and 
_x005F_x1234_ and _x005F_xABCD_",
+                // 3 below check for partially valid cases - 1st format is 
valid, 2nd is invalid.
+                "_x1234_ _xGHIJ_|_x005F_x1234_ _xGHIJ_",
+                "_x0041__x12|_x005F_x0041__x12",
+                "_x0041__x12345|_x005F_x0041__x12345",
+            })
+    void afterCellDataConverted_escapesEveryValidHexPattern(String input, 
String expected) {
+        Assertions.assertEquals(expected, escape(input));
+    }
+
+    @ParameterizedTest(name = "[{index}] {0} is left alone")
+    @ValueSource(
+            strings = {
+                "normalString",
+                "_x12345_", // seventh character is not underscore
+                "_x0041", // one character short of a complete pattern
+                "_x00G1_", // a non-hex character
+                "_x_x0041", // an unterminated pattern
+                "", // empty input must not trip the scan
+                "_x00é1_", // a non-ASCII character
+                "_X1234_", // uppercase X
+            })
+    void afterCellDataConverted_leavesInvalidPatternsUntouched(String input) {
+        Assertions.assertEquals(input, escape(input));
+    }
+
+    /**
+     * Escaping is not idempotent: an already-escaped literal is escaped again
+     */
+    @Test
+    void afterCellDataConverted_escapesAnAlreadyEscapedSequenceAgain() {
+        Assertions.assertEquals("_x005F_x005F_x0041_", 
escape("_x005F_x0041_"));
+    }
+
+    @Test
+    void afterCellDataConverted_ignoresNonStringCellData() {
+        WriteCellData<?> cellData = new 
WriteCellData<>(CellDataTypeEnum.ERROR, "_x0041_");
+
+        handler.afterCellDataConverted(null, null, cellData, cell, null, 0, 
Boolean.FALSE);
+
+        Assertions.assertEquals("_x0041_", cellData.getStringValue());
+    }
+
+    @Test
+    void afterCellDataConverted_ignoresNonSxssfCells() {
+        WriteCellData<?> cellData = new WriteCellData<>("_x0041_");
+
+        handler.afterCellDataConverted(null, null, cellData, 
Mockito.mock(HSSFCell.class), null, 0, Boolean.FALSE);
+
+        Assertions.assertEquals("_x0041_", cellData.getStringValue());
+    }
+
+    @Test
+    void afterCellDataConverted_toleratesNullCellDataAndNullStringValue() {
+        WriteCellData<?> emptyStringData = new 
WriteCellData<>(CellDataTypeEnum.STRING);
+
+        Assertions.assertDoesNotThrow(
+                () -> handler.afterCellDataConverted(null, null, null, cell, 
null, 0, Boolean.FALSE));
+        Assertions.assertDoesNotThrow(
+                () -> handler.afterCellDataConverted(null, null, 
emptyStringData, cell, null, 0, Boolean.FALSE));
+        Assertions.assertNull(emptyStringData.getStringValue());
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to