From 3771eabddd89125f1dfc1aa890c9c510bc441283 Mon Sep 17 00:00:00 2001 From: Ernest Date: Thu, 12 Feb 2026 04:33:20 +0300 Subject: [PATCH] Added Writable implementation --- src/main/java/org/writer/Main.java | 24 +++- src/main/java/org/writer/WritableImpl.java | 76 ++++++++++ .../java/org/writer/WritableImplTest.java | 134 ++++++++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/writer/WritableImpl.java create mode 100644 src/test/java/org/writer/WritableImplTest.java diff --git a/src/main/java/org/writer/Main.java b/src/main/java/org/writer/Main.java index 40e8213..e8bb77e 100644 --- a/src/main/java/org/writer/Main.java +++ b/src/main/java/org/writer/Main.java @@ -1,7 +1,29 @@ package org.writer; +import org.writer.model.Months; +import org.writer.model.Person; +import org.writer.model.Student; + +import java.util.List; + public class Main { public static void main(String[] args) { - System.out.println("Hello world!"); + Writable writable = new WritableImpl(); + + List students = List.of( + new Student("Student 1", List.of("5", "4", "3", "2")), + new Student("Student 2", List.of("2", "1", "1", "2")), + new Student("Student 3", List.of("2", "3", "4", "5")) + ); + writable.writeToFile(students, "Students.csv"); + + List persons = List.of( + new Person("Имя 1", "Фамилия 1", 17, Months.SEPTEMBER, 1996), + new Person("Имя 2", "Фамилия 2", 18, Months.OCTOBER, 1995), + new Person("Имя 3", "Фамилия 3", 19, Months.NOVEMBER, 1994), + new Person("Имя 4", "Фамилия 4", 20, Months.DECEMBER, 1993), + new Person("Имя 5", "Фамилия 5", 21, Months.JANUARY, 1992) + ); + writable.writeToFile(persons, "Persons.csv"); } } \ No newline at end of file diff --git a/src/main/java/org/writer/WritableImpl.java b/src/main/java/org/writer/WritableImpl.java new file mode 100644 index 0000000..ff235ce --- /dev/null +++ b/src/main/java/org/writer/WritableImpl.java @@ -0,0 +1,76 @@ +package org.writer; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + + +public class WritableImpl implements Writable { + + /** + * Writes CSV file from List. + * + * @param data List containing data to be written into CSV file. + * @param fileName Name of CSV file. + */ + @Override + public void writeToFile(List data, String fileName) { + List> fullDataList = new ArrayList<>(); + Set fieldNames = new LinkedHashSet<>(); + + for (Object object : data) { + List subList = new ArrayList<>(); + Field[] fields = object.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + fieldNames.add(field.getName()); + Object fieldValue; + try { + fieldValue = field.get(object); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + + String stringToAdd; + if (fieldValue instanceof Collection collection) { + String joined = collection.stream() + .map(Object::toString) + .map(this::escapeCsv) + .collect(Collectors.joining(", ")); + stringToAdd = escapeCsv(joined); + } else { + stringToAdd = escapeCsv(fieldValue.toString()); + } + subList.add(stringToAdd); + + } + fullDataList.add(subList); + } + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) { + writer.append(String.join(",", fieldNames)); + writer.newLine(); + + List tempList = fullDataList.stream() + .map(strings -> String.join(",", strings)) + .toList(); + for (String string : tempList) { + writer.append(string); + writer.newLine(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private String escapeCsv(String value) { + if (value == null) return ""; + if (value.contains("\"") || value.contains(",") || value.contains("\n")) { + return "\"" + value.replace("\"", "\"\"") + "\""; + } + return value; + } +} diff --git a/src/test/java/org/writer/WritableImplTest.java b/src/test/java/org/writer/WritableImplTest.java new file mode 100644 index 0000000..6c201b3 --- /dev/null +++ b/src/test/java/org/writer/WritableImplTest.java @@ -0,0 +1,134 @@ +package org.writer; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.writer.model.Student; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +class WritableImplTest { + + @TempDir + Path tempDir; + + @Test + void simpleWriteToFile() throws IOException { + WritableImpl writable = new WritableImpl(); + String fileName = "CorrectFileName"; + Path csvFile = tempDir.resolve(fileName); + List students = List.of( + new Student("Student 1", List.of("5", "4", "3", "2")), + new Student("Student 2", List.of("2", "1", "1", "2")), + new Student("Student 3", List.of("2", "3", "4", "5")) + ); + + writable.writeToFile(students, csvFile.toString()); + + assertAll( + () -> assertTrue(Files.exists(csvFile), " "), + () -> assertTrue(Files.isRegularFile(csvFile), " , "), + () -> assertTrue(Files.size(csvFile) > 0, " ") + ); + + List actual = Files.readAllLines(csvFile); + List expected = List.of( + "name,score", + "Student 1,\"5, 4, 3, 2\"", + "Student 2,\"2, 1, 1, 2\"", + "Student 3,\"2, 3, 4, 5\"" + ); + assertEquals(expected, actual); + } + + @Test + void dataHasDoubleQuotes() throws IOException { + WritableImpl writable = new WritableImpl(); + String fileName = "CorrectFileName"; + Path csvFile = tempDir.resolve(fileName); + List students = List.of( + new Student("St\"ude\"nt 1", List.of("5", "4", "3", "2")), + new Student("S\"tud\"ent 2", List.of("2", "1", "1", "2")), + new Student("\"Stu\"dent 3", List.of("2", "3", "4", "5")) + ); + + writable.writeToFile(students, csvFile.toString()); + + assertAll( + () -> assertTrue(Files.exists(csvFile), " "), + () -> assertTrue(Files.isRegularFile(csvFile), " , "), + () -> assertTrue(Files.size(csvFile) > 0, " ") + ); + + List actual = Files.readAllLines(csvFile); + List expected = List.of( + "name,score", + "\"St\"\"ude\"\"nt 1\",\"5, 4, 3, 2\"", + "\"S\"\"tud\"\"ent 2\",\"2, 1, 1, 2\"", + "\"\"\"Stu\"\"dent 3\",\"2, 3, 4, 5\"" + ); + assertEquals(expected, actual); + } + + @Test + void dataHasComma() throws IOException { + WritableImpl writable = new WritableImpl(); + String fileName = "CorrectFileName"; + Path csvFile = tempDir.resolve(fileName); + List students = List.of( + new Student("St,udent 1", List.of("5", "4", "3", "2")), + new Student("Stu,dent 2", List.of("2", "1", "1", "2")), + new Student("Stud,ent 3", List.of("2", "3", "4", "5")) + ); + + writable.writeToFile(students, csvFile.toString()); + + assertAll( + () -> assertTrue(Files.exists(csvFile), " "), + () -> assertTrue(Files.isRegularFile(csvFile), " , "), + () -> assertTrue(Files.size(csvFile) > 0, " ") + ); + + List actual = Files.readAllLines(csvFile); + List expected = List.of( + "name,score", + "\"St,udent 1\",\"5, 4, 3, 2\"", + "\"Stu,dent 2\",\"2, 1, 1, 2\"", + "\"Stud,ent 3\",\"2, 3, 4, 5\"" + ); + assertEquals(expected, actual); + } + + @Test + void dataHasEmptyCollection() throws IOException { + WritableImpl writable = new WritableImpl(); + String fileName = "CorrectFileName"; + Path csvFile = tempDir.resolve(fileName); + List students = List.of( + new Student("Student 1", Collections.emptyList()), + new Student("Student 2", Collections.emptyList()), + new Student("Student 3", Collections.emptyList()) + ); + + writable.writeToFile(students, csvFile.toString()); + + assertAll( + () -> assertTrue(Files.exists(csvFile), " "), + () -> assertTrue(Files.isRegularFile(csvFile), " , "), + () -> assertTrue(Files.size(csvFile) > 0, " ") + ); + + List actual = Files.readAllLines(csvFile); + List expected = List.of( + "name,score", + "Student 1,", + "Student 2,", + "Student 3," + ); + assertEquals(expected, actual); + } +} \ No newline at end of file