using System.Text.Json.Nodes; using Eis.Infrastructure.Administration; namespace Eis.Infrastructure.Tests.Administration; public sealed class AdminResultStatisticsTests { [Theory] [InlineData(0, 100, true)] [InlineData(10, 100, true)] [InlineData(10.5, 100, true)] [InlineData(10.1, 100, false)] [InlineData(-0.5, 100, false)] [InlineData(100.5, 100, false)] public void IsValidScore_OnlyAcceptsWholeOrHalfPoints(double score, double fullScore, bool expected) { Assert.Equal(expected, AdminResultStatistics.IsValidScore(score, fullScore)); } [Fact] public void Calculate_ComputesEachSubjectAndTotalRankingOnceForTheExam() { var exam = Exam("rank_percent", 50); var registrations = new[] { Registration("r1"), Registration("r2"), Registration("r3") }; var results = new[] { Result("r1-s1", "r1", "s1", 90), Result("r1-s2", "r1", "s2", 80), Result("r2-s1", "r2", "s1", 90), Result("r2-s2", "r2", "s2", 70), Result("r3-s1", "r3", "s1", 60), Result("r3-s2", "r3", "s2", 70) }; var calculation = AdminResultStatistics.Calculate(exam, registrations, results, "2026-07-23T00:00:00.000Z"); Assert.Equal(6, calculation.Metrics.Count); Assert.Equal(1, calculation.Metrics.Single(item => item.ResultId == "r1-s1").Rank); Assert.Equal(1, calculation.Metrics.Single(item => item.ResultId == "r2-s1").Rank); Assert.Equal(3, calculation.Metrics.Single(item => item.ResultId == "r3-s1").Rank); Assert.Equal(2, calculation.Metrics.Single(item => item.ResultId == "r2-s2").Rank); Assert.Equal(2, calculation.Metrics.Single(item => item.ResultId == "r3-s2").Rank); var summaries = calculation.Summaries.ToDictionary(item => item.RegistrationId); Assert.Equal(170, summaries["r1"].TotalScore); Assert.Equal(1, summaries["r1"].Rank); Assert.True(summaries["r1"].Qualified); Assert.Equal(2, summaries["r2"].Rank); Assert.True(summaries["r2"].Qualified); Assert.Equal(3, summaries["r3"].Rank); Assert.False(summaries["r3"].Qualified); Assert.All(summaries.Values, item => Assert.Equal(3, item.CohortSize)); } [Fact] public void Calculate_PersistsIncompleteAndDraftStatesWithoutIncludingDraftInPublishedSummary() { var exam = Exam("subject_scores", 0); var registrations = new[] { Registration("r1"), Registration("r2") }; var results = new[] { Result("r1-s1", "r1", "s1", 95), Result("r1-s2", "r1", "s2", 88, published: false), Result("r2-s1", "r2", "s1", 80), Result("r2-s2", "r2", "s2", 75) }; var calculation = AdminResultStatistics.Calculate(exam, registrations, results, "2026-07-23T00:00:00.000Z"); var draft = calculation.Metrics.Single(item => item.ResultId == "r1-s2"); var summaries = calculation.Summaries.ToDictionary(item => item.RegistrationId); Assert.Equal("待发布", draft.Grade); Assert.Equal(2, draft.CohortSize); Assert.False(summaries["r1"].Complete); Assert.Null(summaries["r1"].Qualified); Assert.Equal(1, summaries["r1"].PublishedSubjectCount); Assert.True(summaries["r2"].Complete); } private static OperationalExam Exam(string passPolicy, double passValue) { var subjects = new[] { new JsonObject { ["id"] = "s1", ["name"] = "语文", ["fullScore"] = 100, ["passRule"] = "fixed_score", ["passValue"] = 60 }, new JsonObject { ["id"] = "s2", ["name"] = "数学", ["fullScore"] = 100, ["passRule"] = "fixed_score", ["passValue"] = 60 } }; return new("exam-1", new JsonObject { ["id"] = "exam-1", ["passPolicy"] = passPolicy, ["passValue"] = passValue }, subjects); } private static OperationalRegistration Registration(string id) => new( id, $"user-{id}", "exam-1", "approved", "paid", null, "2026-07-23T00:00:00.000Z", new JsonObject { ["id"] = id, ["subjectIds"] = new JsonArray("s1", "s2") }); private static AdminWorkflowResult Result( string id, string registrationId, string subjectId, double score, bool published = true) => new( id, registrationId, subjectId, score, published ? "" : "待发布", published, "2026-07-23T00:00:00.000Z", published ? "2026-07-23T00:00:00.000Z" : null); }