package com.sztzjy.linkCommerce.service.impl; import com.sztzjy.linkCommerce.config.security.JwtUser; import com.sztzjy.linkCommerce.entity.SchoolClass; import com.sztzjy.linkCommerce.entity.TaskAllocation; import com.sztzjy.linkCommerce.entity.TeachingClassStudent; import com.sztzjy.linkCommerce.entity.TrainingTask; import com.sztzjy.linkCommerce.entity.TrainingTaskClassConfig; import com.sztzjy.linkCommerce.entity.importDto.TrainingTaskImportDTO; import com.sztzjy.linkCommerce.mapper.SchoolClassMapper; import com.sztzjy.linkCommerce.mapper.TaskAllocationMapper; import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper; import com.sztzjy.linkCommerce.mapper.TrainingTaskClassConfigMapper; import com.sztzjy.linkCommerce.mapper.TrainingTaskMapper; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.springframework.jdbc.core.JdbcTemplate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.startsWith; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; class TrainingTaskServiceImplTest { @Test void splitListSupportsCommonSeparators() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); List result = service.splitList("one;two|three"); assertEquals(3, result.size()); assertEquals("one", result.get(0)); assertEquals("three", result.get(2)); } @Test void importTaskValidatesRequiredFields() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); TrainingTaskImportDTO row = new TrainingTaskImportDTO(); row.setTaskName("Teacher Title"); List errors = new ArrayList<>(); TrainingTask task = service.buildTask(row, 2, errors); assertEquals(null, task); assertFalse(errors.isEmpty()); } @Test void importTaskAllowsTeacherEditedTaskNameForBuiltInTask() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); TrainingTaskImportDTO row = new TrainingTaskImportDTO(); row.setProjectName("Foundation"); row.setTaskKey("new-product-survey"); row.setTaskName("Teacher Edited Survey"); row.setSteps("s1;s2"); List errors = new ArrayList<>(); TrainingTask task = service.buildTask(row, 2, errors); assertEquals(0, errors.size()); assertEquals("Teacher Edited Survey", task.getTaskName()); assertTrue(task.getSteps().contains("\"name\":\"s1\"")); assertTrue(task.getSteps().contains("\"name\":\"s2\"")); assertFalse(task.getSteps().contains("Step 3")); } @Test void importTaskRejectsUnknownTaskKeyBecauseTaskCountIsFixed() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); TrainingTaskImportDTO row = new TrainingTaskImportDTO(); row.setProjectName("Custom"); row.setTaskKey("custom-task"); row.setTaskName("Custom Task"); List errors = new ArrayList<>(); TrainingTask task = service.buildTask(row, 2, errors); assertEquals(null, task); assertFalse(errors.isEmpty()); } @Test void updateTaskPersistsTeacherEditedTaskNameAndActualStepCount() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); TrainingTask stored = storedTask("task-1", "new-product-survey"); when(service.trainingTaskMapper.selectByPrimaryKey("task-1")).thenReturn(stored); TrainingTask payload = new TrainingTask(); payload.setProjectName("Changed Project Should Be Ignored"); payload.setTaskKey("unknown-key-should-be-ignored"); payload.setTaskName("Teacher Edited Survey"); payload.setSteps("[\"Only One\"]"); service.update("task-1", payload); ArgumentCaptor captor = ArgumentCaptor.forClass(TrainingTask.class); verify(service.trainingTaskMapper).updateByPrimaryKeySelective(captor.capture()); assertEquals("new-product-survey", captor.getValue().getTaskKey()); assertEquals("Foundation", captor.getValue().getProjectName()); assertEquals("Teacher Edited Survey", captor.getValue().getTaskName()); assertTrue(captor.getValue().getSteps().contains("\"name\":\"Only One\"")); assertFalse(captor.getValue().getSteps().contains("Step 2")); } @Test void updateTaskPreservesStepsBeyondTheBuiltInCount() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); TrainingTask stored = storedTask("task-1", "new-product-survey"); when(service.trainingTaskMapper.selectByPrimaryKey("task-1")).thenReturn(stored); TrainingTask payload = new TrainingTask(); payload.setProjectName("Foundation"); payload.setTaskKey("new-product-survey"); payload.setTaskName("Teacher Edited Survey"); payload.setSteps("[\"Step 1\",\"Step 2\",\"Step 3\",\"Step 4\",\"Custom Step\"]"); service.update("task-1", payload); ArgumentCaptor captor = ArgumentCaptor.forClass(TrainingTask.class); verify(service.trainingTaskMapper).updateByPrimaryKeySelective(captor.capture()); assertTrue(captor.getValue().getSteps().contains("Custom Step")); } @Test void createRejectsUnknownTaskKeyBecauseTaskCountIsFixed() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); TrainingTask task = new TrainingTask(); task.setProjectName("Custom"); task.setTaskKey("custom-task"); task.setTaskName("Custom Task"); assertThrows(IllegalArgumentException.class, () -> service.create(task, "teacher-1")); } @Test void deleteRejectsBuiltInTaskBecauseTaskCountIsFixed() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); assertThrows(IllegalArgumentException.class, () -> service.delete("task-1")); } @Test void importTaskUpdatesExistingTaskByTaskKey() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); TrainingTask existing = storedTask("task-1", "new-product-survey"); when(service.trainingTaskMapper.selectByTaskKey("new-product-survey")).thenReturn(existing); when(service.trainingTaskMapper.selectByPrimaryKey("task-1")).thenReturn(existing); TrainingTaskImportDTO row = new TrainingTaskImportDTO(); row.setProjectName("Foundation"); row.setTaskKey("new-product-survey"); row.setTaskName("Teacher Edited Survey"); row.setObjectives("goal1;goal2"); row.setSteps("s1;s2;s3;s4;s5"); row.setEnabled("true"); List errors = new ArrayList<>(); int count = service.importTasks(Collections.singletonList(row), "teacher-1", errors); assertEquals(1, count); assertEquals(0, errors.size()); ArgumentCaptor captor = ArgumentCaptor.forClass(TrainingTask.class); verify(service.trainingTaskMapper).updateByPrimaryKeySelective(captor.capture()); assertEquals("task-1", captor.getValue().getId()); assertEquals("Teacher Edited Survey", captor.getValue().getTaskName()); assertTrue(captor.getValue().getSteps().contains("\"name\":\"s5\"")); assertTrue(captor.getValue().getSteps().contains("\"id\":\"custom-5\"")); } @Test void importTaskRejectsMissingBuiltInRecordRatherThanCreatingNewTask() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); when(service.trainingTaskMapper.selectByTaskKey("new-product-survey")).thenReturn(null); TrainingTaskImportDTO row = new TrainingTaskImportDTO(); row.setProjectName("Foundation"); row.setTaskKey("new-product-survey"); row.setTaskName("Teacher Edited Survey"); row.setObjectives("goal1;goal2"); row.setSteps("s1;s2;s3;s4"); row.setEnabled("true"); List errors = new ArrayList<>(); int count = service.importTasks(Collections.singletonList(row), "teacher-1", errors); assertEquals(0, count); assertFalse(errors.isEmpty()); verify(service.trainingTaskMapper, never()).insertSelective(any()); } @Test void ensureDefaultTasksBackfillsMissingBuiltInTasksWhenTableAlreadyHasData() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); TrainingTask existing = storedTask("task-1", "new-product-survey"); when(service.trainingTaskMapper.selectByTaskKey("new-product-survey")).thenReturn(existing); service.ensureDefaultTasks("system"); ArgumentCaptor captor = ArgumentCaptor.forClass(TrainingTask.class); verify(service.trainingTaskMapper, times(23)).insertSelective(captor.capture()); assertFalse(captor.getAllValues().stream().anyMatch(task -> "new-product-survey".equals(task.getTaskKey()))); TrainingTask comprehensive = captor.getAllValues().get(captor.getAllValues().size() - 1); assertEquals("comprehensive-case-training", comprehensive.getTaskKey()); assertEquals("综合实训", comprehensive.getProjectName()); assertEquals("综合案例实训", comprehensive.getTaskName()); } @Test void ensureDefaultTasksCreatesTrainingTaskTableBeforeQuerying() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.jdbcTemplate = mock(JdbcTemplate.class); service.ensureDefaultTasks("system"); verify(service.jdbcTemplate).execute(startsWith("CREATE TABLE IF NOT EXISTS training_task (")); verify(service.jdbcTemplate).execute("ALTER TABLE training_task CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); } @Test void ensureDefaultTasksCreatesClassConfigTableBeforeClassScopedQueries() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.jdbcTemplate = mock(JdbcTemplate.class); service.ensureDefaultTasks("system"); verify(service.jdbcTemplate).execute(startsWith("CREATE TABLE IF NOT EXISTS training_task_class_config")); } @Test void listDoesNotFilterDisabledTasksWhenEnabledOnlyIsFalse() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); when(service.trainingTaskMapper.selectByTaskKey(any())).thenReturn(new TrainingTask()); TrainingTask disabledTask = new TrainingTask(); disabledTask.setEnabled(Boolean.FALSE); when(service.trainingTaskMapper.selectList(isNull(), isNull(), isNull())) .thenReturn(Collections.singletonList(disabledTask)); List result = service.list(null, null, false); assertEquals(1, result.size()); assertFalse(result.get(0).getEnabled()); verify(service.trainingTaskMapper, times(2)).selectList(isNull(), isNull(), isNull()); } @Test void studentTaskUsesClassOverrideBeforeDefault() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class); TeachingClassStudent membership = new TeachingClassStudent(); membership.setTeachingClassId("class-1"); when(service.teachingClassStudentMapper.selectActiveByStudentUserId("stu-1")).thenReturn(membership); TrainingTask defaultTask = storedTask("task-1", "new-product-survey"); defaultTask.setTaskName("Default Name"); defaultTask.setKnowledge("Default Knowledge"); when(service.trainingTaskMapper.selectByTaskKey("new-product-survey")).thenReturn(defaultTask); TrainingTaskClassConfig override = overrideTask("config-1", "class-1", "new-product-survey"); override.setTaskName("Class Name"); override.setKnowledge("Class Knowledge"); override.setEnabled(Boolean.TRUE); when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "new-product-survey")).thenReturn(override); TrainingTask result = service.getStudentTaskByTaskKey("new-product-survey", "stu-1"); assertEquals("Class Name", result.getTaskName()); assertEquals("Class Knowledge", result.getKnowledge()); } @Test void studentTaskFallsBackToDefaultWhenClassHasNoOverride() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class); TeachingClassStudent membership = new TeachingClassStudent(); membership.setTeachingClassId("class-1"); when(service.teachingClassStudentMapper.selectActiveByStudentUserId("stu-1")).thenReturn(membership); TrainingTask defaultTask = storedTask("task-1", "new-product-survey"); defaultTask.setTaskName("Default Name"); when(service.trainingTaskMapper.selectByTaskKey("new-product-survey")).thenReturn(defaultTask); TrainingTask result = service.getStudentTaskByTaskKey("new-product-survey", "stu-1"); assertEquals("Default Name", result.getTaskName()); } @Test void teacherCannotEditClassCreatedByAnotherTeacher() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class); SchoolClass schoolClass = new SchoolClass(); schoolClass.setSchoolClassId("class-2"); schoolClass.setClassType("TEACHING"); schoolClass.setCreatedBy("teacher-a"); when(service.schoolClassMapper.selectByPrimaryKey("class-2")).thenReturn(schoolClass); TrainingTask task = storedTask(null, "new-product-survey"); assertThrows(IllegalArgumentException.class, () -> service.saveClassTask("class-2", "new-product-survey", task, "teacher-b")); } @Test void teacherCanReadAnotherTeachersTeachingClassInTheSameSchool() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.schoolClassMapper = mock(SchoolClassMapper.class); SchoolClass schoolClass = teachingClass("class-2", "teacher-a"); schoolClass.setSchoolId("school-1"); when(service.schoolClassMapper.selectByPrimaryKey("class-2")).thenReturn(schoolClass); JwtUser reader = new JwtUser(); reader.setUserId("teacher-b"); reader.setSchoolId("school-1"); assertEquals(schoolClass, service.requireReadableTeachingClass("class-2", reader)); } @Test void teacherCannotReadTeachingClassFromAnotherSchool() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.schoolClassMapper = mock(SchoolClassMapper.class); SchoolClass schoolClass = teachingClass("class-2", "teacher-a"); schoolClass.setSchoolId("school-1"); when(service.schoolClassMapper.selectByPrimaryKey("class-2")).thenReturn(schoolClass); JwtUser reader = new JwtUser(); reader.setUserId("teacher-b"); reader.setSchoolId("school-2"); assertThrows(IllegalArgumentException.class, () -> service.requireReadableTeachingClass("class-2", reader)); } @Test void nonOwnerSameSchoolClassTaskReadDoesNotWriteConfigurations() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class); SchoolClass schoolClass = teachingClass("class-2", "teacher-a"); schoolClass.setSchoolId("school-1"); when(service.schoolClassMapper.selectByPrimaryKey("class-2")).thenReturn(schoolClass); TrainingTask defaultTask = storedTask("task-1", "new-product-survey"); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(Collections.singletonList(defaultTask)); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-2", null)).thenReturn(Collections.emptyList()); JwtUser reader = new JwtUser(); reader.setUserId("teacher-b"); reader.setSchoolId("school-1"); List result = service.listForTeachingClass("class-2", false, reader); assertEquals(1, result.size()); verify(service.trainingTaskClassConfigMapper, never()).insertSelective(any()); verify(service.trainingTaskClassConfigMapper, never()).updateByPrimaryKeySelective(any()); verify(service.trainingTaskClassConfigMapper, never()).deleteByTeachingClass(anyString()); verify(service.trainingTaskClassConfigMapper, never()).deleteByTeachingClassAndTaskKey(anyString(), anyString()); } @Test void ownerClassTaskReadDoesNotWriteConfigurations() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class); SchoolClass schoolClass = teachingClass("class-2", "teacher-a"); schoolClass.setSchoolId("school-1"); when(service.schoolClassMapper.selectByPrimaryKey("class-2")).thenReturn(schoolClass); TrainingTask defaultTask = storedTask("task-1", "new-product-survey"); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(Collections.singletonList(defaultTask)); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-2", null)).thenReturn(Collections.emptyList()); JwtUser owner = new JwtUser(); owner.setUserId("teacher-a"); owner.setSchoolId("school-1"); List result = service.listForTeachingClass("class-2", false, owner); assertEquals(1, result.size()); verify(service.trainingTaskClassConfigMapper, never()).insertSelective(any()); verify(service.trainingTaskClassConfigMapper, never()).updateByPrimaryKeySelective(any()); verify(service.trainingTaskClassConfigMapper, never()).deleteByTeachingClass(anyString()); verify(service.trainingTaskClassConfigMapper, never()).deleteByTeachingClassAndTaskKey(anyString(), anyString()); } @Test void teacherCannotReadTeachingClassWhenSchoolIdIsMissing() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.schoolClassMapper = mock(SchoolClassMapper.class); SchoolClass schoolClass = teachingClass("class-2", "teacher-a"); when(service.schoolClassMapper.selectByPrimaryKey("class-2")).thenReturn(schoolClass); JwtUser reader = new JwtUser(); reader.setUserId("teacher-b"); assertThrows(IllegalArgumentException.class, () -> service.requireReadableTeachingClass("class-2", reader)); } @Test void teacherCannotReadTeachingClassWhenClassSchoolIdIsMissing() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.schoolClassMapper = mock(SchoolClassMapper.class); SchoolClass schoolClass = teachingClass("class-2", "teacher-a"); when(service.schoolClassMapper.selectByPrimaryKey("class-2")).thenReturn(schoolClass); JwtUser reader = new JwtUser(); reader.setUserId("teacher-b"); reader.setSchoolId("school-1"); assertThrows(IllegalArgumentException.class, () -> service.requireReadableTeachingClass("class-2", reader)); } @Test void restoreClassTaskDefaultDeletesOnlySelectedClassTaskCopy() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class); when(service.schoolClassMapper.selectByPrimaryKey("class-1")).thenReturn(teachingClass("class-1", "teacher-1")); service.restoreClassTaskDefault("class-1", "new-product-survey", "teacher-1"); verify(service.trainingTaskClassConfigMapper) .deleteByTeachingClassAndTaskKey("class-1", "new-product-survey"); verify(service.trainingTaskClassConfigMapper, never()).deleteByTeachingClass(anyString()); } @Test void restoreClassTasksDefaultsDeletesOnlySelectedClassCopies() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class); when(service.schoolClassMapper.selectByPrimaryKey("class-1")).thenReturn(teachingClass("class-1", "teacher-1")); service.restoreClassTasksDefaults("class-1", "teacher-1"); verify(service.trainingTaskClassConfigMapper).deleteByTeachingClass("class-1"); } @Test void teacherCannotRestoreAnotherTeachersClass() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class); when(service.schoolClassMapper.selectByPrimaryKey("class-2")).thenReturn(teachingClass("class-2", "teacher-a")); assertThrows(IllegalArgumentException.class, () -> service.restoreClassTasksDefaults("class-2", "teacher-b")); verifyNoInteractions(service.trainingTaskClassConfigMapper); } @Test void saveClassTaskInsertsNewOverrideWhenNoneExists() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class); SchoolClass schoolClass = new SchoolClass(); schoolClass.setSchoolClassId("class-1"); schoolClass.setClassType("TEACHING"); schoolClass.setCreatedBy("teacher-1"); when(service.schoolClassMapper.selectByPrimaryKey("class-1")).thenReturn(schoolClass); TrainingTask defaultTask = storedTask("task-1", "new-product-survey"); defaultTask.setProjectName("Default Project"); defaultTask.setSort(3); defaultTask.setKnowledge("Default Knowledge"); when(service.trainingTaskMapper.selectByTaskKey("new-product-survey")).thenReturn(defaultTask); TrainingTask payload = storedTask(null, "new-product-survey"); payload.setProjectName("Changed Project"); payload.setTaskName("Class Name"); payload.setKnowledge("Class Knowledge"); payload.setMaterialName("Class Material"); payload.setEnabled(Boolean.TRUE); service.saveClassTask("class-1", "new-product-survey", payload, "teacher-1"); ArgumentCaptor captor = ArgumentCaptor.forClass(TrainingTaskClassConfig.class); verify(service.trainingTaskClassConfigMapper, times(25)).insertSelective(captor.capture()); TrainingTaskClassConfig savedOverride = captor.getAllValues().stream() .filter(config -> "new-product-survey".equals(config.getTaskKey())) .filter(config -> "Class Name".equals(config.getTaskName())) .findFirst() .orElseThrow(AssertionError::new); assertEquals("class-1", savedOverride.getTeachingClassId()); assertEquals("Default Project", savedOverride.getProjectName()); assertEquals(Integer.valueOf(3), savedOverride.getSort()); assertEquals("Class Knowledge", savedOverride.getKnowledge()); assertEquals("Class Material", savedOverride.getMaterialName()); } @Test void disabledClassOverrideMasksEnabledDefaultInStudentDetail() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class); TeachingClassStudent membership = new TeachingClassStudent(); membership.setTeachingClassId("class-1"); when(service.teachingClassStudentMapper.selectActiveByStudentUserId("stu-1")).thenReturn(membership); TrainingTask defaultTask = storedTask("task-1", "new-product-survey"); defaultTask.setEnabled(Boolean.TRUE); when(service.trainingTaskMapper.selectByTaskKey("new-product-survey")).thenReturn(defaultTask); TrainingTaskClassConfig override = overrideTask("config-1", "class-1", "new-product-survey"); override.setEnabled(Boolean.FALSE); when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "new-product-survey")).thenReturn(override); TrainingTask result = service.getStudentTaskByTaskKey("new-product-survey", "stu-1"); assertNull(result); } @Test void disabledClassOverrideMasksEnabledDefaultInStudentList() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class); TeachingClassStudent membership = new TeachingClassStudent(); membership.setTeachingClassId("class-1"); when(service.teachingClassStudentMapper.selectActiveByStudentUserId("stu-1")).thenReturn(membership); TrainingTask defaultTask = storedTask("task-1", "new-product-survey"); defaultTask.setEnabled(Boolean.TRUE); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(Collections.singletonList(defaultTask)); TrainingTaskClassConfig override = overrideTask("config-1", "class-1", "new-product-survey"); override.setEnabled(Boolean.FALSE); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)).thenReturn(Collections.singletonList(override)); List result = service.listForStudent("stu-1", true); assertEquals(0, result.size()); } @Test void disabledClassOverrideMasksEnabledDefaultInTeacherClassList() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class); SchoolClass schoolClass = new SchoolClass(); schoolClass.setSchoolClassId("class-1"); schoolClass.setClassType("TEACHING"); schoolClass.setCreatedBy("teacher-1"); schoolClass.setSchoolId("school-1"); when(service.schoolClassMapper.selectByPrimaryKey("class-1")).thenReturn(schoolClass); TrainingTask defaultTask = storedTask("task-1", "new-product-survey"); defaultTask.setEnabled(Boolean.TRUE); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(Collections.singletonList(defaultTask)); TrainingTaskClassConfig override = overrideTask("config-1", "class-1", "new-product-survey"); override.setEnabled(Boolean.FALSE); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)).thenReturn(Collections.singletonList(override)); JwtUser teacher = new JwtUser(); teacher.setUserId("teacher-1"); teacher.setSchoolId("school-1"); List result = service.listForTeachingClass("class-1", true, teacher); assertEquals(0, result.size()); } @Test void studentListHidesComprehensiveTrainingUntilTheClassHasPublishedIt() { TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask comprehensive = comprehensiveTrainingTask(); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) .thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), overrideTask("config-2", "class-1", "comprehensive-case-training"))); when(service.taskAllocationMapper.selectByExample(any())).thenReturn(Collections.emptyList()); List result = service.listForStudent("stu-1", true); assertEquals(List.of("new-product-survey"), result.stream() .map(TrainingTask::getTaskKey) .collect(java.util.stream.Collectors.toList())); } @Test void studentTaskLookupHidesComprehensiveTrainingUntilTheClassHasPublishedIt() { TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTask comprehensive = comprehensiveTrainingTask(); when(service.trainingTaskMapper.selectByTaskKey("comprehensive-case-training")).thenReturn(comprehensive); when(service.taskAllocationMapper.selectByExample(any())).thenReturn(Collections.emptyList()); TrainingTask result = service.getStudentTaskByTaskKey("comprehensive-case-training", "stu-1"); assertNull(result); } @Test void studentTaskLookupReturnsComprehensiveTrainingWhenPublishedAndEnabledForTheClass() { TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTask comprehensive = comprehensiveTrainingTask(); when(service.trainingTaskMapper.selectByTaskKey("comprehensive-case-training")).thenReturn(comprehensive); when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "comprehensive-case-training")) .thenReturn(overrideTask("config-1", "class-1", "comprehensive-case-training")); when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation("comprehensive-case-training", (byte) 0))); TrainingTask result = service.getStudentTaskByTaskKey("comprehensive-case-training", "stu-1"); assertEquals("comprehensive-case-training", result.getTaskKey()); } @Test void studentTaskLookupHidesPublishedComprehensiveTrainingWhenItsClassTaskIsDisabled() { TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTask comprehensive = comprehensiveTrainingTask(); when(service.trainingTaskMapper.selectByTaskKey("comprehensive-case-training")).thenReturn(comprehensive); TrainingTaskClassConfig disabled = overrideTask("config-1", "class-1", "comprehensive-case-training"); disabled.setEnabled(Boolean.FALSE); when(service.trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey("class-1", "comprehensive-case-training")) .thenReturn(disabled); when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation("comprehensive-case-training", (byte) 0))); TrainingTask result = service.getStudentTaskByTaskKey("comprehensive-case-training", "stu-1"); assertNull(result); } @Test void studentListReturnsComprehensiveTrainingWhenPublishedAndEnabledForTheClass() { TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask comprehensive = comprehensiveTrainingTask(); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) .thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), overrideTask("config-2", "class-1", "comprehensive-case-training"))); when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation("new-product-survey", (byte) 0), taskAllocation("comprehensive-case-training", (byte) 0))); List result = service.listForStudent("stu-1", true); assertEquals(List.of("new-product-survey", "comprehensive-case-training"), result.stream() .map(TrainingTask::getTaskKey) .collect(java.util.stream.Collectors.toList())); } @Test void studentListHidesComprehensiveTrainingWhenThePublishedKeyIsRemoved() { TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask comprehensive = comprehensiveTrainingTask(); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) .thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), overrideTask("config-2", "class-1", "comprehensive-case-training"))); when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation("new-product-survey", (byte) 0))); List result = service.listForStudent("stu-1", true); assertEquals(List.of("new-product-survey"), result.stream() .map(TrainingTask::getTaskKey) .collect(java.util.stream.Collectors.toList())); } @Test void studentListHidesComprehensiveTrainingWhenItsPublishedAllocationIsDisabled() { TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask comprehensive = comprehensiveTrainingTask(); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) .thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), overrideTask("config-2", "class-1", "comprehensive-case-training"))); when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation("new-product-survey", (byte) 0), taskAllocation("comprehensive-case-training", (byte) 1))); List result = service.listForStudent("stu-1", true); assertEquals(List.of("new-product-survey"), result.stream() .map(TrainingTask::getTaskKey) .collect(java.util.stream.Collectors.toList())); } @Test void studentListHidesDisabledComprehensiveTrainingWhenDisabledTasksAreRequested() { TrainingTaskServiceImpl service = studentTaskService("class-1"); TrainingTask legacy = storedTask("task-1", "new-product-survey"); TrainingTask comprehensive = comprehensiveTrainingTask(); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(legacy, comprehensive)); TrainingTaskClassConfig disabled = overrideTask("config-2", "class-1", "comprehensive-case-training"); disabled.setEnabled(Boolean.FALSE); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)) .thenReturn(List.of(overrideTask("config-1", "class-1", "new-product-survey"), disabled)); when(service.taskAllocationMapper.selectByExample(any())).thenReturn(List.of( taskAllocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1), taskAllocation("new-product-survey", (byte) 0), taskAllocation("comprehensive-case-training", (byte) 0))); List result = service.listForStudent("stu-1", false); assertEquals(List.of("new-product-survey"), result.stream() .map(TrainingTask::getTaskKey) .collect(java.util.stream.Collectors.toList())); } @Test void teacherClassTaskListIncludesComprehensiveTrainingWithoutPublication() { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class); TrainingTask comprehensive = comprehensiveTrainingTask(); when(service.trainingTaskMapper.selectList(null, null, null)).thenReturn(List.of(comprehensive)); when(service.trainingTaskClassConfigMapper.selectListByTeachingClass("class-1", null)).thenReturn(Collections.emptyList()); SchoolClass schoolClass = teachingClass("class-1", "teacher-1"); schoolClass.setSchoolId("school-1"); when(service.schoolClassMapper.selectByPrimaryKey("class-1")).thenReturn(schoolClass); JwtUser teacher = new JwtUser(); teacher.setUserId("teacher-1"); teacher.setSchoolId("school-1"); List result = service.listForTeachingClass("class-1", true, teacher); assertEquals(List.of("comprehensive-case-training"), result.stream() .map(TrainingTask::getTaskKey) .collect(java.util.stream.Collectors.toList())); } private TrainingTaskServiceImpl studentTaskService(String teachingClassId) { TrainingTaskServiceImpl service = new TrainingTaskServiceImpl(); service.trainingTaskMapper = mock(TrainingTaskMapper.class); service.trainingTaskClassConfigMapper = mock(TrainingTaskClassConfigMapper.class); service.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class); service.taskAllocationMapper = mock(TaskAllocationMapper.class); TeachingClassStudent membership = new TeachingClassStudent(); membership.setTeachingClassId(teachingClassId); when(service.teachingClassStudentMapper.selectActiveByStudentUserId("stu-1")).thenReturn(membership); return service; } private TrainingTask comprehensiveTrainingTask() { TrainingTask task = storedTask("task-comprehensive", "comprehensive-case-training"); task.setProjectName("综合实训"); task.setTaskName("综合案例实训"); task.setSort(1); return task; } private TaskAllocation taskAllocation(String module, byte disabledStatus) { TaskAllocation allocation = new TaskAllocation(); allocation.setModule(module); allocation.setDisabledStatus(disabledStatus); return allocation; } private TrainingTask storedTask(String id, String taskKey) { TrainingTask task = new TrainingTask(); task.setId(id); task.setTaskKey(taskKey); task.setProjectName("Foundation"); task.setTaskName("Original Name"); task.setSteps("[\"Step 1\",\"Step 2\",\"Step 3\",\"Step 4\"]"); task.setSort(7); task.setEnabled(Boolean.TRUE); return task; } private SchoolClass teachingClass(String classId, String createdBy) { SchoolClass schoolClass = new SchoolClass(); schoolClass.setSchoolClassId(classId); schoolClass.setClassType("TEACHING"); schoolClass.setCreatedBy(createdBy); return schoolClass; } private TrainingTaskClassConfig overrideTask(String id, String teachingClassId, String taskKey) { TrainingTaskClassConfig config = new TrainingTaskClassConfig(); config.setId(id); config.setTeachingClassId(teachingClassId); config.setTaskKey(taskKey); config.setProjectName("Foundation"); config.setTaskName("Override Name"); config.setSteps("[\"Step 1\",\"Step 2\",\"Step 3\",\"Step 4\"]"); config.setSort(7); config.setEnabled(Boolean.TRUE); return config; } }