Skip to content

Commit

Permalink
Merge pull request #47 from EvoEsports/feature/more-tests
Browse files Browse the repository at this point in the history
Add more test cases for MtTransformer
  • Loading branch information
araszka authored Feb 4, 2024
2 parents 1eb781c + f2dfd5a commit 9657b5e
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 12 deletions.
16 changes: 16 additions & 0 deletions src/ManiaTemplates/Exceptions/CurlyBraceCountMismatchException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace ManiaTemplates.Exceptions;

public class CurlyBraceCountMismatchException : Exception
{
public CurlyBraceCountMismatchException()
{
}

public CurlyBraceCountMismatchException(string message) : base(message)
{
}

public CurlyBraceCountMismatchException(string message, Exception inner) : base(message, inner)
{
}
}
16 changes: 16 additions & 0 deletions src/ManiaTemplates/Exceptions/EmptyNodeAttributeException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace ManiaTemplates.Exceptions;

public class EmptyNodeAttributeException : Exception
{
public EmptyNodeAttributeException()
{
}

public EmptyNodeAttributeException(string message) : base(message)
{
}

public EmptyNodeAttributeException(string message, Exception inner) : base(message, inner)
{
}
}
16 changes: 16 additions & 0 deletions src/ManiaTemplates/Exceptions/InterpolationRecursionException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace ManiaTemplates.Exceptions;

public class InterpolationRecursionException : Exception
{
public InterpolationRecursionException()
{
}

public InterpolationRecursionException(string message) : base(message)
{
}

public InterpolationRecursionException(string message, Exception inner) : base(message, inner)
{
}
}
81 changes: 71 additions & 10 deletions src/ManiaTemplates/Lib/MtTransformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public string BuildManialink(MtComponent rootComponent, string className, int ve
/// </summary>
private string CreateDoNothingMethod()
{
return _maniaTemplateLanguage.FeatureBlock(@"string DoNothing(){return """";}").ToString();
return _maniaTemplateLanguage.FeatureBlock("""string DoNothing(){ return ""; }""").ToString();
}

/// <summary>
Expand Down Expand Up @@ -121,7 +121,7 @@ private string CreateBodyRenderMethod(string body, MtDataContext context, MtComp
bodyRenderMethod.AppendLine($"var __data = {renderBodyArguments};");

//Root mania script block
string rootScriptBlock = "";
var rootScriptBlock = "";
if (rootComponent.Scripts.Count > 0)
{
rootScriptBlock = CreateManiaScriptBlock(rootComponent);
Expand Down Expand Up @@ -388,8 +388,15 @@ private Dictionary<string, string> GetSlotContentsBySlotName(XmlNode componentNo
continue;
}

//Get the name from the slot attribute, or default if not found.
var slotName = childNode.Attributes?["slot"]?.Value.ToLower() ?? "default";

if (slotName.Trim().Length == 0)
{
throw new EmptyNodeAttributeException(
$"There's a template tag with empty slot name in <{componentNode.Name}></>.");
}

if (slotName == "default")
{
//Do not strip contents for default slot from node
Expand Down Expand Up @@ -779,15 +786,15 @@ private string CreateManiaScriptDirectivesBlock()
}

/// <summary>
/// Checks the attribute list for if-condition and returns it, else null.
/// Checks the attribute list for if-condition and if found removes & returns it, else null.
/// </summary>
private string? GetIfConditionFromNodeAttributes(MtComponentAttributes attributeList)
{
return attributeList.ContainsKey("if") ? attributeList.Pull("if") : null;
}

/// <summary>
/// Checks the attribute list for name and returns it, else "default".
/// Checks the attribute list for name and if found removes & returns it, else "default".
/// </summary>
private string GetNameFromNodeAttributes(MtComponentAttributes attributeList)
{
Expand Down Expand Up @@ -926,7 +933,7 @@ private static string CreateContextClassProperties(MtDataContext context)
/// <summary>
/// Parses the attributes of a XmlNode to an MtComponentAttributes-instance.
/// </summary>
private static MtComponentAttributes GetXmlNodeAttributes(XmlNode node)
public static MtComponentAttributes GetXmlNodeAttributes(XmlNode node)
{
var attributeList = new MtComponentAttributes();
if (node.Attributes == null) return attributeList;
Expand All @@ -944,6 +951,8 @@ private static MtComponentAttributes GetXmlNodeAttributes(XmlNode node)
/// </summary>
private string BuildManiaScripts(MtComponent rootComponent)
{
//TODO: check if method can be removed

var maniaScripts = rootComponent.Scripts.ToDictionary(script => script.ContentHash());
foreach (var (key, value) in _maniaScripts)
{
Expand Down Expand Up @@ -1009,7 +1018,7 @@ private static MtDataContext GetContextFromComponent(MtComponent component, stri
/// Returns C# code representation of the type.
/// </summary>
/// <param name="type">The type.</param>
private static string GetFormattedName(Type type)
public static string GetFormattedName(Type type)
{
if (type.IsSubclassOf(typeof(DynamicObject)))
{
Expand Down Expand Up @@ -1085,7 +1094,7 @@ public static string WrapStringInQuotes(string str)
/// name = Shown in in-game debugger.
/// version = Version for the markup language of Trackmania.
/// </summary>
private static string ManiaLinkStart(string name, int version = 3, string? displayLayer = null)
public static string ManiaLinkStart(string name, int version = 3, string? displayLayer = null)
{
var layer = "";
if (displayLayer != null)
Expand All @@ -1107,7 +1116,7 @@ private static string ManiaLinkEnd()
/// <summary>
/// Creates a xml opening tag for the given string and attribute list.
/// </summary>
private string CreateXmlOpeningTag(string tag, MtComponentAttributes attributeList, bool hasChildren)
public string CreateXmlOpeningTag(string tag, MtComponentAttributes attributeList, bool hasChildren)
{
var output = $"<{tag}";

Expand Down Expand Up @@ -1136,7 +1145,7 @@ private static string CreateXmlClosingTag(string tag)
/// <summary>
/// Converts any valid XML-string into an XmlNode-element.
/// </summary>
private static XmlNode XmlStringToNode(string content)
public static XmlNode XmlStringToNode(string content)
{
var doc = new XmlDocument();
doc.LoadXml($"<doc>{content}</doc>");
Expand All @@ -1149,6 +1158,9 @@ private static XmlNode XmlStringToNode(string content)
/// </summary>
public static string ReplaceCurlyBraces(string value, Func<string, string> curlyContentWrapper)
{
CheckForCurlyBraceCountMismatch(value);
CheckInterpolationRecursion(value);

var matches = TemplateInterpolationRegex.Match(value);
var output = value;

Expand All @@ -1165,10 +1177,59 @@ public static string ReplaceCurlyBraces(string value, Func<string, string> curly
return output;
}

/// <summary>
/// Checks whether double interpolation exists ({{ {{ a }} {{ b }} }}) and throws exception if so.
/// </summary>
public static void CheckInterpolationRecursion(string value)
{
var openCurlyBraces = 0;
foreach (var character in value.ToCharArray())
{
if (character == '{')
{
openCurlyBraces++;

if (openCurlyBraces >= 4)
{
throw new InterpolationRecursionException(
$"Double interpolation found in: {value}. You must not use double curly braces inside other double curly braces.");
}
}
else if (character == '}')
{
openCurlyBraces--;
}
}
}

/// <summary>
/// Checks whether double interpolation exists ({{ {{ a }} {{ b }} }}) and throws exception if so.
/// </summary>
public static void CheckForCurlyBraceCountMismatch(string value)
{
var openCurlyBraces = 0;
foreach (var character in value.ToCharArray())
{
if (character == '{')
{
openCurlyBraces++;
}
else if (character == '}')
{
openCurlyBraces--;
}
}

if (openCurlyBraces != 0)
{
throw new CurlyBraceCountMismatchException($"Found curly brace count mismatch in: {value}.");
}
}

/// <summary>
/// Joins consecutive feature blocks to reduce generated code.
/// </summary>
private static string JoinFeatureBlocks(string manialink)
public static string JoinFeatureBlocks(string manialink)
{
var match = TemplateFeatureControlRegex.Match(manialink);
var output = new Snippet();
Expand Down
87 changes: 86 additions & 1 deletion tests/ManiaTemplates.Tests/Lib/MtTransformerTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml;
using ManiaTemplates.Components;
using ManiaTemplates.Exceptions;
using ManiaTemplates.Languages;
using ManiaTemplates.Lib;
using Xunit.Abstractions;
Expand All @@ -13,6 +15,7 @@ public class MtTransformerTest
private readonly MtTransformer _transformer;
private readonly ManiaTemplateEngine _maniaTemplateEngine = new();
private readonly Regex _hashCodePattern = new("[0-9]{6,10}");

private readonly MtComponent _testComponent = new()
{
Namespaces = new() { "namespace" },
Expand Down Expand Up @@ -131,7 +134,25 @@ public void Should_Import_Components_Recursively()
}

[Fact]
public void Should_Replace_Curly_Braces_Correctly()
public void Should_Throw_Interpolation_Recursion_Exception()
{
Assert.Throws<InterpolationRecursionException>(() =>
MtTransformer.CheckInterpolationRecursion("{{ {{ a }} {{ b }} }}"));
Assert.Throws<InterpolationRecursionException>(() =>
MtTransformer.CheckInterpolationRecursion("{{ {{ b }} }}"));
}

[Fact]
public void Should_Throw_Curly_Brace_Count_Mismatch_Exception()
{
Assert.Throws<CurlyBraceCountMismatchException>(() => MtTransformer.CheckForCurlyBraceCountMismatch("{{ { }}"));
Assert.Throws<CurlyBraceCountMismatchException>(() => MtTransformer.CheckForCurlyBraceCountMismatch("{{ } }}"));
Assert.Throws<CurlyBraceCountMismatchException>(() => MtTransformer.CheckForCurlyBraceCountMismatch("{"));
Assert.Throws<CurlyBraceCountMismatchException>(() => MtTransformer.CheckForCurlyBraceCountMismatch("}}"));
}

[Fact]
public void Should_Replace_Curly_Braces()
{
Assert.Equal("abcd", MtTransformer.ReplaceCurlyBraces("{{a}}{{ b }}{{c }}{{ d}}", s => s));
Assert.Equal("x y z", MtTransformer.ReplaceCurlyBraces("{{x}} {{ y }} {{z }}", s => s));
Expand All @@ -144,5 +165,69 @@ public void Should_Replace_Curly_Braces_Correctly()
public void Should_Wrap_Strings_In_Quotes()
{
Assert.Equal(@"$""unit test""", MtTransformer.WrapStringInQuotes("unit test"));
Assert.Equal(@"$""""", MtTransformer.WrapStringInQuotes(""));
}

[Fact]
public void Should_Join_Feature_Blocks()
{
Assert.Equal("<#+\n unittest \n#>",
MtTransformer.JoinFeatureBlocks("<#+#><#+\n #> <#+ unittest \n#><#+ \n\n\n#>"));
}

[Fact]
public void Should_Convert_String_To_Xml_Node()
{
var node = MtTransformer.XmlStringToNode("<unit>test</unit>");
Assert.IsAssignableFrom<XmlNode>(node);
Assert.Equal("test", node.InnerText);
Assert.Equal("<unit>test</unit>", node.InnerXml);
Assert.Equal("<doc><unit>test</unit></doc>", node.OuterXml);
}

[Fact]
public void Should_Create_Xml_Opening_Tag()
{
var attributeList = new MtComponentAttributes();
Assert.Equal("<test />", _transformer.CreateXmlOpeningTag("test", attributeList, false));
Assert.Equal("<test>", _transformer.CreateXmlOpeningTag("test", attributeList, true));

attributeList["prop"] = "value";
Assert.Equal("""<test prop="value" />""", _transformer.CreateXmlOpeningTag("test", attributeList, false));
Assert.Equal("""<test prop="value">""", _transformer.CreateXmlOpeningTag("test", attributeList, true));
}

[Fact]
public void Should_Create_ManiaLink_Opening_Tag()
{
Assert.Equal("""<manialink version="99" id="Test" name="EvoSC#-Test">""",
MtTransformer.ManiaLinkStart("Test", 99));
Assert.Equal("""<manialink version="99" id="Test" name="EvoSC#-Test" layer="SomeLayer">""",
MtTransformer.ManiaLinkStart("Test", 99, "SomeLayer"));
}

[Fact]
public void Should_Convert_Xml_Node_Arguments_To_MtComponentAttributes_Instance()
{
var node = MtTransformer.XmlStringToNode("""<testNode arg1="test1" arg2="test2">testContent</testNode>""");
if (node.FirstChild == null) return;

var attributes = MtTransformer.GetXmlNodeAttributes(node.FirstChild);
Assert.Equal(2, attributes.Count);
Assert.Equal("test1", attributes["arg1"]);
Assert.Equal("test2", attributes["arg2"]);
}

[Fact]
public void Should_Detect_Correct_Type_String_For_CSharp_Scripting()
{
Assert.Equal("int", MtTransformer.GetFormattedName(0.GetType()));
Assert.Equal("double", MtTransformer.GetFormattedName(0.0.GetType()));
Assert.Equal("string", MtTransformer.GetFormattedName("test".GetType()));
Assert.Equal("System.Collections.Generic.List<string>",
MtTransformer.GetFormattedName(new List<string>().GetType()));
Assert.Equal("System.Collections.Generic.HashSet<string>",
MtTransformer.GetFormattedName(new HashSet<string>().GetType()));
Assert.Equal("dynamic", MtTransformer.GetFormattedName(new TestDynamicObject().GetType()));
}
}
7 changes: 7 additions & 0 deletions tests/ManiaTemplates.Tests/Lib/TestDynamicObject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using System.Dynamic;

namespace ManiaTemplates.Tests.Lib;

public class TestDynamicObject : DynamicObject
{
}
2 changes: 1 addition & 1 deletion tests/ManiaTemplates.Tests/Lib/expected.tt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ i = data.i;
}
List<string> __insertedOneTimeManiaScripts = new List<string>();
List<Action> __maniaScriptRenderMethods = new List<Action>();
string DoNothing(){return "";}
string DoNothing(){ return ""; }
void RenderBody() {
var __data = new CRoot { numbers = numbers,enabled = enabled };
var __outerIndex1 = 0;
Expand Down

0 comments on commit 9657b5e

Please sign in to comment.