using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Collections.Generic; using YesNt.Interpreter.Attributes; using YesNt.Interpreter.Enums; using YesNt.Interpreter.Runtime; namespace YesNt.Interpreter.Tests; [TestClass] public class AddStatementTests { [TestMethod] public void AddStatementStartOfLineExecutesHandlerTest() { List lines = [ "my_command hello" ]; string? capturedArgs = null; YesNtAssert.GetLastLineWithSetup(lines, interpreter => { interpreter.AddStatement("my_command", SearchMode.StartOfLine, SpaceAround.End, args => { capturedArgs = args; }); }); Assert.AreEqual("hello", capturedArgs); } [TestMethod] public void AddStatementConvenienceOverloadHandlerIsCalledTest() { List lines = [ "custom_cmd world" ]; bool handlerCalled = false; YesNtAssert.GetLastLineWithSetup(lines, interpreter => { interpreter.AddStatement("custom_cmd", SearchMode.StartOfLine, SpaceAround.End, _ => { handlerCalled = true; }); }); Assert.IsTrue(handlerCalled); } [TestMethod] public void AddStatementAttributeOverloadHandlerIsCalledTest() { List lines = [ "attr_cmd test" ]; bool handlerCalled = false; YesNtAssert.GetLastLineWithSetup(lines, interpreter => { var attr = new StatementAttribute("attr_cmd", SearchMode.StartOfLine, SpaceAround.End); interpreter.AddStatement(attr, _ => { handlerCalled = true; }); }); Assert.IsTrue(handlerCalled); } [TestMethod] public void AddStatementExactSearchModeTest() { List lines = [ "exact_cmd" ]; bool handlerCalled = false; YesNtAssert.GetLastLineWithSetup(lines, interpreter => { interpreter.AddStatement("exact_cmd", SearchMode.Exact, SpaceAround.None, _ => { handlerCalled = true; }); }); Assert.IsTrue(handlerCalled); } [TestMethod] public void AddStatementContainsSearchModeTest() { List lines = [ "prefix ~mark~ suffix" ]; bool handlerCalled = false; YesNtAssert.GetLastLineWithSetup(lines, interpreter => { interpreter.AddStatement(" ~mark~ ", SearchMode.Contains, SpaceAround.None, _ => { handlerCalled = true; }); }); Assert.IsTrue(handlerCalled); } [TestMethod] public void AddStatementEndOfLineSearchModeTest() { List lines = [ "some text !end" ]; bool handlerCalled = false; YesNtAssert.GetLastLineWithSetup(lines, interpreter => { interpreter.AddStatement(" !end", SearchMode.EndOfLine, SpaceAround.None, _ => { handlerCalled = true; }); }); Assert.IsTrue(handlerCalled); } [TestMethod] public void AddStatementReceivesCorrectArgsTest() { List lines = [ "capture_cmd the quick brown fox" ]; string? capturedArgs = null; YesNtAssert.GetLastLineWithSetup(lines, interpreter => { interpreter.AddStatement("capture_cmd", SearchMode.StartOfLine, SpaceAround.End, args => { capturedArgs = args; }); }); Assert.AreEqual("the quick brown fox", capturedArgs); } [TestMethod] public void AddStatementWorksAlongsideBuiltinStatementsTest() { List lines = [ "custom_log first", "print_line second" ]; bool customCalled = false; YesNtAssert.ContainsDebugOutputWithSetup(lines, "second", interpreter => { interpreter.AddStatement("custom_log", SearchMode.StartOfLine, SpaceAround.End, _ => { customCalled = true; }); }); Assert.IsTrue(customCalled); } [TestMethod] public void AddStatementUnknownStatementFailsTest() { List lines = [ "unknown_command foo" ]; YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement"); } [TestMethod] public void RemoveStatementCausesInvalidStatementTest() { List lines = [ "sleep 100" ]; YesNtAssert.ContainsTerminationMessageWithSetup(lines, "Invalid statement", interpreter => { interpreter.RemoveStatement("sleep"); }); } [TestMethod] public void DisabledStatementIsIgnoredTest() { List lines = [ "var x = hello", "${x}" ]; YesNtAssert.ContainsTerminationMessageWithSetup(lines, "Variable \"x\" not found", interpreter => { interpreter.DisableStatement("var"); }); } [TestMethod] public void DisabledStatementCanBeReenabledTest() { List lines = [ "var result = overwritten", "${result}" ]; YesNtAssert.IsLastLineEqualWithSetup(lines, "overwritten", setup: interpreter => { interpreter.DisableStatement("var"); interpreter.EnableStatement("var"); }); } [TestMethod] public void DisableNonExistentStatementIsNoOpTest() { List lines = [ "var x = ok", "${x}" ]; YesNtAssert.IsLastLineEqualWithSetup(lines, "ok", setup: interpreter => { interpreter.DisableStatement("nonexistent_keyword"); }); } [TestMethod] public void EnableNonDisabledStatementIsNoOpTest() { List lines = [ "var x = ok", "${x}" ]; YesNtAssert.IsLastLineEqualWithSetup(lines, "ok", setup: interpreter => { interpreter.EnableStatement("var"); }); } [TestMethod] public void AddStatementWithHighPriorityRunsBeforeNormalTest() { List lines = [ "priority_cmd arg" ]; int callOrder = 0; int highPriorityOrder = -1; int normalPriorityOrder = -1; YesNtAssert.GetLastLineWithSetup(lines, interpreter => { interpreter.AddStatement( new StatementAttribute("priority_cmd", SearchMode.StartOfLine, SpaceAround.End) { Priority = Priority.High }, _ => highPriorityOrder = callOrder++); interpreter.AddStatement( new StatementAttribute("priority_cmd", SearchMode.StartOfLine, SpaceAround.End) { Priority = Priority.Normal }, _ => normalPriorityOrder = callOrder++); }); Assert.IsTrue(highPriorityOrder < normalPriorityOrder, "High priority statement should execute before Normal priority"); } [TestMethod] public void AddStatementAloneDoesNotReplaceBuiltinTest() { // Adding a custom 'var' handler without RemoveStatement first means BOTH handlers fire. // The built-in still sets the variable, so ${x} resolves normally. List lines = [ "var x = original", "${x}" ]; bool customHandlerCalled = false; YesNtAssert.IsLastLineEqualWithSetup(lines, "original", setup: interpreter => { interpreter.AddStatement("var", SearchMode.StartOfLine, SpaceAround.End, _ => { customHandlerCalled = true; }); }); Assert.IsTrue(customHandlerCalled, "Custom handler should have fired alongside the built-in"); } [TestMethod] public void RemoveThenAddStatementReplacesBuiltinTest() { // RemoveStatement + AddStatement correctly replaces the built-in. // The built-in 'var' is gone, so only the custom handler fires. List lines = [ "var x = original", "${x}" ]; YesNtAssert.ContainsTerminationMessageWithSetup(lines, "Variable \"x\" not found", interpreter => { interpreter.RemoveStatement("var"); interpreter.AddStatement("var", SearchMode.StartOfLine, SpaceAround.End, _ => { }); }); } }