mirror of
https://github.com/Stone-Red-Code/YesNt-Interpreter.git
synced 2026-09-07 16:06:05 +02:00
Add snapcraft & chocolatey manifests and move code to src
This commit is contained in:
@@ -0,0 +1,377 @@
|
||||
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<string> 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<string> 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<string> lines =
|
||||
[
|
||||
"attr_cmd test"
|
||||
];
|
||||
|
||||
bool handlerCalled = false;
|
||||
|
||||
_ = YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
|
||||
{
|
||||
StatementAttribute attr = new StatementAttribute("attr_cmd", SearchMode.StartOfLine, SpaceAround.End);
|
||||
interpreter.AddStatement(attr, _ =>
|
||||
{
|
||||
handlerCalled = true;
|
||||
});
|
||||
});
|
||||
|
||||
Assert.IsTrue(handlerCalled);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AddStatementExactSearchModeTest()
|
||||
{
|
||||
List<string> 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<string> 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<string> 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<string> 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<string> 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<string> lines =
|
||||
[
|
||||
"unknown_command foo"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RemoveStatementCausesInvalidStatementTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"sleep 100"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessageWithSetup(lines, "Invalid statement", interpreter =>
|
||||
{
|
||||
interpreter.RemoveStatement("sleep");
|
||||
});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DisabledStatementIsIgnoredTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = hello",
|
||||
"${x}"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessageWithSetup(lines, "Variable \"x\" not found", interpreter =>
|
||||
{
|
||||
interpreter.DisableStatement("var");
|
||||
});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DisabledStatementCanBeReenabledTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var result = overwritten",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqualWithSetup(lines, "overwritten", setup: interpreter =>
|
||||
{
|
||||
interpreter.DisableStatement("var");
|
||||
interpreter.EnableStatement("var");
|
||||
});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DisableNonExistentStatementIsNoOpTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = ok",
|
||||
"${x}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqualWithSetup(lines, "ok", setup: interpreter =>
|
||||
{
|
||||
interpreter.DisableStatement("nonexistent_keyword");
|
||||
});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EnableNonDisabledStatementIsNoOpTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = ok",
|
||||
"${x}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqualWithSetup(lines, "ok", setup: interpreter =>
|
||||
{
|
||||
interpreter.EnableStatement("var");
|
||||
});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AddStatementWithHighPriorityRunsBeforeNormalTest()
|
||||
{
|
||||
List<string> 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<string> 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<string> lines =
|
||||
[
|
||||
"var x = original",
|
||||
"${x}"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessageWithSetup(lines, "Variable \"x\" not found", interpreter =>
|
||||
{
|
||||
interpreter.RemoveStatement("var");
|
||||
interpreter.AddStatement("var", SearchMode.StartOfLine, SpaceAround.End, _ => { });
|
||||
});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AddStatementWithRuntimeInfoCanSetVariableTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"set_var foo",
|
||||
"${foo}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqualWithSetup(lines, "hello", interpreter =>
|
||||
{
|
||||
interpreter.AddStatement("set_var", SearchMode.StartOfLine, SpaceAround.End, (args, rt) =>
|
||||
{
|
||||
rt.Variables[args] = "hello";
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AddStatementWithRuntimeInfoCanReadVariableTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var greeting = world",
|
||||
"echo_var greeting"
|
||||
];
|
||||
|
||||
string? captured = null;
|
||||
|
||||
YesNtAssert.GetLastLineWithSetup(lines, interpreter =>
|
||||
{
|
||||
interpreter.AddStatement("echo_var", SearchMode.StartOfLine, SpaceAround.End, (args, rt) =>
|
||||
{
|
||||
_ = rt.Variables.TryGetValue(args, out captured);
|
||||
});
|
||||
});
|
||||
|
||||
Assert.AreEqual("world", captured);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
[assembly: Parallelize(Workers = 0, Scope = ExecutionScope.MethodLevel)]
|
||||
@@ -0,0 +1,80 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class CodeFlowStatementsTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ExitStopsExecutionTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var result = before",
|
||||
"exit",
|
||||
"var result = after",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Planned termination by code");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AbortAllStopsExecutionTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"abort_all",
|
||||
"var result = after",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Canceling all tasks");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ThrowTerminatesWithErrorFlagTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"throw bad"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "with the message: bad");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ErrorTerminatesWithMessageTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"error soft"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "with the message: soft");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MissingLabelFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"goto nowhere"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Label \"nowhere\" not found");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MissingFunctionFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"call nowhere"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Function \"nowhere\" not found");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class CodeFlowTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void FunctionTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"call yes",
|
||||
"func yes:",
|
||||
"global result = 1",
|
||||
"return",
|
||||
"${result}"
|
||||
];
|
||||
YesNtAssert.IsLastLineEqual(lines, "1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LabelsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var result = 1",
|
||||
"goto yes",
|
||||
"var result = 0",
|
||||
"label yes:",
|
||||
"${result}"
|
||||
];
|
||||
YesNtAssert.IsLastLineEqual(lines, "1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IfBlockTrueTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var result = low",
|
||||
"if 6 > 5:",
|
||||
"var result = high",
|
||||
"end_if",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "high");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IfElseFalseBranchTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var result = low",
|
||||
"if 6 < 5:",
|
||||
"var result = high",
|
||||
"else:",
|
||||
"var result = medium",
|
||||
"end_if",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "medium");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void NestedIfElseTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var result = 0",
|
||||
"if 1 == 1:",
|
||||
"if 2 == 3:",
|
||||
"var result = 1",
|
||||
"else:",
|
||||
"var result = 2",
|
||||
"end_if",
|
||||
"end_if",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "2");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WhileLoopTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var i = 3",
|
||||
"while ${i} > 0:",
|
||||
"var i = ${i} - 1 calc",
|
||||
"end_while",
|
||||
"${i}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "0");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void WhileSkipBodyWhenFalseTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var i = 0",
|
||||
"while ${i} > 0:",
|
||||
"var i = 99",
|
||||
"end_while",
|
||||
"${i}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "0");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void NestedWhileLoopTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var outer = 2",
|
||||
"var count = 0",
|
||||
"while ${outer} > 0:",
|
||||
"var inner = 2",
|
||||
"while ${inner} > 0:",
|
||||
"var count = ${count} + 1 calc",
|
||||
"var inner = ${inner} - 1 calc",
|
||||
"end_while",
|
||||
"var outer = ${outer} - 1 calc",
|
||||
"end_while",
|
||||
"${count}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "4");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IfElseTrueSkipsElseBranchTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var result = 0",
|
||||
"if 2 > 1:",
|
||||
"var result = 1",
|
||||
"else:",
|
||||
"var result = 2",
|
||||
"end_if",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IfWithoutElseFalseSkipsBodyTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var result = 5",
|
||||
"if 1 == 2:",
|
||||
"var result = 1",
|
||||
"end_if",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "5");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IfGotoTrueTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var result = 0",
|
||||
"if 1 == 1 goto done",
|
||||
"var result = 2",
|
||||
"label done:",
|
||||
"var result = ${result} + 1 calc",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IfCallTrueTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"func set_result:",
|
||||
"global result = ok",
|
||||
"return",
|
||||
"if 1 == 1 call set_result",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "ok");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GotoInsideLoopExitsLoopTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var hit = no",
|
||||
"while 1 == 1:",
|
||||
"var hit = yes",
|
||||
"goto done",
|
||||
"end_while",
|
||||
"label done:",
|
||||
"${hit}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "yes");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LabelWithoutColonFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"label loop"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void FunctionWithoutColonFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"func missing"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MissingEndIfFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"if 1 == 2:",
|
||||
"var result = 1"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "No matching end_if found");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ElseWithoutIfFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"else:"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "No matching end_if found");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MissingEndWhileFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var i = 0",
|
||||
"while ${i} > 1:",
|
||||
"var i = ${i} + 1 calc"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "No matching end_while found");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EndWhileWithoutWhileFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"end_while"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "No matching while found");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using YesNt.Interpreter.Runtime;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class ConsoleStatementsTests
|
||||
{
|
||||
private static readonly object ConsoleLock = new object();
|
||||
|
||||
[TestMethod]
|
||||
public void PrintLineWritesOutputTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"print_line hello"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsDebugOutput(lines, "hello");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PrintWritesOutputTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"print hello"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsDebugOutput(lines, "hello");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ClearThrowsInNonInteractiveConsoleTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"clear"
|
||||
];
|
||||
|
||||
_ = Assert.Throws<IOException>(() => YesNtAssert.GetLastLine(lines));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReadLineReplacesTokenTest()
|
||||
{
|
||||
lock (ConsoleLock)
|
||||
{
|
||||
TextReader originalIn = Console.In;
|
||||
|
||||
try
|
||||
{
|
||||
Console.SetIn(new StringReader("typed value" + Environment.NewLine));
|
||||
|
||||
List<string> lines =
|
||||
[
|
||||
"var value = %read_line",
|
||||
"${value}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "typed value");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetIn(originalIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[DoNotParallelize] // timing-sensitive: relies on Thread.Sleep to let the interpreter reach %read_key
|
||||
public void ReadKeyCanBeInterruptedByStopTest()
|
||||
{
|
||||
YesNtInterpreter interpreter = new YesNtInterpreter();
|
||||
|
||||
AutoResetEvent onDone = new AutoResetEvent(false);
|
||||
StringBuilder output = new StringBuilder();
|
||||
|
||||
interpreter.OnDebugOutput += (s) => _ = output.Append(s);
|
||||
interpreter.OnLineExecuted += (e) =>
|
||||
{
|
||||
if (e is null)
|
||||
{
|
||||
_ = onDone.Set();
|
||||
}
|
||||
};
|
||||
|
||||
List<string> lines =
|
||||
[
|
||||
"var value = %read_key"
|
||||
];
|
||||
|
||||
_ = Task.Run(() => interpreter.Execute(lines, true));
|
||||
|
||||
Thread.Sleep(100);
|
||||
interpreter.Stop();
|
||||
|
||||
_ = onDone.WaitOne(TimeSpan.FromSeconds(3));
|
||||
|
||||
StringAssert.Contains(output.ToString(), "Terminated by external process");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class FunctionStatementsTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void FunctionCallWithInParameterTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"goto main",
|
||||
"func echo:",
|
||||
"global result = %in",
|
||||
"return",
|
||||
"label main:",
|
||||
"call echo with hello",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "hello");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void HasInAndHasOutTokensTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"goto main",
|
||||
"func probe:",
|
||||
"global hasInBefore = %has_in",
|
||||
"var consume = %in",
|
||||
"global hasInAfter = %has_in",
|
||||
"push_out ${hasInBefore}",
|
||||
"push_out ${hasInAfter}",
|
||||
"return",
|
||||
"label main:",
|
||||
"call probe with x",
|
||||
"var hasOut = %has_out",
|
||||
"${hasOut}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "True");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OutParameterReadTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"goto main",
|
||||
"func make:",
|
||||
"push_out out_value",
|
||||
"return",
|
||||
"label main:",
|
||||
"call make with anything",
|
||||
"var value = %out",
|
||||
"${value}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "out_value");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OutParameterWithoutValueFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = %out"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "No out argument in stack");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void InParameterOutsideFunctionFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = %in"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Statement not allowed outside of function");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ReturnOutsideFunctionFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"return"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Statement not allowed outside of function");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PushOutOutsideFunctionFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"push_out value"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Statement not allowed outside of function");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void FunctionWithoutColonFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"func missing"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void NestedFunctionDefinitionFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"func outer:",
|
||||
"func inner:",
|
||||
"return"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Nested functions are not allowed");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LocalVariableDoesNotLeakToCallerTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"goto main",
|
||||
"func modify:",
|
||||
"var x = inner",
|
||||
"return",
|
||||
"label main:",
|
||||
"var x = outer",
|
||||
"call modify",
|
||||
"${x}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "outer");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ClearCallStackRunsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"clear_call_stack",
|
||||
"var result = ok",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "ok");
|
||||
}
|
||||
|
||||
// --- Error path tests ---
|
||||
|
||||
[TestMethod]
|
||||
public void AccessInWithoutArgFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"goto main",
|
||||
"func noin:",
|
||||
"var x = %in",
|
||||
"return",
|
||||
"label main:",
|
||||
"call noin"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "No in argument in stack");
|
||||
}
|
||||
|
||||
// --- Nested scope tests ---
|
||||
|
||||
[TestMethod]
|
||||
public void GlobalModifiedInsideFunctionIsVisibleAfterReturnTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"goto main",
|
||||
"func setglobal:",
|
||||
"global shared = modified",
|
||||
"return",
|
||||
"label main:",
|
||||
"global shared = original",
|
||||
"call setglobal",
|
||||
"${shared}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "modified");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void NestedFunctionCallsHaveIndependentLocalScopesTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"goto main",
|
||||
"func outer:",
|
||||
"var x = outer_val",
|
||||
"call inner",
|
||||
"push_out ${x}",
|
||||
"return",
|
||||
"func inner:",
|
||||
"var x = inner_val",
|
||||
"return",
|
||||
"label main:",
|
||||
"call outer",
|
||||
"var result = %out",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "outer_val");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class ListStatementsTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ListCreateAddGetTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list items new",
|
||||
"list items add a",
|
||||
"list items add b",
|
||||
"list items get 1",
|
||||
"var result = %out",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "b");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListSetAndInsertTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list items new",
|
||||
"list items add a",
|
||||
"list items add c",
|
||||
"list items insert 1 b",
|
||||
"list items set 2 d",
|
||||
"list items get 2",
|
||||
"var result = %out",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "d");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListRemoveAndLengthTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list items new",
|
||||
"list items add a",
|
||||
"list items add b",
|
||||
"list items add c",
|
||||
"list items remove 1",
|
||||
"list items length",
|
||||
"var len = %out",
|
||||
"${len}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "2");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListClearTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list items new",
|
||||
"list items add a",
|
||||
"list items clear",
|
||||
"list items length",
|
||||
"var len = %out",
|
||||
"${len}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "0");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListDeleteTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list items new",
|
||||
"list items delete",
|
||||
"list items length"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "List \"items\" not found");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListMissingFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list missing get 0"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "List \"missing\" not found");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListInvalidIndexFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list items new",
|
||||
"list items add a",
|
||||
"list items get 3"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Index 3 out of range");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListInvalidSyntaxFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list items add"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListScopeInsideFunctionTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"goto main",
|
||||
"func make:",
|
||||
"list items new",
|
||||
"list items add x",
|
||||
"list items get 0",
|
||||
"push_out %out",
|
||||
"return",
|
||||
"label main:",
|
||||
"call make",
|
||||
"var result = %out",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "x");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ListAddWithSpacesTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list items new",
|
||||
"list items add \"hello world\"",
|
||||
"list items get 0",
|
||||
"var result = %out eval",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "hello world");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class PredefinedVariableStatementsTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void TimeTokenProducesUnixTimestampTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"%time"
|
||||
];
|
||||
|
||||
string? value = YesNtAssert.GetLastLine(lines);
|
||||
Assert.IsNotNull(value);
|
||||
Assert.IsTrue(long.TryParse(value, out long parsed));
|
||||
|
||||
long now = DateTimeOffset.Now.ToUnixTimeSeconds();
|
||||
Assert.IsTrue(Math.Abs(now - parsed) < 10);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OsTokenProducesValueTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"%os"
|
||||
];
|
||||
|
||||
string? value = YesNtAssert.GetLastLine(lines);
|
||||
Assert.IsFalse(string.IsNullOrWhiteSpace(value));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CpuTokenProducesValueTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"%cpu"
|
||||
];
|
||||
|
||||
string? value = YesNtAssert.GetLastLine(lines);
|
||||
Assert.IsFalse(string.IsNullOrWhiteSpace(value));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Is64TokenProducesBooleanTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"%is64"
|
||||
];
|
||||
|
||||
string? value = YesNtAssert.GetLastLine(lines);
|
||||
Assert.AreEqual(Environment.Is64BitOperatingSystem.ToString(), value);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PiTokenProducesPiTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"%pi"
|
||||
];
|
||||
|
||||
string? value = YesNtAssert.GetLastLine(lines);
|
||||
Assert.IsNotNull(value);
|
||||
Assert.IsTrue(double.TryParse(value, out double parsed));
|
||||
Assert.IsTrue(Math.Abs(parsed - Math.PI) < 0.001d);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void RandTokenProducesIntegerTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"%rand"
|
||||
];
|
||||
|
||||
string? value = YesNtAssert.GetLastLine(lines);
|
||||
Assert.IsNotNull(value);
|
||||
Assert.IsTrue(int.TryParse(value, out int parsed));
|
||||
Assert.IsTrue(parsed >= 32767);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MultipleRandTokensAreReplacedTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"%rand %rand"
|
||||
];
|
||||
|
||||
string? value = YesNtAssert.GetLastLine(lines);
|
||||
Assert.IsNotNull(value);
|
||||
|
||||
string[] parts = value.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
Assert.AreEqual(2, parts.Length);
|
||||
Assert.IsTrue(int.TryParse(parts[0], out _));
|
||||
Assert.IsTrue(int.TryParse(parts[1], out _));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class ProcessingStatementsTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void MultiplicationTest()
|
||||
{
|
||||
YesNtAssert.IsLineEqual("10 * 10 calc", "100");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DivisionTest()
|
||||
{
|
||||
YesNtAssert.IsLineEqual("90 / 4 calc", "22.5");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AdditionTest()
|
||||
{
|
||||
YesNtAssert.IsLineEqual("10 + 10 calc", "20");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SubtractionTest()
|
||||
{
|
||||
YesNtAssert.IsLineEqual("10 - 10 calc", "0");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ModulusTest()
|
||||
{
|
||||
YesNtAssert.IsLineEqual("10 % 3 calc", "1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ExponentiationTest()
|
||||
{
|
||||
YesNtAssert.IsLineEqual("2 ^ 3 calc", "8");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EvalRawTildeSequenceIsLiteralTest()
|
||||
{
|
||||
YesNtAssert.IsLineEqual("hello~nliworld eval", "hello~nliworld");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EvalDecodesStringLiteralEscapesTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = \"hello\\nworld\"",
|
||||
"${x} eval"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "hello\nworld");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CalcRespectsPrecedenceTest()
|
||||
{
|
||||
YesNtAssert.IsLineEqual("2 + 3 * 4 calc", "14");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void CalcParenthesesOverridePrecedenceTest()
|
||||
{
|
||||
YesNtAssert.IsLineEqual("(2 + 3) * 4 calc", "20");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SleepZeroIsValidTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"sleep 0",
|
||||
"var result = ok",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "ok");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SleepInvalidValueFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"sleep nope"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "\"nope\" is not a valid time-out value");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SleepRunsAndContinuesTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"sleep 5",
|
||||
"var result = ok",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "ok");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LengthPushesOutParameterTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"length hello",
|
||||
"var value = %out",
|
||||
"${value}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "5");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ImportLoadsScriptTest()
|
||||
{
|
||||
string tempFile = Path.Combine(Path.GetTempPath(), $"yesnt-import-{Guid.NewGuid():N}.ynt");
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(tempFile, "var imported = yes");
|
||||
|
||||
List<string> lines =
|
||||
[
|
||||
$"import {tempFile}",
|
||||
"${imported}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "yes");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (File.Exists(tempFile))
|
||||
{
|
||||
File.Delete(tempFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ImportMissingFileFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
$"import {Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"))}.ynt"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Could not find file");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TaskCanUpdateGlobalVariableTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"global result = 0",
|
||||
"global result = 1 task",
|
||||
"while ${result} == 0:",
|
||||
"sleep 10",
|
||||
"end_while",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "1", timeout: 3000);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MultipleTasksRunConcurrentlyTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"global a = 0",
|
||||
"global b = 0",
|
||||
"global a = 1 task",
|
||||
"global b = 2 task",
|
||||
"while ${a} == 0:",
|
||||
"sleep 10",
|
||||
"end_while",
|
||||
"while ${b} == 0:",
|
||||
"sleep 10",
|
||||
"end_while",
|
||||
"${b}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "2", timeout: 3000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class StringLiteralStatementsTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void StringLiteralWithSpacesWorksTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var msg = \"hello world\"",
|
||||
"${msg}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "hello world");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void StringLiteralEscapesWorkTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var msg = \"a\\n\\t\\\"b\"",
|
||||
"${msg}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "a\n\t\"b");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void StringLiteralPreventsVariableInterpolationTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = hidden",
|
||||
"print_line \"${x}\""
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsDebugOutput(lines, "${x}");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void StringLiteralWorksWithListAddTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"list items new",
|
||||
"list items add \"hello world\"",
|
||||
"list items get 0",
|
||||
"var result = %out",
|
||||
"${result}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "hello world");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EmptyStringLiteralHasLengthZeroTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = \"\"",
|
||||
"length ${x}",
|
||||
"var len = %out",
|
||||
"${len}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "0");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EscapedBackslashProducesLiteralBackslashTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var msg = \"\\\\n\"", // YesNt source: "\\n" → \n (backslash + n, 2 chars)
|
||||
"length ${msg}",
|
||||
"var len = %out",
|
||||
"${len}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "2");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UnknownEscapeSequenceBecomesCharTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var msg = \"\\q\"", // YesNt source: "\q" → q (1 char)
|
||||
"length ${msg}",
|
||||
"var len = %out",
|
||||
"${len}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "1");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void UnterminatedStringLiteralFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var msg = \"hello"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Invalid string literal");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class SystemStatementsTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ExecWithArgsRunsProcessTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"exec cmd with /c,echo yesnt",
|
||||
"var exitCode = %out",
|
||||
"${exitCode}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "0");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ExecWithInStackArgsRunsProcessTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"push_in /c",
|
||||
"push_in echo yesnt",
|
||||
"exec cmd",
|
||||
"var exitCode = %out",
|
||||
"${exitCode}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "0");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ExecInvalidProgramFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"exec does_not_exist_abc_xyz"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Failed to start \"does_not_exist_abc_xyz\"");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class VariableStatementsTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void LetAndReadVariableTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var value = hi",
|
||||
"${value}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "hi");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GlobalVariableReadTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"global value = hi",
|
||||
"${value}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "hi");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LocalVariableOverridesGlobalTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"global value = global",
|
||||
"var value = local",
|
||||
"${value}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "local");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DeleteLocalVariableTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var value = a",
|
||||
"delete value",
|
||||
"global value = b",
|
||||
"${value}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "b");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DeleteMissingVariableFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"delete missing"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Variable \"missing\" not found");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LetInvalidSyntaxFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var a"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Invalid statement");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void LetInvalidNameFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var a b = 1"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Invalid syntax");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OverwriteVariableTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = first",
|
||||
"var x = second",
|
||||
"${x}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "second");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void EmptyStringVariableHasLengthZeroTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"var x = \"\"",
|
||||
"length ${x}",
|
||||
"var len = %out",
|
||||
"${len}"
|
||||
];
|
||||
|
||||
YesNtAssert.IsLastLineEqual(lines, "0");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MissingVariableReferenceFailsTest()
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
"${missing}"
|
||||
];
|
||||
|
||||
YesNtAssert.ContainsTerminationMessage(lines, "Variable \"missing\" not found");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="4.1.0" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="4.1.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="8.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\YesNt.Interpreter\YesNt.Interpreter.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,126 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
using YesNt.Interpreter.Runtime;
|
||||
|
||||
namespace YesNt.Interpreter.Tests;
|
||||
|
||||
internal static class YesNtAssert
|
||||
{
|
||||
public static void IsLastLineEqual(List<string> lines, string expected, int timeout = 1000)
|
||||
{
|
||||
(DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout);
|
||||
Assert.AreEqual(expected, debugEventArgs?.CurrentLine);
|
||||
}
|
||||
|
||||
public static void IsLineEqual(string line, string expected, int timeout = 1000)
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
line
|
||||
];
|
||||
|
||||
(DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout);
|
||||
Assert.AreEqual(expected, debugEventArgs?.CurrentLine);
|
||||
}
|
||||
|
||||
public static void IsLineNotEqual(string line, string expected, int timeout = 1000)
|
||||
{
|
||||
List<string> lines =
|
||||
[
|
||||
line
|
||||
];
|
||||
|
||||
(DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout);
|
||||
Assert.AreNotEqual(expected, debugEventArgs?.CurrentLine);
|
||||
}
|
||||
|
||||
public static void ContainsTerminationMessage(List<string> lines, string expectedMessageFragment, int timeout = 1000)
|
||||
{
|
||||
(_, string debugOutput) = ExecuteAndCapture(lines, timeout);
|
||||
|
||||
StringAssert.Contains(debugOutput, expectedMessageFragment);
|
||||
}
|
||||
|
||||
public static void ContainsDebugOutput(List<string> lines, string expectedFragment, int timeout = 1000)
|
||||
{
|
||||
(_, string debugOutput) = ExecuteAndCapture(lines, timeout);
|
||||
|
||||
StringAssert.Contains(debugOutput, expectedFragment);
|
||||
}
|
||||
|
||||
public static string? GetLastLine(List<string> lines, int timeout = 1000)
|
||||
{
|
||||
(DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout);
|
||||
return debugEventArgs?.CurrentLine;
|
||||
}
|
||||
|
||||
public static void LastLineMatches(List<string> lines, string pattern, int timeout = 1000)
|
||||
{
|
||||
string? value = GetLastLine(lines, timeout);
|
||||
Assert.IsNotNull(value);
|
||||
StringAssert.Matches(value, new Regex(pattern));
|
||||
}
|
||||
|
||||
public static void IsLastLineEqualWithSetup(List<string> lines, string expected, Action<YesNtInterpreter> setup, int timeout = 1000)
|
||||
{
|
||||
(DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout, setup);
|
||||
Assert.AreEqual(expected, debugEventArgs?.CurrentLine);
|
||||
}
|
||||
|
||||
public static void ContainsDebugOutputWithSetup(List<string> lines, string expectedFragment, Action<YesNtInterpreter> setup, int timeout = 1000)
|
||||
{
|
||||
(_, string debugOutput) = ExecuteAndCapture(lines, timeout, setup);
|
||||
StringAssert.Contains(debugOutput, expectedFragment);
|
||||
}
|
||||
|
||||
public static void ContainsTerminationMessageWithSetup(List<string> lines, string expectedMessageFragment, Action<YesNtInterpreter> setup, int timeout = 1000)
|
||||
{
|
||||
(_, string debugOutput) = ExecuteAndCapture(lines, timeout, setup);
|
||||
StringAssert.Contains(debugOutput, expectedMessageFragment);
|
||||
}
|
||||
|
||||
public static string? GetLastLineWithSetup(List<string> lines, Action<YesNtInterpreter> setup, int timeout = 1000)
|
||||
{
|
||||
(DebugEventArgs? debugEventArgs, _) = ExecuteAndCapture(lines, timeout, setup);
|
||||
return debugEventArgs?.CurrentLine;
|
||||
}
|
||||
|
||||
private static (DebugEventArgs? LastDebugEvent, string DebugOutput) ExecuteAndCapture(List<string> lines, int timeout, Action<YesNtInterpreter>? setup = null)
|
||||
{
|
||||
YesNtInterpreter yesNtInterpreter = new YesNtInterpreter();
|
||||
setup?.Invoke(yesNtInterpreter);
|
||||
|
||||
AutoResetEvent onDone = new AutoResetEvent(false);
|
||||
DebugEventArgs? debugEventArgs = null;
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
|
||||
yesNtInterpreter.OnLineExecuted += (er) =>
|
||||
{
|
||||
if (er is not null)
|
||||
{
|
||||
debugEventArgs = er;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = onDone.Set();
|
||||
}
|
||||
};
|
||||
|
||||
yesNtInterpreter.OnDebugOutput += (s) =>
|
||||
{
|
||||
_ = outputBuilder.Append(s);
|
||||
};
|
||||
|
||||
yesNtInterpreter.Execute(lines, true);
|
||||
|
||||
_ = onDone.WaitOne(TimeSpan.FromMilliseconds(timeout));
|
||||
|
||||
return (debugEventArgs, outputBuilder.ToString());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user