From ba59fa12dac6419014f8cfe652a9c50bc99e42db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Sun, 30 Aug 2026 20:34:10 +0700 Subject: [PATCH 01/29] feat: reworked classes StudentCsvWriter and StudentCsvReader --- .../project/datasource/StudentCsvReader.java | 79 +++++++++++++++++++ .../project/datasource/StudentCsvWriter.java | 73 +++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 app/src/main/java/ru/project/datasource/StudentCsvReader.java create mode 100644 app/src/main/java/ru/project/datasource/StudentCsvWriter.java diff --git a/app/src/main/java/ru/project/datasource/StudentCsvReader.java b/app/src/main/java/ru/project/datasource/StudentCsvReader.java new file mode 100644 index 0000000..7403caa --- /dev/null +++ b/app/src/main/java/ru/project/datasource/StudentCsvReader.java @@ -0,0 +1,79 @@ +package ru.project.datasource; + +import ru.project.student.Student; +import ru.project.student.StudentBuilder; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; + +public class StudentCsvReader implements Iterator { + private static final String GROUP_NUMBER = "groupNumber"; + private static final String AVERAGE_GRADE = "averageGrade"; + private static final String RECORD_BOOK_NUMBER = "recordBookNumber"; + + private final CSVParser parser; + private final Iterator records; + + public StudentCsvReader(String absoluteFilePath) { + Path path = Paths.get(absoluteFilePath); + if (!path.isAbsolute()) { + throw new IllegalArgumentException("File path must be absolute"); + } + + try { + CSVFormat format = CSVFormat.DEFAULT.builder() + .setHeader() + .setSkipHeaderRecord(true) + .build(); + this.parser = CSVParser.parse(path, StandardCharsets.UTF_8, format); + validateHeader(parser.getHeaderMap()); + this.records = parser.iterator(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public boolean hasNext() { + return records.hasNext(); + } + + @Override + public Student next() { + if (!records.hasNext()) { + throw new NoSuchElementException(); + } + + CSVRecord record = records.next(); + if (record.size() != 3) { + throw new IllegalArgumentException( + "Expected 3 columns, but got " + record.size()); + } + + double averageGrade = Double.parseDouble(record.get(AVERAGE_GRADE)); + return new StudentBuilder() + .setGroupNumber(record.get(GROUP_NUMBER)) + .setAverageGrade(averageGrade) + .setRecordBookNumber(record.get(RECORD_BOOK_NUMBER)) + .build(); + } + + private static void validateHeader(Map headerMap) { + String[] expected = {GROUP_NUMBER, AVERAGE_GRADE, RECORD_BOOK_NUMBER}; + if (headerMap.size() != expected.length + || !headerMap.keySet().containsAll(Arrays.asList(expected))) { + throw new IllegalArgumentException("Invalid CSV header"); + } + } +} diff --git a/app/src/main/java/ru/project/datasource/StudentCsvWriter.java b/app/src/main/java/ru/project/datasource/StudentCsvWriter.java new file mode 100644 index 0000000..c086ec0 --- /dev/null +++ b/app/src/main/java/ru/project/datasource/StudentCsvWriter.java @@ -0,0 +1,73 @@ +package ru.project.datasource; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import ru.project.student.Student; +import ru.project.collection.MyList; +import ru.project.collection.MyLinkedList; + + +public class StudentCsvWriter{ + private static final String[] HEADER = { + "groupNumber", "averageGrade", "recordBookNumber" + }; + private static final DateTimeFormatter FILE_NAME_FORMAT = + DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm"); + + private final Path requestedPath; + private Path actualPath; + + public StudentCsvWriter(String absoluteFilePath) { + Path path = Paths.get(absoluteFilePath); + if (!path.isAbsolute()) { + throw new IllegalArgumentException("File path must be absolute"); + } + this.requestedPath = path; + } + + public void write(Student student) throws IOException { + Path target = resolveTargetPath(); + boolean fileExists = Files.exists(target); + + StandardOpenOption[] options = fileExists + ? new StandardOpenOption[]{StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.APPEND} + : new StandardOpenOption[]{StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE}; + + try (BufferedWriter writer = Files.newBufferedWriter(target, StandardCharsets.UTF_8, options); + CSVPrinter printer = new CSVPrinter(writer, CSVFormat.DEFAULT)) { + if (!fileExists) { + printer.printRecord((Object[]) HEADER); + } + printer.printRecord( + student.getGroupNumber(), + Double.toString(student.getAverageGrade()), + student.getRecordBookNumber() + ); + } + } + + private Path resolveTargetPath() { + if (actualPath != null) { + return actualPath; + } + if (Files.exists(requestedPath)) { + actualPath = requestedPath; + return actualPath; + } + + Path parent = requestedPath.getParent(); + String fileName = "students-" + LocalDateTime.now().format(FILE_NAME_FORMAT) + ".csv"; + actualPath = parent == null ? Paths.get(fileName).toAbsolutePath() : parent.resolve(fileName); + return actualPath; + } +} \ No newline at end of file From cb5068465d8749555ba822af177862187f9ca0a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Sun, 30 Aug 2026 22:38:01 +0700 Subject: [PATCH 02/29] refactor: integrate StudentCsvParser into FileDataSource --- .../ru/project/datasource/FileDataSource.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 app/src/main/java/ru/project/datasource/FileDataSource.java diff --git a/app/src/main/java/ru/project/datasource/FileDataSource.java b/app/src/main/java/ru/project/datasource/FileDataSource.java new file mode 100644 index 0000000..62c1d83 --- /dev/null +++ b/app/src/main/java/ru/project/datasource/FileDataSource.java @@ -0,0 +1,39 @@ +package ru.project.datasource; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Collector; +import ru.project.student.Student; +import ru.project.collection.MyList; +import ru.project.collection.MyLinkedList; + +public class FileDataSource implements DataSource{ + private final String fileName; + + public FileDataSource(String fileName) { + this.fileName = fileName; + } + + @Override + public MyList create() { + MyList resultList = new MyLinkedList<>(); + try { + StudentCsvReader reader = new StudentCsvReader(fileName); + while reader.hasNext() { + result.append(reader.next()); + } + } + catch (IllegalArgumentException e){ + System.out.println(e.getMessage()); + return null; + } + catch (NoSuchElementException e){ + System.out.println("No such element"); + return null; + } + } +} From 0e6ff523e8aa721909ec7f3f17eb7d92ec298c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Sun, 30 Aug 2026 22:46:05 +0700 Subject: [PATCH 03/29] fix: import java.util.NoSuchElementException into FileDataSource --- app/src/main/java/ru/project/datasource/FileDataSource.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/ru/project/datasource/FileDataSource.java b/app/src/main/java/ru/project/datasource/FileDataSource.java index 62c1d83..b2c70d9 100644 --- a/app/src/main/java/ru/project/datasource/FileDataSource.java +++ b/app/src/main/java/ru/project/datasource/FileDataSource.java @@ -7,6 +7,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.stream.Collector; +import java.util.NoSuchElementException; import ru.project.student.Student; import ru.project.collection.MyList; import ru.project.collection.MyLinkedList; From 808e1eadbb5e8d0b23a38db38bd72994f950b12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Sun, 23 Aug 2026 23:10:10 +0700 Subject: [PATCH 04/29] feat: adding class student and data source interface --- app/src/main/java/ru/project/DataSource.java | 3 +++ .../main/java/ru/project/FileDataSource.java | 16 +++++++++++++ app/src/main/java/ru/project/Main.java | 15 ++++++++++++ .../java/ru/project/ManualDataSource.java | 16 +++++++++++++ app/src/main/java/ru/project/MyList.java | 2 ++ .../java/ru/project/RandomDataSource.java | 6 +++++ app/src/main/java/ru/project/Student.java | 11 +++++++++ .../main/java/ru/project/StudentBuilder.java | 23 +++++++++++++++++++ 8 files changed, 92 insertions(+) create mode 100644 app/src/main/java/ru/project/DataSource.java create mode 100644 app/src/main/java/ru/project/FileDataSource.java create mode 100644 app/src/main/java/ru/project/Main.java create mode 100644 app/src/main/java/ru/project/ManualDataSource.java create mode 100644 app/src/main/java/ru/project/MyList.java create mode 100644 app/src/main/java/ru/project/RandomDataSource.java create mode 100644 app/src/main/java/ru/project/Student.java create mode 100644 app/src/main/java/ru/project/StudentBuilder.java diff --git a/app/src/main/java/ru/project/DataSource.java b/app/src/main/java/ru/project/DataSource.java new file mode 100644 index 0000000..38f09f8 --- /dev/null +++ b/app/src/main/java/ru/project/DataSource.java @@ -0,0 +1,3 @@ +public interface DataSource { + MyList fill(int size); +} diff --git a/app/src/main/java/ru/project/FileDataSource.java b/app/src/main/java/ru/project/FileDataSource.java new file mode 100644 index 0000000..298e375 --- /dev/null +++ b/app/src/main/java/ru/project/FileDataSource.java @@ -0,0 +1,16 @@ +public class FileDataSource implements DataSource{ + private String path; + + public FileDataSource(String path) { + this.path = path; + } + + public void setPath(String path) { + this.path = path; + } + + @Override + public MyList fill(int size) { + return null; + } +} diff --git a/app/src/main/java/ru/project/Main.java b/app/src/main/java/ru/project/Main.java new file mode 100644 index 0000000..930198c --- /dev/null +++ b/app/src/main/java/ru/project/Main.java @@ -0,0 +1,15 @@ +//TIP To Run code, press or +// click the icon in the gutter. +public class Main { + public static void main(String[] args) { + //TIP Press with your caret at the highlighted text + // to see how IntelliJ IDEA suggests fixing it. + System.out.printf("Hello and welcome!"); + + for (int i = 1; i <= 5; i++) { + //TIP Press to start debugging your code. We have set one breakpoint + // for you, but you can always add more by pressing . + System.out.println("i = " + i); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/project/ManualDataSource.java b/app/src/main/java/ru/project/ManualDataSource.java new file mode 100644 index 0000000..c373daf --- /dev/null +++ b/app/src/main/java/ru/project/ManualDataSource.java @@ -0,0 +1,16 @@ +import java.util.Scanner; + +public class ManualDataSource implements DataSource{ + @Override + public MyList fill(int size) { + String strToParse; + Scanner scanner = new Scanner(System.in); + while(true){ + strToParse = scanner.next(); + if (strToParse.equals("0")) + break; + } + scanner.close(); + return null; + } +} diff --git a/app/src/main/java/ru/project/MyList.java b/app/src/main/java/ru/project/MyList.java new file mode 100644 index 0000000..153dca1 --- /dev/null +++ b/app/src/main/java/ru/project/MyList.java @@ -0,0 +1,2 @@ +public class MyList { +} diff --git a/app/src/main/java/ru/project/RandomDataSource.java b/app/src/main/java/ru/project/RandomDataSource.java new file mode 100644 index 0000000..021df21 --- /dev/null +++ b/app/src/main/java/ru/project/RandomDataSource.java @@ -0,0 +1,6 @@ +public class RandomDataSource implements DataSource{ + @Override + public MyList fill(int size) { + return null; + } +} diff --git a/app/src/main/java/ru/project/Student.java b/app/src/main/java/ru/project/Student.java new file mode 100644 index 0000000..d3fc714 --- /dev/null +++ b/app/src/main/java/ru/project/Student.java @@ -0,0 +1,11 @@ +public class Student { + private final String groupNumber; + private final double averageGrade; + private final String recordBookNumber; + + public Student(String groupNumber, double averageGrade, String recordBookNumber) { + this.groupNumber = groupNumber; + this.averageGrade = averageGrade; + this.recordBookNumber = recordBookNumber; + } +} diff --git a/app/src/main/java/ru/project/StudentBuilder.java b/app/src/main/java/ru/project/StudentBuilder.java new file mode 100644 index 0000000..9a5146b --- /dev/null +++ b/app/src/main/java/ru/project/StudentBuilder.java @@ -0,0 +1,23 @@ +public class StudentBuilder { + private String groupNumber; + private double averageGrade; + private String recordBookNumber; + + public void setGroupNumber(String groupNumber) { + this.groupNumber = groupNumber; + } + + public void setAverageGrade(double averageGrade) { + this.averageGrade = averageGrade; + } + + public void setRecordBookNumber(String recordBookNumber) { + this.recordBookNumber = recordBookNumber; + } + + public Student build(){ + //TODO: Реализовать проверку на корректность введенных значений + + return new Student(groupNumber,averageGrade, recordBookNumber); + } +} From 8fa66b10d2ff0553a88b881b3e90b81128d7fae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Mon, 24 Aug 2026 22:54:19 +0700 Subject: [PATCH 05/29] feat: add StringParser and reworking project structure --- app/src/main/java/ru/project/DataSource.java | 3 -- .../main/java/ru/project/FileDataSource.java | 16 --------- app/src/main/java/ru/project/Main.java | 15 -------- .../java/ru/project/ManualDataSource.java | 16 --------- app/src/main/java/ru/project/MyList.java | 2 -- app/src/main/java/ru/project/Student.java | 11 ------ .../main/java/ru/project/StudentBuilder.java | 23 ------------ .../ru/project/datasource/DataSource.java | 9 +++++ .../ru/project/datasource/FileDataSource.java | 36 ++++++++++--------- .../project/datasource/ManualDataSource.java | 29 +++++++++++++++ .../{ => datasource}/RandomDataSource.java | 5 +++ .../ru/project/datasource/StringParser.java | 20 +++++++++++ 12 files changed, 82 insertions(+), 103 deletions(-) delete mode 100644 app/src/main/java/ru/project/DataSource.java delete mode 100644 app/src/main/java/ru/project/FileDataSource.java delete mode 100644 app/src/main/java/ru/project/Main.java delete mode 100644 app/src/main/java/ru/project/ManualDataSource.java delete mode 100644 app/src/main/java/ru/project/MyList.java delete mode 100644 app/src/main/java/ru/project/Student.java delete mode 100644 app/src/main/java/ru/project/StudentBuilder.java create mode 100644 app/src/main/java/ru/project/datasource/DataSource.java create mode 100644 app/src/main/java/ru/project/datasource/ManualDataSource.java rename app/src/main/java/ru/project/{ => datasource}/RandomDataSource.java (57%) create mode 100644 app/src/main/java/ru/project/datasource/StringParser.java diff --git a/app/src/main/java/ru/project/DataSource.java b/app/src/main/java/ru/project/DataSource.java deleted file mode 100644 index 38f09f8..0000000 --- a/app/src/main/java/ru/project/DataSource.java +++ /dev/null @@ -1,3 +0,0 @@ -public interface DataSource { - MyList fill(int size); -} diff --git a/app/src/main/java/ru/project/FileDataSource.java b/app/src/main/java/ru/project/FileDataSource.java deleted file mode 100644 index 298e375..0000000 --- a/app/src/main/java/ru/project/FileDataSource.java +++ /dev/null @@ -1,16 +0,0 @@ -public class FileDataSource implements DataSource{ - private String path; - - public FileDataSource(String path) { - this.path = path; - } - - public void setPath(String path) { - this.path = path; - } - - @Override - public MyList fill(int size) { - return null; - } -} diff --git a/app/src/main/java/ru/project/Main.java b/app/src/main/java/ru/project/Main.java deleted file mode 100644 index 930198c..0000000 --- a/app/src/main/java/ru/project/Main.java +++ /dev/null @@ -1,15 +0,0 @@ -//TIP To Run code, press or -// click the icon in the gutter. -public class Main { - public static void main(String[] args) { - //TIP Press with your caret at the highlighted text - // to see how IntelliJ IDEA suggests fixing it. - System.out.printf("Hello and welcome!"); - - for (int i = 1; i <= 5; i++) { - //TIP Press to start debugging your code. We have set one breakpoint - // for you, but you can always add more by pressing . - System.out.println("i = " + i); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/ru/project/ManualDataSource.java b/app/src/main/java/ru/project/ManualDataSource.java deleted file mode 100644 index c373daf..0000000 --- a/app/src/main/java/ru/project/ManualDataSource.java +++ /dev/null @@ -1,16 +0,0 @@ -import java.util.Scanner; - -public class ManualDataSource implements DataSource{ - @Override - public MyList fill(int size) { - String strToParse; - Scanner scanner = new Scanner(System.in); - while(true){ - strToParse = scanner.next(); - if (strToParse.equals("0")) - break; - } - scanner.close(); - return null; - } -} diff --git a/app/src/main/java/ru/project/MyList.java b/app/src/main/java/ru/project/MyList.java deleted file mode 100644 index 153dca1..0000000 --- a/app/src/main/java/ru/project/MyList.java +++ /dev/null @@ -1,2 +0,0 @@ -public class MyList { -} diff --git a/app/src/main/java/ru/project/Student.java b/app/src/main/java/ru/project/Student.java deleted file mode 100644 index d3fc714..0000000 --- a/app/src/main/java/ru/project/Student.java +++ /dev/null @@ -1,11 +0,0 @@ -public class Student { - private final String groupNumber; - private final double averageGrade; - private final String recordBookNumber; - - public Student(String groupNumber, double averageGrade, String recordBookNumber) { - this.groupNumber = groupNumber; - this.averageGrade = averageGrade; - this.recordBookNumber = recordBookNumber; - } -} diff --git a/app/src/main/java/ru/project/StudentBuilder.java b/app/src/main/java/ru/project/StudentBuilder.java deleted file mode 100644 index 9a5146b..0000000 --- a/app/src/main/java/ru/project/StudentBuilder.java +++ /dev/null @@ -1,23 +0,0 @@ -public class StudentBuilder { - private String groupNumber; - private double averageGrade; - private String recordBookNumber; - - public void setGroupNumber(String groupNumber) { - this.groupNumber = groupNumber; - } - - public void setAverageGrade(double averageGrade) { - this.averageGrade = averageGrade; - } - - public void setRecordBookNumber(String recordBookNumber) { - this.recordBookNumber = recordBookNumber; - } - - public Student build(){ - //TODO: Реализовать проверку на корректность введенных значений - - return new Student(groupNumber,averageGrade, recordBookNumber); - } -} diff --git a/app/src/main/java/ru/project/datasource/DataSource.java b/app/src/main/java/ru/project/datasource/DataSource.java new file mode 100644 index 0000000..d8ad27f --- /dev/null +++ b/app/src/main/java/ru/project/datasource/DataSource.java @@ -0,0 +1,9 @@ +package ru.project.datasource; + +import ru.project.student.Student; +import ru.project.collection.MyList; + + +public interface DataSource { + MyList fill(int size); +} diff --git a/app/src/main/java/ru/project/datasource/FileDataSource.java b/app/src/main/java/ru/project/datasource/FileDataSource.java index b2c70d9..4b2c048 100644 --- a/app/src/main/java/ru/project/datasource/FileDataSource.java +++ b/app/src/main/java/ru/project/datasource/FileDataSource.java @@ -7,34 +7,36 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.stream.Collector; -import java.util.NoSuchElementException; import ru.project.student.Student; import ru.project.collection.MyList; -import ru.project.collection.MyLinkedList; public class FileDataSource implements DataSource{ - private final String fileName; + private String fileName; public FileDataSource(String fileName) { this.fileName = fileName; } + public void setFileName(String fileName) { + this.fileName = fileName; + } + @Override - public MyList create() { - MyList resultList = new MyLinkedList<>(); - try { - StudentCsvReader reader = new StudentCsvReader(fileName); - while reader.hasNext() { - result.append(reader.next()); - } - } - catch (IllegalArgumentException e){ - System.out.println(e.getMessage()); - return null; - } - catch (NoSuchElementException e){ - System.out.println("No such element"); + public MyList fill(int size) { + Path path = Paths.get(fileName); + try(var lines = Files.lines(path)){ + return lines.skip(1) + .limit(size) + .map(e -> StringParser.parseString(e)) + .filter(e -> !(e == null)) + .collect(Collector.of(MyList::new, + MyList::add, + (left, right) -> left.addAll(right))); + }catch(FileNotFoundException e){ + System.out.println("File not found."); return null; + } catch (IOException e) { + throw new RuntimeException(e); } } } diff --git a/app/src/main/java/ru/project/datasource/ManualDataSource.java b/app/src/main/java/ru/project/datasource/ManualDataSource.java new file mode 100644 index 0000000..f24c73a --- /dev/null +++ b/app/src/main/java/ru/project/datasource/ManualDataSource.java @@ -0,0 +1,29 @@ +package ru.project.datasource; + +import java.util.Scanner; +import ru.project.student.Student; +import ru.project.collection.MyList; + +public class ManualDataSource implements DataSource{ + @Override + public MyList fill(int size) { + MyList result = new MyList<>(); + String strToParse; + Student student; + Scanner scanner = new Scanner(System.in); + for (short i = 0; i < size; i++){ + strToParse = scanner.next(); + if (strToParse.equals("0")) + break; + student = StringParser.parseString(strToParse); + if (student == null){ + System.out.println("Oops! Invalid input"); + } + else{ + result.add(student); + } + } + scanner.close(); + return null; + } +} diff --git a/app/src/main/java/ru/project/RandomDataSource.java b/app/src/main/java/ru/project/datasource/RandomDataSource.java similarity index 57% rename from app/src/main/java/ru/project/RandomDataSource.java rename to app/src/main/java/ru/project/datasource/RandomDataSource.java index 021df21..8d5442e 100644 --- a/app/src/main/java/ru/project/RandomDataSource.java +++ b/app/src/main/java/ru/project/datasource/RandomDataSource.java @@ -1,3 +1,8 @@ +package ru.project.datasource; + +import ru.project.student.Student; +import ru.project.collection.MyList; + public class RandomDataSource implements DataSource{ @Override public MyList fill(int size) { diff --git a/app/src/main/java/ru/project/datasource/StringParser.java b/app/src/main/java/ru/project/datasource/StringParser.java new file mode 100644 index 0000000..2bfdd26 --- /dev/null +++ b/app/src/main/java/ru/project/datasource/StringParser.java @@ -0,0 +1,20 @@ +package ru.project.datasource; + +import ru.project.student.Student; +import ru.project.student.StudentBuilder; +import ru.project.collection.MyList; + +public class StringParser { + public static Student parseString(String str){ + String [] parts = str.split(";"); + try{ + return new StudentBuilder() + .setGroupNumber(parts[0]) + .setAverageGrade(Double.valueOf(parts[1])) + .setRecordBookNumber(parts[2]) + .build(); + }catch(NumberFormatException e){ + return null; + } + } +} From 02e14a987a9e2f2c43732814b5c7316b9ffa05b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Tue, 25 Aug 2026 22:18:22 +0700 Subject: [PATCH 06/29] feat: add random generation instances of class Student --- .../project/datasource/RandomDataSource.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/app/src/main/java/ru/project/datasource/RandomDataSource.java b/app/src/main/java/ru/project/datasource/RandomDataSource.java index 8d5442e..f81cf77 100644 --- a/app/src/main/java/ru/project/datasource/RandomDataSource.java +++ b/app/src/main/java/ru/project/datasource/RandomDataSource.java @@ -1,11 +1,36 @@ package ru.project.datasource; import ru.project.student.Student; +import ru.project.student.StudentBuilder; import ru.project.collection.MyList; +import java.util.Random; public class RandomDataSource implements DataSource{ + private final String CHARS = "АБВГДЕЖХИКЛМНОПРСТУФХЦЧЩЭЮЯ"; + + private String getRandomGroupNumber(Random random){ + StringBuilder buildRes = new StringBuilder(CHARS.charAt(random.nextInt(CHARS.length()))); + buildRes.append('-'); + buildRes.append(String.format("%03d", random.nextInt(999))); + return buildRes.toString(); + } + private String getRandomRecordBookNumber(Random random){ + StringBuilder buildRes = new StringBuilder(CHARS.charAt(random.nextInt(CHARS.length()))); + buildRes.append(String.format("%08d", random.nextInt(99999999))); + return buildRes.toString(); + } + @Override public MyList fill(int size) { + Random random = new Random(); + MyList result = new MyList<>(); + for (short i = 0; i Date: Fri, 28 Aug 2026 22:52:52 +0700 Subject: [PATCH 07/29] feat: add class FileWriter to append data to file --- .../ru/project/datasource/DataSource.java | 2 +- .../ru/project/datasource/FileDataSource.java | 15 ++++---- .../ru/project/datasource/FileWriter.java | 36 ++++++++++++++++++ .../project/datasource/ManualDataSource.java | 18 ++++++++- .../project/datasource/RandomDataSource.java | 34 +++++++++++------ .../ru/project/datasource/StudentBuffer.java | 37 +++++++++++++++++++ 6 files changed, 121 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/ru/project/datasource/FileWriter.java create mode 100644 app/src/main/java/ru/project/datasource/StudentBuffer.java diff --git a/app/src/main/java/ru/project/datasource/DataSource.java b/app/src/main/java/ru/project/datasource/DataSource.java index d8ad27f..08530a2 100644 --- a/app/src/main/java/ru/project/datasource/DataSource.java +++ b/app/src/main/java/ru/project/datasource/DataSource.java @@ -5,5 +5,5 @@ import ru.project.collection.MyList; public interface DataSource { - MyList fill(int size); + MyList create(); } diff --git a/app/src/main/java/ru/project/datasource/FileDataSource.java b/app/src/main/java/ru/project/datasource/FileDataSource.java index 4b2c048..88de258 100644 --- a/app/src/main/java/ru/project/datasource/FileDataSource.java +++ b/app/src/main/java/ru/project/datasource/FileDataSource.java @@ -9,6 +9,7 @@ import java.nio.file.Paths; import java.util.stream.Collector; import ru.project.student.Student; import ru.project.collection.MyList; +import ru.project.collection.MyLinkedList; public class FileDataSource implements DataSource{ private String fileName; @@ -22,16 +23,16 @@ public class FileDataSource implements DataSource{ } @Override - public MyList fill(int size) { - Path path = Paths.get(fileName); + public MyList create() { + Path path = Paths.of(fileName); try(var lines = Files.lines(path)){ - return lines.skip(1) - .limit(size) + return lines + //.skip(1) .map(e -> StringParser.parseString(e)) .filter(e -> !(e == null)) - .collect(Collector.of(MyList::new, - MyList::add, - (left, right) -> left.addAll(right))); + .collect(Collector.of(MyLinkedList::new, + MyLinkedList::add, + (left, right) -> left; }catch(FileNotFoundException e){ System.out.println("File not found."); return null; diff --git a/app/src/main/java/ru/project/datasource/FileWriter.java b/app/src/main/java/ru/project/datasource/FileWriter.java new file mode 100644 index 0000000..7b2f366 --- /dev/null +++ b/app/src/main/java/ru/project/datasource/FileWriter.java @@ -0,0 +1,36 @@ +package ru.project.datasource; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import ru.project.student.Student; +import ru.project.collection.MyList; +import ru.project.collection.MyLinkedList; +import ru.project.collection.Iterator; + +public class FileWriter { + private Path path; + + public FileWriter(String absolutePath) { + this.path = Path.of(absolutePath); + } + + public void write(MyList iist){ + //int sizeOfCollection = list.size(); + try (BufferedWriter writer = Files.newBufferedWriter( + path, + StandardOpenOption.CREATE, + StandardOpenOption.APPEND + )) { + Iterator iterator = list.getIterator(); + while (iterator.hasNext()){ + writer.write(iterator.next().toFileString()); + writer.newLine(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/app/src/main/java/ru/project/datasource/ManualDataSource.java b/app/src/main/java/ru/project/datasource/ManualDataSource.java index f24c73a..d7c46e7 100644 --- a/app/src/main/java/ru/project/datasource/ManualDataSource.java +++ b/app/src/main/java/ru/project/datasource/ManualDataSource.java @@ -3,11 +3,25 @@ package ru.project.datasource; import java.util.Scanner; import ru.project.student.Student; import ru.project.collection.MyList; +import ru.project.collection.MyLinkedList; public class ManualDataSource implements DataSource{ + private int size; + private MyList bufferMyList = new MyLinkedList<>(); + + public ManualDataSource(int size) { + this.size = size; + } + + public boolean setStudent( + int index, + String groupNumber, + double averageGrade, + int recordBookNumber + ){} @Override - public MyList fill(int size) { - MyList result = new MyList<>(); + public MyList create() { + MyList result = new MyLinkedList<>(); String strToParse; Student student; Scanner scanner = new Scanner(System.in); diff --git a/app/src/main/java/ru/project/datasource/RandomDataSource.java b/app/src/main/java/ru/project/datasource/RandomDataSource.java index f81cf77..d109fa2 100644 --- a/app/src/main/java/ru/project/datasource/RandomDataSource.java +++ b/app/src/main/java/ru/project/datasource/RandomDataSource.java @@ -3,34 +3,46 @@ package ru.project.datasource; import ru.project.student.Student; import ru.project.student.StudentBuilder; import ru.project.collection.MyList; +import ru.project.collection.MyLinkedList; import java.util.Random; public class RandomDataSource implements DataSource{ - private final String CHARS = "АБВГДЕЖХИКЛМНОПРСТУФХЦЧЩЭЮЯ"; + private final int size; + //private final String CHARS = "АБВГДЕЖХИКЛМНОПРСТУФХЦЧЩЭЮЯ"; + private int upperBounRecordBookNumber; + + public RandomDataSource(int size) { + this.size = size; + } + + public void setUpperBounRecordBookNumber(int upperBounRecordBookNumber) { + this.upperBounRecordBookNumber = upperBounRecordBookNumber; + } private String getRandomGroupNumber(Random random){ - StringBuilder buildRes = new StringBuilder(CHARS.charAt(random.nextInt(CHARS.length()))); - buildRes.append('-'); - buildRes.append(String.format("%03d", random.nextInt(999))); - return buildRes.toString(); + char prefix = (char)(random.nextInt(26) + (int)'A')4 + String result = prefix + String.format("%02d", random.nextInt(100)); + return result; } - private String getRandomRecordBookNumber(Random random){ + /*private String getRandomRecordBookNumber(Random random){ StringBuilder buildRes = new StringBuilder(CHARS.charAt(random.nextInt(CHARS.length()))); buildRes.append(String.format("%08d", random.nextInt(99999999))); return buildRes.toString(); - } + }*/ @Override - public MyList fill(int size) { + public MyList create() { + if (upperBounRecordBookNumber < 0) + throw new IllegalException("The upper bound is negative!!!"); Random random = new Random(); - MyList result = new MyList<>(); + MyList result = new MyLinkedList<>(); for (short i = 0; i Date: Sun, 30 Aug 2026 22:38:01 +0700 Subject: [PATCH 08/29] refactor: integrate StudentCsvParser into FileDataSource --- .../ru/project/datasource/FileDataSource.java | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/ru/project/datasource/FileDataSource.java b/app/src/main/java/ru/project/datasource/FileDataSource.java index 88de258..62c1d83 100644 --- a/app/src/main/java/ru/project/datasource/FileDataSource.java +++ b/app/src/main/java/ru/project/datasource/FileDataSource.java @@ -12,32 +12,28 @@ import ru.project.collection.MyList; import ru.project.collection.MyLinkedList; public class FileDataSource implements DataSource{ - private String fileName; + private final String fileName; public FileDataSource(String fileName) { this.fileName = fileName; } - public void setFileName(String fileName) { - this.fileName = fileName; - } - @Override public MyList create() { - Path path = Paths.of(fileName); - try(var lines = Files.lines(path)){ - return lines - //.skip(1) - .map(e -> StringParser.parseString(e)) - .filter(e -> !(e == null)) - .collect(Collector.of(MyLinkedList::new, - MyLinkedList::add, - (left, right) -> left; - }catch(FileNotFoundException e){ - System.out.println("File not found."); + MyList resultList = new MyLinkedList<>(); + try { + StudentCsvReader reader = new StudentCsvReader(fileName); + while reader.hasNext() { + result.append(reader.next()); + } + } + catch (IllegalArgumentException e){ + System.out.println(e.getMessage()); + return null; + } + catch (NoSuchElementException e){ + System.out.println("No such element"); return null; - } catch (IOException e) { - throw new RuntimeException(e); } } } From bf256e8247f63732d3b2b08bd7c17cab6d37fc1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Sun, 30 Aug 2026 22:46:05 +0700 Subject: [PATCH 09/29] fix: import java.util.NoSuchElementException into FileDataSource --- app/src/main/java/ru/project/datasource/FileDataSource.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/ru/project/datasource/FileDataSource.java b/app/src/main/java/ru/project/datasource/FileDataSource.java index 62c1d83..b2c70d9 100644 --- a/app/src/main/java/ru/project/datasource/FileDataSource.java +++ b/app/src/main/java/ru/project/datasource/FileDataSource.java @@ -7,6 +7,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.stream.Collector; +import java.util.NoSuchElementException; import ru.project.student.Student; import ru.project.collection.MyList; import ru.project.collection.MyLinkedList; From 4f1064ddafccacab04b32f8867669767af3df7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Mon, 31 Aug 2026 01:29:12 +0700 Subject: [PATCH 10/29] fix: fixing some syntax errors (part 1) --- app/pom.xml | 5 +++++ app/src/main/java/ru/project/datasource/FileDataSource.java | 5 +++-- app/src/main/java/ru/project/datasource/FileWriter.java | 6 +++--- .../main/java/ru/project/datasource/ManualDataSource.java | 4 +++- .../main/java/ru/project/datasource/RandomDataSource.java | 4 ++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/pom.xml b/app/pom.xml index 509e563..9caf260 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -41,6 +41,11 @@ junit-jupiter-params test + + org.apache.commons + commons-csv + 1.14.1 + diff --git a/app/src/main/java/ru/project/datasource/FileDataSource.java b/app/src/main/java/ru/project/datasource/FileDataSource.java index b2c70d9..1c80464 100644 --- a/app/src/main/java/ru/project/datasource/FileDataSource.java +++ b/app/src/main/java/ru/project/datasource/FileDataSource.java @@ -24,9 +24,10 @@ public class FileDataSource implements DataSource{ MyList resultList = new MyLinkedList<>(); try { StudentCsvReader reader = new StudentCsvReader(fileName); - while reader.hasNext() { - result.append(reader.next()); + while (reader.hasNext()) { + resultList.add(reader.next()); } + return resultList; } catch (IllegalArgumentException e){ System.out.println(e.getMessage()); diff --git a/app/src/main/java/ru/project/datasource/FileWriter.java b/app/src/main/java/ru/project/datasource/FileWriter.java index 7b2f366..5d78d89 100644 --- a/app/src/main/java/ru/project/datasource/FileWriter.java +++ b/app/src/main/java/ru/project/datasource/FileWriter.java @@ -8,7 +8,7 @@ import java.nio.file.StandardOpenOption; import ru.project.student.Student; import ru.project.collection.MyList; import ru.project.collection.MyLinkedList; -import ru.project.collection.Iterator; +//import ru.project.collection.Iterator; public class FileWriter { private Path path; @@ -24,11 +24,11 @@ public class FileWriter { StandardOpenOption.CREATE, StandardOpenOption.APPEND )) { - Iterator iterator = list.getIterator(); + /*Iterator iterator = list.getIterator(); while (iterator.hasNext()){ writer.write(iterator.next().toFileString()); writer.newLine(); - } + }*/ } catch (IOException e) { throw new RuntimeException(e); } diff --git a/app/src/main/java/ru/project/datasource/ManualDataSource.java b/app/src/main/java/ru/project/datasource/ManualDataSource.java index d7c46e7..a6ae64c 100644 --- a/app/src/main/java/ru/project/datasource/ManualDataSource.java +++ b/app/src/main/java/ru/project/datasource/ManualDataSource.java @@ -18,7 +18,9 @@ public class ManualDataSource implements DataSource{ String groupNumber, double averageGrade, int recordBookNumber - ){} + ){ + return true; + } @Override public MyList create() { MyList result = new MyLinkedList<>(); diff --git a/app/src/main/java/ru/project/datasource/RandomDataSource.java b/app/src/main/java/ru/project/datasource/RandomDataSource.java index d109fa2..9239aad 100644 --- a/app/src/main/java/ru/project/datasource/RandomDataSource.java +++ b/app/src/main/java/ru/project/datasource/RandomDataSource.java @@ -20,7 +20,7 @@ public class RandomDataSource implements DataSource{ } private String getRandomGroupNumber(Random random){ - char prefix = (char)(random.nextInt(26) + (int)'A')4 + char prefix = (char)(random.nextInt(26) + (int)'A'); String result = prefix + String.format("%02d", random.nextInt(100)); return result; } @@ -33,7 +33,7 @@ public class RandomDataSource implements DataSource{ @Override public MyList create() { if (upperBounRecordBookNumber < 0) - throw new IllegalException("The upper bound is negative!!!"); + throw new IllegalArgumentException("The upper bound is negative!!!"); Random random = new Random(); MyList result = new MyLinkedList<>(); for (short i = 0; i Date: Mon, 31 Aug 2026 16:22:03 +0700 Subject: [PATCH 11/29] refactor: removing unused file StringParser.java --- .../ru/project/datasource/StringParser.java | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 app/src/main/java/ru/project/datasource/StringParser.java diff --git a/app/src/main/java/ru/project/datasource/StringParser.java b/app/src/main/java/ru/project/datasource/StringParser.java deleted file mode 100644 index 2bfdd26..0000000 --- a/app/src/main/java/ru/project/datasource/StringParser.java +++ /dev/null @@ -1,20 +0,0 @@ -package ru.project.datasource; - -import ru.project.student.Student; -import ru.project.student.StudentBuilder; -import ru.project.collection.MyList; - -public class StringParser { - public static Student parseString(String str){ - String [] parts = str.split(";"); - try{ - return new StudentBuilder() - .setGroupNumber(parts[0]) - .setAverageGrade(Double.valueOf(parts[1])) - .setRecordBookNumber(parts[2]) - .build(); - }catch(NumberFormatException e){ - return null; - } - } -} From 7408b0fd418aa222991b89b8aa8f1b49eb806016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Mon, 31 Aug 2026 16:39:56 +0700 Subject: [PATCH 12/29] fix: fixing syntax errors (part 2) --- app/src/main/java/ru/project/datasource/ManualDataSource.java | 4 ++-- app/src/main/java/ru/project/datasource/StudentCsvReader.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/ru/project/datasource/ManualDataSource.java b/app/src/main/java/ru/project/datasource/ManualDataSource.java index a6ae64c..a5bdad7 100644 --- a/app/src/main/java/ru/project/datasource/ManualDataSource.java +++ b/app/src/main/java/ru/project/datasource/ManualDataSource.java @@ -23,7 +23,7 @@ public class ManualDataSource implements DataSource{ } @Override public MyList create() { - MyList result = new MyLinkedList<>(); + /*MyList result = new MyLinkedList<>(); String strToParse; Student student; Scanner scanner = new Scanner(System.in); @@ -39,7 +39,7 @@ public class ManualDataSource implements DataSource{ result.add(student); } } - scanner.close(); + scanner.close();*/ return null; } } diff --git a/app/src/main/java/ru/project/datasource/StudentCsvReader.java b/app/src/main/java/ru/project/datasource/StudentCsvReader.java index 7403caa..7e39bee 100644 --- a/app/src/main/java/ru/project/datasource/StudentCsvReader.java +++ b/app/src/main/java/ru/project/datasource/StudentCsvReader.java @@ -62,10 +62,11 @@ public class StudentCsvReader implements Iterator { } double averageGrade = Double.parseDouble(record.get(AVERAGE_GRADE)); + int recordBookNumber = Integer.parseInt(record.get(RECORD_BOOK_NUMBER)); return new StudentBuilder() .setGroupNumber(record.get(GROUP_NUMBER)) .setAverageGrade(averageGrade) - .setRecordBookNumber(record.get(RECORD_BOOK_NUMBER)) + .setRecordBookNumber(recordBookNumber) .build(); } From eef7b45172bd26a28c8e7a023e360601a0bb00e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Mon, 31 Aug 2026 21:28:16 +0700 Subject: [PATCH 13/29] test: add test class DataSourceReaderTest --- .../datasource/DataSourceReaderTest.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 app/src/test/java/ru/project/datasource/DataSourceReaderTest.java diff --git a/app/src/test/java/ru/project/datasource/DataSourceReaderTest.java b/app/src/test/java/ru/project/datasource/DataSourceReaderTest.java new file mode 100644 index 0000000..740904c --- /dev/null +++ b/app/src/test/java/ru/project/datasource/DataSourceReaderTest.java @@ -0,0 +1,116 @@ +package ru.project.datasource; + +import java.io.UncheckedIOException; +import java.util.NoSuchElementException; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; + +import ru.project.collection.MyList; +import ru.project.collection.MyLinkedList; + +import ru.project.student.Student; +import ru.project.student.StudentBuilder; + +class DataSourceReaderTest{ + private StudentCsvReader valideReader; + //Testing StudentCsvReader + @BeforeEach + void setUp(){ + valideReader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\sample.csv"); + } + + @Test + void readerTestRejectRelativePath(){ + assertThrows(IllegalArgumentException.class, () -> new StudentCsvReader("/Users/Dexp/TestData/sample.csv")); + } + + @Test + void readerRejectPathIsDir(){ + assertThrows(UncheckedIOException.class, () -> new StudentCsvReader("C:\\Users\\Dexp\\TestData")); + } + + @Test + void readerTestFileNotExist(){ + assertThrows(UncheckedIOException.class, () -> new StudentCsvReader("C:\\Users\\Dexp\\TestData\\sss.csv")); + } + + @Test + void testSkipsHeader(){ + Student student = valideReader.next(); + assertTrue(!(student.getGroupNumber()=="groupNumber")); + } + + @Test + void testCreationStudentOnValidData(){ + Student student = valideReader.next(); + assertEquals(student.getGroupNumber(), "A21"); + assertEquals(student.getAverageGrade(), 5.0); + assertEquals(student.getRecordBookNumber(), 331); + } + + @Test + void testNotSkippingFirstStudent(){ + boolean hn = valideReader.hasNext(); + hn = valideReader.hasNext(); + Student student = valideReader.next(); + assertEquals(student.getGroupNumber(), "A21"); + assertEquals(student.getAverageGrade(), 5.0); + assertEquals(student.getRecordBookNumber(), 331); + } + + @Test + void testValidEndsOfFile(){ + Student student = valideReader.next(); + student = valideReader.next(); + assertTrue(!valideReader.hasNext()); + } + + @Test + void testOutOfIndex(){ + assertThrows(NoSuchElementException.class, () -> { + Student student = valideReader.next(); + student = valideReader.next(); + student = valideReader.next(); + }); + } + + @Test + void readerTestRejectFewParametres(){ + assertThrows(IllegalArgumentException.class, () -> { + StudentCsvReader reader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\fewparameters.csv"); + Student student = reader.next(); + }); + } + + @Test + void readerTestRejectInvalidGroupNumber(){ + assertThrows(IllegalArgumentException.class, () -> { + StudentCsvReader reader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_groupnumber.csv"); + Student student = reader.next(); + }); + } + + @Test + void readerTestRejectInvalidAverageGrade(){ + assertThrows(IllegalArgumentException.class, () -> { + StudentCsvReader reader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_averagegrade.csv"); + Student student = reader.next(); + }); + } + + @Test + void readerTestRejectInvalidRecordBookNumber(){ + assertThrows(IllegalArgumentException.class, () -> { + StudentCsvReader reader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_recordbooknumber.csv"); + Student student = reader.next(); + }); + } +} \ No newline at end of file From 3b09d15163ab8d838b393219cc5d750b5d33daf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Mon, 31 Aug 2026 22:30:45 +0700 Subject: [PATCH 14/29] feat: reworking StudentCsvReader. Added the aability to specify row number when an exception is thrown out --- .../project/datasource/StudentCsvReader.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/ru/project/datasource/StudentCsvReader.java b/app/src/main/java/ru/project/datasource/StudentCsvReader.java index 7e39bee..156608e 100644 --- a/app/src/main/java/ru/project/datasource/StudentCsvReader.java +++ b/app/src/main/java/ru/project/datasource/StudentCsvReader.java @@ -25,7 +25,10 @@ public class StudentCsvReader implements Iterator { private final CSVParser parser; private final Iterator records; + private int lineOfFile; + public StudentCsvReader(String absoluteFilePath) { + lineOfFile = 0; Path path = Paths.get(absoluteFilePath); if (!path.isAbsolute()) { throw new IllegalArgumentException("File path must be absolute"); @@ -51,6 +54,7 @@ public class StudentCsvReader implements Iterator { @Override public Student next() { + lineOfFile++; if (!records.hasNext()) { throw new NoSuchElementException(); } @@ -58,16 +62,21 @@ public class StudentCsvReader implements Iterator { CSVRecord record = records.next(); if (record.size() != 3) { throw new IllegalArgumentException( - "Expected 3 columns, but got " + record.size()); + "Problem at line " + lineOfFile + ".Expected 3 columns, but got " + record.size()); + } + try { + double averageGrade = Double.parseDouble(record.get(AVERAGE_GRADE)); + int recordBookNumber = Integer.parseInt(record.get(RECORD_BOOK_NUMBER)); + return new StudentBuilder() + .setGroupNumber(record.get(GROUP_NUMBER)) + .setAverageGrade(averageGrade) + .setRecordBookNumber(recordBookNumber) + .build(); + } + catch (NumberFormatException e){ + throw new IllegalArgumentException( + "Problem at line " + lineOfFile + ". Unacceptable type convertation"); } - - double averageGrade = Double.parseDouble(record.get(AVERAGE_GRADE)); - int recordBookNumber = Integer.parseInt(record.get(RECORD_BOOK_NUMBER)); - return new StudentBuilder() - .setGroupNumber(record.get(GROUP_NUMBER)) - .setAverageGrade(averageGrade) - .setRecordBookNumber(recordBookNumber) - .build(); } private static void validateHeader(Map headerMap) { From fad97d8e9573f714b9235bd929321c5558428ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Mon, 31 Aug 2026 22:33:56 +0700 Subject: [PATCH 15/29] refactor: removing unused class ManualDataSource --- .../project/datasource/ManualDataSource.java | 45 ------------------- 1 file changed, 45 deletions(-) delete mode 100644 app/src/main/java/ru/project/datasource/ManualDataSource.java diff --git a/app/src/main/java/ru/project/datasource/ManualDataSource.java b/app/src/main/java/ru/project/datasource/ManualDataSource.java deleted file mode 100644 index a5bdad7..0000000 --- a/app/src/main/java/ru/project/datasource/ManualDataSource.java +++ /dev/null @@ -1,45 +0,0 @@ -package ru.project.datasource; - -import java.util.Scanner; -import ru.project.student.Student; -import ru.project.collection.MyList; -import ru.project.collection.MyLinkedList; - -public class ManualDataSource implements DataSource{ - private int size; - private MyList bufferMyList = new MyLinkedList<>(); - - public ManualDataSource(int size) { - this.size = size; - } - - public boolean setStudent( - int index, - String groupNumber, - double averageGrade, - int recordBookNumber - ){ - return true; - } - @Override - public MyList create() { - /*MyList result = new MyLinkedList<>(); - String strToParse; - Student student; - Scanner scanner = new Scanner(System.in); - for (short i = 0; i < size; i++){ - strToParse = scanner.next(); - if (strToParse.equals("0")) - break; - student = StringParser.parseString(strToParse); - if (student == null){ - System.out.println("Oops! Invalid input"); - } - else{ - result.add(student); - } - } - scanner.close();*/ - return null; - } -} From 3cca9402bb94c9933f4a443f782495ae4ef4adcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Mon, 31 Aug 2026 22:56:53 +0700 Subject: [PATCH 16/29] feature: improved handling exception NoSuchElementException --- app/src/main/java/ru/project/datasource/FileDataSource.java | 2 +- app/src/main/java/ru/project/datasource/StudentCsvReader.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/ru/project/datasource/FileDataSource.java b/app/src/main/java/ru/project/datasource/FileDataSource.java index 1c80464..d15f63e 100644 --- a/app/src/main/java/ru/project/datasource/FileDataSource.java +++ b/app/src/main/java/ru/project/datasource/FileDataSource.java @@ -34,7 +34,7 @@ public class FileDataSource implements DataSource{ return null; } catch (NoSuchElementException e){ - System.out.println("No such element"); + System.out.println(e.getMessage() + "No such element"); return null; } } diff --git a/app/src/main/java/ru/project/datasource/StudentCsvReader.java b/app/src/main/java/ru/project/datasource/StudentCsvReader.java index 156608e..6e04c97 100644 --- a/app/src/main/java/ru/project/datasource/StudentCsvReader.java +++ b/app/src/main/java/ru/project/datasource/StudentCsvReader.java @@ -56,7 +56,7 @@ public class StudentCsvReader implements Iterator { public Student next() { lineOfFile++; if (!records.hasNext()) { - throw new NoSuchElementException(); + throw new NoSuchElementException("Problem at line " + lineOfFile + "."); } CSVRecord record = records.next(); From f1c6aa1443a66ea0cbf34b079877ed38f25db717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BE=D0=BB=D0=BE=D0=B4=D0=B8=D0=BD=20=D0=93=D0=B5?= =?UTF-8?q?=D1=80=D0=BC=D0=B0=D0=BD?= Date: Mon, 31 Aug 2026 22:58:32 +0400 Subject: [PATCH 17/29] refactor: remove obsolete data source infrastructure - remove legacy DataSource implementations - remove obsolete file and random data source classes --- .../ru/project/datasource/DataSource.java | 9 --- .../ru/project/datasource/FileDataSource.java | 41 ----------- .../ru/project/datasource/FileWriter.java | 36 --------- .../project/datasource/RandomDataSource.java | 48 ------------ .../ru/project/datasource/StudentBuffer.java | 37 ---------- .../project/datasource/StudentCsvWriter.java | 73 ------------------- 6 files changed, 244 deletions(-) delete mode 100644 app/src/main/java/ru/project/datasource/DataSource.java delete mode 100644 app/src/main/java/ru/project/datasource/FileDataSource.java delete mode 100644 app/src/main/java/ru/project/datasource/FileWriter.java delete mode 100644 app/src/main/java/ru/project/datasource/RandomDataSource.java delete mode 100644 app/src/main/java/ru/project/datasource/StudentBuffer.java delete mode 100644 app/src/main/java/ru/project/datasource/StudentCsvWriter.java diff --git a/app/src/main/java/ru/project/datasource/DataSource.java b/app/src/main/java/ru/project/datasource/DataSource.java deleted file mode 100644 index 08530a2..0000000 --- a/app/src/main/java/ru/project/datasource/DataSource.java +++ /dev/null @@ -1,9 +0,0 @@ -package ru.project.datasource; - -import ru.project.student.Student; -import ru.project.collection.MyList; - - -public interface DataSource { - MyList create(); -} diff --git a/app/src/main/java/ru/project/datasource/FileDataSource.java b/app/src/main/java/ru/project/datasource/FileDataSource.java deleted file mode 100644 index d15f63e..0000000 --- a/app/src/main/java/ru/project/datasource/FileDataSource.java +++ /dev/null @@ -1,41 +0,0 @@ -package ru.project.datasource; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.stream.Collector; -import java.util.NoSuchElementException; -import ru.project.student.Student; -import ru.project.collection.MyList; -import ru.project.collection.MyLinkedList; - -public class FileDataSource implements DataSource{ - private final String fileName; - - public FileDataSource(String fileName) { - this.fileName = fileName; - } - - @Override - public MyList create() { - MyList resultList = new MyLinkedList<>(); - try { - StudentCsvReader reader = new StudentCsvReader(fileName); - while (reader.hasNext()) { - resultList.add(reader.next()); - } - return resultList; - } - catch (IllegalArgumentException e){ - System.out.println(e.getMessage()); - return null; - } - catch (NoSuchElementException e){ - System.out.println(e.getMessage() + "No such element"); - return null; - } - } -} diff --git a/app/src/main/java/ru/project/datasource/FileWriter.java b/app/src/main/java/ru/project/datasource/FileWriter.java deleted file mode 100644 index 5d78d89..0000000 --- a/app/src/main/java/ru/project/datasource/FileWriter.java +++ /dev/null @@ -1,36 +0,0 @@ -package ru.project.datasource; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import ru.project.student.Student; -import ru.project.collection.MyList; -import ru.project.collection.MyLinkedList; -//import ru.project.collection.Iterator; - -public class FileWriter { - private Path path; - - public FileWriter(String absolutePath) { - this.path = Path.of(absolutePath); - } - - public void write(MyList iist){ - //int sizeOfCollection = list.size(); - try (BufferedWriter writer = Files.newBufferedWriter( - path, - StandardOpenOption.CREATE, - StandardOpenOption.APPEND - )) { - /*Iterator iterator = list.getIterator(); - while (iterator.hasNext()){ - writer.write(iterator.next().toFileString()); - writer.newLine(); - }*/ - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/app/src/main/java/ru/project/datasource/RandomDataSource.java b/app/src/main/java/ru/project/datasource/RandomDataSource.java deleted file mode 100644 index 9239aad..0000000 --- a/app/src/main/java/ru/project/datasource/RandomDataSource.java +++ /dev/null @@ -1,48 +0,0 @@ -package ru.project.datasource; - -import ru.project.student.Student; -import ru.project.student.StudentBuilder; -import ru.project.collection.MyList; -import ru.project.collection.MyLinkedList; -import java.util.Random; - -public class RandomDataSource implements DataSource{ - private final int size; - //private final String CHARS = "АБВГДЕЖХИКЛМНОПРСТУФХЦЧЩЭЮЯ"; - private int upperBounRecordBookNumber; - - public RandomDataSource(int size) { - this.size = size; - } - - public void setUpperBounRecordBookNumber(int upperBounRecordBookNumber) { - this.upperBounRecordBookNumber = upperBounRecordBookNumber; - } - - private String getRandomGroupNumber(Random random){ - char prefix = (char)(random.nextInt(26) + (int)'A'); - String result = prefix + String.format("%02d", random.nextInt(100)); - return result; - } - /*private String getRandomRecordBookNumber(Random random){ - StringBuilder buildRes = new StringBuilder(CHARS.charAt(random.nextInt(CHARS.length()))); - buildRes.append(String.format("%08d", random.nextInt(99999999))); - return buildRes.toString(); - }*/ - - @Override - public MyList create() { - if (upperBounRecordBookNumber < 0) - throw new IllegalArgumentException("The upper bound is negative!!!"); - Random random = new Random(); - MyList result = new MyLinkedList<>(); - for (short i = 0; i Date: Mon, 31 Aug 2026 23:08:50 +0400 Subject: [PATCH 18/29] refactor(io): rename StudentCsvReader package --- .../project/datasource/StudentCsvReader.java | 89 ------------------- .../java/ru/project/io/StudentCsvReader.java | 83 +++++++++++++++++ 2 files changed, 83 insertions(+), 89 deletions(-) delete mode 100644 app/src/main/java/ru/project/datasource/StudentCsvReader.java create mode 100644 app/src/main/java/ru/project/io/StudentCsvReader.java diff --git a/app/src/main/java/ru/project/datasource/StudentCsvReader.java b/app/src/main/java/ru/project/datasource/StudentCsvReader.java deleted file mode 100644 index 6e04c97..0000000 --- a/app/src/main/java/ru/project/datasource/StudentCsvReader.java +++ /dev/null @@ -1,89 +0,0 @@ -package ru.project.datasource; - -import ru.project.student.Student; -import ru.project.student.StudentBuilder; - -import org.apache.commons.csv.CSVFormat; -import org.apache.commons.csv.CSVParser; -import org.apache.commons.csv.CSVRecord; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Iterator; -import java.util.Map; -import java.util.NoSuchElementException; - -public class StudentCsvReader implements Iterator { - private static final String GROUP_NUMBER = "groupNumber"; - private static final String AVERAGE_GRADE = "averageGrade"; - private static final String RECORD_BOOK_NUMBER = "recordBookNumber"; - - private final CSVParser parser; - private final Iterator records; - - private int lineOfFile; - - public StudentCsvReader(String absoluteFilePath) { - lineOfFile = 0; - Path path = Paths.get(absoluteFilePath); - if (!path.isAbsolute()) { - throw new IllegalArgumentException("File path must be absolute"); - } - - try { - CSVFormat format = CSVFormat.DEFAULT.builder() - .setHeader() - .setSkipHeaderRecord(true) - .build(); - this.parser = CSVParser.parse(path, StandardCharsets.UTF_8, format); - validateHeader(parser.getHeaderMap()); - this.records = parser.iterator(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public boolean hasNext() { - return records.hasNext(); - } - - @Override - public Student next() { - lineOfFile++; - if (!records.hasNext()) { - throw new NoSuchElementException("Problem at line " + lineOfFile + "."); - } - - CSVRecord record = records.next(); - if (record.size() != 3) { - throw new IllegalArgumentException( - "Problem at line " + lineOfFile + ".Expected 3 columns, but got " + record.size()); - } - try { - double averageGrade = Double.parseDouble(record.get(AVERAGE_GRADE)); - int recordBookNumber = Integer.parseInt(record.get(RECORD_BOOK_NUMBER)); - return new StudentBuilder() - .setGroupNumber(record.get(GROUP_NUMBER)) - .setAverageGrade(averageGrade) - .setRecordBookNumber(recordBookNumber) - .build(); - } - catch (NumberFormatException e){ - throw new IllegalArgumentException( - "Problem at line " + lineOfFile + ". Unacceptable type convertation"); - } - } - - private static void validateHeader(Map headerMap) { - String[] expected = {GROUP_NUMBER, AVERAGE_GRADE, RECORD_BOOK_NUMBER}; - if (headerMap.size() != expected.length - || !headerMap.keySet().containsAll(Arrays.asList(expected))) { - throw new IllegalArgumentException("Invalid CSV header"); - } - } -} diff --git a/app/src/main/java/ru/project/io/StudentCsvReader.java b/app/src/main/java/ru/project/io/StudentCsvReader.java new file mode 100644 index 0000000..586fb5b --- /dev/null +++ b/app/src/main/java/ru/project/io/StudentCsvReader.java @@ -0,0 +1,83 @@ +package ru.project.io; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; +import ru.project.student.Student; +import ru.project.student.StudentBuilder; + +public class StudentCsvReader implements Iterator { + private static final String GROUP_NUMBER = "groupNumber"; + private static final String AVERAGE_GRADE = "averageGrade"; + private static final String RECORD_BOOK_NUMBER = "recordBookNumber"; + + private final CSVParser parser; + private final Iterator records; + + private int lineOfFile; + + public StudentCsvReader(String absoluteFilePath) { + lineOfFile = 0; + Path path = Paths.get(absoluteFilePath); + if (!path.isAbsolute()) { + throw new IllegalArgumentException("File path must be absolute"); + } + + try { + CSVFormat format = CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true).build(); + this.parser = CSVParser.parse(path, StandardCharsets.UTF_8, format); + validateHeader(parser.getHeaderMap()); + this.records = parser.iterator(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + @Override + public boolean hasNext() { + return records.hasNext(); + } + + @Override + public Student next() { + lineOfFile++; + if (!records.hasNext()) { + throw new NoSuchElementException("Problem at line " + lineOfFile + "."); + } + + CSVRecord record = records.next(); + if (record.size() != 3) { + throw new IllegalArgumentException( + "Problem at line " + lineOfFile + ".Expected 3 columns, but got " + record.size()); + } + try { + double averageGrade = Double.parseDouble(record.get(AVERAGE_GRADE)); + int recordBookNumber = Integer.parseInt(record.get(RECORD_BOOK_NUMBER)); + return new StudentBuilder() + .setGroupNumber(record.get(GROUP_NUMBER)) + .setAverageGrade(averageGrade) + .setRecordBookNumber(recordBookNumber) + .build(); + } catch (NumberFormatException e) { + throw new IllegalArgumentException( + "Problem at line " + lineOfFile + ". Unacceptable type convertation"); + } + } + + private static void validateHeader(Map headerMap) { + String[] expected = {GROUP_NUMBER, AVERAGE_GRADE, RECORD_BOOK_NUMBER}; + if (headerMap.size() != expected.length + || !headerMap.keySet().containsAll(Arrays.asList(expected))) { + throw new IllegalArgumentException("Invalid CSV header"); + } + } +} From 217f9594bdb7c45f7abc9621211b93de220242a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BE=D0=BB=D0=BE=D0=B4=D0=B8=D0=BD=20=D0=93=D0=B5?= =?UTF-8?q?=D1=80=D0=BC=D0=B0=D0=BD?= Date: Mon, 31 Aug 2026 23:13:45 +0400 Subject: [PATCH 19/29] refactor(test): replace DataSourceReader tests with StudentCsvReader tests --- .../datasource/DataSourceReaderTest.java | 116 ---------------- .../ru/project/io/StudentCsvReaderTest.java | 127 ++++++++++++++++++ 2 files changed, 127 insertions(+), 116 deletions(-) delete mode 100644 app/src/test/java/ru/project/datasource/DataSourceReaderTest.java create mode 100644 app/src/test/java/ru/project/io/StudentCsvReaderTest.java diff --git a/app/src/test/java/ru/project/datasource/DataSourceReaderTest.java b/app/src/test/java/ru/project/datasource/DataSourceReaderTest.java deleted file mode 100644 index 740904c..0000000 --- a/app/src/test/java/ru/project/datasource/DataSourceReaderTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package ru.project.datasource; - -import java.io.UncheckedIOException; -import java.util.NoSuchElementException; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.BeforeEach; - -import ru.project.collection.MyList; -import ru.project.collection.MyLinkedList; - -import ru.project.student.Student; -import ru.project.student.StudentBuilder; - -class DataSourceReaderTest{ - private StudentCsvReader valideReader; - //Testing StudentCsvReader - @BeforeEach - void setUp(){ - valideReader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\sample.csv"); - } - - @Test - void readerTestRejectRelativePath(){ - assertThrows(IllegalArgumentException.class, () -> new StudentCsvReader("/Users/Dexp/TestData/sample.csv")); - } - - @Test - void readerRejectPathIsDir(){ - assertThrows(UncheckedIOException.class, () -> new StudentCsvReader("C:\\Users\\Dexp\\TestData")); - } - - @Test - void readerTestFileNotExist(){ - assertThrows(UncheckedIOException.class, () -> new StudentCsvReader("C:\\Users\\Dexp\\TestData\\sss.csv")); - } - - @Test - void testSkipsHeader(){ - Student student = valideReader.next(); - assertTrue(!(student.getGroupNumber()=="groupNumber")); - } - - @Test - void testCreationStudentOnValidData(){ - Student student = valideReader.next(); - assertEquals(student.getGroupNumber(), "A21"); - assertEquals(student.getAverageGrade(), 5.0); - assertEquals(student.getRecordBookNumber(), 331); - } - - @Test - void testNotSkippingFirstStudent(){ - boolean hn = valideReader.hasNext(); - hn = valideReader.hasNext(); - Student student = valideReader.next(); - assertEquals(student.getGroupNumber(), "A21"); - assertEquals(student.getAverageGrade(), 5.0); - assertEquals(student.getRecordBookNumber(), 331); - } - - @Test - void testValidEndsOfFile(){ - Student student = valideReader.next(); - student = valideReader.next(); - assertTrue(!valideReader.hasNext()); - } - - @Test - void testOutOfIndex(){ - assertThrows(NoSuchElementException.class, () -> { - Student student = valideReader.next(); - student = valideReader.next(); - student = valideReader.next(); - }); - } - - @Test - void readerTestRejectFewParametres(){ - assertThrows(IllegalArgumentException.class, () -> { - StudentCsvReader reader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\fewparameters.csv"); - Student student = reader.next(); - }); - } - - @Test - void readerTestRejectInvalidGroupNumber(){ - assertThrows(IllegalArgumentException.class, () -> { - StudentCsvReader reader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_groupnumber.csv"); - Student student = reader.next(); - }); - } - - @Test - void readerTestRejectInvalidAverageGrade(){ - assertThrows(IllegalArgumentException.class, () -> { - StudentCsvReader reader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_averagegrade.csv"); - Student student = reader.next(); - }); - } - - @Test - void readerTestRejectInvalidRecordBookNumber(){ - assertThrows(IllegalArgumentException.class, () -> { - StudentCsvReader reader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_recordbooknumber.csv"); - Student student = reader.next(); - }); - } -} \ No newline at end of file diff --git a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java new file mode 100644 index 0000000..60db7de --- /dev/null +++ b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java @@ -0,0 +1,127 @@ +package ru.project.io; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.UncheckedIOException; +import java.util.NoSuchElementException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import ru.project.student.Student; + +class StudentCsvReaderTest { + private StudentCsvReader valideReader; + + // Testing StudentCsvReader + @BeforeEach + void setUp() { + valideReader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\sample.csv"); + } + + @Test + void readerTestRejectRelativePath() { + assertThrows( + IllegalArgumentException.class, + () -> new StudentCsvReader("/Users/Dexp/TestData/sample.csv")); + } + + @Test + void readerRejectPathIsDir() { + assertThrows( + UncheckedIOException.class, () -> new StudentCsvReader("C:\\Users\\Dexp\\TestData")); + } + + @Test + void readerTestFileNotExist() { + assertThrows( + UncheckedIOException.class, + () -> new StudentCsvReader("C:\\Users\\Dexp\\TestData\\sss.csv")); + } + + @Test + void testSkipsHeader() { + Student student = valideReader.next(); + assertTrue(!(student.getGroupNumber() == "groupNumber")); + } + + @Test + void testCreationStudentOnValidData() { + Student student = valideReader.next(); + assertEquals(student.getGroupNumber(), "A21"); + assertEquals(student.getAverageGrade(), 5.0); + assertEquals(student.getRecordBookNumber(), 331); + } + + @Test + void testNotSkippingFirstStudent() { + boolean hn = valideReader.hasNext(); + hn = valideReader.hasNext(); + Student student = valideReader.next(); + assertEquals(student.getGroupNumber(), "A21"); + assertEquals(student.getAverageGrade(), 5.0); + assertEquals(student.getRecordBookNumber(), 331); + } + + @Test + void testValidEndsOfFile() { + Student student = valideReader.next(); + student = valideReader.next(); + assertTrue(!valideReader.hasNext()); + } + + @Test + void testOutOfIndex() { + assertThrows( + NoSuchElementException.class, + () -> { + Student student = valideReader.next(); + student = valideReader.next(); + student = valideReader.next(); + }); + } + + @Test + void readerTestRejectFewParametres() { + assertThrows( + IllegalArgumentException.class, + () -> { + StudentCsvReader reader = + new StudentCsvReader("C:\\Users\\Dexp\\TestData\\fewparameters.csv"); + Student student = reader.next(); + }); + } + + @Test + void readerTestRejectInvalidGroupNumber() { + assertThrows( + IllegalArgumentException.class, + () -> { + StudentCsvReader reader = + new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_groupnumber.csv"); + Student student = reader.next(); + }); + } + + @Test + void readerTestRejectInvalidAverageGrade() { + assertThrows( + IllegalArgumentException.class, + () -> { + StudentCsvReader reader = + new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_averagegrade.csv"); + Student student = reader.next(); + }); + } + + @Test + void readerTestRejectInvalidRecordBookNumber() { + assertThrows( + IllegalArgumentException.class, + () -> { + StudentCsvReader reader = + new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_recordbooknumber.csv"); + Student student = reader.next(); + }); + } +} From a06f36683dbe9b30c4bf0534b9de0ddbb6c201e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Tue, 1 Sep 2026 13:56:52 +0700 Subject: [PATCH 20/29] refactor: replace org.apache.commons.csv.CSVFormat.Builder.build() with org.apache.commons.csv.CSVFormat.Builder.get() --- app/src/main/java/ru/project/io/StudentCsvReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/ru/project/io/StudentCsvReader.java b/app/src/main/java/ru/project/io/StudentCsvReader.java index 586fb5b..b44a738 100644 --- a/app/src/main/java/ru/project/io/StudentCsvReader.java +++ b/app/src/main/java/ru/project/io/StudentCsvReader.java @@ -33,7 +33,7 @@ public class StudentCsvReader implements Iterator { } try { - CSVFormat format = CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true).build(); + CSVFormat format = CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true).get(); this.parser = CSVParser.parse(path, StandardCharsets.UTF_8, format); validateHeader(parser.getHeaderMap()); this.records = parser.iterator(); From fc847750e8be3bef980c7e8caa0a197f2f8ca60f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Tue, 1 Sep 2026 14:20:45 +0700 Subject: [PATCH 21/29] refactor (test): remove variables at StudentCsvReaderTest never used --- .../test/java/ru/project/io/StudentCsvReaderTest.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java index 60db7de..d8355bc 100644 --- a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java +++ b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java @@ -1,6 +1,7 @@ package ru.project.io; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -42,7 +43,7 @@ class StudentCsvReaderTest { @Test void testSkipsHeader() { Student student = valideReader.next(); - assertTrue(!(student.getGroupNumber() == "groupNumber")); + assertNotEquals(student.getGroupNumber(), "groupNumber"); } @Test @@ -55,8 +56,8 @@ class StudentCsvReaderTest { @Test void testNotSkippingFirstStudent() { - boolean hn = valideReader.hasNext(); - hn = valideReader.hasNext(); + valideReader.hasNext(); + valideReader.hasNext(); Student student = valideReader.next(); assertEquals(student.getGroupNumber(), "A21"); assertEquals(student.getAverageGrade(), 5.0); @@ -65,8 +66,8 @@ class StudentCsvReaderTest { @Test void testValidEndsOfFile() { - Student student = valideReader.next(); - student = valideReader.next(); + valideReader.next(); + valideReader.next(); assertTrue(!valideReader.hasNext()); } From d0bf5f84fcaa9f7e08516756eb471d4a49e96eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Tue, 1 Sep 2026 14:54:01 +0700 Subject: [PATCH 22/29] refactor (test): add final String ABSOLUTE_DIR into StudentCsvReaderTest --- .../java/ru/project/io/StudentCsvReaderTest.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java index d8355bc..2ba9ed1 100644 --- a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java +++ b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java @@ -12,12 +12,13 @@ import org.junit.jupiter.api.Test; import ru.project.student.Student; class StudentCsvReaderTest { + private final String ABSOLUTE_DIR = "C:\\Users\\Dexp\\TestData\\" private StudentCsvReader valideReader; // Testing StudentCsvReader @BeforeEach void setUp() { - valideReader = new StudentCsvReader("C:\\Users\\Dexp\\TestData\\sample.csv"); + valideReader = new StudentCsvReader(ABSOLUTE_DIR + "sample.csv"); } @Test @@ -30,14 +31,14 @@ class StudentCsvReaderTest { @Test void readerRejectPathIsDir() { assertThrows( - UncheckedIOException.class, () -> new StudentCsvReader("C:\\Users\\Dexp\\TestData")); + UncheckedIOException.class, () -> new StudentCsvReader(ABSOLUTE_DIR)); } @Test void readerTestFileNotExist() { assertThrows( UncheckedIOException.class, - () -> new StudentCsvReader("C:\\Users\\Dexp\\TestData\\sss.csv")); + () -> new StudentCsvReader(ABSOLUTE_DIR + "sss.csv")); } @Test @@ -88,7 +89,7 @@ class StudentCsvReaderTest { IllegalArgumentException.class, () -> { StudentCsvReader reader = - new StudentCsvReader("C:\\Users\\Dexp\\TestData\\fewparameters.csv"); + new StudentCsvReader(ABSOLUTE_DIR + "fewparameters.csv"); Student student = reader.next(); }); } @@ -99,7 +100,7 @@ class StudentCsvReaderTest { IllegalArgumentException.class, () -> { StudentCsvReader reader = - new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_groupnumber.csv"); + new StudentCsvReader(ABSOLUTE_DIR + "invalid_groupnumber.csv"); Student student = reader.next(); }); } @@ -110,7 +111,7 @@ class StudentCsvReaderTest { IllegalArgumentException.class, () -> { StudentCsvReader reader = - new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_averagegrade.csv"); + new StudentCsvReader(ABSOLUTE_DIR + "invalid_averagegrade.csv"); Student student = reader.next(); }); } @@ -121,7 +122,7 @@ class StudentCsvReaderTest { IllegalArgumentException.class, () -> { StudentCsvReader reader = - new StudentCsvReader("C:\\Users\\Dexp\\TestData\\invalid_recordbooknumber.csv"); + new StudentCsvReader(ABSOLUTE_DIR + "invalid_recordbooknumber.csv"); Student student = reader.next(); }); } From 537c91d98138e4e5fe7d28ade80f81dc7bc59adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Tue, 1 Sep 2026 15:14:50 +0700 Subject: [PATCH 23/29] test: add test csv-files --- TestData/fewparameters.csv | 2 ++ TestData/invalid_averagegrade.csv | 2 ++ TestData/invalid_groupnumber.csv | 2 ++ TestData/invalid_header.csv | 1 + TestData/invalid_recordbooknumber.csv | 2 ++ TestData/sample.csv | 3 +++ 6 files changed, 12 insertions(+) create mode 100644 TestData/fewparameters.csv create mode 100644 TestData/invalid_averagegrade.csv create mode 100644 TestData/invalid_groupnumber.csv create mode 100644 TestData/invalid_header.csv create mode 100644 TestData/invalid_recordbooknumber.csv create mode 100644 TestData/sample.csv diff --git a/TestData/fewparameters.csv b/TestData/fewparameters.csv new file mode 100644 index 0000000..56f72ca --- /dev/null +++ b/TestData/fewparameters.csv @@ -0,0 +1,2 @@ +groupNumber,averageGrade,recordBookNumber +A21,5.0 \ No newline at end of file diff --git a/TestData/invalid_averagegrade.csv b/TestData/invalid_averagegrade.csv new file mode 100644 index 0000000..860b9e8 --- /dev/null +++ b/TestData/invalid_averagegrade.csv @@ -0,0 +1,2 @@ +groupNumber,averageGrade,recordBookNumber +A21,-1.0,111 \ No newline at end of file diff --git a/TestData/invalid_groupnumber.csv b/TestData/invalid_groupnumber.csv new file mode 100644 index 0000000..12ac7c4 --- /dev/null +++ b/TestData/invalid_groupnumber.csv @@ -0,0 +1,2 @@ +groupNumber,averageGrade,recordBookNumber +A123,4.0,111 \ No newline at end of file diff --git a/TestData/invalid_header.csv b/TestData/invalid_header.csv new file mode 100644 index 0000000..a08b1a1 --- /dev/null +++ b/TestData/invalid_header.csv @@ -0,0 +1 @@ +groupNumber;averageGrade;recordBookNomber diff --git a/TestData/invalid_recordbooknumber.csv b/TestData/invalid_recordbooknumber.csv new file mode 100644 index 0000000..5020f73 --- /dev/null +++ b/TestData/invalid_recordbooknumber.csv @@ -0,0 +1,2 @@ +groupNumber,averageGrade,recordBookNumber +A21,5.0,-1 \ No newline at end of file diff --git a/TestData/sample.csv b/TestData/sample.csv new file mode 100644 index 0000000..dc39a74 --- /dev/null +++ b/TestData/sample.csv @@ -0,0 +1,3 @@ +groupNumber,averageGrade,recordBookNumber +A21,5.0,331 +A21,4.0,332 \ No newline at end of file From 8c4f2e22c45f7433da733e7cbdc2e96aa93c24eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Tue, 1 Sep 2026 16:23:31 +0700 Subject: [PATCH 24/29] refactor: remove test csv-files --- TestData/fewparameters.csv | 2 -- TestData/invalid_averagegrade.csv | 2 -- TestData/invalid_groupnumber.csv | 2 -- TestData/invalid_header.csv | 1 - TestData/invalid_recordbooknumber.csv | 2 -- TestData/sample.csv | 3 --- 6 files changed, 12 deletions(-) delete mode 100644 TestData/fewparameters.csv delete mode 100644 TestData/invalid_averagegrade.csv delete mode 100644 TestData/invalid_groupnumber.csv delete mode 100644 TestData/invalid_header.csv delete mode 100644 TestData/invalid_recordbooknumber.csv delete mode 100644 TestData/sample.csv diff --git a/TestData/fewparameters.csv b/TestData/fewparameters.csv deleted file mode 100644 index 56f72ca..0000000 --- a/TestData/fewparameters.csv +++ /dev/null @@ -1,2 +0,0 @@ -groupNumber,averageGrade,recordBookNumber -A21,5.0 \ No newline at end of file diff --git a/TestData/invalid_averagegrade.csv b/TestData/invalid_averagegrade.csv deleted file mode 100644 index 860b9e8..0000000 --- a/TestData/invalid_averagegrade.csv +++ /dev/null @@ -1,2 +0,0 @@ -groupNumber,averageGrade,recordBookNumber -A21,-1.0,111 \ No newline at end of file diff --git a/TestData/invalid_groupnumber.csv b/TestData/invalid_groupnumber.csv deleted file mode 100644 index 12ac7c4..0000000 --- a/TestData/invalid_groupnumber.csv +++ /dev/null @@ -1,2 +0,0 @@ -groupNumber,averageGrade,recordBookNumber -A123,4.0,111 \ No newline at end of file diff --git a/TestData/invalid_header.csv b/TestData/invalid_header.csv deleted file mode 100644 index a08b1a1..0000000 --- a/TestData/invalid_header.csv +++ /dev/null @@ -1 +0,0 @@ -groupNumber;averageGrade;recordBookNomber diff --git a/TestData/invalid_recordbooknumber.csv b/TestData/invalid_recordbooknumber.csv deleted file mode 100644 index 5020f73..0000000 --- a/TestData/invalid_recordbooknumber.csv +++ /dev/null @@ -1,2 +0,0 @@ -groupNumber,averageGrade,recordBookNumber -A21,5.0,-1 \ No newline at end of file diff --git a/TestData/sample.csv b/TestData/sample.csv deleted file mode 100644 index dc39a74..0000000 --- a/TestData/sample.csv +++ /dev/null @@ -1,3 +0,0 @@ -groupNumber,averageGrade,recordBookNumber -A21,5.0,331 -A21,4.0,332 \ No newline at end of file From 2f50097de00fcf395e35135beb8d59eb66643487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=95=D1=80=D1=88=D0=BE=D0=B2=20=D0=92=D0=BB=D0=B0=D0=B4?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B0=D0=B2?= Date: Tue, 1 Sep 2026 17:46:02 +0700 Subject: [PATCH 25/29] test: add temp directory for test csv's, add test for invalid header --- .../ru/project/io/StudentCsvReaderTest.java | 100 ++++++++++++++++-- 1 file changed, 90 insertions(+), 10 deletions(-) diff --git a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java index 2ba9ed1..2be00de 100644 --- a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java +++ b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java @@ -6,39 +6,59 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.charset.StandardCharsets; import java.util.NoSuchElementException; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.Test; import ru.project.student.Student; class StudentCsvReaderTest { - private final String ABSOLUTE_DIR = "C:\\Users\\Dexp\\TestData\\" - private StudentCsvReader valideReader; + @TempDir Path tempDir; + private Path studentPath; // Testing StudentCsvReader + + @BeforeAll + void generateStudentTestFile(){ + studentPath = tempDir.resolve("students.csv"); + Files.write( + studentPath, + new String[]{ + "groupNumber,averageGrade,recordBookNumber", + "A21,5.0,331", + "A21,4.0,332" + }, + StandardCharsets.UTF_8 + ); + } + @BeforeEach void setUp() { - valideReader = new StudentCsvReader(ABSOLUTE_DIR + "sample.csv"); + valideReader = new StudentCsvReader(studentPath.toAbsolutePath().toString()); } @Test void readerTestRejectRelativePath() { assertThrows( IllegalArgumentException.class, - () -> new StudentCsvReader("/Users/Dexp/TestData/sample.csv")); + () -> new StudentCsvReader(studentPath.toString())); } @Test void readerRejectPathIsDir() { assertThrows( - UncheckedIOException.class, () -> new StudentCsvReader(ABSOLUTE_DIR)); + UncheckedIOException.class, () -> new StudentCsvReader(tempDir.toAbsolutePath())); } @Test void readerTestFileNotExist() { assertThrows( UncheckedIOException.class, - () -> new StudentCsvReader(ABSOLUTE_DIR + "sss.csv")); + () -> new StudentCsvReader(tempDir.resolve("sss.csv").toAbsolutePath().toString())); } @Test @@ -88,8 +108,17 @@ class StudentCsvReaderTest { assertThrows( IllegalArgumentException.class, () -> { + Path path = tempDir.resolve("fewparameters.csv"); + Files.write( + path, + new String[]{ + "groupNumber,averageGrade,recordBookNumber", + "A21,5.0" + }, + StandardCharsets.UTF_8 + ); StudentCsvReader reader = - new StudentCsvReader(ABSOLUTE_DIR + "fewparameters.csv"); + new StudentCsvReader(path.toAbsolutePath().toString()); Student student = reader.next(); }); } @@ -99,8 +128,18 @@ class StudentCsvReaderTest { assertThrows( IllegalArgumentException.class, () -> { + Path path = tempDir.resolve("invalid_groupnumber.csv"); + Files.write( + path, + new String[]{ + "groupNumber,averageGrade,recordBookNumber", + "AAA,5.0,331", + "A21,4.0,332" + }, + StandardCharsets.UTF_8 + ); StudentCsvReader reader = - new StudentCsvReader(ABSOLUTE_DIR + "invalid_groupnumber.csv"); + new StudentCsvReader(path.toAbsolutePath().toString()); Student student = reader.next(); }); } @@ -110,8 +149,18 @@ class StudentCsvReaderTest { assertThrows( IllegalArgumentException.class, () -> { + Path path = tempDir.resolve("invalid_averagegrade.csv"); + Files.write( + path, + new String[]{ + "groupNumber,averageGrade,recordBookNumber", + "A21,-5.0,331", + "A21,4.0,332" + }, + StandardCharsets.UTF_8 + ); StudentCsvReader reader = - new StudentCsvReader(ABSOLUTE_DIR + "invalid_averagegrade.csv"); + new StudentCsvReader(path.toAbsolutePath().toString()); Student student = reader.next(); }); } @@ -121,9 +170,40 @@ class StudentCsvReaderTest { assertThrows( IllegalArgumentException.class, () -> { + Path path = tempDir.resolve("invalid_recordbooknumber.csv"); + Files.write( + path, + new String[]{ + "groupNumber,averageGrade,recordBookNumber", + "A21,5.0,-331", + "A21,4.0,332" + }, + StandardCharsets.UTF_8 + ); StudentCsvReader reader = - new StudentCsvReader(ABSOLUTE_DIR + "invalid_recordbooknumber.csv"); + new StudentCsvReader(path.toAbsolutePath().toString()); Student student = reader.next(); }); } + + @Test + void testInvalidHeader(){ + assertThrows( + IllegalArgumentException.class, + () -> { + Path path = tempDir.resolve("invalid_header.csv"); + Files.write( + path, + new String[]{ + "groupNumber,averageGrade,recordBookNomber", + "A21,5.0,-331", + "A21,4.0,332" + }, + StandardCharsets.UTF_8 + ); + StudentCsvReader reader = + new StudentCsvReader(path.toAbsolutePath().toString()); + Student student = reader.next(); + }); + } } From ff83c48650f3b2feffc5deb3f874b3676b769cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BE=D0=BB=D0=BE=D0=B4=D0=B8=D0=BD=20=D0=93=D0=B5?= =?UTF-8?q?=D1=80=D0=BC=D0=B0=D0=BD?= Date: Tue, 1 Sep 2026 15:55:41 +0400 Subject: [PATCH 26/29] style: reformat source and tests, fix imports and packages --- .../ru/project/collectors/MyCollectors.java | 17 +- .../project/collectors/MyListCollector.java | 58 +- .../finder/StudentOccurrenceIndexFinder.java | 211 +++--- .../java/ru/project/io/StudentCsvReader.java | 4 +- .../project/search/StudentSearchService.java | 42 +- .../project/collection/MyLinkedListTest.java | 236 +++---- .../collectors/MyListCollectorTest.java | 88 ++- .../StudentOccurrenceIndexFinderTest.java | 229 +++---- .../ru/project/io/StudentCsvReaderTest.java | 116 ++-- .../ru/project/search/StudentSearchTest.java | 601 +++++++++--------- 10 files changed, 792 insertions(+), 810 deletions(-) diff --git a/app/src/main/java/ru/project/collectors/MyCollectors.java b/app/src/main/java/ru/project/collectors/MyCollectors.java index d0d7cf5..83b7ae8 100644 --- a/app/src/main/java/ru/project/collectors/MyCollectors.java +++ b/app/src/main/java/ru/project/collectors/MyCollectors.java @@ -1,15 +1,12 @@ package ru.project.collectors; + import java.util.stream.Collector; +import ru.project.collection.MyList; -public class MyCollectors -{ - private MyCollectors() { +public class MyCollectors { + private MyCollectors() {} - } - - public static Collector, MyList> toMyList() - { - return new MyListCollector<>(); - - } + public static Collector, MyList> toMyList() { + return new MyListCollector<>(); + } } diff --git a/app/src/main/java/ru/project/collectors/MyListCollector.java b/app/src/main/java/ru/project/collectors/MyListCollector.java index bb168e4..c5958b0 100644 --- a/app/src/main/java/ru/project/collectors/MyListCollector.java +++ b/app/src/main/java/ru/project/collectors/MyListCollector.java @@ -1,43 +1,41 @@ package ru.project.collectors; -import java.util.Collections; + import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; -public class MyListCollector implements Collector, MyList> -{ - @Override - public Supplier> supplier() - { - return () -> new MyLinkedList<>(); - } +import ru.project.collection.MyLinkedList; +import ru.project.collection.MyList; - @Override - public BiConsumer, T> accumulator() { +public class MyListCollector implements Collector, MyList> { + @Override + public Supplier> supplier() { + return () -> new MyLinkedList<>(); + } - return (list, element) -> list.add(element); - } + @Override + public BiConsumer, T> accumulator() { - @Override - public BinaryOperator> combiner() { - return (list1, list2) -> { - list1.addAll(list2); - return list1; - }; - } + return (list, element) -> list.add(element); + } - @Override - public Function, MyList> finisher() - { - return list -> list; - } + @Override + public BinaryOperator> combiner() { + return (list1, list2) -> { + list1.addAll(list2); + return list1; + }; + } - @Override - public Set characteristics() { - return java.util.Set.of( - Collector.Characteristics.IDENTITY_FINISH - ); - } + @Override + public Function, MyList> finisher() { + return list -> list; + } + + @Override + public Set characteristics() { + return java.util.Set.of(Collector.Characteristics.IDENTITY_FINISH); + } } diff --git a/app/src/main/java/ru/project/finder/StudentOccurrenceIndexFinder.java b/app/src/main/java/ru/project/finder/StudentOccurrenceIndexFinder.java index 7e7c3d2..45ac263 100644 --- a/app/src/main/java/ru/project/finder/StudentOccurrenceIndexFinder.java +++ b/app/src/main/java/ru/project/finder/StudentOccurrenceIndexFinder.java @@ -1,125 +1,132 @@ package ru.project.finder; + import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -public class StudentOccurrenceIndexFinder -{ - public int[] findOccurrences(MyList students, Student target) { - if (students == null) { - throw new IllegalArgumentException(); - } - if (target == null) { - throw new IllegalArgumentException(); - } - if (students.isEmpty()) { - return new int[0]; - } - int size = students.size(); - int threadCount = calculateThreadCount(size); - int chunkSize = countChunkSize(size, threadCount); +import ru.project.collection.MyLinkedList; +import ru.project.collection.MyList; +import ru.project.student.Student; - ExecutorService executor = Executors.newFixedThreadPool(threadCount); - MyList>> futures = new MyLinkedList<>(); +public class StudentOccurrenceIndexFinder { + public int[] findOccurrences(MyList students, Student target) { + if (students == null) { + throw new IllegalArgumentException(); + } + if (target == null) { + throw new IllegalArgumentException(); + } + if (students.isEmpty()) { + return new int[0]; + } + int size = students.size(); + int threadCount = calculateThreadCount(size); + int chunkSize = countChunkSize(size, threadCount); - for (int i = 0; i < threadCount; i++) { - int fromIndex = i * chunkSize; - int toIndex = Math.min(fromIndex + chunkSize, size); + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + MyList>> futures = new MyLinkedList<>(); - if (fromIndex >= toIndex) { - break; - } + for (int i = 0; i < threadCount; i++) { + int fromIndex = i * chunkSize; + int toIndex = Math.min(fromIndex + chunkSize, size); - final int start = fromIndex; - final int end = toIndex; + if (fromIndex >= toIndex) { + break; + } - Future> future = executor.submit(() -> { + final int start = fromIndex; + final int end = toIndex; + + Future> future = + executor.submit( + () -> { return findInRange(students, target, start, end); - }); - futures.add(future); + }); + futures.add(future); + } + MyList allIndices = new MyLinkedList<>(); + try { + for (int i = 0; i < futures.size(); i++) { + Future> future = futures.get(i); + MyList partialResult = future.get(); + + if (partialResult != null) { + for (int j = 0; j < partialResult.size(); j++) { + allIndices.add(partialResult.get(j)); + } } - MyList allIndices = new MyLinkedList<>(); - try { - for (int i = 0; i < futures.size(); i++) { - Future> future = futures.get(i); - MyList partialResult = future.get(); - - if (partialResult != null) { - for (int j = 0; j < partialResult.size(); j++) { - allIndices.add(partialResult.get(j)); - } - } - } - } catch (Exception e) { - throw new RuntimeException("Ошибка при поиске", e); - } finally { - executor.shutdown(); - } - - sortList(allIndices); - - int[] resultArray = new int[allIndices.size()]; - for (int i = 0; i < allIndices.size(); i++) { - resultArray[i] = allIndices.get(i); - } - - return resultArray; + } + } catch (Exception e) { + throw new RuntimeException("Ошибка при поиске", e); + } finally { + executor.shutdown(); } - private void sortList(MyList list) { - if (list.size() <= 1) return; + sortList(allIndices); - MyList sorted = new MyLinkedList<>(); - - for (int i = 0; i < list.size(); i++) { - int value = list.get(i); - int insertIndex = 0; - while (insertIndex < sorted.size()) { - if (sorted.get(insertIndex) > value) { - break; - } - insertIndex++; - } - - MyList temp = new MyLinkedList<>(); - for (int k = 0; k < insertIndex; k++) { - temp.add(sorted.get(k)); - } - temp.add(value); - for (int k = insertIndex; k < sorted.size(); k++) { - temp.add(sorted.get(k)); - } - sorted = temp; - } - - while (!list.isEmpty()) { - list.remove(0); - } - - for (int i = 0; i < sorted.size(); i++) { - list.add(sorted.get(i)); - } + int[] resultArray = new int[allIndices.size()]; + for (int i = 0; i < allIndices.size(); i++) { + resultArray[i] = allIndices.get(i); } - private int calculateThreadCount(int size) { - int processors = Runtime.getRuntime().availableProcessors(); - return Math.min(processors, size); - } + return resultArray; + } - private int countChunkSize(int size, int threadCount) { - if (threadCount == 0) return 0; - return (size + threadCount - 1) / threadCount; - } + private void sortList(MyList list) { + if (list.size() <= 1) return; - private MyList findInRange(MyList students, Student target, int fromIndex, int toIndex) { - MyList foundIndices = new MyLinkedList<>(); + MyList sorted = new MyLinkedList<>(); - for (int i = fromIndex; i < toIndex; i++) { - Student current = students.get(i); - if (current != null && current.equals(target)) { - foundIndices.add(i); - } + for (int i = 0; i < list.size(); i++) { + int value = list.get(i); + int insertIndex = 0; + while (insertIndex < sorted.size()) { + if (sorted.get(insertIndex) > value) { + break; } + insertIndex++; + } - return foundIndices; + MyList temp = new MyLinkedList<>(); + for (int k = 0; k < insertIndex; k++) { + temp.add(sorted.get(k)); + } + temp.add(value); + for (int k = insertIndex; k < sorted.size(); k++) { + temp.add(sorted.get(k)); + } + sorted = temp; } + + while (!list.isEmpty()) { + list.remove(0); + } + + for (int i = 0; i < sorted.size(); i++) { + list.add(sorted.get(i)); + } + } + + private int calculateThreadCount(int size) { + int processors = Runtime.getRuntime().availableProcessors(); + return Math.min(processors, size); + } + + private int countChunkSize(int size, int threadCount) { + if (threadCount == 0) return 0; + return (size + threadCount - 1) / threadCount; + } + + private MyList findInRange( + MyList students, Student target, int fromIndex, int toIndex) { + MyList foundIndices = new MyLinkedList<>(); + + for (int i = fromIndex; i < toIndex; i++) { + Student current = students.get(i); + if (current != null && current.equals(target)) { + foundIndices.add(i); + } + } + + return foundIndices; + } } diff --git a/app/src/main/java/ru/project/io/StudentCsvReader.java b/app/src/main/java/ru/project/io/StudentCsvReader.java index b44a738..a6b93c4 100644 --- a/app/src/main/java/ru/project/io/StudentCsvReader.java +++ b/app/src/main/java/ru/project/io/StudentCsvReader.java @@ -25,9 +25,9 @@ public class StudentCsvReader implements Iterator { private int lineOfFile; - public StudentCsvReader(String absoluteFilePath) { + public StudentCsvReader(Path path2) { lineOfFile = 0; - Path path = Paths.get(absoluteFilePath); + Path path = Paths.get(path2); if (!path.isAbsolute()) { throw new IllegalArgumentException("File path must be absolute"); } diff --git a/app/src/main/java/ru/project/search/StudentSearchService.java b/app/src/main/java/ru/project/search/StudentSearchService.java index 4ced3c9..dc3a366 100644 --- a/app/src/main/java/ru/project/search/StudentSearchService.java +++ b/app/src/main/java/ru/project/search/StudentSearchService.java @@ -1,30 +1,30 @@ package ru.project.search; -import ru.project.list.MyList; -import ru.project.list.MyLinkedList; +import ru.project.collection.MyLinkedList; +import ru.project.collection.MyList; import ru.project.student.Student; public class StudentSearchService { - private final StudentSearchCriteria criteria; + private final StudentSearchCriteria criteria; - public StudentSearchService(StudentSearchCriteria criteria) { - if (criteria == null) { - throw new IllegalArgumentException("Criteria must not be null"); - } - this.criteria = criteria; + public StudentSearchService(StudentSearchCriteria criteria) { + if (criteria == null) { + throw new IllegalArgumentException("Criteria must not be null"); } + this.criteria = criteria; + } - public MyList find(MyList students) { - if (students == null) { - return new MyLinkedList<>(); - } - MyList result = new MyLinkedList<>(); - for (int i = 0; i < students.size(); i++) { - Student s = students.get(i); - if (criteria.matches(s)) { - result.add(s); - } - } - return result; + public MyList find(MyList students) { + if (students == null) { + return new MyLinkedList<>(); } -} \ No newline at end of file + MyList result = new MyLinkedList<>(); + for (int i = 0; i < students.size(); i++) { + Student s = students.get(i); + if (criteria.matches(s)) { + result.add(s); + } + } + return result; + } +} diff --git a/app/src/test/java/ru/project/collection/MyLinkedListTest.java b/app/src/test/java/ru/project/collection/MyLinkedListTest.java index 6c43673..8137964 100644 --- a/app/src/test/java/ru/project/collection/MyLinkedListTest.java +++ b/app/src/test/java/ru/project/collection/MyLinkedListTest.java @@ -1,130 +1,138 @@ -package ru.test.maven.spring; -import org.junit.jupiter.api.Test; +package ru.project.collection; + import static org.junit.jupiter.api.Assertions.*; -public class MyLinkedListTest -{ - @Test - public void shouldTestAdd() { - MyLinkedList list = new MyLinkedList<>(); - list.add(10); - list.add(20); - list.add(30); - assertEquals(10, list.get(0)); - assertEquals(20, list.get(1)); - assertEquals(30, list.get(2)); - } - @Test - public void shouldTestGet() - { - MyLinkedList list = new MyLinkedList<>(); - list.add(10); - assertEquals(10, list.get(0)); - } - @Test - public void shouldTestRemove() { - MyLinkedList list = new MyLinkedList<>(); - list.add(10); - list.add(20); - list.add(30); - list.remove(0); +import org.junit.jupiter.api.Test; - assertEquals(2, list.size()); - assertEquals(20, list.get(0)); - assertEquals(30, list.get(1)); - } - @Test - void shouldTestSet() { - MyLinkedList list = new MyLinkedList<>(); - list.add("A"); - list.add("B"); - list.add("C"); +public class MyLinkedListTest { + @Test + public void shouldTestAdd() { + MyLinkedList list = new MyLinkedList<>(); + list.add(10); + list.add(20); + list.add(30); - String oldValue = list.set(1, "Z"); + assertEquals(10, list.get(0)); + assertEquals(20, list.get(1)); + assertEquals(30, list.get(2)); + } - assertEquals("B", oldValue); - assertEquals("Z", list.get(1)); - assertEquals(3, list.size()); + @Test + public void shouldTestGet() { + MyLinkedList list = new MyLinkedList<>(); + list.add(10); + assertEquals(10, list.get(0)); + } - } - @Test - void shouldTestSize() - { - MyLinkedList list = new MyLinkedList<>(); - list.add(1); - list.add(2); - list.add(3); - assertEquals(3, list.size()); - } - @Test - void shouldTestisEmpty() - { - MyLinkedList list = new MyLinkedList<>(); - assertTrue(list.isEmpty()); - } - @Test - void shouldTestGet_OutOfBounds_ThrowsException() { - MyLinkedList list = new MyLinkedList<>(); - list.add(1); + @Test + public void shouldTestRemove() { + MyLinkedList list = new MyLinkedList<>(); + list.add(10); + list.add(20); + list.add(30); + list.remove(0); - assertThrows(IllegalArgumentException.class, () -> list.get(-1)); - assertThrows(IllegalArgumentException.class, () -> list.get(1)); // index == size - assertThrows(IllegalArgumentException.class, () -> list.get(5)); // index > size - } - @Test - void shouldTestSet_OutOfBounds_ThrowsException() { - MyLinkedList list = new MyLinkedList<>(); - list.add(1); + assertEquals(2, list.size()); + assertEquals(20, list.get(0)); + assertEquals(30, list.get(1)); + } - assertThrows(IllegalArgumentException.class, () -> list.set(-1, 99)); - assertThrows(IllegalArgumentException.class, () -> list.set(1, 99)); - } - @Test - void shouldTestRemove_IndexGreaterThanSize_ThrowsException() { - MyLinkedList list = new MyLinkedList<>(); - list.add("man"); - assertThrows(IndexOutOfBoundsException.class, () -> list.remove(5)); - } - @Test - void shouldTestRemove_NegativeIndex_ThrowsException() { - MyLinkedList list = new MyLinkedList<>(); - list.add("1"); - list.add("2"); + @Test + void shouldTestSet() { + MyLinkedList list = new MyLinkedList<>(); + list.add("A"); + list.add("B"); + list.add("C"); - assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1)); - } - @Test - void shouldTestaddAll_nonEmptySource_toEmptyList_addsAllElementsInOrder() { - MyList list = new MyLinkedList<>(); - MyList source = new MyLinkedList<>(); - source.add("A"); - source.add("B"); - source.add("C"); + String oldValue = list.set(1, "Z"); - list.addAll(source); + assertEquals("B", oldValue); + assertEquals("Z", list.get(1)); + assertEquals(3, list.size()); + } - assertEquals(3, list.size()); - assertEquals("A", list.get(0)); - assertEquals("B", list.get(1)); - assertEquals("C", list.get(2)); - } + @Test + void shouldTestSize() { + MyLinkedList list = new MyLinkedList<>(); + list.add(1); + list.add(2); + list.add(3); + assertEquals(3, list.size()); + } - @Test - void shouldTestaddAll_toNonEmptyList_appendsAtEnd() { - MyList list = new MyLinkedList<>(); - list.add("X"); - list.add("Y"); + @Test + void shouldTestisEmpty() { + MyLinkedList list = new MyLinkedList<>(); + assertTrue(list.isEmpty()); + } - MyList source = new MyLinkedList<>(); - source.add("A"); - source.add("B"); + @Test + void shouldTestGet_OutOfBounds_ThrowsException() { + MyLinkedList list = new MyLinkedList<>(); + list.add(1); - list.addAll(source); + assertThrows(IllegalArgumentException.class, () -> list.get(-1)); + assertThrows(IllegalArgumentException.class, () -> list.get(1)); // index == size + assertThrows(IllegalArgumentException.class, () -> list.get(5)); // index > size + } - assertEquals(4, list.size()); - assertEquals("X", list.get(0)); - assertEquals("Y", list.get(1)); - assertEquals("A", list.get(2)); - assertEquals("B", list.get(3)); - } + @Test + void shouldTestSet_OutOfBounds_ThrowsException() { + MyLinkedList list = new MyLinkedList<>(); + list.add(1); + + assertThrows(IllegalArgumentException.class, () -> list.set(-1, 99)); + assertThrows(IllegalArgumentException.class, () -> list.set(1, 99)); + } + + @Test + void shouldTestRemove_IndexGreaterThanSize_ThrowsException() { + MyLinkedList list = new MyLinkedList<>(); + list.add("man"); + assertThrows(IndexOutOfBoundsException.class, () -> list.remove(5)); + } + + @Test + void shouldTestRemove_NegativeIndex_ThrowsException() { + MyLinkedList list = new MyLinkedList<>(); + list.add("1"); + list.add("2"); + + assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1)); + } + + @Test + void shouldTestaddAll_nonEmptySource_toEmptyList_addsAllElementsInOrder() { + MyList list = new MyLinkedList<>(); + MyList source = new MyLinkedList<>(); + source.add("A"); + source.add("B"); + source.add("C"); + + list.addAll(source); + + assertEquals(3, list.size()); + assertEquals("A", list.get(0)); + assertEquals("B", list.get(1)); + assertEquals("C", list.get(2)); + } + + @Test + void shouldTestaddAll_toNonEmptyList_appendsAtEnd() { + MyList list = new MyLinkedList<>(); + list.add("X"); + list.add("Y"); + + MyList source = new MyLinkedList<>(); + source.add("A"); + source.add("B"); + + list.addAll(source); + + assertEquals(4, list.size()); + assertEquals("X", list.get(0)); + assertEquals("Y", list.get(1)); + assertEquals("A", list.get(2)); + assertEquals("B", list.get(3)); + } } diff --git a/app/src/test/java/ru/project/collectors/MyListCollectorTest.java b/app/src/test/java/ru/project/collectors/MyListCollectorTest.java index 3ca8d21..35abcbc 100644 --- a/app/src/test/java/ru/project/collectors/MyListCollectorTest.java +++ b/app/src/test/java/ru/project/collectors/MyListCollectorTest.java @@ -1,64 +1,58 @@ -package ru.test.maven.spring; -import org.junit.jupiter.api.Test; +package ru.project.collectors; + import static org.junit.jupiter.api.Assertions.*; + import java.util.Set; import java.util.stream.Collector; import java.util.stream.IntStream; -import java.util.Collections; +import org.junit.jupiter.api.Test; +import ru.project.collection.MyList; -public class MyListCollectorTest -{ - private final MyListCollector collector = new MyListCollector<>(); +public class MyListCollectorTest { + private final MyListCollector collector = new MyListCollector<>(); - @Test - void shouldTestCollectInOrderSequential() { - MyList result = IntStream.range(0, 10) - .boxed() - .collect(MyCollectors.toMyList()); - - assertEquals(10, result.size()); - for (int i = 0; i < result.size(); i++) { - assertEquals(i, (int) result.get(i)); - } + @Test + void shouldTestCollectInOrderSequential() { + MyList result = IntStream.range(0, 10).boxed().collect(MyCollectors.toMyList()); + assertEquals(10, result.size()); + for (int i = 0; i < result.size(); i++) { + assertEquals(i, (int) result.get(i)); } + } - @Test - void shouldTestCollectInOrderParallel() { - MyList result = IntStream.range(0, 100) - .parallel() - .boxed() - .collect(MyCollectors.toMyList()); + @Test + void shouldTestCollectInOrderParallel() { + MyList result = + IntStream.range(0, 100).parallel().boxed().collect(MyCollectors.toMyList()); - assertEquals(100, result.size()); - for (int i = 0; i < result.size(); i++) { - assertEquals(i, (int) result.get(i)); - } + assertEquals(100, result.size()); + for (int i = 0; i < result.size(); i++) { + assertEquals(i, (int) result.get(i)); } + } - @Test - void shouldTestHandleEmptyStream() { - MyList result = IntStream.empty() - .boxed() - .collect(MyCollectors.toMyList()); + @Test + void shouldTestHandleEmptyStream() { + MyList result = IntStream.empty().boxed().collect(MyCollectors.toMyList()); - assertTrue(result.isEmpty()); + assertTrue(result.isEmpty()); + } - } - @Test - void shouldTestNotUseStandardList() { - MyList result = IntStream.range(0, 5) - .mapToObj(i -> "item" + i) - .collect(MyCollectors.toMyList()); + @Test + void shouldTestNotUseStandardList() { + MyList result = + IntStream.range(0, 5).mapToObj(i -> "item" + i).collect(MyCollectors.toMyList()); - assertInstanceOf(MyList.class, result); - assertFalse(result instanceof java.util.List); - } - @Test - void shouldTestHaveCorrectCharacteristics() { - Set characteristics = collector.characteristics(); - assertTrue(characteristics.contains(java.util.stream.Collector.Characteristics.IDENTITY_FINISH)); - assertFalse(characteristics.contains(java.util.stream.Collector.Characteristics.UNORDERED)); - } + assertInstanceOf(MyList.class, result); + assertFalse(result instanceof java.util.List); + } + @Test + void shouldTestHaveCorrectCharacteristics() { + Set characteristics = collector.characteristics(); + assertTrue( + characteristics.contains(java.util.stream.Collector.Characteristics.IDENTITY_FINISH)); + assertFalse(characteristics.contains(java.util.stream.Collector.Characteristics.UNORDERED)); + } } diff --git a/app/src/test/java/ru/project/finder/StudentOccurrenceIndexFinderTest.java b/app/src/test/java/ru/project/finder/StudentOccurrenceIndexFinderTest.java index b61ed58..3e5c710 100644 --- a/app/src/test/java/ru/project/finder/StudentOccurrenceIndexFinderTest.java +++ b/app/src/test/java/ru/project/finder/StudentOccurrenceIndexFinderTest.java @@ -1,134 +1,137 @@ package ru.project.finder; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.*; -public class StudentOccurrenceIndexFinderTest -{ - private StudentOccurrenceIndexFinder finder; - private MyList students; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import ru.project.collection.MyLinkedList; +import ru.project.collection.MyList; +import ru.project.student.Student; - @BeforeEach - void setUp() { - finder = new StudentOccurrenceIndexFinder(); - students = new MyLinkedList<>(); - } +public class StudentOccurrenceIndexFinderTest { + private StudentOccurrenceIndexFinder finder; + private MyList students; - @Test - void shouldTesfindOccurrences_emptyList_returnsEmptyArray() { - int[] result = finder.findOccurrences(students, new Student("A12", 4.5, 1)); - assertEquals(0, result.length); - } - @Test - void shouldTesfindOccurrences_noMatches_returnsEmptyArray() { - students.add(new Student("A12", 4.0, 101)); - students.add(new Student("B23", 3.5, 102)); - Student target = new Student("C34", 4.8, 103); // такого нет + @BeforeEach + void setUp() { + finder = new StudentOccurrenceIndexFinder(); + students = new MyLinkedList<>(); + } - int[] result = finder.findOccurrences(students, target); - assertEquals(0, result.length); - } - @Test - void shouldTesfindOccurrences_singleMatch_returnsCorrectIndex() { - students.add(new Student("A12", 4.0, 101)); - students.add(new Student("B23", 3.5, 102)); // target здесь - students.add(new Student("C34", 4.8, 103)); + @Test + void shouldTesfindOccurrences_emptyList_returnsEmptyArray() { + int[] result = finder.findOccurrences(students, new Student("A12", 4.5, 1)); + assertEquals(0, result.length); + } - Student target = new Student("B23", 3.5, 102); - int[] result = finder.findOccurrences(students, target); + @Test + void shouldTesfindOccurrences_noMatches_returnsEmptyArray() { + students.add(new Student("A12", 4.0, 101)); + students.add(new Student("B23", 3.5, 102)); + Student target = new Student("C34", 4.8, 103); // такого нет - assertEquals(1, result.length); - assertEquals(1, result[0]); - } - @Test - void shouldTesfindOccurrences_multipleMatches_returnsAllIndicesSorted() { - // индексы: 0, 2, 4 — должны вернуться в порядке возрастания - students.add(new Student("A12", 4.5, 101)); // match - students.add(new Student("B23", 3.8, 102)); - students.add(new Student("A12", 4.5, 101)); // match - students.add(new Student("C34", 4.0, 103)); - students.add(new Student("A12", 4.5, 101)); // match + int[] result = finder.findOccurrences(students, target); + assertEquals(0, result.length); + } - Student target = new Student("A12", 4.5, 101); - int[] result = finder.findOccurrences(students, target); + @Test + void shouldTesfindOccurrences_singleMatch_returnsCorrectIndex() { + students.add(new Student("A12", 4.0, 101)); + students.add(new Student("B23", 3.5, 102)); // target здесь + students.add(new Student("C34", 4.8, 103)); - assertEquals(3, result.length); - assertArrayEquals(new int[]{0, 2, 4}, result); - } + Student target = new Student("B23", 3.5, 102); + int[] result = finder.findOccurrences(students, target); - @Test - void shouldTesfindOccurrences_allElementsMatch_returnsAllIndices() { - Student s = new Student("X99", 5.0, 999); - students.add(s); - students.add(s); - students.add(s); + assertEquals(1, result.length); + assertEquals(1, result[0]); + } - int[] result = finder.findOccurrences(students, s); - assertEquals(3, result.length); - assertArrayEquals(new int[]{0, 1, 2}, result); - } + @Test + void shouldTesfindOccurrences_multipleMatches_returnsAllIndicesSorted() { + // индексы: 0, 2, 4 — должны вернуться в порядке возрастания + students.add(new Student("A12", 4.5, 101)); // match + students.add(new Student("B23", 3.8, 102)); + students.add(new Student("A12", 4.5, 101)); // match + students.add(new Student("C34", 4.0, 103)); + students.add(new Student("A12", 4.5, 101)); // match - @Test - void shouldTesfindOccurrences_differentAverageGrade_noMatch() { - students.add(new Student("A12", 4.50, 101)); - Student target = new Student("A12", 4.51, 101); // отличается балл + Student target = new Student("A12", 4.5, 101); + int[] result = finder.findOccurrences(students, target); - int[] result = finder.findOccurrences(students, target); - assertEquals(0, result.length); - } + assertEquals(3, result.length); + assertArrayEquals(new int[] {0, 2, 4}, result); + } + + @Test + void shouldTesfindOccurrences_allElementsMatch_returnsAllIndices() { + Student s = new Student("X99", 5.0, 999); + students.add(s); + students.add(s); + students.add(s); + + int[] result = finder.findOccurrences(students, s); + assertEquals(3, result.length); + assertArrayEquals(new int[] {0, 1, 2}, result); + } + + @Test + void shouldTesfindOccurrences_differentAverageGrade_noMatch() { + students.add(new Student("A12", 4.50, 101)); + Student target = new Student("A12", 4.51, 101); // отличается балл + + int[] result = finder.findOccurrences(students, target); + assertEquals(0, result.length); + } + + @Test + void shouldTesfindOccurrences_differentGroupNumber_noMatch() { + students.add(new Student("A12", 4.5, 101)); + Student target = new Student("B12", 4.5, 101); // другая группа + + int[] result = finder.findOccurrences(students, target); + assertEquals(0, result.length); + } + + @Test + void shouldTesfindOccurrences_differentRecordBookNumber_noMatch() { + students.add(new Student("A12", 4.5, 101)); + Student target = new Student("A12", 4.5, 102); // другой номер зачетки + + int[] result = finder.findOccurrences(students, target); + assertEquals(0, result.length); + } + + @Test + void shouldTesfindOccurrences_nullList_throwsException() { + Student target = new Student("A12", 4.5, 101); + assertThrows(IllegalArgumentException.class, () -> finder.findOccurrences(null, target)); + } + + @Test + void shouldTesfindOccurrences_nullTarget_throwsException() { + assertThrows(IllegalArgumentException.class, () -> finder.findOccurrences(students, null)); + } + + @Test + void shouldTesfindOccurrences_resultIsSorted() { + String[] validGroups = {"A00", "A01", "B12", "C99", "X55"}; + + for (int i = 0; i < 50; i++) { + String group = validGroups[i % validGroups.length]; + double grade = (3.0 + (i % 3)) / 2.0; + if (i % 3 == 0) { - @Test - void shouldTesfindOccurrences_differentGroupNumber_noMatch() { students.add(new Student("A12", 4.5, 101)); - Student target = new Student("B12", 4.5, 101); // другая группа - - int[] result = finder.findOccurrences(students, target); - assertEquals(0, result.length); + } else { + students.add(new Student(group, grade, 200 + i)); + } } + Student target = new Student("A12", 4.5, 101); + int[] result = finder.findOccurrences(students, target); - @Test - void shouldTesfindOccurrences_differentRecordBookNumber_noMatch() { - students.add(new Student("A12", 4.5, 101)); - Student target = new Student("A12", 4.5, 102); // другой номер зачетки - - int[] result = finder.findOccurrences(students, target); - assertEquals(0, result.length); - } - - - @Test - void shouldTesfindOccurrences_nullList_throwsException() { - Student target = new Student("A12", 4.5, 101); - assertThrows(IllegalArgumentException.class, () -> finder.findOccurrences(null, target)); - } - - - @Test - void shouldTesfindOccurrences_nullTarget_throwsException() { - assertThrows(IllegalArgumentException.class, () -> finder.findOccurrences(students, null)); - } - @Test - void shouldTesfindOccurrences_resultIsSorted() { - String[] validGroups = {"A00", "A01", "B12", "C99", "X55"}; - - for (int i = 0; i < 50; i++) { - String group = validGroups[i % validGroups.length]; - double grade = (3.0 + (i % 3)) / 2.0; - if (i % 3 == 0) { - - students.add(new Student("A12", 4.5, 101)); - } else { - students.add(new Student(group, grade, 200 + i)); - } - } - Student target = new Student("A12", 4.5, 101); - int[] result = finder.findOccurrences(students, target); - - - for (int i = 1; i < result.length; i++) { - assertTrue(result[i] > result[i - 1], "Результат должен быть отсортирован"); - } + for (int i = 1; i < result.length; i++) { + assertTrue(result[i] > result[i - 1], "Результат должен быть отсортирован"); } + } } diff --git a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java index 2be00de..1ca6657 100644 --- a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java +++ b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java @@ -6,14 +6,14 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.charset.StandardCharsets; import java.util.NoSuchElementException; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import ru.project.student.Student; class StudentCsvReaderTest { @@ -23,17 +23,12 @@ class StudentCsvReaderTest { // Testing StudentCsvReader @BeforeAll - void generateStudentTestFile(){ + void generateStudentTestFile() { studentPath = tempDir.resolve("students.csv"); Files.write( - studentPath, - new String[]{ - "groupNumber,averageGrade,recordBookNumber", - "A21,5.0,331", - "A21,4.0,332" - }, - StandardCharsets.UTF_8 - ); + studentPath, + new String[] {"groupNumber,averageGrade,recordBookNumber", "A21,5.0,331", "A21,4.0,332"}, + StandardCharsets.UTF_8); } @BeforeEach @@ -44,14 +39,12 @@ class StudentCsvReaderTest { @Test void readerTestRejectRelativePath() { assertThrows( - IllegalArgumentException.class, - () -> new StudentCsvReader(studentPath.toString())); + IllegalArgumentException.class, () -> new StudentCsvReader(studentPath.toString())); } @Test void readerRejectPathIsDir() { - assertThrows( - UncheckedIOException.class, () -> new StudentCsvReader(tempDir.toAbsolutePath())); + assertThrows(UncheckedIOException.class, () -> new StudentCsvReader(tempDir.toAbsolutePath())); } @Test @@ -110,15 +103,10 @@ class StudentCsvReaderTest { () -> { Path path = tempDir.resolve("fewparameters.csv"); Files.write( - path, - new String[]{ - "groupNumber,averageGrade,recordBookNumber", - "A21,5.0" - }, - StandardCharsets.UTF_8 - ); - StudentCsvReader reader = - new StudentCsvReader(path.toAbsolutePath().toString()); + path, + new String[] {"groupNumber,averageGrade,recordBookNumber", "A21,5.0"}, + StandardCharsets.UTF_8); + StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); Student student = reader.next(); }); } @@ -130,16 +118,12 @@ class StudentCsvReaderTest { () -> { Path path = tempDir.resolve("invalid_groupnumber.csv"); Files.write( - path, - new String[]{ - "groupNumber,averageGrade,recordBookNumber", - "AAA,5.0,331", - "A21,4.0,332" - }, - StandardCharsets.UTF_8 - ); - StudentCsvReader reader = - new StudentCsvReader(path.toAbsolutePath().toString()); + path, + new String[] { + "groupNumber,averageGrade,recordBookNumber", "AAA,5.0,331", "A21,4.0,332" + }, + StandardCharsets.UTF_8); + StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); Student student = reader.next(); }); } @@ -151,16 +135,12 @@ class StudentCsvReaderTest { () -> { Path path = tempDir.resolve("invalid_averagegrade.csv"); Files.write( - path, - new String[]{ - "groupNumber,averageGrade,recordBookNumber", - "A21,-5.0,331", - "A21,4.0,332" - }, - StandardCharsets.UTF_8 - ); - StudentCsvReader reader = - new StudentCsvReader(path.toAbsolutePath().toString()); + path, + new String[] { + "groupNumber,averageGrade,recordBookNumber", "A21,-5.0,331", "A21,4.0,332" + }, + StandardCharsets.UTF_8); + StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); Student student = reader.next(); }); } @@ -172,38 +152,30 @@ class StudentCsvReaderTest { () -> { Path path = tempDir.resolve("invalid_recordbooknumber.csv"); Files.write( - path, - new String[]{ - "groupNumber,averageGrade,recordBookNumber", - "A21,5.0,-331", - "A21,4.0,332" - }, - StandardCharsets.UTF_8 - ); - StudentCsvReader reader = - new StudentCsvReader(path.toAbsolutePath().toString()); + path, + new String[] { + "groupNumber,averageGrade,recordBookNumber", "A21,5.0,-331", "A21,4.0,332" + }, + StandardCharsets.UTF_8); + StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); Student student = reader.next(); }); } @Test - void testInvalidHeader(){ + void testInvalidHeader() { assertThrows( - IllegalArgumentException.class, - () -> { - Path path = tempDir.resolve("invalid_header.csv"); - Files.write( - path, - new String[]{ - "groupNumber,averageGrade,recordBookNomber", - "A21,5.0,-331", - "A21,4.0,332" - }, - StandardCharsets.UTF_8 - ); - StudentCsvReader reader = - new StudentCsvReader(path.toAbsolutePath().toString()); - Student student = reader.next(); - }); + IllegalArgumentException.class, + () -> { + Path path = tempDir.resolve("invalid_header.csv"); + Files.write( + path, + new String[] { + "groupNumber,averageGrade,recordBookNomber", "A21,5.0,-331", "A21,4.0,332" + }, + StandardCharsets.UTF_8); + StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); + Student student = reader.next(); + }); } } diff --git a/app/src/test/java/ru/project/search/StudentSearchTest.java b/app/src/test/java/ru/project/search/StudentSearchTest.java index d12bd9c..db43fa1 100644 --- a/app/src/test/java/ru/project/search/StudentSearchTest.java +++ b/app/src/test/java/ru/project/search/StudentSearchTest.java @@ -1,314 +1,317 @@ package ru.project.search; -import org.junit.jupiter.api.Test; -import ru.project.list.MyList; -import ru.project.list.MyLinkedList; -import ru.project.student.Student; - import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import ru.project.collection.MyLinkedList; +import ru.project.collection.MyList; +import ru.project.student.Student; + class StudentSearchTest { - @Test - void testGroupNumberRangeMatchesInside() { - StudentSearchCriteria criteria = new GroupNumberRangeCriteria("A10", "C30"); - Student student = new Student("B20", 4.5, 123); - assertTrue(criteria.matches(student)); + @Test + void testGroupNumberRangeMatchesInside() { + StudentSearchCriteria criteria = new GroupNumberRangeCriteria("A10", "C30"); + Student student = new Student("B20", 4.5, 123); + assertTrue(criteria.matches(student)); + } + + @Test + void testGroupNumberRangeMatchesLowerBoundary() { + StudentSearchCriteria criteria = new GroupNumberRangeCriteria("A10", "C30"); + Student student = new Student("A10", 4.5, 123); + assertTrue(criteria.matches(student)); + } + + @Test + void testGroupNumberRangeMatchesUpperBoundary() { + StudentSearchCriteria criteria = new GroupNumberRangeCriteria("A10", "C30"); + Student student = new Student("C30", 4.5, 123); + assertTrue(criteria.matches(student)); + } + + @Test + void testGroupNumberRangeDoesNotMatchOutside() { + StudentSearchCriteria criteria = new GroupNumberRangeCriteria("A10", "C30"); + Student student = new Student("D00", 4.5, 123); + assertFalse(criteria.matches(student)); + } + + @Test + void testGroupNumberRangeInvalidMinMaxThrowsException() { + assertThrows(IllegalArgumentException.class, () -> new GroupNumberRangeCriteria("C30", "A10")); + } + + @Test + void testGroupNumberRangeNullValuesThrowsException() { + assertThrows(IllegalArgumentException.class, () -> new GroupNumberRangeCriteria(null, "A10")); + assertThrows(IllegalArgumentException.class, () -> new GroupNumberRangeCriteria("A10", null)); + } + + @Test + void testAverageGradeRangeMatchesInside() { + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + Student student = new Student("A12", 4.5, 123); + assertTrue(criteria.matches(student)); + } + + @Test + void testAverageGradeRangeMatchesLowerBoundary() { + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + Student student = new Student("A12", 4.0, 123); + assertTrue(criteria.matches(student)); + } + + @Test + void testAverageGradeRangeMatchesUpperBoundary() { + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + Student student = new Student("A12", 5.0, 123); + assertTrue(criteria.matches(student)); + } + + @Test + void testAverageGradeRangeDoesNotMatchBelow() { + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + Student student = new Student("A12", 3.9, 123); + assertFalse(criteria.matches(student)); + } + + @Test + void testAverageGradeRangeDoesNotMatchAbove() { + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + Student student = new Student("A12", 5.1, 123); + assertFalse(criteria.matches(student)); + } + + @Test + void testAverageGradeRangeInvalidMinMaxThrowsException() { + assertThrows(IllegalArgumentException.class, () -> new AverageGradeRangeCriteria(5.0, 4.0)); + } + + @Test + void testRecordBookNumberRangeMatchesInside() { + StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); + Student student = new Student("A12", 4.5, 150); + assertTrue(criteria.matches(student)); + } + + @Test + void testRecordBookNumberRangeMatchesLowerBoundary() { + StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); + Student student = new Student("A12", 4.5, 100); + assertTrue(criteria.matches(student)); + } + + @Test + void testRecordBookNumberRangeMatchesUpperBoundary() { + StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); + Student student = new Student("A12", 4.5, 200); + assertTrue(criteria.matches(student)); + } + + @Test + void testRecordBookNumberRangeDoesNotMatchBelow() { + StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); + Student student = new Student("A12", 4.5, 99); + assertFalse(criteria.matches(student)); + } + + @Test + void testRecordBookNumberRangeDoesNotMatchAbove() { + StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); + Student student = new Student("A12", 4.5, 201); + assertFalse(criteria.matches(student)); + } + + @Test + void testRecordBookNumberRangeInvalidMinMaxThrowsException() { + assertThrows(IllegalArgumentException.class, () -> new RecordBookNumberRangeCriteria(200, 100)); + } + + @Test + void testCompositeIntersectionEmptyReturnsTrue() { + CompositeStudentSearchCriteria composite = + new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); + Student student = new Student("A12", 4.5, 123); + assertTrue(composite.matches(student)); + } + + @Test + void testCompositeUnionEmptyReturnsFalse() { + CompositeStudentSearchCriteria composite = + new CompositeStudentSearchCriteria(SearchOperation.UNION); + Student student = new Student("A12", 4.5, 123); + assertFalse(composite.matches(student)); + } + + @Test + void testCompositeIntersectionAllTrue() { + CompositeStudentSearchCriteria composite = + new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); + composite.add(new GroupNumberRangeCriteria("A10", "C30")); + composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); + Student student = new Student("B20", 4.5, 123); + assertTrue(composite.matches(student)); + } + + @Test + void testCompositeIntersectionOneFalse() { + CompositeStudentSearchCriteria composite = + new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); + composite.add(new GroupNumberRangeCriteria("A10", "C30")); + composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); + Student student = new Student("B20", 3.5, 123); + assertFalse(composite.matches(student)); + } + + @Test + void testCompositeUnionOneTrue() { + CompositeStudentSearchCriteria composite = + new CompositeStudentSearchCriteria(SearchOperation.UNION); + composite.add(new GroupNumberRangeCriteria("A10", "C30")); + composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); + Student student = new Student("D00", 4.5, 123); + assertTrue(composite.matches(student)); + } + + @Test + void testCompositeUnionAllFalse() { + CompositeStudentSearchCriteria composite = + new CompositeStudentSearchCriteria(SearchOperation.UNION); + composite.add(new GroupNumberRangeCriteria("A10", "C30")); + composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); + Student student = new Student("D00", 3.5, 123); + assertFalse(composite.matches(student)); + } + + @Test + void testCompositeWithNestedComposite() { + CompositeStudentSearchCriteria outer = + new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); + outer.add(new GroupNumberRangeCriteria("A10", "C30")); + + CompositeStudentSearchCriteria inner = + new CompositeStudentSearchCriteria(SearchOperation.UNION); + inner.add(new AverageGradeRangeCriteria(4.0, 5.0)); + inner.add(new RecordBookNumberRangeCriteria(100, 200)); + + outer.add(inner); + + Student student = new Student("B20", 4.5, 150); + assertTrue(outer.matches(student)); + student = new Student("B20", 3.5, 150); + assertFalse(outer.matches(student)); + student = new Student("D00", 4.5, 150); + assertFalse(outer.matches(student)); + } + + @Test + void testSearchServiceWithSingleCriteria() { + MyList students = new MyLinkedList<>(); + students.add(new Student("A10", 4.5, 1)); + students.add(new Student("B20", 3.8, 2)); + students.add(new Student("C30", 4.9, 3)); + + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + StudentSearchService service = new StudentSearchService(criteria); + MyList result = service.find(students); + + assertEquals(2, result.size()); + assertEquals("A10", result.get(0).getGroupNumber()); + assertEquals("C30", result.get(1).getGroupNumber()); + } + + @Test + void testSearchServiceEmptyResult() { + MyList students = new MyLinkedList<>(); + students.add(new Student("A10", 3.5, 1)); + students.add(new Student("B20", 3.8, 2)); + + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + StudentSearchService service = new StudentSearchService(criteria); + MyList result = service.find(students); + + assertEquals(0, result.size()); + } + + @Test + void testSearchServiceEmptyCollection() { + MyList students = new MyLinkedList<>(); + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + StudentSearchService service = new StudentSearchService(criteria); + MyList result = service.find(students); + assertEquals(0, result.size()); + } + + @Test + void testSearchServicePreservesOrder() { + MyList students = new MyLinkedList<>(); + students.add(new Student("Z00", 4.5, 1)); + students.add(new Student("A10", 4.5, 2)); + students.add(new Student("M30", 4.5, 3)); + + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + StudentSearchService service = new StudentSearchService(criteria); + MyList result = service.find(students); + + assertEquals(3, result.size()); + assertEquals("Z00", result.get(0).getGroupNumber()); + assertEquals("A10", result.get(1).getGroupNumber()); + assertEquals("M30", result.get(2).getGroupNumber()); + } + + @Test + void testSearchServiceDoesNotModifyOriginal() { + MyList original = new MyLinkedList<>(); + original.add(new Student("A10", 4.5, 1)); + original.add(new Student("B20", 3.8, 2)); + + MyList copy = new MyLinkedList<>(); + for (int i = 0; i < original.size(); i++) { + copy.add(original.get(i)); } - @Test - void testGroupNumberRangeMatchesLowerBoundary() { - StudentSearchCriteria criteria = new GroupNumberRangeCriteria("A10", "C30"); - Student student = new Student("A10", 4.5, 123); - assertTrue(criteria.matches(student)); + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + StudentSearchService service = new StudentSearchService(criteria); + service.find(original); + + assertEquals(copy.size(), original.size()); + for (int i = 0; i < copy.size(); i++) { + assertEquals(copy.get(i).getGroupNumber(), original.get(i).getGroupNumber()); } + } - @Test - void testGroupNumberRangeMatchesUpperBoundary() { - StudentSearchCriteria criteria = new GroupNumberRangeCriteria("A10", "C30"); - Student student = new Student("C30", 4.5, 123); - assertTrue(criteria.matches(student)); - } + @Test + void testSearchServiceWithNullCriteriaThrowsException() { + assertThrows(IllegalArgumentException.class, () -> new StudentSearchService(null)); + } - @Test - void testGroupNumberRangeDoesNotMatchOutside() { - StudentSearchCriteria criteria = new GroupNumberRangeCriteria("A10", "C30"); - Student student = new Student("D00", 4.5, 123); - assertFalse(criteria.matches(student)); - } + @Test + void testSearchServiceWithCompositeCriteria() { + MyList students = new MyLinkedList<>(); + students.add(new Student("A10", 4.5, 1)); + students.add(new Student("B20", 4.5, 2)); + students.add(new Student("C30", 3.5, 3)); - @Test - void testGroupNumberRangeInvalidMinMaxThrowsException() { - assertThrows(IllegalArgumentException.class, - () -> new GroupNumberRangeCriteria("C30", "A10")); - } + CompositeStudentSearchCriteria composite = + new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); + composite.add(new GroupNumberRangeCriteria("A10", "B20")); + composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); - @Test - void testGroupNumberRangeNullValuesThrowsException() { - assertThrows(IllegalArgumentException.class, - () -> new GroupNumberRangeCriteria(null, "A10")); - assertThrows(IllegalArgumentException.class, - () -> new GroupNumberRangeCriteria("A10", null)); - } + StudentSearchService service = new StudentSearchService(composite); + MyList result = service.find(students); - @Test - void testAverageGradeRangeMatchesInside() { - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - Student student = new Student("A12", 4.5, 123); - assertTrue(criteria.matches(student)); - } + assertEquals(2, result.size()); + assertEquals("A10", result.get(0).getGroupNumber()); + assertEquals("B20", result.get(1).getGroupNumber()); + } - @Test - void testAverageGradeRangeMatchesLowerBoundary() { - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - Student student = new Student("A12", 4.0, 123); - assertTrue(criteria.matches(student)); - } - - @Test - void testAverageGradeRangeMatchesUpperBoundary() { - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - Student student = new Student("A12", 5.0, 123); - assertTrue(criteria.matches(student)); - } - - @Test - void testAverageGradeRangeDoesNotMatchBelow() { - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - Student student = new Student("A12", 3.9, 123); - assertFalse(criteria.matches(student)); - } - - @Test - void testAverageGradeRangeDoesNotMatchAbove() { - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - Student student = new Student("A12", 5.1, 123); - assertFalse(criteria.matches(student)); - } - - @Test - void testAverageGradeRangeInvalidMinMaxThrowsException() { - assertThrows(IllegalArgumentException.class, - () -> new AverageGradeRangeCriteria(5.0, 4.0)); - } - - @Test - void testRecordBookNumberRangeMatchesInside() { - StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); - Student student = new Student("A12", 4.5, 150); - assertTrue(criteria.matches(student)); - } - - @Test - void testRecordBookNumberRangeMatchesLowerBoundary() { - StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); - Student student = new Student("A12", 4.5, 100); - assertTrue(criteria.matches(student)); - } - - @Test - void testRecordBookNumberRangeMatchesUpperBoundary() { - StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); - Student student = new Student("A12", 4.5, 200); - assertTrue(criteria.matches(student)); - } - - @Test - void testRecordBookNumberRangeDoesNotMatchBelow() { - StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); - Student student = new Student("A12", 4.5, 99); - assertFalse(criteria.matches(student)); - } - - @Test - void testRecordBookNumberRangeDoesNotMatchAbove() { - StudentSearchCriteria criteria = new RecordBookNumberRangeCriteria(100, 200); - Student student = new Student("A12", 4.5, 201); - assertFalse(criteria.matches(student)); - } - - @Test - void testRecordBookNumberRangeInvalidMinMaxThrowsException() { - assertThrows(IllegalArgumentException.class, - () -> new RecordBookNumberRangeCriteria(200, 100)); - } - - @Test - void testCompositeIntersectionEmptyReturnsTrue() { - CompositeStudentSearchCriteria composite = new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); - Student student = new Student("A12", 4.5, 123); - assertTrue(composite.matches(student)); - } - - @Test - void testCompositeUnionEmptyReturnsFalse() { - CompositeStudentSearchCriteria composite = new CompositeStudentSearchCriteria(SearchOperation.UNION); - Student student = new Student("A12", 4.5, 123); - assertFalse(composite.matches(student)); - } - - @Test - void testCompositeIntersectionAllTrue() { - CompositeStudentSearchCriteria composite = new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); - composite.add(new GroupNumberRangeCriteria("A10", "C30")); - composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); - Student student = new Student("B20", 4.5, 123); - assertTrue(composite.matches(student)); - } - - @Test - void testCompositeIntersectionOneFalse() { - CompositeStudentSearchCriteria composite = new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); - composite.add(new GroupNumberRangeCriteria("A10", "C30")); - composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); - Student student = new Student("B20", 3.5, 123); - assertFalse(composite.matches(student)); - } - - @Test - void testCompositeUnionOneTrue() { - CompositeStudentSearchCriteria composite = new CompositeStudentSearchCriteria(SearchOperation.UNION); - composite.add(new GroupNumberRangeCriteria("A10", "C30")); - composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); - Student student = new Student("D00", 4.5, 123); - assertTrue(composite.matches(student)); - } - - @Test - void testCompositeUnionAllFalse() { - CompositeStudentSearchCriteria composite = new CompositeStudentSearchCriteria(SearchOperation.UNION); - composite.add(new GroupNumberRangeCriteria("A10", "C30")); - composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); - Student student = new Student("D00", 3.5, 123); - assertFalse(composite.matches(student)); - } - - @Test - void testCompositeWithNestedComposite() { - CompositeStudentSearchCriteria outer = new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); - outer.add(new GroupNumberRangeCriteria("A10", "C30")); - - CompositeStudentSearchCriteria inner = new CompositeStudentSearchCriteria(SearchOperation.UNION); - inner.add(new AverageGradeRangeCriteria(4.0, 5.0)); - inner.add(new RecordBookNumberRangeCriteria(100, 200)); - - outer.add(inner); - - Student student = new Student("B20", 4.5, 150); - assertTrue(outer.matches(student)); - student = new Student("B20", 3.5, 150); - assertFalse(outer.matches(student)); - student = new Student("D00", 4.5, 150); - assertFalse(outer.matches(student)); - } - - @Test - void testSearchServiceWithSingleCriteria() { - MyList students = new MyLinkedList<>(); - students.add(new Student("A10", 4.5, 1)); - students.add(new Student("B20", 3.8, 2)); - students.add(new Student("C30", 4.9, 3)); - - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - StudentSearchService service = new StudentSearchService(criteria); - MyList result = service.find(students); - - assertEquals(2, result.size()); - assertEquals("A10", result.get(0).getGroupNumber()); - assertEquals("C30", result.get(1).getGroupNumber()); - } - - @Test - void testSearchServiceEmptyResult() { - MyList students = new MyLinkedList<>(); - students.add(new Student("A10", 3.5, 1)); - students.add(new Student("B20", 3.8, 2)); - - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - StudentSearchService service = new StudentSearchService(criteria); - MyList result = service.find(students); - - assertEquals(0, result.size()); - } - - @Test - void testSearchServiceEmptyCollection() { - MyList students = new MyLinkedList<>(); - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - StudentSearchService service = new StudentSearchService(criteria); - MyList result = service.find(students); - assertEquals(0, result.size()); - } - - @Test - void testSearchServicePreservesOrder() { - MyList students = new MyLinkedList<>(); - students.add(new Student("Z00", 4.5, 1)); - students.add(new Student("A10", 4.5, 2)); - students.add(new Student("M30", 4.5, 3)); - - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - StudentSearchService service = new StudentSearchService(criteria); - MyList result = service.find(students); - - assertEquals(3, result.size()); - assertEquals("Z00", result.get(0).getGroupNumber()); - assertEquals("A10", result.get(1).getGroupNumber()); - assertEquals("M30", result.get(2).getGroupNumber()); - } - - @Test - void testSearchServiceDoesNotModifyOriginal() { - MyList original = new MyLinkedList<>(); - original.add(new Student("A10", 4.5, 1)); - original.add(new Student("B20", 3.8, 2)); - - MyList copy = new MyLinkedList<>(); - for (int i = 0; i < original.size(); i++) { - copy.add(original.get(i)); - } - - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - StudentSearchService service = new StudentSearchService(criteria); - service.find(original); - - assertEquals(copy.size(), original.size()); - for (int i = 0; i < copy.size(); i++) { - assertEquals(copy.get(i).getGroupNumber(), original.get(i).getGroupNumber()); - } - } - - @Test - void testSearchServiceWithNullCriteriaThrowsException() { - assertThrows(IllegalArgumentException.class, - () -> new StudentSearchService(null)); - } - - @Test - void testSearchServiceWithCompositeCriteria() { - MyList students = new MyLinkedList<>(); - students.add(new Student("A10", 4.5, 1)); - students.add(new Student("B20", 4.5, 2)); - students.add(new Student("C30", 3.5, 3)); - - CompositeStudentSearchCriteria composite = new CompositeStudentSearchCriteria(SearchOperation.INTERSECTION); - composite.add(new GroupNumberRangeCriteria("A10", "B20")); - composite.add(new AverageGradeRangeCriteria(4.0, 5.0)); - - StudentSearchService service = new StudentSearchService(composite); - MyList result = service.find(students); - - assertEquals(2, result.size()); - assertEquals("A10", result.get(0).getGroupNumber()); - assertEquals("B20", result.get(1).getGroupNumber()); - } - - @Test - void testSearchServiceWithNullStudentListReturnsEmpty() { - StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); - StudentSearchService service = new StudentSearchService(criteria); - MyList result = service.find(null); - assertNotNull(result); - assertEquals(0, result.size()); - } -} \ No newline at end of file + @Test + void testSearchServiceWithNullStudentListReturnsEmpty() { + StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0); + StudentSearchService service = new StudentSearchService(criteria); + MyList result = service.find(null); + assertNotNull(result); + assertEquals(0, result.size()); + } +} From 34d08eb39753673a8450805d1ce54ef001d022ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D0=B0=D0=B4=D0=B6=D0=B8=D0=BA=D1=83=D1=80=D0=B1?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=A2=D0=B5=D0=BC=D0=B8=D1=80=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD?= Date: Tue, 1 Sep 2026 16:23:57 +0300 Subject: [PATCH 27/29] fix: corrected errors in exceptions and tests --- .../java/ru/project/io/StudentCsvReader.java | 120 ++++---- .../ru/project/io/StudentCsvReaderTest.java | 261 +++++++----------- 2 files changed, 161 insertions(+), 220 deletions(-) diff --git a/app/src/main/java/ru/project/io/StudentCsvReader.java b/app/src/main/java/ru/project/io/StudentCsvReader.java index a6b93c4..8dc2bb5 100644 --- a/app/src/main/java/ru/project/io/StudentCsvReader.java +++ b/app/src/main/java/ru/project/io/StudentCsvReader.java @@ -14,70 +14,76 @@ import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; import ru.project.student.Student; import ru.project.student.StudentBuilder; - -public class StudentCsvReader implements Iterator { + public class StudentCsvReader implements Iterator { private static final String GROUP_NUMBER = "groupNumber"; private static final String AVERAGE_GRADE = "averageGrade"; private static final String RECORD_BOOK_NUMBER = "recordBookNumber"; - private final CSVParser parser; private final Iterator records; - - private int lineOfFile; - - public StudentCsvReader(Path path2) { - lineOfFile = 0; - Path path = Paths.get(path2); - if (!path.isAbsolute()) { - throw new IllegalArgumentException("File path must be absolute"); + private int lineOfFile=0; + public StudentCsvReader(Path path) { + if (!path.isAbsolute()) { + throw new IllegalArgumentException("File path must be absolute"); + } + try { + CSVFormat format = CSVFormat.DEFAULT.builder() + .setHeader() + .setSkipHeaderRecord(true) + .build(); + this.parser = CSVParser.parse(path, StandardCharsets.UTF_8, format); + validateHeader(parser.getHeaderMap()); + this.records = parser.iterator(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } } - - try { - CSVFormat format = CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true).get(); - this.parser = CSVParser.parse(path, StandardCharsets.UTF_8, format); - validateHeader(parser.getHeaderMap()); - this.records = parser.iterator(); - } catch (IOException e) { - throw new UncheckedIOException(e); + @Override + public boolean hasNext() { + return records.hasNext(); } - } - - @Override - public boolean hasNext() { - return records.hasNext(); - } - - @Override - public Student next() { - lineOfFile++; - if (!records.hasNext()) { - throw new NoSuchElementException("Problem at line " + lineOfFile + "."); - } - - CSVRecord record = records.next(); - if (record.size() != 3) { - throw new IllegalArgumentException( - "Problem at line " + lineOfFile + ".Expected 3 columns, but got " + record.size()); - } - try { - double averageGrade = Double.parseDouble(record.get(AVERAGE_GRADE)); - int recordBookNumber = Integer.parseInt(record.get(RECORD_BOOK_NUMBER)); + @Override + public Student next() { + if (!records.hasNext()) { + throw new NoSuchElementException("No more records at line " + (lineOfFile + 1)); + } + lineOfFile++; + CSVRecord record = records.next(); + if (record.size() != 3) { + throw new IllegalArgumentException( + "Problem at line " + lineOfFile + ". Expected 3 columns, but got " + record.size()); + } + String groupNumber = record.get(GROUP_NUMBER); + String averageGradeStr = record.get(AVERAGE_GRADE); + String recordBookNumberStr = record.get(RECORD_BOOK_NUMBER); + double averageGrade; + int recordBookNumber; + try { + averageGrade = Double.parseDouble(averageGradeStr); + } catch (NumberFormatException e) { + throw new IllegalArgumentException( + "Problem at line " + lineOfFile + ": cannot parse averageGrade '" + averageGradeStr + "' as double", e); + } + try { + recordBookNumber = Integer.parseInt(recordBookNumberStr); + } catch (NumberFormatException e) { + throw new IllegalArgumentException( + "Problem at line " + lineOfFile + ": cannot parse recordBookNumber '" + recordBookNumberStr + "' as int", e); + } return new StudentBuilder() - .setGroupNumber(record.get(GROUP_NUMBER)) - .setAverageGrade(averageGrade) - .setRecordBookNumber(recordBookNumber) - .build(); - } catch (NumberFormatException e) { - throw new IllegalArgumentException( - "Problem at line " + lineOfFile + ". Unacceptable type convertation"); + .setGroupNumber(groupNumber) + .setAverageGrade(averageGrade) + .setRecordBookNumber(recordBookNumber) + .build(); + } + @Override + public void close() throws IOException { + parser.close(); + } + private static void validateHeader(Map headerMap) { + String[] expected = {GROUP_NUMBER, AVERAGE_GRADE, RECORD_BOOK_NUMBER}; + if (headerMap.size() != expected.length + || !headerMap.keySet().containsAll(Arrays.asList(expected))) { + throw new IllegalArgumentException("Invalid CSV header"); + } } } - - private static void validateHeader(Map headerMap) { - String[] expected = {GROUP_NUMBER, AVERAGE_GRADE, RECORD_BOOK_NUMBER}; - if (headerMap.size() != expected.length - || !headerMap.keySet().containsAll(Arrays.asList(expected))) { - throw new IllegalArgumentException("Invalid CSV header"); - } - } -} diff --git a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java index 1ca6657..ed1bb02 100644 --- a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java +++ b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java @@ -1,10 +1,8 @@ package ru.project.io; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; - import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -15,167 +13,104 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import ru.project.student.Student; - +import ru.project.collection.MyLinkedList; +import ru.project.collection.MyList; +import ru.project.collectors.MyCollectors; +import ru.project.collectors.MyListCollector; class StudentCsvReaderTest { - @TempDir Path tempDir; - private Path studentPath; + @TempDir + Path tempDir; + @Test + void shouldTestreadValidCsvIntoMyList() throws IOException { + Path csv = tempDir.resolve("students.csv"); + String content = String.join("\n", + "groupNumber,averageGrade,recordBookNumber", + "M10,4.5,12345", // валидно: 1 буква + 2 цифры + "B05,3.8,12346" // валидно + ); + Files.writeString(csv, content, StandardCharsets.UTF_8); + try (var reader = new StudentCsvReader(csv.toAbsolutePath())) { + var studentStream = StreamSupport.stream( + Spliterators.spliteratorUnknownSize(reader, 0), + false + ); + MyList students = studentStream + .collect(MyCollectors.toMyList()); + assertEquals(2, students.size()); + assertEquals("M10", students.get(0).getGroupNumber()); + assertEquals(4.5, students.get(0).getAverageGrade(), 0.0); + assertEquals(12345, students.get(0).getRecordBookNumber()); + assertEquals("B05", students.get(1).getGroupNumber()); + assertEquals(3.8, students.get(1).getAverageGrade(), 0.0); + assertEquals(12346, students.get(1).getRecordBookNumber()); + } + } + @Test + void shouldTestinvalidHeaderThrowsException() throws IOException { + Path csv = tempDir.resolve("bad-header.csv"); + String content = """ + badGroup,badGrade,badBook + M101,4.5,12345 + """; + Files.writeString(csv, content, StandardCharsets.UTF_8); + IllegalArgumentException ex = assertThrows( + IllegalArgumentException.class, + () -> new StudentCsvReader(csv.toAbsolutePath()) + ); + assertTrue(ex.getMessage().contains("Invalid CSV header")); + } + @Test + void shouldTestwrongColumnCountThrowsException() throws IOException { + Path csv = tempDir.resolve("wrong-columns.csv"); + String content = """ + groupNumber,averageGrade,recordBookNumber + M101,4.5 + """; + Files.writeString(csv, content, StandardCharsets.UTF_8); + var reader = new StudentCsvReader(csv.toAbsolutePath()); + assertTrue(reader.hasNext()); + // следующая строка имеет только 2 колонки + IllegalArgumentException ex = assertThrows( + IllegalArgumentException.class, + reader::next + ); + assertTrue(ex.getMessage().contains("Expected 3 columns")); + } + @Test + void shouldTestparseErrorThrowsExceptionWithDetails() throws IOException { + Path csv = tempDir.resolve("parse-error.csv"); + String content = """ + groupNumber,averageGrade,recordBookNumber + M101,not-a-number,12345 + """; + Files.writeString(csv, content, StandardCharsets.UTF_8); - // Testing StudentCsvReader - - @BeforeAll - void generateStudentTestFile() { - studentPath = tempDir.resolve("students.csv"); - Files.write( - studentPath, - new String[] {"groupNumber,averageGrade,recordBookNumber", "A21,5.0,331", "A21,4.0,332"}, - StandardCharsets.UTF_8); - } - - @BeforeEach - void setUp() { - valideReader = new StudentCsvReader(studentPath.toAbsolutePath().toString()); - } - - @Test - void readerTestRejectRelativePath() { - assertThrows( - IllegalArgumentException.class, () -> new StudentCsvReader(studentPath.toString())); - } - - @Test - void readerRejectPathIsDir() { - assertThrows(UncheckedIOException.class, () -> new StudentCsvReader(tempDir.toAbsolutePath())); - } - - @Test - void readerTestFileNotExist() { - assertThrows( - UncheckedIOException.class, - () -> new StudentCsvReader(tempDir.resolve("sss.csv").toAbsolutePath().toString())); - } - - @Test - void testSkipsHeader() { - Student student = valideReader.next(); - assertNotEquals(student.getGroupNumber(), "groupNumber"); - } - - @Test - void testCreationStudentOnValidData() { - Student student = valideReader.next(); - assertEquals(student.getGroupNumber(), "A21"); - assertEquals(student.getAverageGrade(), 5.0); - assertEquals(student.getRecordBookNumber(), 331); - } - - @Test - void testNotSkippingFirstStudent() { - valideReader.hasNext(); - valideReader.hasNext(); - Student student = valideReader.next(); - assertEquals(student.getGroupNumber(), "A21"); - assertEquals(student.getAverageGrade(), 5.0); - assertEquals(student.getRecordBookNumber(), 331); - } - - @Test - void testValidEndsOfFile() { - valideReader.next(); - valideReader.next(); - assertTrue(!valideReader.hasNext()); - } - - @Test - void testOutOfIndex() { - assertThrows( - NoSuchElementException.class, - () -> { - Student student = valideReader.next(); - student = valideReader.next(); - student = valideReader.next(); - }); - } - - @Test - void readerTestRejectFewParametres() { - assertThrows( - IllegalArgumentException.class, - () -> { - Path path = tempDir.resolve("fewparameters.csv"); - Files.write( - path, - new String[] {"groupNumber,averageGrade,recordBookNumber", "A21,5.0"}, - StandardCharsets.UTF_8); - StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); - Student student = reader.next(); - }); - } - - @Test - void readerTestRejectInvalidGroupNumber() { - assertThrows( - IllegalArgumentException.class, - () -> { - Path path = tempDir.resolve("invalid_groupnumber.csv"); - Files.write( - path, - new String[] { - "groupNumber,averageGrade,recordBookNumber", "AAA,5.0,331", "A21,4.0,332" - }, - StandardCharsets.UTF_8); - StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); - Student student = reader.next(); - }); - } - - @Test - void readerTestRejectInvalidAverageGrade() { - assertThrows( - IllegalArgumentException.class, - () -> { - Path path = tempDir.resolve("invalid_averagegrade.csv"); - Files.write( - path, - new String[] { - "groupNumber,averageGrade,recordBookNumber", "A21,-5.0,331", "A21,4.0,332" - }, - StandardCharsets.UTF_8); - StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); - Student student = reader.next(); - }); - } - - @Test - void readerTestRejectInvalidRecordBookNumber() { - assertThrows( - IllegalArgumentException.class, - () -> { - Path path = tempDir.resolve("invalid_recordbooknumber.csv"); - Files.write( - path, - new String[] { - "groupNumber,averageGrade,recordBookNumber", "A21,5.0,-331", "A21,4.0,332" - }, - StandardCharsets.UTF_8); - StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); - Student student = reader.next(); - }); - } - - @Test - void testInvalidHeader() { - assertThrows( - IllegalArgumentException.class, - () -> { - Path path = tempDir.resolve("invalid_header.csv"); - Files.write( - path, - new String[] { - "groupNumber,averageGrade,recordBookNomber", "A21,5.0,-331", "A21,4.0,332" - }, - StandardCharsets.UTF_8); - StudentCsvReader reader = new StudentCsvReader(path.toAbsolutePath().toString()); - Student student = reader.next(); - }); - } + var reader = new StudentCsvReader(csv.toAbsolutePath()); + assertTrue(reader.hasNext()); + IllegalArgumentException ex = assertThrows( + IllegalArgumentException.class, + reader::next + ); + assertTrue(ex.getMessage().contains("cannot parse averageGrade")); + } + @Test + void shouldTestemptyDataAfterHeaderThrowsNoSuchElement() throws IOException { + Path csv = tempDir.resolve("empty-data.csv"); + String content = """ + groupNumber,averageGrade,recordBookNumber + """; + Files.writeString(csv, content, StandardCharsets.UTF_8); + var reader = new StudentCsvReader(csv.toAbsolutePath()); + assertFalse(reader.hasNext()); + assertThrows(NoSuchElementException.class, reader::next); + } + @Test + void shouldTestrelativePathThrowsException() { + Path relative = Path.of("relative-path.csv"); + IllegalArgumentException ex = assertThrows( + IllegalArgumentException.class, + () -> new StudentCsvReader(relative) + ); + assertTrue(ex.getMessage().contains("absolute")); + } } From 712fe6c112bb4c444975438508b12c0ce91f6d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D0=B0=D0=B4=D0=B6=D0=B8=D0=BA=D1=83=D1=80=D0=B1?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=A2=D0=B5=D0=BC=D0=B8=D1=80=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD?= Date: Tue, 1 Sep 2026 17:11:08 +0300 Subject: [PATCH 28/29] fix: fixed errors and tests --- .../java/ru/project/io/StudentCsvReader.java | 4 +- .../ru/project/io/StudentCsvReaderTest.java | 62 ++++++++++--------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/ru/project/io/StudentCsvReader.java b/app/src/main/java/ru/project/io/StudentCsvReader.java index 8dc2bb5..5974c04 100644 --- a/app/src/main/java/ru/project/io/StudentCsvReader.java +++ b/app/src/main/java/ru/project/io/StudentCsvReader.java @@ -14,7 +14,7 @@ import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; import ru.project.student.Student; import ru.project.student.StudentBuilder; - public class StudentCsvReader implements Iterator { + public class StudentCsvReader implements Iterator, AutoCloseable { private static final String GROUP_NUMBER = "groupNumber"; private static final String AVERAGE_GRADE = "averageGrade"; private static final String RECORD_BOOK_NUMBER = "recordBookNumber"; @@ -29,7 +29,7 @@ import ru.project.student.StudentBuilder; CSVFormat format = CSVFormat.DEFAULT.builder() .setHeader() .setSkipHeaderRecord(true) - .build(); + .get(); this.parser = CSVParser.parse(path, StandardCharsets.UTF_8, format); validateHeader(parser.getHeaderMap()); this.records = parser.iterator(); diff --git a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java index ed1bb02..3541f35 100644 --- a/app/src/test/java/ru/project/io/StudentCsvReaderTest.java +++ b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java @@ -1,22 +1,17 @@ package ru.project.io; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import java.io.UncheckedIOException; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.NoSuchElementException; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; +import java.util.Spliterators; +import java.util.stream.StreamSupport; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import ru.project.student.Student; -import ru.project.collection.MyLinkedList; import ru.project.collection.MyList; import ru.project.collectors.MyCollectors; -import ru.project.collectors.MyListCollector; +import static org.junit.jupiter.api.Assertions.*; class StudentCsvReaderTest { @TempDir Path tempDir; @@ -25,8 +20,8 @@ class StudentCsvReaderTest { Path csv = tempDir.resolve("students.csv"); String content = String.join("\n", "groupNumber,averageGrade,recordBookNumber", - "M10,4.5,12345", // валидно: 1 буква + 2 цифры - "B05,3.8,12346" // валидно + "M10,4.5,12345", + "B05,3.8,12346" ); Files.writeString(csv, content, StandardCharsets.UTF_8); try (var reader = new StudentCsvReader(csv.toAbsolutePath())) { @@ -67,14 +62,15 @@ class StudentCsvReaderTest { M101,4.5 """; Files.writeString(csv, content, StandardCharsets.UTF_8); - var reader = new StudentCsvReader(csv.toAbsolutePath()); - assertTrue(reader.hasNext()); - // следующая строка имеет только 2 колонки - IllegalArgumentException ex = assertThrows( - IllegalArgumentException.class, - reader::next - ); - assertTrue(ex.getMessage().contains("Expected 3 columns")); + try (var reader = new StudentCsvReader(csv.toAbsolutePath())) { + assertTrue(reader.hasNext()); + + IllegalArgumentException ex = assertThrows( + IllegalArgumentException.class, + reader::next + ); + assertTrue(ex.getMessage().contains("Expected 3 columns")); + } } @Test void shouldTestparseErrorThrowsExceptionWithDetails() throws IOException { @@ -84,14 +80,15 @@ class StudentCsvReaderTest { M101,not-a-number,12345 """; Files.writeString(csv, content, StandardCharsets.UTF_8); + try (var reader = new StudentCsvReader(csv.toAbsolutePath())) { + assertTrue(reader.hasNext()); - var reader = new StudentCsvReader(csv.toAbsolutePath()); - assertTrue(reader.hasNext()); - IllegalArgumentException ex = assertThrows( - IllegalArgumentException.class, - reader::next - ); - assertTrue(ex.getMessage().contains("cannot parse averageGrade")); + IllegalArgumentException ex = assertThrows( + IllegalArgumentException.class, + reader::next + ); + assertTrue(ex.getMessage().contains("cannot parse averageGrade")); + } } @Test void shouldTestemptyDataAfterHeaderThrowsNoSuchElement() throws IOException { @@ -100,17 +97,22 @@ class StudentCsvReaderTest { groupNumber,averageGrade,recordBookNumber """; Files.writeString(csv, content, StandardCharsets.UTF_8); - var reader = new StudentCsvReader(csv.toAbsolutePath()); - assertFalse(reader.hasNext()); - assertThrows(NoSuchElementException.class, reader::next); + + // ИСПРАВЛЕНО: добавлен try-with-resources + try (var reader = new StudentCsvReader(csv.toAbsolutePath())) { + assertFalse(reader.hasNext()); + + assertThrows(NoSuchElementException.class, reader::next); + } } @Test void shouldTestrelativePathThrowsException() { Path relative = Path.of("relative-path.csv"); + IllegalArgumentException ex = assertThrows( IllegalArgumentException.class, () -> new StudentCsvReader(relative) ); assertTrue(ex.getMessage().contains("absolute")); } -} + } \ No newline at end of file From 2971548e5280d4125b05b6b8922ff2de2204371b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=93=D0=B0=D0=B4=D0=B6=D0=B8=D0=BA=D1=83=D1=80=D0=B1?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=A2=D0=B5=D0=BC=D0=B8=D1=80=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD?= Date: Tue, 1 Sep 2026 17:24:27 +0300 Subject: [PATCH 29/29] chore: remove unused Paths --- app/src/main/java/ru/project/io/StudentCsvReader.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/ru/project/io/StudentCsvReader.java b/app/src/main/java/ru/project/io/StudentCsvReader.java index 5974c04..db2a4a9 100644 --- a/app/src/main/java/ru/project/io/StudentCsvReader.java +++ b/app/src/main/java/ru/project/io/StudentCsvReader.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Arrays; import java.util.Iterator; import java.util.Map;