style(code): unify formatting across io and search components
This commit is contained in:
@@ -13,76 +13,89 @@ 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>, AutoCloseable {
|
|
||||||
|
public class StudentCsvReader implements Iterator<Student>, AutoCloseable {
|
||||||
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 = 0;
|
||||||
public StudentCsvReader(Path path) {
|
|
||||||
if (!path.isAbsolute()) {
|
public StudentCsvReader(Path path) {
|
||||||
throw new IllegalArgumentException("File path must be absolute");
|
if (!path.isAbsolute()) {
|
||||||
}
|
throw new IllegalArgumentException("File path must be absolute");
|
||||||
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
|
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());
|
||||||
@Override
|
this.records = parser.iterator();
|
||||||
public Student next() {
|
} catch (IOException e) {
|
||||||
if (!records.hasNext()) {
|
throw new UncheckedIOException(e);
|
||||||
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(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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return records.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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(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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,20 +3,20 @@ package ru.project.search;
|
|||||||
import ru.project.student.Student;
|
import ru.project.student.Student;
|
||||||
|
|
||||||
public class AverageGradeRangeCriteria implements StudentSearchCriteria {
|
public class AverageGradeRangeCriteria implements StudentSearchCriteria {
|
||||||
private final double min;
|
private final double min;
|
||||||
private final double max;
|
private final double max;
|
||||||
|
|
||||||
public AverageGradeRangeCriteria(double min, double max) {
|
public AverageGradeRangeCriteria(double min, double max) {
|
||||||
if (min > max) {
|
if (min > max) {
|
||||||
throw new IllegalArgumentException("Min grade must be <= max grade");
|
throw new IllegalArgumentException("Min grade must be <= max grade");
|
||||||
}
|
|
||||||
this.min = min;
|
|
||||||
this.max = max;
|
|
||||||
}
|
}
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Student student) {
|
public boolean matches(Student student) {
|
||||||
double grade = student.getAverageGrade();
|
double grade = student.getAverageGrade();
|
||||||
return grade >= min && grade <= max;
|
return grade >= min && grade <= max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
package ru.project.search;
|
package ru.project.search;
|
||||||
|
|
||||||
import ru.project.student.Student;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import ru.project.student.Student;
|
||||||
|
|
||||||
public class CompositeStudentSearchCriteria implements StudentSearchCriteria {
|
public class CompositeStudentSearchCriteria implements StudentSearchCriteria {
|
||||||
private final SearchOperation operation;
|
private final SearchOperation operation;
|
||||||
private final List<StudentSearchCriteria> criteriaList = new ArrayList<>();
|
private final List<StudentSearchCriteria> criteriaList = new ArrayList<>();
|
||||||
|
|
||||||
public CompositeStudentSearchCriteria(SearchOperation operation) {
|
public CompositeStudentSearchCriteria(SearchOperation operation) {
|
||||||
if (operation == null) {
|
if (operation == null) {
|
||||||
throw new IllegalArgumentException("Operation must not be null");
|
throw new IllegalArgumentException("Operation must not be null");
|
||||||
}
|
}
|
||||||
this.operation = operation;
|
this.operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(StudentSearchCriteria criteria) {
|
||||||
|
if (criteria == null) {
|
||||||
|
throw new IllegalArgumentException("Criteria must not be null");
|
||||||
|
}
|
||||||
|
criteriaList.add(criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(StudentSearchCriteria criteria) {
|
||||||
|
criteriaList.remove(criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(Student student) {
|
||||||
|
if (criteriaList.isEmpty()) {
|
||||||
|
return operation == SearchOperation.INTERSECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(StudentSearchCriteria criteria) {
|
if (operation == SearchOperation.UNION) {
|
||||||
if (criteria == null) {
|
for (StudentSearchCriteria c : criteriaList) {
|
||||||
throw new IllegalArgumentException("Criteria must not be null");
|
if (c.matches(student)) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
criteriaList.add(criteria);
|
}
|
||||||
}
|
return false;
|
||||||
|
} else {
|
||||||
public void remove(StudentSearchCriteria criteria) {
|
for (StudentSearchCriteria c : criteriaList) {
|
||||||
criteriaList.remove(criteria);
|
if (!c.matches(student)) {
|
||||||
}
|
return false;
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(Student student) {
|
|
||||||
if (criteriaList.isEmpty()) {
|
|
||||||
return operation == SearchOperation.INTERSECTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operation == SearchOperation.UNION) {
|
|
||||||
for (StudentSearchCriteria c : criteriaList) {
|
|
||||||
if (c.matches(student)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
for (StudentSearchCriteria c : criteriaList) {
|
|
||||||
if (!c.matches(student)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,23 +3,23 @@ package ru.project.search;
|
|||||||
import ru.project.student.Student;
|
import ru.project.student.Student;
|
||||||
|
|
||||||
public class GroupNumberRangeCriteria implements StudentSearchCriteria {
|
public class GroupNumberRangeCriteria implements StudentSearchCriteria {
|
||||||
private final String min;
|
private final String min;
|
||||||
private final String max;
|
private final String max;
|
||||||
|
|
||||||
public GroupNumberRangeCriteria(String min, String max) {
|
public GroupNumberRangeCriteria(String min, String max) {
|
||||||
if (min == null || max == null) {
|
if (min == null || max == null) {
|
||||||
throw new IllegalArgumentException("Min and max must not be null");
|
throw new IllegalArgumentException("Min and max must not be null");
|
||||||
}
|
|
||||||
if (min.compareTo(max) > 0) {
|
|
||||||
throw new IllegalArgumentException("Min group must be <= max group");
|
|
||||||
}
|
|
||||||
this.min = min;
|
|
||||||
this.max = max;
|
|
||||||
}
|
}
|
||||||
|
if (min.compareTo(max) > 0) {
|
||||||
|
throw new IllegalArgumentException("Min group must be <= max group");
|
||||||
|
}
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Student student) {
|
public boolean matches(Student student) {
|
||||||
String group = student.getGroupNumber();
|
String group = student.getGroupNumber();
|
||||||
return group.compareTo(min) >= 0 && group.compareTo(max) <= 0;
|
return group.compareTo(min) >= 0 && group.compareTo(max) <= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,20 +3,20 @@ package ru.project.search;
|
|||||||
import ru.project.student.Student;
|
import ru.project.student.Student;
|
||||||
|
|
||||||
public class RecordBookNumberRangeCriteria implements StudentSearchCriteria {
|
public class RecordBookNumberRangeCriteria implements StudentSearchCriteria {
|
||||||
private final int min;
|
private final int min;
|
||||||
private final int max;
|
private final int max;
|
||||||
|
|
||||||
public RecordBookNumberRangeCriteria(int min, int max) {
|
public RecordBookNumberRangeCriteria(int min, int max) {
|
||||||
if (min > max) {
|
if (min > max) {
|
||||||
throw new IllegalArgumentException("Min record number must be <= max");
|
throw new IllegalArgumentException("Min record number must be <= max");
|
||||||
}
|
|
||||||
this.min = min;
|
|
||||||
this.max = max;
|
|
||||||
}
|
}
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Student student) {
|
public boolean matches(Student student) {
|
||||||
int number = student.getRecordBookNumber();
|
int number = student.getRecordBookNumber();
|
||||||
return number >= min && number <= max;
|
return number >= min && number <= max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package ru.project.search;
|
package ru.project.search;
|
||||||
|
|
||||||
public enum SearchOperation {
|
public enum SearchOperation {
|
||||||
UNION,
|
UNION,
|
||||||
INTERSECTION
|
INTERSECTION
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ package ru.project.search;
|
|||||||
import ru.project.student.Student;
|
import ru.project.student.Student;
|
||||||
|
|
||||||
public interface StudentSearchCriteria {
|
public interface StudentSearchCriteria {
|
||||||
boolean matches(Student student);
|
boolean matches(Student student);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
package ru.project.io;
|
package ru.project.io;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -8,111 +11,106 @@ import java.util.Spliterators;
|
|||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
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.collection.MyList;
|
import ru.project.collection.MyList;
|
||||||
import ru.project.collectors.MyCollectors;
|
import ru.project.collectors.MyCollectors;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import ru.project.student.Student;
|
||||||
|
|
||||||
class StudentCsvReaderTest {
|
class StudentCsvReaderTest {
|
||||||
@TempDir
|
@TempDir Path 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"
|
|
||||||
);
|
|
||||||
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);
|
|
||||||
try (var reader = new StudentCsvReader(csv.toAbsolutePath())) {
|
|
||||||
assertTrue(reader.hasNext());
|
|
||||||
|
|
||||||
IllegalArgumentException ex = assertThrows(
|
@Test
|
||||||
IllegalArgumentException.class,
|
void shouldTestreadValidCsvIntoMyList() throws IOException {
|
||||||
reader::next
|
Path csv = tempDir.resolve("students.csv");
|
||||||
);
|
String content =
|
||||||
assertTrue(ex.getMessage().contains("Expected 3 columns"));
|
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());
|
||||||
|
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 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);
|
|
||||||
try (var reader = new StudentCsvReader(csv.toAbsolutePath())) {
|
|
||||||
assertTrue(reader.hasNext());
|
|
||||||
|
|
||||||
IllegalArgumentException ex = assertThrows(
|
@Test
|
||||||
IllegalArgumentException.class,
|
void shouldTestinvalidHeaderThrowsException() throws IOException {
|
||||||
reader::next
|
Path csv = tempDir.resolve("bad-header.csv");
|
||||||
);
|
String content =
|
||||||
assertTrue(ex.getMessage().contains("cannot parse averageGrade"));
|
"""
|
||||||
}
|
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);
|
||||||
|
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 shouldTestemptyDataAfterHeaderThrowsNoSuchElement() throws IOException {
|
|
||||||
Path csv = tempDir.resolve("empty-data.csv");
|
|
||||||
String content = """
|
|
||||||
groupNumber,averageGrade,recordBookNumber
|
|
||||||
""";
|
|
||||||
Files.writeString(csv, content, StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
// ИСПРАВЛЕНО: добавлен try-with-resources
|
@Test
|
||||||
try (var reader = new StudentCsvReader(csv.toAbsolutePath())) {
|
void shouldTestparseErrorThrowsExceptionWithDetails() throws IOException {
|
||||||
assertFalse(reader.hasNext());
|
Path csv = tempDir.resolve("parse-error.csv");
|
||||||
|
String content =
|
||||||
|
"""
|
||||||
|
groupNumber,averageGrade,recordBookNumber
|
||||||
|
M101,not-a-number,12345
|
||||||
|
""";
|
||||||
|
Files.writeString(csv, content, StandardCharsets.UTF_8);
|
||||||
|
try (var reader = new StudentCsvReader(csv.toAbsolutePath())) {
|
||||||
|
assertTrue(reader.hasNext());
|
||||||
|
|
||||||
assertThrows(NoSuchElementException.class, reader::next);
|
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, reader::next);
|
||||||
}
|
assertTrue(ex.getMessage().contains("cannot parse averageGrade"));
|
||||||
}
|
}
|
||||||
@Test
|
}
|
||||||
void shouldTestrelativePathThrowsException() {
|
|
||||||
Path relative = Path.of("relative-path.csv");
|
|
||||||
|
|
||||||
IllegalArgumentException ex = assertThrows(
|
@Test
|
||||||
IllegalArgumentException.class,
|
void shouldTestemptyDataAfterHeaderThrowsNoSuchElement() throws IOException {
|
||||||
() -> new StudentCsvReader(relative)
|
Path csv = tempDir.resolve("empty-data.csv");
|
||||||
);
|
String content =
|
||||||
assertTrue(ex.getMessage().contains("absolute"));
|
"""
|
||||||
|
groupNumber,averageGrade,recordBookNumber
|
||||||
|
""";
|
||||||
|
Files.writeString(csv, content, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
// ИСПРАВЛЕНО: добавлен 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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user