diff --git a/app/pom.xml b/app/pom.xml index 3094443..d5108b2 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -42,6 +42,12 @@ test + + org.apache.commons + commons-csv + 1.14.1 + + com.googlecode.lanterna lanterna diff --git a/app/src/main/java/ru/project/App.java b/app/src/main/java/ru/project/App.java deleted file mode 100644 index 73f5efa..0000000 --- a/app/src/main/java/ru/project/App.java +++ /dev/null @@ -1,45 +0,0 @@ -package ru.project; - -import com.googlecode.lanterna.gui2.MultiWindowTextGUI; -import com.googlecode.lanterna.screen.Screen; -import com.googlecode.lanterna.terminal.DefaultTerminalFactory; -import ru.project.model.AppState; -import ru.project.ui.main.MainMenu; - -public final class App { - - private App() {} - - public static void main(String[] args) { - Screen screen = null; - - try { - DefaultTerminalFactory terminalFactory = new DefaultTerminalFactory(); - - screen = terminalFactory.createScreen(); - screen.startScreen(); - - MultiWindowTextGUI gui = new MultiWindowTextGUI(screen); - - AppState state = new AppState(); - - MainMenu mainMenu = new MainMenu(gui, state); - - mainMenu.showModal(); - - } catch (Exception e) { - System.err.println("Произошла ошибка при выполнении программы:"); - e.printStackTrace(); - - } finally { - if (screen != null) { - try { - screen.stopScreen(); - } catch (Exception e) { - System.err.println("Не удалось корректно завершить работу терминала:"); - e.printStackTrace(); - } - } - } - } -} diff --git a/app/src/main/java/ru/project/MyCollectors.java b/app/src/main/java/ru/project/MyCollectors.java deleted file mode 100644 index 20840c3..0000000 --- a/app/src/main/java/ru/project/MyCollectors.java +++ /dev/null @@ -1,10 +0,0 @@ -package ru.test.maven.spring; -import java.util.stream.Collector; -public class MyCollectors -{ - private MyCollectors() { - } - public static Collector, MyList> toMyList() { - return new MyListCollector<>(); - } -} \ No newline at end of file diff --git a/app/src/main/java/ru/project/MyListCollector.java b/app/src/main/java/ru/project/MyListCollector.java deleted file mode 100644 index f731379..0000000 --- a/app/src/main/java/ru/project/MyListCollector.java +++ /dev/null @@ -1,41 +0,0 @@ -package ru.test.maven.spring; -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<>(); - } - @Override - public BiConsumer, T> accumulator() { - - return (list, element) -> list.add(element); - } - @Override - public BinaryOperator> combiner() { - return (list1, list2) -> { - for (int i = 0; i < list2.size(); i++) { - list1.add(list2.get(i)); - } - return list1; - }; - } - @Override - public Function, MyList> finisher() - { - return list -> list; - } - @Override - public Set characteristics() { - return java.util.Set.of( - Collector.Characteristics.IDENTITY_FINISH - ); - } -} \ No newline at end of file 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 new file mode 100644 index 0000000..db2a4a9 --- /dev/null +++ b/app/src/main/java/ru/project/io/StudentCsvReader.java @@ -0,0 +1,88 @@ +package ru.project.io; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +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, AutoCloseable { + 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=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(); + 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("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 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/random/RandomStudentGenerator.java b/app/src/main/java/ru/project/random/RandomStudentGenerator.java new file mode 100644 index 0000000..25e6032 --- /dev/null +++ b/app/src/main/java/ru/project/random/RandomStudentGenerator.java @@ -0,0 +1,156 @@ +package ru.project.random; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import ru.project.collection.MyLinkedList; +import ru.project.collection.MyList; +import ru.project.student.Student; +import java.util.Random; +import java.util.regex.Pattern; + +public class RandomStudentGenerator +{ + private static final Random RANDOM = new Random(); + private String minGroupNumber; + private String maxGroupNumber; + private Double minAverageGrade; + private Double maxAverageGrade; + private Integer minRecordBookNumber; + private Integer maxRecordBookNumber; + private static final double DEFAULT_MIN_GRADE = 0.0; + private static final double DEFAULT_MAX_GRADE = 5.0; + private static final int DEFAULT_MIN_RECORD_BOOK = 1; + private static final String GROUP_PATTERN_REGEX = "^[A-Z][0-9]{2}$"; + private static final Pattern GROUP_PATTERN = Pattern.compile(GROUP_PATTERN_REGEX); + public RandomStudentGenerator setMinGroupNumber(String minGroupNumber) { + if (minGroupNumber != null && !GROUP_PATTERN.matcher(minGroupNumber).matches()) { + throw new IllegalArgumentException("minGroupNumber does not match Student group pattern: " + GROUP_PATTERN_REGEX); + } + this.minGroupNumber = minGroupNumber; + return this; + } + public RandomStudentGenerator setMaxGroupNumber(String maxGroupNumber) { + if (maxGroupNumber != null && !GROUP_PATTERN.matcher(maxGroupNumber).matches()) { + throw new IllegalArgumentException("maxGroupNumber does not match Student group pattern: " + GROUP_PATTERN_REGEX); + } + this.maxGroupNumber = maxGroupNumber; + return this; + } + + public RandomStudentGenerator setMinAverageGrade(double minAverageGrade) { + if (minAverageGrade < DEFAULT_MIN_GRADE || minAverageGrade > DEFAULT_MAX_GRADE) { + throw new IllegalArgumentException( + "minAverageGrade out of Student allowed range [" + DEFAULT_MIN_GRADE + ", " + DEFAULT_MAX_GRADE + "]" + ); + } + this.minAverageGrade = minAverageGrade; + return this; + } + + public RandomStudentGenerator setMaxAverageGrade(double maxAverageGrade) { + if (maxAverageGrade < DEFAULT_MIN_GRADE || maxAverageGrade > DEFAULT_MAX_GRADE) { + throw new IllegalArgumentException( + "maxAverageGrade out of Student allowed range [" + DEFAULT_MIN_GRADE + ", " + DEFAULT_MAX_GRADE + "]" + ); + } + this.maxAverageGrade = maxAverageGrade; + return this; + } + + public RandomStudentGenerator setMinRecordBookNumber(int minRecordBookNumber) { + if (minRecordBookNumber < DEFAULT_MIN_RECORD_BOOK) { + throw new IllegalArgumentException( + "minRecordBookNumber must be >= " + DEFAULT_MIN_RECORD_BOOK + ); + } + this.minRecordBookNumber = minRecordBookNumber; + return this; + } + + public RandomStudentGenerator setMaxRecordBookNumber(int maxRecordBookNumber) { + if (maxRecordBookNumber < DEFAULT_MIN_RECORD_BOOK) { + throw new IllegalArgumentException( + "maxRecordBookNumber must be >= " + DEFAULT_MIN_RECORD_BOOK + ); + } + this.maxRecordBookNumber = maxRecordBookNumber; + return this; + } + public MyList generate(int size) { + if (size < 0) { + throw new IllegalArgumentException("size must be non-negative"); + } + validateRanges(); + MyList result = new MyLinkedList<>(); + for (int i = 0; i < size; i++) { + String group = generateGroupNumber(); + double grade = generateAverageGrade(); + int recordBook = generateRecordBookNumber(); + + Student student = new StudentBuilder() + .setGroupNumber(group) + .setAverageGrade(grade) + .setRecordBookNumber(recordBook) + .build(); + + result.add(student); + } + return result; + } + private void validateRanges() { + + double effectiveMinGrade = (minAverageGrade != null) ? minAverageGrade : DEFAULT_MIN_GRADE; + double effectiveMaxGrade = (maxAverageGrade != null) ? maxAverageGrade : DEFAULT_MAX_GRADE; + if (effectiveMinGrade > effectiveMaxGrade) { + throw new IllegalArgumentException("minAverageGrade cannot be greater than maxAverageGrade"); + } + int effectiveMinRecord = (minRecordBookNumber != null) ? minRecordBookNumber : DEFAULT_MIN_RECORD_BOOK; + int effectiveMaxRecord = (maxRecordBookNumber != null) ? maxRecordBookNumber : Integer.MAX_VALUE; + if (effectiveMaxRecord == Integer.MAX_VALUE) { + effectiveMaxRecord = effectiveMinRecord + 999_999; + } + if (effectiveMinRecord > effectiveMaxRecord) { + throw new IllegalArgumentException("minRecordBookNumber cannot be greater than maxRecordBookNumber"); + } + if (minGroupNumber != null && maxGroupNumber != null) { + if (minGroupNumber.compareTo(maxGroupNumber) > 0) { + throw new IllegalArgumentException("minGroupNumber cannot be greater than maxGroupNumber"); + } + } + } + private String generateGroupNumber() { + String min = (minGroupNumber != null) ? minGroupNumber : "A00"; + String max = (maxGroupNumber != null) ? maxGroupNumber : "Z99"; + char minLetter = min.charAt(0); + char maxLetter = max.charAt(0); + int minDigit = Integer.parseInt(min.substring(1)); + int maxDigit = Integer.parseInt(max.substring(1)); + char letter = (char) (minLetter + RANDOM.nextInt((maxLetter - minLetter) + 1)); + int digit; + if (letter == minLetter && letter == maxLetter) { + digit = minDigit + RANDOM.nextInt((maxDigit - minDigit) + 1); + } else if (letter == minLetter) { + digit = minDigit + RANDOM.nextInt(100 - minDigit); + } else if (letter == maxLetter) { + digit = RANDOM.nextInt(maxDigit + 1); + } else { + digit = RANDOM.nextInt(100); + } + return letter + String.format("%02d", digit); + } + + private double generateAverageGrade() { + double min = (minAverageGrade != null) ? minAverageGrade : DEFAULT_MIN_GRADE; + double max = (maxAverageGrade != null) ? maxAverageGrade : DEFAULT_MAX_GRADE; + + double range = max - min; + return min + (range * RANDOM.nextDouble()); + } + private int generateRecordBookNumber() { + int min = (minRecordBookNumber != null) ? minRecordBookNumber : DEFAULT_MIN_RECORD_BOOK; + int max = (maxRecordBookNumber != null) ? maxRecordBookNumber : min + 999_999; // разумный максимум + if (max < min) { + max = min; + } + return min + RANDOM.nextInt((max - min) + 1); + } +} diff --git a/app/src/main/java/ru/project/search/StudentSearchService.java b/app/src/main/java/ru/project/search/StudentSearchService.java index 4d92689..0c7fe16 100644 --- a/app/src/main/java/ru/project/search/StudentSearchService.java +++ b/app/src/main/java/ru/project/search/StudentSearchService.java @@ -5,26 +5,26 @@ import ru.project.collection.MyLinkedList; 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/AppTest.java b/app/src/test/java/ru/project/AppTest.java deleted file mode 100644 index 44a05ef..0000000 --- a/app/src/test/java/ru/project/AppTest.java +++ /dev/null @@ -1,15 +0,0 @@ -package ru.project; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; - -/** Unit test for simple App. */ -public class AppTest { - - /** Rigorous Test :-) */ - @Test - public void shouldAnswerWithTrue() { - assertTrue(true); - } -} diff --git a/app/src/test/java/ru/project/MyListCollectorTest.java b/app/src/test/java/ru/project/MyListCollectorTest.java deleted file mode 100644 index 6155d57..0000000 --- a/app/src/test/java/ru/project/MyListCollectorTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package ru.test.maven.spring; -import org.junit.jupiter.api.Test; -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; -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 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)); - } - } - - @Test - void shouldTestHandleEmptyStream() { - MyList result = IntStream.empty() - .boxed() - .collect(MyCollectors.toMyList()); - - assertTrue(result.isEmpty()); - - } - @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)); - } - -} 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 new file mode 100644 index 0000000..3541f35 --- /dev/null +++ b/app/src/test/java/ru/project/io/StudentCsvReaderTest.java @@ -0,0 +1,118 @@ +package ru.project.io; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.NoSuchElementException; +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.*; +class StudentCsvReaderTest { + @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 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( + 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); + try (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); + + // ИСПРАВЛЕНО: добавлен 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 diff --git a/app/src/test/java/ru/project/random/RandomStudentGeneratorTest.java b/app/src/test/java/ru/project/random/RandomStudentGeneratorTest.java new file mode 100644 index 0000000..2b5a4be --- /dev/null +++ b/app/src/test/java/ru/project/random/RandomStudentGeneratorTest.java @@ -0,0 +1,157 @@ +package ru.project.random; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import ru.project.collection.MyLinkedList; +import ru.project.collection.MyList; +import ru.project.student.Student; +import java.util.regex.Pattern; +import static org.junit.jupiter.api.Assertions.*; +public class RandomStudentGeneratorTest +{ + private static final Pattern GROUP_PATTERN = Pattern.compile("^[A-Z][0-9]{2}$"); + private static final double MIN_GRADE = 0.0; + private static final double MAX_GRADE = 5.0; + @Test + void shouldTestgenerate_withoutConstraints_returnsCorrectSizeAndValidStudents() { + int size = 100; + RandomStudentGenerator generator = new RandomStudentGenerator(); + MyList students = generator.generate(size); + assertEquals(size, students.size(), "Размер списка должен совпадать с запрошенным"); + for (int i = 0; i < students.size(); i++) { + Student s = students.get(i); + assertTrue(GROUP_PATTERN.matcher(s.getGroupNumber()).matches(), + "groupNumber должен соответствовать шаблону A00–Z99"); + assertTrue(s.getAverageGrade() >= MIN_GRADE && s.getAverageGrade() <= MAX_GRADE, + "averageGrade должен быть в диапазоне [0.0, 5.0]"); + assertTrue(s.getRecordBookNumber() >= 1, + "recordBookNumber должен быть >= 1"); + } + } + @Test + void shouldTestgenerate_withGroupRange_respectsLexicographicalBounds() { + RandomStudentGenerator generator = new RandomStudentGenerator() + .setMinGroupNumber("A00") + .setMaxGroupNumber("B99"); + MyList students = generator.generate(200); + assertEquals(200, students.size()); + for (int i = 0; i < students.size(); i++) { + Student s = students.get(i); + String g = s.getGroupNumber(); + assertTrue(g.compareTo("A00") >= 0, "Группа не должна быть меньше A00"); + assertTrue(g.compareTo("B99") <= 0, "Группа не должна быть больше B99"); + assertTrue(GROUP_PATTERN.matcher(g).matches(), "Группа должна соответствовать шаблону"); + } + } + @Test + void shouldTestgenerate_withGradeRange_respectsBounds() { + double minGrade = 3.0; + double maxGrade = 4.0; + + RandomStudentGenerator generator = new RandomStudentGenerator() + .setMinAverageGrade(minGrade) + .setMaxAverageGrade(maxGrade); + MyList students = generator.generate(100); + + for (int i = 0; i < students.size(); i++) { + Student s = students.get(i); + double g = s.getAverageGrade(); + assertTrue(g >= minGrade && g <= maxGrade, + "averageGrade должен быть в заданном диапазоне"); + } + } + @Test + void shouldTestgenerate_withRecordBookRange_respectsBounds() { + int minRec = 10_000; + int maxRec = 20_000; + + RandomStudentGenerator generator = new RandomStudentGenerator() + .setMinRecordBookNumber(minRec) + .setMaxRecordBookNumber(maxRec); + MyList students = generator.generate(100); + + for (int i = 0; i < students.size(); i++) { + Student s = students.get(i); + int r = s.getRecordBookNumber(); + assertTrue(r >= minRec && r <= maxRec, + "recordBookNumber должен быть в заданном диапазоне"); + } + } + + @Test + void shouldTestgenerate_negativeSize_throwsException() { + RandomStudentGenerator generator = new RandomStudentGenerator(); + assertThrows(IllegalArgumentException.class, () -> generator.generate(-1)); + } + @Test + void shouldTestsetMinGroupNumber_invalidPattern_throwsException() { + RandomStudentGenerator generator = new RandomStudentGenerator(); + assertThrows(IllegalArgumentException.class, + () -> generator.setMinGroupNumber("invalid")); + } + @Test + void shouldTestsetMaxGroupNumber_invalidPattern_throwsException() { + RandomStudentGenerator generator = new RandomStudentGenerator(); + assertThrows(IllegalArgumentException.class, + () -> generator.setMaxGroupNumber("ZZ")); // не 2 цифры + } + @Test + void shouldTestsetMinMaxGroupNumber_minGreaterThanMax_throwsException() { + RandomStudentGenerator generator = new RandomStudentGenerator(); + assertThrows(IllegalArgumentException.class, + () -> generator.setMinGroupNumber("C00").setMaxGroupNumber("A99").generate(1)); + } + @Test + void shouldTestsetMinAverageGrade_outOfRange_throwsException() { + RandomStudentGenerator generator = new RandomStudentGenerator(); + assertThrows(IllegalArgumentException.class, + () -> generator.setMinAverageGrade(-0.1)); + assertThrows(IllegalArgumentException.class, + () -> generator.setMinAverageGrade(5.1)); + } + @Test + void shouldTestsetMaxAverageGrade_outOfRange_throwsException() { + RandomStudentGenerator generator = new RandomStudentGenerator(); + assertThrows(IllegalArgumentException.class, + () -> generator.setMaxAverageGrade(-0.1)); + assertThrows(IllegalArgumentException.class, + () -> generator.setMaxAverageGrade(5.1)); + } + @Test + void shouldTestsetMinMaxAverageGrade_minGreaterThanMax_throwsException() { + RandomStudentGenerator generator = new RandomStudentGenerator(); + assertThrows(IllegalArgumentException.class, + () -> generator.setMinAverageGrade(4.0).setMaxAverageGrade(3.0).generate(1)); + } + @Test + void shouldTestsetMinRecordBookNumber_lessThanAllowed_throwsException() { + RandomStudentGenerator generator = new RandomStudentGenerator(); + assertThrows(IllegalArgumentException.class, + () -> generator.setMinRecordBookNumber(0)); + } + @Test + void shouldTestsetMinMaxRecordBookNumber_minGreaterThanMax_throwsException() { + RandomStudentGenerator generator = new RandomStudentGenerator(); + assertThrows(IllegalArgumentException.class, + () -> generator.setMinRecordBookNumber(20_000).setMaxRecordBookNumber(10_000).generate(1)); + } + @Test + void shouldTestchainedBuilderStyle_worksAsExpected() { + RandomStudentGenerator generator = new RandomStudentGenerator() + .setMinGroupNumber("A00") + .setMaxGroupNumber("Z99") + .setMinAverageGrade(2.0) + .setMaxAverageGrade(4.0) + .setMinRecordBookNumber(1_000) + .setMaxRecordBookNumber(9_999); + MyList students = generator.generate(50); + assertEquals(50, students.size()); + for (int i = 0; i < students.size(); i++) { + Student s = students.get(i); + assertTrue(s.getGroupNumber().compareTo("A00") >= 0 + && s.getGroupNumber().compareTo("Z99") <= 0); + assertTrue(s.getAverageGrade() >= 2.0 && s.getAverageGrade() <= 4.0); + assertTrue(s.getRecordBookNumber() >= 1_000 && s.getRecordBookNumber() <= 9_999); + } + } +} diff --git a/app/src/test/java/ru/project/search/StudentSearchTest.java b/app/src/test/java/ru/project/search/StudentSearchTest.java index e76e122..9ef14ef 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 static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.Test; import ru.project.collection.MyList; import ru.project.collection.MyLinkedList; import ru.project.student.Student; -import static org.junit.jupiter.api.Assertions.*; - 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()); + } +}