Skip to content

Commit d6290ec

Browse files
committed
test: add tests for escape-hex-write-handler
1 parent 30a0b74 commit d6290ec

1 file changed

Lines changed: 173 additions & 0 deletions

File tree

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.fesod.sheet.write.handler;
21+
22+
import java.io.BufferedReader;
23+
import java.io.File;
24+
import java.io.FileReader;
25+
import java.io.IOException;
26+
import java.util.ArrayList;
27+
import java.util.Collections;
28+
import java.util.List;
29+
import org.apache.fesod.sheet.FesodSheet;
30+
import org.apache.fesod.sheet.enums.CellDataTypeEnum;
31+
import org.apache.fesod.sheet.metadata.data.WriteCellData;
32+
import org.apache.fesod.sheet.testkit.Tags;
33+
import org.apache.fesod.sheet.testkit.enums.ExcelFormat;
34+
import org.apache.fesod.sheet.testkit.params.ExcelFormatSource;
35+
import org.apache.poi.ss.usermodel.Workbook;
36+
import org.apache.poi.ss.usermodel.WorkbookFactory;
37+
import org.apache.poi.xssf.streaming.SXSSFCell;
38+
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
39+
import org.junit.jupiter.api.Assertions;
40+
import org.junit.jupiter.api.Tag;
41+
import org.junit.jupiter.api.Test;
42+
import org.junit.jupiter.api.io.TempDir;
43+
import org.junit.jupiter.params.ParameterizedTest;
44+
import org.junit.jupiter.params.provider.CsvSource;
45+
import org.junit.jupiter.params.provider.ValueSource;
46+
47+
@Tag(Tags.UNIT)
48+
class EscapeHexCellWriteHandlerTest {
49+
50+
@TempDir
51+
File tempDir;
52+
53+
private final EscapeHexCellWriteHandler handler = new EscapeHexCellWriteHandler();
54+
55+
/**
56+
* Runs the handler over a string cell and returns the value it left behind.
57+
*/
58+
private String escape(String input) throws IOException {
59+
try (SXSSFWorkbook workbook = new SXSSFWorkbook()) {
60+
SXSSFCell cell = workbook.createSheet().createRow(0).createCell(0);
61+
WriteCellData<?> cellData = new WriteCellData<>(input);
62+
handler.afterCellDataConverted(null, null, cellData, cell, null, 0, Boolean.FALSE);
63+
return cellData.getStringValue();
64+
}
65+
}
66+
67+
@ParameterizedTest(name = "[{index}] {0} -> {1}")
68+
@CsvSource(
69+
delimiter = '|',
70+
value = {
71+
"_xB9f0_|_x005F_xB9f0_",
72+
"abc_x0041_|abc_x005F_x0041_",
73+
"_x0041__x0042_|_x005F_x0041__x005F_x0042_",
74+
"_xB9f0_ and _x1234_ and _xABCD_|_x005F_xB9f0_ and _x005F_x1234_ and _x005F_xABCD_",
75+
// 3 below check for partially valid cases - 1st format is valid, 2nd is invalid.
76+
"_x1234_ _xGHIJ_|_x005F_x1234_ _xGHIJ_",
77+
"_x0041__x12|_x005F_x0041__x12",
78+
"_x0041__x12345|_x005F_x0041__x12345",
79+
})
80+
void afterCellDataConverted_escapesEveryValidHexPattern(String input, String expected) throws IOException {
81+
Assertions.assertEquals(expected, escape(input));
82+
}
83+
84+
@ParameterizedTest(name = "[{index}] {0} is left alone")
85+
@ValueSource(
86+
strings = {
87+
"normalString",
88+
"_x12345_", // seventh character is not underscore
89+
"_x0041", // one character short of a complete pattern
90+
"_x00G1_", // a non-hex character
91+
"_x_x0041", // an unterminated pattern
92+
"", // empty input must not trip the scan
93+
"_x00é1_", // a non-ASCII character
94+
"_X1234_", // uppercase X
95+
})
96+
void afterCellDataConverted_leavesInvalidPatternsUntouched(String input) throws IOException {
97+
Assertions.assertEquals(input, escape(input));
98+
}
99+
100+
/**
101+
* Escaping is not idempotent: an already-escaped literal is escaped again
102+
*/
103+
@Test
104+
void afterCellDataConverted_escapesAnAlreadyEscapedSequenceAgain() throws IOException {
105+
Assertions.assertEquals("_x005F_x005F_x0041_", escape("_x005F_x0041_"));
106+
}
107+
108+
@Test
109+
void afterCellDataConverted_ignoresNonStringCellData() throws IOException {
110+
try (SXSSFWorkbook workbook = new SXSSFWorkbook()) {
111+
SXSSFCell cell = workbook.createSheet().createRow(0).createCell(0);
112+
WriteCellData<?> cellData = new WriteCellData<>(CellDataTypeEnum.ERROR, "_x0041_");
113+
114+
handler.afterCellDataConverted(null, null, cellData, cell, null, 0, Boolean.FALSE);
115+
116+
Assertions.assertEquals("_x0041_", cellData.getStringValue());
117+
}
118+
}
119+
120+
@Test
121+
void afterCellDataConverted_toleratesNullCellDataAndNullStringValue() throws IOException {
122+
try (SXSSFWorkbook workbook = new SXSSFWorkbook()) {
123+
SXSSFCell cell = workbook.createSheet().createRow(0).createCell(0);
124+
WriteCellData<?> emptyStringData = new WriteCellData<>(CellDataTypeEnum.STRING);
125+
126+
Assertions.assertDoesNotThrow(
127+
() -> handler.afterCellDataConverted(null, null, null, cell, null, 0, Boolean.FALSE));
128+
Assertions.assertDoesNotThrow(
129+
() -> handler.afterCellDataConverted(null, null, emptyStringData, cell, null, 0, Boolean.FALSE));
130+
Assertions.assertNull(emptyStringData.getStringValue());
131+
}
132+
}
133+
134+
private File writeEscapedWorkbook(ExcelFormat format) throws IOException {
135+
File file = format.createTempFile("escape-hex", tempDir);
136+
List<List<String>> rows = new ArrayList<>();
137+
rows.add(Collections.singletonList("_xB9f0_ and _x1234_"));
138+
139+
FesodSheet.write(file)
140+
.excelType(format.toExcelTypeEnum())
141+
.head(Collections.singletonList(Collections.singletonList("value")))
142+
.registerWriteHandler(new EscapeHexCellWriteHandler())
143+
.sheet("escape")
144+
.doWrite(rows);
145+
return file;
146+
}
147+
148+
private String readBackFirstDataValue(File file, ExcelFormat format) throws IOException {
149+
if (format == ExcelFormat.CSV) {
150+
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
151+
reader.readLine(); // header
152+
return reader.readLine();
153+
}
154+
}
155+
try (Workbook workbook = WorkbookFactory.create(file)) {
156+
return workbook.getSheetAt(0).getRow(1).getCell(0).getStringCellValue();
157+
}
158+
}
159+
160+
/**
161+
* Writes a file with the handler registered and reads it back: the caller must see the literal they typed.
162+
*
163+
* <p>All three formats expect the same value, for different reasons. On XLSX the handler escapes the sequence
164+
* and POI's reader decodes that escape away again. On XLS and CSV the handler never fires, since it only
165+
* touches {@link SXSSFCell}, so there was nothing to undo.
166+
*/
167+
@ParameterizedTest(name = "[{index}] {0} round-trips the literal hex sequence")
168+
@ExcelFormatSource
169+
void registeredOnAWrite_keepsLiteralHexSequencesIntactAcrossFormats(ExcelFormat format) throws IOException {
170+
File file = writeEscapedWorkbook(format);
171+
Assertions.assertEquals("_xB9f0_ and _x1234_", readBackFirstDataValue(file, format));
172+
}
173+
}

0 commit comments

Comments
 (0)