#5 8 9 10 12 13 17 - готовы. #15 - тест

This commit is contained in:
Zuev
2026-07-27 02:23:26 +03:00
parent 3e8722a26b
commit a78a93f2f0
21 changed files with 413 additions and 102 deletions

View File

@@ -7,6 +7,7 @@ import com.magistr.app.repository.*;
import com.magistr.app.service.AcademicCalendarGridService;
import com.magistr.app.service.AcademicStructureService;
import com.magistr.app.service.ScheduleGeneratorService;
import com.magistr.app.utils.AcademicCalendarTitleBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
@@ -152,9 +153,6 @@ public class AcademicCalendarController {
if (request == null) {
throw new IllegalArgumentException("Передайте данные календарного графика");
}
if (request.title() == null || request.title().isBlank()) {
throw new IllegalArgumentException("Название графика обязательно");
}
if (request.courseCount() == null || request.courseCount() <= 0) {
throw new IllegalArgumentException("Количество курсов должно быть больше нуля");
}
@@ -178,7 +176,7 @@ public class AcademicCalendarController {
EducationForm studyForm = educationFormRepository.findById(request.studyFormId())
.orElseThrow(() -> new IllegalArgumentException("Форма обучения не найдена"));
calendar.setTitle(request.title().trim());
calendar.setTitle(AcademicCalendarTitleBuilder.build(year, speciality, profile, studyForm));
calendar.setAcademicYear(year);
calendar.setSpeciality(speciality);
calendar.setSpecialtyProfile(profile);

View File

@@ -20,6 +20,7 @@ import com.magistr.app.repository.SpecialtiesRepository;
import com.magistr.app.repository.SpecialtyProfileRepository;
import com.magistr.app.repository.StudentGroupCalendarAssignmentRepository;
import com.magistr.app.repository.SubgroupRepository;
import com.magistr.app.utils.AcademicCalendarTitleBuilder;
import com.magistr.app.utils.CourseAndSemesterCalculator;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
@@ -126,7 +127,12 @@ public class AcademicStructureService {
);
}
calendar.setTitle(request.title().trim());
calendar.setTitle(AcademicCalendarTitleBuilder.build(
candidate.academicYear(),
candidate.speciality(),
candidate.profile(),
candidate.studyForm()
));
applyCalendarDimensions(calendar, candidate, request.courseCount());
AcademicCalendar saved = saveCalendar(calendar);
clearScheduleCacheAfterCommit();
@@ -208,9 +214,6 @@ public class AcademicStructureService {
if (request == null) {
throw new IllegalArgumentException("Передайте данные календарного графика");
}
if (request.title() == null || request.title().isBlank()) {
throw new IllegalArgumentException("Название графика обязательно");
}
if (request.courseCount() == null || request.courseCount() <= 0) {
throw new IllegalArgumentException("Количество курсов должно быть больше нуля");
}

View File

@@ -0,0 +1,38 @@
package com.magistr.app.utils;
import com.magistr.app.model.AcademicYear;
import com.magistr.app.model.EducationForm;
import com.magistr.app.model.Speciality;
import com.magistr.app.model.SpecialtyProfile;
import java.util.List;
public final class AcademicCalendarTitleBuilder {
private static final String SEPARATOR = "";
private AcademicCalendarTitleBuilder() {
}
public static String build(AcademicYear academicYear,
Speciality speciality,
SpecialtyProfile profile,
EducationForm studyForm) {
List<String> parts = List.of(
normalize(speciality == null ? null : speciality.getSpecialityCode()),
normalize(profile == null ? null : profile.getName()),
normalize(studyForm == null ? null : studyForm.getName()),
normalize(academicYear == null ? null : academicYear.getTitle())
);
if (parts.stream().anyMatch(String::isBlank)) {
throw new IllegalArgumentException(
"Невозможно сформировать название календарного графика из выбранных параметров"
);
}
return String.join(SEPARATOR, parts);
}
private static String normalize(String value) {
return value == null ? "" : value.trim();
}
}

View File

@@ -0,0 +1,98 @@
package com.magistr.app.controller;
import com.magistr.app.dto.AcademicCalendarDto;
import com.magistr.app.model.AcademicCalendar;
import com.magistr.app.model.AcademicYear;
import com.magistr.app.model.EducationForm;
import com.magistr.app.model.Speciality;
import com.magistr.app.model.SpecialtyProfile;
import com.magistr.app.repository.AcademicCalendarDayRepository;
import com.magistr.app.repository.AcademicCalendarRepository;
import com.magistr.app.repository.AcademicCalendarSubjectRepository;
import com.magistr.app.repository.AcademicYearRepository;
import com.magistr.app.repository.EducationFormRepository;
import com.magistr.app.repository.SpecialtiesRepository;
import com.magistr.app.repository.SpecialtyProfileRepository;
import com.magistr.app.repository.SubjectRepository;
import com.magistr.app.service.AcademicCalendarGridService;
import com.magistr.app.service.AcademicStructureService;
import com.magistr.app.service.ScheduleGeneratorService;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class AcademicCalendarControllerTest {
@Test
void createCalendarBuildsTitleWithoutClientValue() {
AcademicCalendarRepository calendarRepository = mock(AcademicCalendarRepository.class);
AcademicYearRepository academicYearRepository = mock(AcademicYearRepository.class);
SpecialtiesRepository specialtiesRepository = mock(SpecialtiesRepository.class);
SpecialtyProfileRepository profileRepository = mock(SpecialtyProfileRepository.class);
EducationFormRepository educationFormRepository = mock(EducationFormRepository.class);
AcademicYear year = new AcademicYear();
year.setId(1L);
year.setTitle("2026-2027");
year.setStartDate(LocalDate.of(2026, 9, 1));
year.setEndDate(LocalDate.of(2027, 6, 30));
Speciality speciality = new Speciality(2L, "Программная инженерия", "09.03.04");
SpecialtyProfile profile = new SpecialtyProfile();
profile.setId(3L);
profile.setSpeciality(speciality);
profile.setName("Разработка ПО");
EducationForm studyForm = new EducationForm();
studyForm.setId(4L);
studyForm.setName("Очная");
when(academicYearRepository.findById(1L)).thenReturn(Optional.of(year));
when(specialtiesRepository.findById(2L)).thenReturn(Optional.of(speciality));
when(profileRepository.findById(3L)).thenReturn(Optional.of(profile));
when(educationFormRepository.findById(4L)).thenReturn(Optional.of(studyForm));
when(calendarRepository.save(any(AcademicCalendar.class)))
.thenAnswer(invocation -> invocation.getArgument(0));
AcademicCalendarController controller = new AcademicCalendarController(
calendarRepository,
mock(AcademicCalendarDayRepository.class),
academicYearRepository,
specialtiesRepository,
profileRepository,
educationFormRepository,
mock(SubjectRepository.class),
mock(AcademicCalendarSubjectRepository.class),
mock(AcademicCalendarGridService.class),
mock(ScheduleGeneratorService.class),
mock(AcademicStructureService.class)
);
AcademicCalendarDto request = new AcademicCalendarDto(
null,
null,
1L,
null,
null,
null,
2L,
null,
null,
3L,
null,
4L,
null,
4
);
var response = controller.createCalendar(request);
assertThat(response.getStatusCode().value()).isEqualTo(200);
assertThat(response.getBody()).isInstanceOf(AcademicCalendarDto.class);
assertThat(((AcademicCalendarDto) response.getBody()).title())
.isEqualTo("09.03.04 — Разработка ПО — Очная — 2026-2027");
}
}

View File

@@ -168,6 +168,18 @@ class AcademicStructureServiceTest {
.hasMessage("Нельзя уменьшить количество курсов: есть дисциплины старших семестров");
}
@Test
void buildsCalendarTitleFromDimensionsInsteadOfRequestField() {
AcademicCalendar saved = service.updateCalendar(
CALENDAR_ID,
calendarRequest(4, FORM_ID)
);
assertThat(saved.getTitle())
.isEqualTo("09.03.01 — Без профиля — Бакалавриат — 2025-2026");
verify(calendarRepository).saveAndFlush(calendar);
}
@Test
void rejectsGroupDimensionChangeAndKeepsAssignment() {
when(assignmentRepository.findByGroupIdWithDetails(GROUP_ID))
@@ -280,7 +292,7 @@ class AcademicStructureServiceTest {
private AcademicCalendarDto calendarRequest(int courseCount, long studyFormId) {
return new AcademicCalendarDto(
CALENDAR_ID,
"График 2026",
null,
YEAR_ID,
null,
null,

View File

@@ -0,0 +1,40 @@
package com.magistr.app.utils;
import com.magistr.app.model.AcademicYear;
import com.magistr.app.model.EducationForm;
import com.magistr.app.model.Speciality;
import com.magistr.app.model.SpecialtyProfile;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class AcademicCalendarTitleBuilderTest {
@Test
void buildsTitleFromCalendarDimensions() {
AcademicYear year = new AcademicYear();
year.setTitle(" 2026-2027 ");
Speciality speciality = new Speciality();
speciality.setSpecialityCode(" 09.03.04 ");
SpecialtyProfile profile = new SpecialtyProfile();
profile.setName(" Программная инженерия ");
EducationForm studyForm = new EducationForm();
studyForm.setName(" Очная ");
assertThat(AcademicCalendarTitleBuilder.build(year, speciality, profile, studyForm))
.isEqualTo("09.03.04 — Программная инженерия — Очная — 2026-2027");
}
@Test
void rejectsIncompleteDimensions() {
assertThatThrownBy(() -> AcademicCalendarTitleBuilder.build(
new AcademicYear(),
new Speciality(),
new SpecialtyProfile(),
new EducationForm()
))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Невозможно сформировать название календарного графика из выбранных параметров");
}
}