style(code): unify formatting across io and search components

This commit is contained in:
2026-09-02 13:14:28 +04:00
parent d7f4d30cc3
commit 1ec1d68a02
8 changed files with 261 additions and 250 deletions
@@ -13,6 +13,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<Student>, AutoCloseable {
private static final String GROUP_NUMBER = "groupNumber";
private static final String AVERAGE_GRADE = "averageGrade";
@@ -20,15 +21,13 @@ import ru.project.student.StudentBuilder;
private final CSVParser parser;
private final Iterator<CSVRecord> records;
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)
.get();
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();
@@ -36,10 +35,12 @@ import ru.project.student.StudentBuilder;
throw new UncheckedIOException(e);
}
}
@Override
public boolean hasNext() {
return records.hasNext();
}
@Override
public Student next() {
if (!records.hasNext()) {
@@ -60,13 +61,23 @@ import ru.project.student.StudentBuilder;
averageGrade = Double.parseDouble(averageGradeStr);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
"Problem at line " + lineOfFile + ": cannot parse averageGrade '" + averageGradeStr + "' as double", e);
"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);
"Problem at line "
+ lineOfFile
+ ": cannot parse recordBookNumber '"
+ recordBookNumberStr
+ "' as int",
e);
}
return new StudentBuilder()
.setGroupNumber(groupNumber)
@@ -74,10 +85,12 @@ import ru.project.student.StudentBuilder;
.setRecordBookNumber(recordBookNumber)
.build();
}
@Override
public void close() throws IOException {
parser.close();
}
private static void validateHeader(Map<String, Integer> headerMap) {
String[] expected = {GROUP_NUMBER, AVERAGE_GRADE, RECORD_BOOK_NUMBER};
if (headerMap.size() != expected.length
@@ -1,8 +1,8 @@
package ru.project.search;
import ru.project.student.Student;
import java.util.ArrayList;
import java.util.List;
import ru.project.student.Student;
public class CompositeStudentSearchCriteria implements StudentSearchCriteria {
private final SearchOperation operation;
@@ -1,4 +1,7 @@
package ru.project.io;
import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -8,29 +11,24 @@ 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.MyList;
import ru.project.collectors.MyCollectors;
import static org.junit.jupiter.api.Assertions.*;
import ru.project.student.Student;
class StudentCsvReaderTest {
@TempDir
Path tempDir;
@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",
"B05,3.8,12346"
);
String content =
String.join(
"\n", "groupNumber,averageGrade,recordBookNumber", "M10,4.5,12345", "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<Student> students = studentStream
.collect(MyCollectors.toMyList());
var studentStream =
StreamSupport.stream(Spliterators.spliteratorUnknownSize(reader, 0), false);
MyList<Student> students = studentStream.collect(MyCollectors.toMyList());
assertEquals(2, students.size());
assertEquals("M10", students.get(0).getGroupNumber());
assertEquals(4.5, students.get(0).getAverageGrade(), 0.0);
@@ -40,24 +38,27 @@ class StudentCsvReaderTest {
assertEquals(12346, students.get(1).getRecordBookNumber());
}
}
@Test
void shouldTestinvalidHeaderThrowsException() throws IOException {
Path csv = tempDir.resolve("bad-header.csv");
String content = """
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())
);
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 = """
String content =
"""
groupNumber,averageGrade,recordBookNumber
M101,4.5
""";
@@ -65,17 +66,16 @@ class StudentCsvReaderTest {
try (var reader = new StudentCsvReader(csv.toAbsolutePath())) {
assertTrue(reader.hasNext());
IllegalArgumentException ex = assertThrows(
IllegalArgumentException.class,
reader::next
);
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 = """
String content =
"""
groupNumber,averageGrade,recordBookNumber
M101,not-a-number,12345
""";
@@ -83,17 +83,16 @@ class StudentCsvReaderTest {
try (var reader = new StudentCsvReader(csv.toAbsolutePath())) {
assertTrue(reader.hasNext());
IllegalArgumentException ex = assertThrows(
IllegalArgumentException.class,
reader::next
);
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 = """
String content =
"""
groupNumber,averageGrade,recordBookNumber
""";
Files.writeString(csv, content, StandardCharsets.UTF_8);
@@ -105,14 +104,13 @@ class StudentCsvReaderTest {
assertThrows(NoSuchElementException.class, reader::next);
}
}
@Test
void shouldTestrelativePathThrowsException() {
Path relative = Path.of("relative-path.csv");
IllegalArgumentException ex = assertThrows(
IllegalArgumentException.class,
() -> new StudentCsvReader(relative)
);
IllegalArgumentException ex =
assertThrows(IllegalArgumentException.class, () -> new StudentCsvReader(relative));
assertTrue(ex.getMessage().contains("absolute"));
}
}