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/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); + } + } +}