fix: corrected errors in exceptions and tests
This commit is contained in:
@@ -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<Student> {
|
||||
public class StudentCsvReader implements Iterator<Student> {
|
||||
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<CSVRecord> 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<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;
|
||||
|
||||
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<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
|
||||
|
||||
@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"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user