From 9bf898af7a74806b9bf63b7c7ff7dd2ccc7a7c54 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Wed, 17 Aug 2022 11:34:00 -0500 Subject: [PATCH] Update to handle BOM char and index-out-of-bounds condition --- .../core/adapters/CsvToQRecordAdapter.java | 11 +++- .../adapters/CsvToQRecordAdapterTest.java | 57 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/adapters/CsvToQRecordAdapter.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/adapters/CsvToQRecordAdapter.java index 3d5493a3..98f85478 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/adapters/CsvToQRecordAdapter.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/adapters/CsvToQRecordAdapter.java @@ -95,6 +95,15 @@ public class CsvToQRecordAdapter throw (new IllegalArgumentException("Empty csv value was provided.")); } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // once, from a DOS csv file (that had come from Excel), we had a "" character (FEFF, Byte-order marker) at the start of a // + // CSV, which caused our first header to not match... So, let us strip away any FEFF or FFFE's at the start of CSV strings. // + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + if(csv.length() > 1 && (csv.charAt(0) == 0xfeff || csv.charAt(0) == 0xfffe)) + { + csv = csv.substring(1); + } + try { /////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -118,7 +127,7 @@ public class CsvToQRecordAdapter // put values from the CSV record into a map of header -> value // ////////////////////////////////////////////////////////////////// Map csvValues = new HashMap<>(); - for(int i = 0; i < headers.size(); i++) + for(int i = 0; i < headers.size() && i < csvRecord.size(); i++) { csvValues.put(headers.get(i), csvRecord.get(i)); } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/adapters/CsvToQRecordAdapterTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/adapters/CsvToQRecordAdapterTest.java index 2593b3e2..a81e5b53 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/adapters/CsvToQRecordAdapterTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/adapters/CsvToQRecordAdapterTest.java @@ -31,6 +31,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -281,4 +282,60 @@ class CsvToQRecordAdapterTest // todo - this is what the method header comment means when it says we don't handle all cases well... // Assertions.assertEquals(List.of("A", "B", "C", "C 2", "C 3"), csvToQRecordAdapter.makeHeadersUnique(List.of("A", "B", "C 2", "C", "C 3"))); } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testByteOrderMarker() + { + CsvToQRecordAdapter csvToQRecordAdapter = new CsvToQRecordAdapter(); + List records = csvToQRecordAdapter.buildRecordsFromCsv(""" + id,firstName + 1,John""", TestUtils.defineTablePerson(), null); + + assertEquals(1, records.get(0).getValueInteger("id")); + assertEquals("John", records.get(0).getValueString("firstName")); + } + + + + /******************************************************************************* + ** Fix an IndexOutOfBounds that we used to throw. + *******************************************************************************/ + @Test + void testTooFewBodyColumns() + { + CsvToQRecordAdapter csvToQRecordAdapter = new CsvToQRecordAdapter(); + List records = csvToQRecordAdapter.buildRecordsFromCsv(""" + id,firstName,lastName + 1,John""", TestUtils.defineTablePerson(), null); + + assertEquals(1, records.get(0).getValueInteger("id")); + assertEquals("John", records.get(0).getValueString("firstName")); + assertNull(records.get(0).getValueString("lastName")); + } + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + public void testTooFewColumnsIndexMapping() + { + int index = 1; + QIndexBasedFieldMapping mapping = new QIndexBasedFieldMapping() + .withMapping("id", index++) + .withMapping("firstName", index++) + .withMapping("lastName", index++); + + CsvToQRecordAdapter csvToQRecordAdapter = new CsvToQRecordAdapter(); + List records = csvToQRecordAdapter.buildRecordsFromCsv("1,John", TestUtils.defineTablePerson(), mapping); + + assertEquals(1, records.get(0).getValueInteger("id")); + assertEquals("John", records.get(0).getValueString("firstName")); + assertNull(records.get(0).getValueString("lastName")); + } + }