using Serilog.Events;
using Xunit;
using YZWater.Core.Services;
namespace YZWater.Core.Tests.Services;
///
/// 测点数据质量事件的记录方式回归。
/// 背景:现场报警历史被"测点 X 读取失败 / 已恢复"刷满 —— 一次抖动就是"点位数 × 2"行,
/// 真报警被埋掉,而且这些行是系统自动确认的流水,操作员既确认不了也复位不了,
/// 误点复位还会让程序往 PLC 的复位地址写一次脉冲。
/// 现在一轮最多两条汇总(明细仍在日志文件里),且带独立类型 Quality。
///
[Collection("Serilog minimum level")]
public class QualityJournalTests : IDisposable
{
private readonly LogEventLevel _originalLevel = LogService.MinimumLevel;
private readonly AlarmService _service;
public QualityJournalTests()
{
LogService.ApplyMinimumLevel("Error");
_service = new AlarmService(PlcPollingService.Instance);
}
public void Dispose()
{
_service.Dispose();
LogService.ApplyMinimumLevel(_originalLevel.ToString());
}
[Fact]
public void TwentyBadTags_SummarizeIntoOneMessage_NotTwenty()
{
var lost = Enumerable.Range(1, 20).Select(i => $"{i}#泵.Run").ToList();
var (lostMessage, restoredMessage) =
PlcPollingService.BuildQualityJournalMessages(lost, new List());
Assert.Null(restoredMessage);
Assert.NotNull(lostMessage);
var message = lostMessage!;
// 一条消息讲清规模,而不是一个点一条流水
Assert.Contains("20", message);
Assert.Contains("共 20 个", message);
// 清单截断到前 8 个,避免整张点位表被塞进一条记录
Assert.DoesNotContain("20#泵.Run", message);
Assert.Contains("8#泵.Run", message);
// 键名拼错时 LanguageService 会原样返回键,这条断言保证模板真的解析了
Assert.DoesNotContain("TagQualityLostSummary", message);
}
[Fact]
public void LostAndRestored_ProduceTwoSeparateMessages()
{
var (lost, restored) = PlcPollingService.BuildQualityJournalMessages(
new List { "DI.高压报警" }, new List { "1#泵.Fault", "2#泵.Fault" });
Assert.NotNull(lost);
Assert.Contains("DI.高压报警", lost);
Assert.NotNull(restored);
Assert.Contains("1#泵.Fault", restored);
Assert.DoesNotContain("DI.高压报警", restored);
}
[Fact]
public void NoTransitions_ProduceNoRows()
{
var (lost, restored) = PlcPollingService.BuildQualityJournalMessages(
new List(), new List());
Assert.Null(lost);
Assert.Null(restored);
}
///
/// 诊断流水不得进入活跃报警集合 —— 否则它会占用报警位、被升级/泛溢逻辑统计,
/// 还会让"复位"误以为有东西可复位而去写 PLC。
///
[Fact]
public void JournalAlarm_NeverBecomesAnActiveAlarm()
{
_service.RecordJournalAlarm("1 个测点读取失败:1#泵.Run", level: 1, alarmType: "Quality");
Assert.Equal(0, _service.ActiveAlarmCount);
Assert.False(_service.HasActiveAlarm);
}
}