using System.Text; using MrGameEng.Core; using Xunit; namespace MrGameEng.DevConsole.Tests; public class DevConsoleTests { private static string Visible(DevConsole console, int lines = 50) { var sb = new StringBuilder(); console.BuildVisibleText(sb, lines); return sb.ToString(); } [Fact] public void Execute_RunsRegisteredCommand_WithArguments() { using var console = new DevConsole(); string[]? received = null; console.Register("test", "test command", (_, args) => received = args); console.Execute("test one two"); Assert.NotNull(received); Assert.Equal(["one", "two"], received!); Assert.Contains("> test one two", Visible(console)); } [Fact] public void Execute_UnknownCommand_ReportsWithoutThrowing() { using var console = new DevConsole(); console.Execute("nosuchcommand"); Assert.Contains("unknown command 'nosuchcommand'", Visible(console)); } [Fact] public void Execute_HandlerException_IsCaughtAndLogged() { using var console = new DevConsole(); console.Register("boom", "throws", (_, _) => throw new InvalidOperationException("kaboom")); console.Execute("boom"); Assert.Contains("[err] kaboom", Visible(console)); } [Fact] public void RingBuffer_OverflowDropsOldestLines() { using var console = new DevConsole(capacity: 4); for (var i = 0; i < 10; i++) { console.WriteLine($"line{i}"); } var visible = Visible(console); Assert.DoesNotContain("line5", visible); Assert.Contains("line6", visible); Assert.Contains("line9", visible); } [Fact] public void BuildVisibleText_RespectsWindowAndScroll() { using var console = new DevConsole(); for (var i = 0; i < 10; i++) { console.WriteLine($"line{i}"); } var sb = new StringBuilder(); console.BuildVisibleText(sb, 3); Assert.Equal("line7\nline8\nline9", sb.ToString()); console.Scroll(+2); console.BuildVisibleText(sb, 3); Assert.StartsWith("line5\nline6\nline7", sb.ToString()); } [Fact] public void History_NavigatesUpAndDown() { using var console = new DevConsole(); console.Register("a", "", (_, _) => { }); console.Execute("a 1"); console.Execute("a 2"); Assert.Equal("a 2", console.HistoryPrevious()); Assert.Equal("a 1", console.HistoryPrevious()); Assert.Equal("a 1", console.HistoryPrevious()); // упёрлись в начало Assert.Equal("a 2", console.HistoryNext()); Assert.Equal("", console.HistoryNext()); // за последним — пустая строка } [Fact] public void Complete_SingleMatch_CompletesWithTrailingSpace() { using var console = new DevConsole(); Assert.Equal("echo ", console.Complete("ec")); } [Fact] public void Complete_MultipleMatches_ReturnsCommonPrefix_AndListsOptions() { using var console = new DevConsole(); console.Register("spawn", "", (_, _) => { }); console.Register("spawnall", "", (_, _) => { }); var completed = console.Complete("sp"); Assert.Equal("spawn", completed); Assert.Contains("spawn spawnall", Visible(console)); } [Fact] public void LogMessages_AreCaptured_WithLevelTags() { using var console = new DevConsole(); Log.Info("plain info"); Log.Warning("careful"); var visible = Visible(console); Assert.Contains("plain info", visible); Assert.Contains("[warn] careful", visible); } [Fact] public void Revision_ChangesOnlyOnVisibleChanges() { using var console = new DevConsole(); var before = console.Revision; console.WriteLine("x"); Assert.NotEqual(before, console.Revision); before = console.Revision; _ = Visible(console); // чтение не меняет ревизию Assert.Equal(before, console.Revision); } }