Merge branch 'develop' into feature/csv-student-io

This commit is contained in:
t1-f
2026-09-01 18:17:02 +03:00
committed by GitHub
18 changed files with 1266 additions and 905 deletions
+6
View File
@@ -42,6 +42,12 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.14.1</version>
</dependency>
<dependency>
<groupId>com.googlecode.lanterna</groupId>
<artifactId>lanterna</artifactId>
-45
View File
@@ -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();
}
}
}
}
}
@@ -1,10 +0,0 @@
package ru.test.maven.spring;
import java.util.stream.Collector;
public class MyCollectors
{
private MyCollectors() {
}
public static <T> Collector<T, MyList<T>, MyList<T>> toMyList() {
return new MyListCollector<>();
}
}
@@ -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 <T> implements Collector<T, MyList<T>, MyList<T>>
{
@Override
public Supplier<MyList<T>> supplier()
{
return () -> new MyLinkedList<>();
}
@Override
public BiConsumer<MyList<T>, T> accumulator() {
return (list, element) -> list.add(element);
}
@Override
public BinaryOperator<MyList<T>> combiner() {
return (list1, list2) -> {
for (int i = 0; i < list2.size(); i++) {
list1.add(list2.get(i));
}
return list1;
};
}
@Override
public Function<MyList<T>, MyList<T>> finisher()
{
return list -> list;
}
@Override
public Set<Collector.Characteristics> characteristics() {
return java.util.Set.of(
Collector.Characteristics.IDENTITY_FINISH
);
}
}
@@ -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 <T> Collector<T, MyList<T>, MyList<T>> toMyList()
{
return new MyListCollector<>();
}
public static <T> Collector<T, MyList<T>, MyList<T>> toMyList() {
return new MyListCollector<>();
}
}
@@ -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 <T> implements Collector<T, MyList<T>, MyList<T>>
{
@Override
public Supplier<MyList<T>> supplier()
{
return () -> new MyLinkedList<>();
}
import ru.project.collection.MyLinkedList;
import ru.project.collection.MyList;
@Override
public BiConsumer<MyList<T>, T> accumulator() {
public class MyListCollector<T> implements Collector<T, MyList<T>, MyList<T>> {
@Override
public Supplier<MyList<T>> supplier() {
return () -> new MyLinkedList<>();
}
return (list, element) -> list.add(element);
}
@Override
public BiConsumer<MyList<T>, T> accumulator() {
@Override
public BinaryOperator<MyList<T>> combiner() {
return (list1, list2) -> {
list1.addAll(list2);
return list1;
};
}
return (list, element) -> list.add(element);
}
@Override
public Function<MyList<T>, MyList<T>> finisher()
{
return list -> list;
}
@Override
public BinaryOperator<MyList<T>> combiner() {
return (list1, list2) -> {
list1.addAll(list2);
return list1;
};
}
@Override
public Set<Collector.Characteristics> characteristics() {
return java.util.Set.of(
Collector.Characteristics.IDENTITY_FINISH
);
}
@Override
public Function<MyList<T>, MyList<T>> finisher() {
return list -> list;
}
@Override
public Set<Collector.Characteristics> characteristics() {
return java.util.Set.of(Collector.Characteristics.IDENTITY_FINISH);
}
}
@@ -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<Student> 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<Future<MyList<Integer>>> futures = new MyLinkedList<>();
public class StudentOccurrenceIndexFinder {
public int[] findOccurrences(MyList<Student> 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<Future<MyList<Integer>>> 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<MyList<Integer>> future = executor.submit(() -> {
final int start = fromIndex;
final int end = toIndex;
Future<MyList<Integer>> future =
executor.submit(
() -> {
return findInRange(students, target, start, end);
});
futures.add(future);
});
futures.add(future);
}
MyList<Integer> allIndices = new MyLinkedList<>();
try {
for (int i = 0; i < futures.size(); i++) {
Future<MyList<Integer>> future = futures.get(i);
MyList<Integer> partialResult = future.get();
if (partialResult != null) {
for (int j = 0; j < partialResult.size(); j++) {
allIndices.add(partialResult.get(j));
}
}
MyList<Integer> allIndices = new MyLinkedList<>();
try {
for (int i = 0; i < futures.size(); i++) {
Future<MyList<Integer>> future = futures.get(i);
MyList<Integer> 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<Integer> list) {
if (list.size() <= 1) return;
sortList(allIndices);
MyList<Integer> 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<Integer> 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<Integer> list) {
if (list.size() <= 1) return;
private MyList<Integer> findInRange(MyList<Student> students, Student target, int fromIndex, int toIndex) {
MyList<Integer> foundIndices = new MyLinkedList<>();
MyList<Integer> 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<Integer> 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<Integer> findInRange(
MyList<Student> students, Student target, int fromIndex, int toIndex) {
MyList<Integer> 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;
}
}
@@ -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<Student>, 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<CSVRecord> records;
private int lineOfFile=0;
public StudentCsvReader(Path path) {
if (!path.isAbsolute()) {
throw new IllegalArgumentException("File path must be absolute");
}
try {
CSVFormat format = CSVFormat.DEFAULT.builder()
.setHeader()
.setSkipHeaderRecord(true)
.get();
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<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");
}
}
}
@@ -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<Student> generate(int size) {
if (size < 0) {
throw new IllegalArgumentException("size must be non-negative");
}
validateRanges();
MyList<Student> 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);
}
}
@@ -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<Student> find(MyList<Student> students) {
if (students == null) {
return new MyLinkedList<>();
}
MyList<Student> 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<Student> find(MyList<Student> students) {
if (students == null) {
return new MyLinkedList<>();
}
}
MyList<Student> 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;
}
}
-15
View File
@@ -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);
}
}
@@ -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<Integer> collector = new MyListCollector<>();
@Test
void shouldTestCollectInOrderSequential() {
MyList<Integer> 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<Integer> 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<Integer> result = IntStream.empty()
.boxed()
.collect(MyCollectors.toMyList());
assertTrue(result.isEmpty());
}
@Test
void shouldTestNotUseStandardList() {
MyList<String> 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<Collector.Characteristics> characteristics = collector.characteristics();
assertTrue(characteristics.contains(java.util.stream.Collector.Characteristics.IDENTITY_FINISH));
assertFalse(characteristics.contains(java.util.stream.Collector.Characteristics.UNORDERED));
}
}
@@ -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<Integer> 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<Integer> list = new MyLinkedList<>();
list.add(10);
assertEquals(10, list.get(0));
}
@Test
public void shouldTestRemove() {
MyLinkedList<Integer> 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<String> list = new MyLinkedList<>();
list.add("A");
list.add("B");
list.add("C");
public class MyLinkedListTest {
@Test
public void shouldTestAdd() {
MyLinkedList<Integer> 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<Integer> list = new MyLinkedList<>();
list.add(10);
assertEquals(10, list.get(0));
}
}
@Test
void shouldTestSize()
{
MyLinkedList<Integer> list = new MyLinkedList<>();
list.add(1);
list.add(2);
list.add(3);
assertEquals(3, list.size());
}
@Test
void shouldTestisEmpty()
{
MyLinkedList<Integer> list = new MyLinkedList<>();
assertTrue(list.isEmpty());
}
@Test
void shouldTestGet_OutOfBounds_ThrowsException() {
MyLinkedList<Integer> list = new MyLinkedList<>();
list.add(1);
@Test
public void shouldTestRemove() {
MyLinkedList<Integer> 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<Integer> 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<String> list = new MyLinkedList<>();
list.add("man");
assertThrows(IndexOutOfBoundsException.class, () -> list.remove(5));
}
@Test
void shouldTestRemove_NegativeIndex_ThrowsException() {
MyLinkedList<String> list = new MyLinkedList<>();
list.add("1");
list.add("2");
@Test
void shouldTestSet() {
MyLinkedList<String> 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<String> list = new MyLinkedList<>();
MyList<String> 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<Integer> list = new MyLinkedList<>();
list.add(1);
list.add(2);
list.add(3);
assertEquals(3, list.size());
}
@Test
void shouldTestaddAll_toNonEmptyList_appendsAtEnd() {
MyList<String> list = new MyLinkedList<>();
list.add("X");
list.add("Y");
@Test
void shouldTestisEmpty() {
MyLinkedList<Integer> list = new MyLinkedList<>();
assertTrue(list.isEmpty());
}
MyList<String> source = new MyLinkedList<>();
source.add("A");
source.add("B");
@Test
void shouldTestGet_OutOfBounds_ThrowsException() {
MyLinkedList<Integer> 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<Integer> 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<String> list = new MyLinkedList<>();
list.add("man");
assertThrows(IndexOutOfBoundsException.class, () -> list.remove(5));
}
@Test
void shouldTestRemove_NegativeIndex_ThrowsException() {
MyLinkedList<String> list = new MyLinkedList<>();
list.add("1");
list.add("2");
assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1));
}
@Test
void shouldTestaddAll_nonEmptySource_toEmptyList_addsAllElementsInOrder() {
MyList<String> list = new MyLinkedList<>();
MyList<String> 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<String> list = new MyLinkedList<>();
list.add("X");
list.add("Y");
MyList<String> 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));
}
}
@@ -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<Integer> collector = new MyListCollector<>();
public class MyListCollectorTest {
private final MyListCollector<Integer> collector = new MyListCollector<>();
@Test
void shouldTestCollectInOrderSequential() {
MyList<Integer> 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<Integer> 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<Integer> result = IntStream.range(0, 100)
.parallel()
.boxed()
.collect(MyCollectors.toMyList());
@Test
void shouldTestCollectInOrderParallel() {
MyList<Integer> 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<Integer> result = IntStream.empty()
.boxed()
.collect(MyCollectors.toMyList());
@Test
void shouldTestHandleEmptyStream() {
MyList<Integer> result = IntStream.empty().boxed().collect(MyCollectors.toMyList());
assertTrue(result.isEmpty());
assertTrue(result.isEmpty());
}
}
@Test
void shouldTestNotUseStandardList() {
MyList<String> result = IntStream.range(0, 5)
.mapToObj(i -> "item" + i)
.collect(MyCollectors.toMyList());
@Test
void shouldTestNotUseStandardList() {
MyList<String> 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<Collector.Characteristics> 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<Collector.Characteristics> characteristics = collector.characteristics();
assertTrue(
characteristics.contains(java.util.stream.Collector.Characteristics.IDENTITY_FINISH));
assertFalse(characteristics.contains(java.util.stream.Collector.Characteristics.UNORDERED));
}
}
@@ -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<Student> 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<Student> 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], "Результат должен быть отсортирован");
}
}
}
@@ -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<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(
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"));
}
}
@@ -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<Student> 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<Student> 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<Student> 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<Student> 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<Student> 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);
}
}
}
@@ -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<Student> 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<Student> result = service.find(students);
assertEquals(2, result.size());
assertEquals("A10", result.get(0).getGroupNumber());
assertEquals("C30", result.get(1).getGroupNumber());
}
@Test
void testSearchServiceEmptyResult() {
MyList<Student> 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<Student> result = service.find(students);
assertEquals(0, result.size());
}
@Test
void testSearchServiceEmptyCollection() {
MyList<Student> students = new MyLinkedList<>();
StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0);
StudentSearchService service = new StudentSearchService(criteria);
MyList<Student> result = service.find(students);
assertEquals(0, result.size());
}
@Test
void testSearchServicePreservesOrder() {
MyList<Student> 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<Student> 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<Student> original = new MyLinkedList<>();
original.add(new Student("A10", 4.5, 1));
original.add(new Student("B20", 3.8, 2));
MyList<Student> 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<Student> 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<Student> 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<Student> 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<Student> result = service.find(students);
assertEquals(2, result.size());
assertEquals("A10", result.get(0).getGroupNumber());
assertEquals("C30", result.get(1).getGroupNumber());
}
@Test
void testSearchServiceEmptyResult() {
MyList<Student> 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<Student> result = service.find(students);
assertEquals(0, result.size());
}
@Test
void testSearchServiceEmptyCollection() {
MyList<Student> students = new MyLinkedList<>();
StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0);
StudentSearchService service = new StudentSearchService(criteria);
MyList<Student> result = service.find(students);
assertEquals(0, result.size());
}
@Test
void testSearchServicePreservesOrder() {
MyList<Student> 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<Student> 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<Student> original = new MyLinkedList<>();
original.add(new Student("A10", 4.5, 1));
original.add(new Student("B20", 3.8, 2));
MyList<Student> 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<Student> 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<Student> 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<Student> result = service.find(null);
assertNotNull(result);
assertEquals(0, result.size());
}
}
@Test
void testSearchServiceWithNullStudentListReturnsEmpty() {
StudentSearchCriteria criteria = new AverageGradeRangeCriteria(4.0, 5.0);
StudentSearchService service = new StudentSearchService(criteria);
MyList<Student> result = service.find(null);
assertNotNull(result);
assertEquals(0, result.size());
}
}