using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using ZB.MOM.WW.Audit; using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit; namespace ZB.MOM.WW.ScadaBridge.InboundAPI.Tests; /// /// Flow Debugger step logs (design 2026-09-09 D7): the central Log global's per-message cap. /// Final review M2 — the site runtime's ScriptLogger.Clip already backed off a char when the /// cap landed between the halves of a surrogate pair; this side did not, so an emoji straddling the /// boundary left a LONE surrogate on the row (which breaks JSON serialization further down the pipe). /// public class InboundScriptLoggerTests { private static (InboundScriptLogger Logger, List Rows) MakeTraced(int maxLines = 200) { var rows = new List(); var logger = new InboundScriptLogger( NullLogger.Instance, rows.Add, maxLines, "DelmiaRecipeDownload", Guid.NewGuid(), "central-a"); return (logger, rows); } [Fact] public void ASurrogatePairStraddlingTheCap_IsDroppedWhole() { var (logger, rows) = MakeTraced(); var straddling = new string('x', InboundScriptLogger.MaxMessageChars - 1) + "🚀" + new string('y', 10); logger.Info(straddling); var message = Assert.Single(rows).AsRow().RequestSummary!; Assert.Equal(InboundScriptLogger.MaxMessageChars, message.Length); Assert.EndsWith("…", message); Assert.DoesNotContain(message, static c => char.IsSurrogate(c)); } [Fact] public void AnOverlongMessageWithNoSurrogateAtTheBoundary_KeepsTheFullCap() { var (logger, rows) = MakeTraced(); logger.Info(new string('x', InboundScriptLogger.MaxMessageChars + 500)); var message = Assert.Single(rows).AsRow().RequestSummary!; Assert.Equal(InboundScriptLogger.MaxMessageChars + 1, message.Length); // cap + the ellipsis Assert.Equal(new string('x', InboundScriptLogger.MaxMessageChars) + "…", message); } [Fact] public void AMessageExactlyAtTheCap_PassesThroughUnclipped() { var (logger, rows) = MakeTraced(); var exact = new string('x', InboundScriptLogger.MaxMessageChars); logger.Info(exact); Assert.Equal(exact, Assert.Single(rows).AsRow().RequestSummary); } }