fix: corrected errors in exceptions and tests

This commit is contained in:
Гаджикурбанов Темирлан
2026-09-01 16:23:57 +03:00
parent ff83c48650
commit 34d08eb397
2 changed files with 161 additions and 220 deletions
@@ -14,70 +14,76 @@ import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord; import org.apache.commons.csv.CSVRecord;
import ru.project.student.Student; import ru.project.student.Student;
import ru.project.student.StudentBuilder; import ru.project.student.StudentBuilder;
public class StudentCsvReader implements Iterator<Student> {
public class StudentCsvReader implements Iterator<Student> {
private static final String GROUP_NUMBER = "groupNumber"; private static final String GROUP_NUMBER = "groupNumber";
private static final String AVERAGE_GRADE = "averageGrade"; private static final String AVERAGE_GRADE = "averageGrade";
private static final String RECORD_BOOK_NUMBER = "recordBookNumber"; private static final String RECORD_BOOK_NUMBER = "recordBookNumber";
private final CSVParser parser; private final CSVParser parser;
private final Iterator<CSVRecord> records; private final Iterator<CSVRecord> records;
private int lineOfFile=0;
private int lineOfFile; public StudentCsvReader(Path path) {
if (!path.isAbsolute()) {
public StudentCsvReader(Path path2) { throw new IllegalArgumentException("File path must be absolute");
lineOfFile = 0; }
Path path = Paths.get(path2); try {
if (!path.isAbsolute()) { CSVFormat format = CSVFormat.DEFAULT.builder()
throw new IllegalArgumentException("File path must be absolute"); .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
try { public boolean hasNext() {
CSVFormat format = CSVFormat.DEFAULT.builder().setHeader().setSkipHeaderRecord(true).get(); return records.hasNext();
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 Student next() {
@Override if (!records.hasNext()) {
public boolean hasNext() { throw new NoSuchElementException("No more records at line " + (lineOfFile + 1));
return records.hasNext(); }
} lineOfFile++;
CSVRecord record = records.next();
@Override if (record.size() != 3) {
public Student next() { throw new IllegalArgumentException(
lineOfFile++; "Problem at line " + lineOfFile + ". Expected 3 columns, but got " + record.size());
if (!records.hasNext()) { }
throw new NoSuchElementException("Problem at line " + lineOfFile + "."); String groupNumber = record.get(GROUP_NUMBER);
} String averageGradeStr = record.get(AVERAGE_GRADE);
String recordBookNumberStr = record.get(RECORD_BOOK_NUMBER);
CSVRecord record = records.next(); double averageGrade;
if (record.size() != 3) { int recordBookNumber;
throw new IllegalArgumentException( try {
"Problem at line " + lineOfFile + ".Expected 3 columns, but got " + record.size()); averageGrade = Double.parseDouble(averageGradeStr);
} } catch (NumberFormatException e) {
try { throw new IllegalArgumentException(
double averageGrade = Double.parseDouble(record.get(AVERAGE_GRADE)); "Problem at line " + lineOfFile + ": cannot parse averageGrade '" + averageGradeStr + "' as double", e);
int recordBookNumber = Integer.parseInt(record.get(RECORD_BOOK_NUMBER)); }
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() return new StudentBuilder()
.setGroupNumber(record.get(GROUP_NUMBER)) .setGroupNumber(groupNumber)
.setAverageGrade(averageGrade) .setAverageGrade(averageGrade)
.setRecordBookNumber(recordBookNumber) .setRecordBookNumber(recordBookNumber)
.build(); .build();
} catch (NumberFormatException e) { }
throw new IllegalArgumentException( @Override
"Problem at line " + lineOfFile + ". Unacceptable type convertation"); 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
|| !headerMap.keySet().containsAll(Arrays.asList(expected))) {
throw new IllegalArgumentException("Invalid CSV header");
}
} }
} }
private static void validateHeader(Map<String, Integer> 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");
}
}
}
@@ -1,10 +1,8 @@
package ru.project.io; package ru.project.io;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; 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.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import ru.project.student.Student; 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 { class StudentCsvReaderTest {
@TempDir Path tempDir; @TempDir
private Path studentPath; 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<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);
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 var reader = new StudentCsvReader(csv.toAbsolutePath());
assertTrue(reader.hasNext());
@BeforeAll IllegalArgumentException ex = assertThrows(
void generateStudentTestFile() { IllegalArgumentException.class,
studentPath = tempDir.resolve("students.csv"); reader::next
Files.write( );
studentPath, assertTrue(ex.getMessage().contains("cannot parse averageGrade"));
new String[] {"groupNumber,averageGrade,recordBookNumber", "A21,5.0,331", "A21,4.0,332"}, }
StandardCharsets.UTF_8); @Test
} void shouldTestemptyDataAfterHeaderThrowsNoSuchElement() throws IOException {
Path csv = tempDir.resolve("empty-data.csv");
@BeforeEach String content = """
void setUp() { groupNumber,averageGrade,recordBookNumber
valideReader = new StudentCsvReader(studentPath.toAbsolutePath().toString()); """;
} Files.writeString(csv, content, StandardCharsets.UTF_8);
var reader = new StudentCsvReader(csv.toAbsolutePath());
@Test assertFalse(reader.hasNext());
void readerTestRejectRelativePath() { assertThrows(NoSuchElementException.class, reader::next);
assertThrows( }
IllegalArgumentException.class, () -> new StudentCsvReader(studentPath.toString())); @Test
} void shouldTestrelativePathThrowsException() {
Path relative = Path.of("relative-path.csv");
@Test IllegalArgumentException ex = assertThrows(
void readerRejectPathIsDir() { IllegalArgumentException.class,
assertThrows(UncheckedIOException.class, () -> new StudentCsvReader(tempDir.toAbsolutePath())); () -> new StudentCsvReader(relative)
} );
assertTrue(ex.getMessage().contains("absolute"));
@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();
});
}
} }