From 5f07781f275f8dc5e2e0ea2e321603412a847b9d Mon Sep 17 00:00:00 2001
From: Christopher Bohn <bohn@unl.edu>
Date: Sun, 19 Jan 2020 11:13:02 -0600
Subject: [PATCH] Completed refactor

- Writing to CSV is now done with openCSV calls, and client is
  responsible for lifecycle of injected dependencies (closes #1)
- Because of the openCSV calls, commas within a field are now allowed
  on output, as is enclosing a field in quotes (closes #3)
- Because reading had already been rewritten using openCSV calls,
  reading already could handle quoted fields that contained commas; we
  simply didn't have a test for it until now (closes #2)
---
 .../edu/unl/cse/csv_io/CSVReaderWriter.java   | 24 +++----
 .../unl/cse/csv_io/CSVReaderWriterTest.java   | 66 ++++++++++++++++++-
 2 files changed, 77 insertions(+), 13 deletions(-)

diff --git a/src/main/java/edu/unl/cse/csv_io/CSVReaderWriter.java b/src/main/java/edu/unl/cse/csv_io/CSVReaderWriter.java
index f81437c..1b9a16a 100644
--- a/src/main/java/edu/unl/cse/csv_io/CSVReaderWriter.java
+++ b/src/main/java/edu/unl/cse/csv_io/CSVReaderWriter.java
@@ -43,16 +43,16 @@ public class CSVReaderWriter {
         return csvList;
     }
 
-    private static Collection<Map<String, String>> parseCSV(InputStreamReader inputStreamReader,
+    private static Collection<Map<String, String>> parseCSV(Reader reader,
                                                             Collection<Map<String, String>> destination) {
         Map<String, String> line;
         try {
-            CSVReaderHeaderAware csvReader = new CSVReaderHeaderAwareBuilder(inputStreamReader).build();
+            CSVReaderHeaderAware csvReader = new CSVReaderHeaderAwareBuilder(reader).build();
             while ((line = csvReader.readMap()) != null) {
                 destination.add(line);
             }
         } catch (NullPointerException ignored) {
-            // CSVReaderHeaderAwareBuilder.build() throws NullPointerException if inputStreamReader is empty
+            // CSVReaderHeaderAwareBuilder.build() throws NullPointerException if reader is empty
         } catch (IOException ioException) {
             System.err.println("Error reading CSV file.  " + ioException);
         } catch (CsvValidationException csvValidationException) {
@@ -69,8 +69,8 @@ public class CSVReaderWriter {
         URL resource = classLoader.getResource("csv/" + filename);
         if (resource != null) {
             File file = new File(resource.getPath());
-            try (OutputStream outputStream = new FileOutputStream(file)) {
-                placeCSVonStream(data, outputStream);
+            try (FileWriter fileWriter = new FileWriter(file)) {
+                placeCSVonWriter(data, fileWriter);
             } catch (FileNotFoundException fileNotFoundException) {
                 System.err.println("Could not open " + filename + "; probably due to a bad pathname.  " + fileNotFoundException);
                 wroteFile = false;
@@ -85,13 +85,7 @@ public class CSVReaderWriter {
         return wroteFile;
     }
 
-    static void placeCSVonStream(Collection<Map<String, String>> data, OutputStream outputStream) throws IOException {
-        OutputStreamWriter writer = new OutputStreamWriter(outputStream);
-        placeCSVonWriter(data, writer);
-        writer.close();
-    }
-
-    static void placeCSVonWriter(Collection<Map<String, String>> data, OutputStreamWriter writer) {
+    static void placeCSVonWriter(Collection<Map<String, String>> data, Writer writer) {
         CSVWriter csvWriter = new CSVWriter(writer);
         List<String[]> allLines = new LinkedList<>();
         String[] fieldNames = getFieldNames(data);
@@ -128,6 +122,12 @@ public class CSVReaderWriter {
     static Set<Map<String, String>> parseCSV(InputStream inputStream) {
         return (Set<Map<String, String>>) parseCSV(new InputStreamReader(inputStream), new HashSet<>());
     }
+
+    static void placeCSVonStream(Collection<Map<String, String>> data, OutputStream outputStream) throws IOException {
+        OutputStreamWriter writer = new OutputStreamWriter(outputStream);
+        placeCSVonWriter(data, writer);
+        writer.close();
+    }
     
 /*
     public static void main(String[] args) {
diff --git a/src/test/java/edu/unl/cse/csv_io/CSVReaderWriterTest.java b/src/test/java/edu/unl/cse/csv_io/CSVReaderWriterTest.java
index 693c460..c7e5418 100644
--- a/src/test/java/edu/unl/cse/csv_io/CSVReaderWriterTest.java
+++ b/src/test/java/edu/unl/cse/csv_io/CSVReaderWriterTest.java
@@ -14,6 +14,7 @@ import static org.hamcrest.CoreMatchers.*;
 public class CSVReaderWriterTest {
     private static InputStream inputStream;
     private static OutputStream outputStream;
+    private static Writer writer;
 
     private static void placeCSVStringOnInputStream(String[][] data) {
         String CSVString = createCSVString(data);
@@ -35,10 +36,13 @@ public class CSVReaderWriterTest {
     @Before
     public void setUp() {
         outputStream = new ByteArrayOutputStream();
+        writer = new OutputStreamWriter(outputStream);
     }
 
     @After
-    public void tearDown() {
+    public void tearDown() throws IOException {
+        writer.close();
+        outputStream.close();
     }
 
     @Test
@@ -125,6 +129,36 @@ public class CSVReaderWriterTest {
         assertEquals(expectedResultSize, result.size());
     }
 
+    @Test
+    public void testReadingWithComma() {
+        // Input
+        String[] headers = {"header1", "header2"};
+        String[][] rows = {{"datum1", "datum2"}, {"datum3", "datum4"}, {"\"datum5, datum6\"", "datum7 datum8"}};
+        String[][] data = {headers, rows[0], rows[1], rows[2]};
+        // Output
+        placeCSVStringOnInputStream(data);
+        Set<Map<String, String>> result;
+        result = CSVReaderWriter.parseCSV(inputStream);
+        // Oracle -- Header
+        Set<String> expectedKeys = new HashSet<>(Arrays.asList(headers));
+        // Oracle -- Rows
+        String[][] parsedRows = {rows[0], rows[1], {"datum5, datum6", "datum7 datum8"}};
+        Map<String, String>[] expectedRows = new Map[3];
+        for (int i = 0; i < expectedRows.length; i++) {
+            expectedRows[i] = new HashMap<>();
+            for (int j = 0; j < headers.length; j++) {
+                expectedRows[i].put(headers[j], parsedRows[i][j]);
+            }
+        }
+        // Compare
+        assertNotNull(result);
+        Map<String, String> aRow = (Map<String, String>) result.toArray()[0];
+        assertEquals(expectedKeys, aRow.keySet());
+        for (Map<String, String> expectedRow : expectedRows) {
+            assertTrue(result.contains(expectedRow));
+        }
+    }
+
     // We probably should test malformed CSVs, but this is good enough for students' starter code
 
     @Test
@@ -153,4 +187,34 @@ public class CSVReaderWriterTest {
         assertTrue(expectedCSVStringOption1.equals(output) || expectedCSVStringOption2.equals(output));
         assertThat(output, either(is(expectedCSVStringOption1)).or(is(expectedCSVStringOption2)));
     }
+
+    @Test
+    public void testWritingWithComma() throws IOException {
+        // Input
+        String[] headers = {"header1", "header2"};
+        String[][] rows = {{"datum1", "datum2"}, {"datum3", "datum4"}, {"datum5, datum6", "datum7 datum8"}};
+        Map<String, String>[] inputRows = new Map[3];
+        for (int i = 0; i < inputRows.length; i++) {
+            inputRows[i] = new HashMap<>(2);
+            inputRows[i].put(headers[0], rows[i][0]);
+            inputRows[i].put(headers[1], rows[i][1]);
+        }
+        Set<Map<String, String>> input = new HashSet<>(Arrays.asList(inputRows));
+        // Oracle
+        String[] formattedRow2 = {"\"datum5, datum6\"", "datum7 datum8"};
+        String[][] data = {headers, rows[0], rows[1], formattedRow2};
+        String expectedCSVStringOption1 = createCSVString(data);
+        Collections.reverse(Arrays.asList(headers));
+        Collections.reverse(Arrays.asList(rows[0]));
+        Collections.reverse(Arrays.asList(rows[1]));
+        Collections.reverse(Arrays.asList(formattedRow2));
+        String expectedCSVStringOption2 = createCSVString(data);
+        // Output
+        CSVReaderWriter.placeCSVonWriter(input, writer);
+        writer.flush();
+        String output = outputStream.toString();
+        // Compare
+        assertTrue(expectedCSVStringOption1.equals(output) || expectedCSVStringOption2.equals(output));
+        assertThat(output, either(is(expectedCSVStringOption1)).or(is(expectedCSVStringOption2)));
+    }
 }
\ No newline at end of file
-- 
GitLab