using System.Text.Json; 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 GraduationAuditsControllerTests { [Fact] public async Task GetBatch_ReturnsPagedResultsAndWholeBatchSummary() { 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 college = new College { Code = "CS", Name = "计算机学院" }; var major = new Major { Code = "SE", Name = "软件工程", CollegeId = college.Id, DegreeType = "工学" }; var administrativeClass = new AdministrativeClass { Code = "SE2601", Name = "软件工程2601班", MajorId = major.Id, Grade = 2026 }; var batch = new GraduationAuditBatch { Name = "2030届毕业资格审核", GraduationYear = 2030, EnrollmentYear = 2026 }; db.AddRange(college, major, administrativeClass, batch); for (var index = 1; index <= 25; index++) { var student = new Student { StudentNumber = $"2026{index:0000}", Name = index == 17 ? "分页检索学生" : $"学生{index:00}", AdministrativeClassId = administrativeClass.Id, EnrollmentYear = 2026, EnrollmentDate = new DateOnly(2026, 9, 1) }; db.Students.Add(student); db.GraduationAuditResults.Add(new GraduationAuditResult { GraduationAuditBatchId = batch.Id, StudentId = student.Id, StudentStatusSnapshot = StudentStatus.Active, RequiredCredits = 160, EarnedCredits = 150, RequiredCourseCount = 40, PassedRequiredCourseCount = 38, FailedCourseCount = 1, MissingCourseNames = "毕业设计", CalculatedConclusion = index % 2 == 0 ? GraduationAuditConclusion.Eligible : GraduationAuditConclusion.Ineligible, Conclusion = index % 2 == 0 ? GraduationAuditConclusion.Eligible : GraduationAuditConclusion.Ineligible, IsOverridden = index == 1 }); } await db.SaveChangesAsync(); var controller = new GraduationAuditsController(db, new AllDataScope()); var pageResult = Assert.IsType(await controller.GetBatch( batch.Id, page: 2, pageSize: 10)); using var pageJson = ToJson(pageResult.Value); Assert.Equal(25, pageJson.RootElement.GetProperty("resultCount").GetInt32()); Assert.Equal(12, pageJson.RootElement.GetProperty("eligibleCount").GetInt32()); Assert.Equal(13, pageJson.RootElement.GetProperty("ineligibleCount").GetInt32()); Assert.Equal(1, pageJson.RootElement.GetProperty("overrideCount").GetInt32()); var pagedResults = pageJson.RootElement.GetProperty("results"); Assert.Equal(25, pagedResults.GetProperty("total").GetInt32()); Assert.Equal(2, pagedResults.GetProperty("page").GetInt32()); Assert.Equal(10, pagedResults.GetProperty("items").GetArrayLength()); var filteredResult = Assert.IsType(await controller.GetBatch( batch.Id, keyword: "分页检索", conclusion: GraduationAuditConclusion.Ineligible)); using var filteredJson = ToJson(filteredResult.Value); var filteredResults = filteredJson.RootElement.GetProperty("results"); Assert.Equal(1, filteredResults.GetProperty("total").GetInt32()); Assert.Equal( "分页检索学生", filteredResults.GetProperty("items")[0].GetProperty("name").GetString()); } private static JsonDocument ToJson(object? value) => JsonDocument.Parse( JsonSerializer.Serialize(value, new JsonSerializerOptions(JsonSerializerDefaults.Web))); private sealed class AllDataScope : ICurrentUserDataScope { public CurrentUserScope Current { get; } = new( Guid.NewGuid(), "校级教务", null, DataScope.All, new HashSet([SystemRoles.AcademicAdmin])); } }