using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using SSPCTester.Logic.Models; using SSPCTester.Logic.Report; namespace SSPCTester.Tests; public sealed class WordReportGeneratorTests { [Fact] public void WordReport_GeneratesOpenXmlDocumentWithSimSunTextAndImage() { string output = Path.Combine(Path.GetTempPath(), $"SSPCTester-report-{Guid.NewGuid():N}.docx"); try { var project = BuildProject(); var generator = new WordReportGenerator { CurveImages = { [1] = new CurveReportImages(MinimalPng, MinimalPng) } }; generator.Generate(project, output); Assert.True(File.Exists(output)); Assert.True(new FileInfo(output).Length > 4_000); using var document = WordprocessingDocument.Open(output, false); string text = document.MainDocumentPart!.Document.Body!.InnerText; Assert.Contains("动态参数检测报告", text); Assert.Contains("ProjectA", text); Assert.Contains("基础测试", text); Assert.Contains("功率损耗", text); var fontNames = document.MainDocumentPart.Document.Descendants() .SelectMany(x => new[] { x.Ascii?.Value, x.HighAnsi?.Value, x.EastAsia?.Value }) .Where(x => !string.IsNullOrWhiteSpace(x)) .ToArray(); Assert.Contains("SimSun", fontNames); Assert.Equal(2, document.MainDocumentPart.ImageParts.Count()); } finally { if (File.Exists(output)) File.Delete(output); } } [Fact] public void WordReport_GeneratesWithoutCurveImages() { string output = Path.Combine(Path.GetTempPath(), $"SSPCTester-report-{Guid.NewGuid():N}.docx"); try { new WordReportGenerator().Generate(BuildProject(), output); Assert.True(File.Exists(output)); using var document = WordprocessingDocument.Open(output, false); Assert.Contains("开启与关断曲线", document.MainDocumentPart!.Document.Body!.InnerText); } finally { if (File.Exists(output)) File.Delete(output); } } private static Project BuildProject() { var project = new Project { Name = "ProjectA", CreatedAt = new DateTime(2026, 6, 28, 9, 0, 0), Dut = new DutInfo { ProductName = "SSPC", Model = "M24", SerialNumber = "SN001", Manufacturer = "Factory" }, Site = new TestSiteInfo { Tester = "Tester", TestDate = new DateTime(2026, 6, 28), Remark = "OK" } }; project.BasicResults.Add(new ChannelResult { Channel = 1, VoltageOn = 28.0, CurrentOn = 1.0, VoltageOff = 0.01, Status = TestStatus.Pass }); project.CurveResults.Add(new CurveResultRow { Channel = 1, OnTimeMs = 1.2, RiseTimeMs = 0.9, OffTimeMs = 1.1, FallTimeMs = 0.8, Status = TestStatus.Pass }); project.PowerResults.Add(new PowerLossRow { Channel = 1, Vin = 28.0, Iin = 1.0, Vout = 27.5, Iout = 1.0, MeasuredPowerOut = 27.5, Status = TestStatus.Pass }); project.ProtectResults.Add(new ProtectRow { ProtectType = "短路", Trigger = "输出短路", TripTimeMs = 2.1, Status = TestStatus.Pass }); return project; } private static readonly byte[] MinimalPng = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; }