Copilot commented on code in PR #629:
URL: https://github.com/apache/commons-csv/pull/629#discussion_r3665163030


##########
src/test/java/org/apache/commons/csv/CSVPrinterTest.java:
##########
@@ -1721,6 +1729,29 @@ void testPrinter7() throws IOException {
         }
     }
 
+    @Test
+    void testPrintNullValueStartingRecord() throws IOException {

Review Comment:
   Given the regression is about ‘leading null renders empty -> blank line -> 
dropped by ignoreEmptyLines’, it would be valuable to add an assertion for 
`QuoteMode.ALL` here as well. That both documents the intended behavior for 
‘quote all’ with null/empty values and will catch the remaining dropped-record 
scenario if `QuoteMode.ALL` isn’t handled in the runtime fix.



##########
src/test/java/org/apache/commons/csv/CSVPrinterTest.java:
##########
@@ -1721,6 +1729,29 @@ void testPrinter7() throws IOException {
         }
     }
 
+    @Test
+    void testPrintNullValueStartingRecord() throws IOException {
+        final StringWriter sw = new StringWriter();
+        try (CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT)) {
+            printer.printRecord("a");
+            printer.printRecord((Object) null);
+            printer.printRecord("b");
+        }
+        final String csv = sw.toString();
+        assertEquals("a" + RECORD_SEPARATOR + "\"\"" + RECORD_SEPARATOR + "b" 
+ RECORD_SEPARATOR, csv);
+        try (CSVParser parser = CSVParser.parse(csv, CSVFormat.DEFAULT)) {
+            final List<CSVRecord> records = parser.getRecords();
+            assertEquals(3, records.size());
+            assertArrayEquals(new String[] { "" }, records.get(1).values());
+        }
+        // An explicit MINIMAL quote mode encapsulates it too.
+        assertEquals("\"\"" + RECORD_SEPARATOR, 
printNullRecord(CSVFormat.DEFAULT.builder().setQuoteMode(QuoteMode.MINIMAL).get()));
+        // ALL_NON_NULL encodes null as the bare empty field, so it must stay 
unquoted.
+        assertEquals(RECORD_SEPARATOR, 
printNullRecord(CSVFormat.DEFAULT.builder().setQuoteMode(QuoteMode.ALL_NON_NULL).get()));
+        // Without a quote character there is nothing to encapsulate with.
+        assertEquals(RECORD_SEPARATOR, 
printNullRecord(CSVFormat.DEFAULT.builder().setQuote(null).get()));

Review Comment:
   Given the regression is about ‘leading null renders empty -> blank line -> 
dropped by ignoreEmptyLines’, it would be valuable to add an assertion for 
`QuoteMode.ALL` here as well. That both documents the intended behavior for 
‘quote all’ with null/empty values and will catch the remaining dropped-record 
scenario if `QuoteMode.ALL` isn’t handled in the runtime fix.



##########
src/main/java/org/apache/commons/csv/CSVFormat.java:
##########
@@ -2272,7 +2281,17 @@ private void print(final Object object, final 
CharSequence value, final Appendab
                 out.append(getDelimiterString());
             }
             if (object == null) {
-                out.append(value);
+                if (len == 0 && newRecord && isQuoteCharacterSet() && 
isMinimalQuoteMode()) {
+                    // Encapsulate like printWithQuotes does for an empty 
value that starts a record: an
+                    // unquoted one makes the whole line empty, and a parser 
with ignoreEmptyLines enabled
+                    // then drops the record. ALL_NON_NULL and NON_NUMERIC are 
excluded because they encode
+                    // null as the bare empty field.
+                    final char quoteChar = quoteCharacter.charValue(); // 
Explicit unboxing is intentional
+                    out.append(quoteChar);
+                    out.append(quoteChar);
+                } else {
+                    out.append(value);
+                }

Review Comment:
   This fixes the dropped-record case for MINIMAL/unset, but the same 
dropped-record behavior can still occur for `QuoteMode.ALL` (which conceptually 
should quote empty fields too). With `quoteMode == ALL`, a leading null that 
renders empty will still be output as a blank line and can be dropped when 
parsing with `ignoreEmptyLines`. Consider extending the condition to also 
encapsulate for `QuoteMode.ALL` (while still excluding 
`ALL_NON_NULL`/`NON_NUMERIC` as intended), or otherwise aligning null-handling 
with the quote-mode semantics so ‘quote all’ doesn’t emit an empty record as an 
empty line.



##########
src/test/java/org/apache/commons/csv/CSVPrinterTest.java:
##########
@@ -1854,8 +1885,8 @@ void testPrintRecordsWithObjectArray() throws IOException 
{
             printer.printRecords(objectArray);
             assertEquals(objectArray.length, printer.getRecordCount());
         }
-        assertEquals(6, charArrayWriter.size());
-        assertEquals("\n\n\n\n\n\n", charArrayWriter.toString());
+        assertEquals(16, charArrayWriter.size());
+        assertEquals("\"\"\n\"\"\n\"\"\n\n\"\"\n\"\"\n", 
charArrayWriter.toString());

Review Comment:
   The `16` here is a magic number that duplicates the information already 
encoded by the expected string, which can make future changes more error-prone 
(string changes without updating the size). Consider deriving the expected size 
from the expected string (e.g., compare `charArrayWriter.size()` to 
`expected.length()`), or dropping the separate size assertion if the full 
string assertion is sufficient.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to