using Jiaowu.Api.Controllers; using Jiaowu.Api.Domain.Academic; using Jiaowu.Api.Domain.Identity; using Jiaowu.Api.Infrastructure.Auth; using Jiaowu.Api.Infrastructure.Persistence; using Microsoft.AspNetCore.Mvc; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; namespace Jiaowu.Api.Tests; public sealed class TeachingWorkflowRosterTests { [Fact] public async Task ClassAssignedStudents_AppearAcrossTeacherWorkflows() { await using var connection = new SqliteConnection("Data Source=:memory:"); await connection.OpenAsync(); var options = new DbContextOptionsBuilder() .UseSqlite(connection) .Options; await using var db = new AppDbContext(options); await db.Database.EnsureCreatedAsync(); var teacherUserId = Guid.NewGuid(); var teacherUser = new ApplicationUser { Id = teacherUserId, UserName = "T001", NormalizedUserName = "T001", DisplayName = "张老师" }; var college = new College { Code = "CS", Name = "计算机学院" }; var major = new Major { Code = "080901", Name = "计算机科学与技术", CollegeId = college.Id, DegreeType = "工学学士" }; var administrativeClass = new AdministrativeClass { Code = "CS2026-01", Name = "计科 2026-1 班", MajorId = major.Id, Grade = 2026 }; var student = new Student { StudentNumber = "202601001", Name = "周同学", AdministrativeClassId = administrativeClass.Id, EnrollmentYear = 2026, EnrollmentDate = new DateOnly(2026, 9, 1) }; var teacher = new Teacher { TeacherNumber = "T001", Name = "张老师", CollegeId = college.Id, UserId = teacherUserId }; var course = new Course { Code = "CS101", Name = "程序设计基础", CollegeId = college.Id, Credits = 4, TotalHours = 64, LectureHours = 48, PracticeHours = 16, Nature = CourseNature.MajorRequired, AssessmentMethod = AssessmentMethod.Examination }; var term = new AcademicTerm { Code = "2026-1", Name = "2026—2027 学年第一学期", AcademicYear = "2026-2027", Season = TermSeason.Autumn, StartDate = new DateOnly(2026, 9, 1), EndDate = new DateOnly(2027, 1, 20) }; var task = new TeachingTask { TaskNumber = "2026-1-CS101-01", Name = "程序设计基础教学班", AcademicTermId = term.Id, CourseId = course.Id, Capacity = 60, Status = TeachingTaskStatus.Published, Teachers = [ new TeachingTaskTeacher { TeacherId = teacher.Id, IsPrimary = true } ], Classes = [ new TeachingTaskClass { AdministrativeClassId = administrativeClass.Id } ] }; db.AddRange( teacherUser, college, major, administrativeClass, student, teacher, course, term, task); await db.SaveChangesAsync(); var scope = new TeacherDataScope(teacherUserId); var attendance = new AttendanceController(db, scope); var attendanceResult = await attendance.CreateSheet( new AttendanceSheetRequest( task.Id, "第1周点名", new DateTime(2026, 9, 3), null, AttendanceCheckInMethod.Manual, null, null, null, null), CancellationToken.None); Assert.IsType(attendanceResult); Assert.Equal(1, await db.AttendanceRecords.CountAsync()); var grades = new GradesController(db, scope); var gradeResult = await grades.CreateSheet( new GradeSheetRequest(task.Id, 40, 60, []), CancellationToken.None); Assert.IsType(gradeResult); Assert.Equal(1, await db.GradeRecords.CountAsync()); var selections = new CourseSelectionsController(db, scope); Assert.Single(ReadItems(await selections.GetMyTeachingTasks( term.Id, CancellationToken.None))); var roster = Assert.IsType( await selections.GetTeachingTaskRoster(task.Id, CancellationToken.None)); Assert.Equal(1, ReadIntProperty(roster.Value!, "StudentCount")); var adjustments = new CourseAdjustmentsController(db, scope); Assert.Single(ReadItems(await adjustments.GetTaskOptions( term.Id, CancellationToken.None))); } private static List ReadItems(ActionResult result) { var ok = Assert.IsType(result); return Assert.IsAssignableFrom(ok.Value) .Cast() .ToList(); } private static int ReadIntProperty(object value, string name) => (int)value.GetType().GetProperty(name)!.GetValue(value)!; private sealed class TeacherDataScope(Guid userId) : ICurrentUserDataScope { public CurrentUserScope Current { get; } = new( userId, "张老师", null, DataScope.Self, new HashSet([SystemRoles.Teacher])); } }