diff --git a/.gitignore b/.gitignore index e5e574e..06a2f4f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ obj/ /packages/ riderModule.iml /_ReSharper.Caches/\ -/.idea/ \ No newline at end of file +/.idea/ +Htmt.sln.DotSettings.user diff --git a/Htmt/AttributeParsers/GenericValueAttributeParser.cs b/Htmt/AttributeParsers/GenericValueAttributeParser.cs index 2419939..f60c152 100644 --- a/Htmt/AttributeParsers/GenericValueAttributeParser.cs +++ b/Htmt/AttributeParsers/GenericValueAttributeParser.cs @@ -5,7 +5,7 @@ namespace Htmt.AttributeParsers; public class GenericValueAttributeParser : IAttributeParser { public string XTag => "//*[@*[starts-with(name(), 'x:')]]"; - + public void Parse(XmlDocument xml, Dictionary data, XmlNodeList? nodes) { // No nodes found @@ -13,15 +13,15 @@ public void Parse(XmlDocument xml, Dictionary data, XmlNodeList { return; } - + foreach (var node in nodes) { if (node is not XmlElement n) continue; - + var attributes = n.Attributes.Cast() .Where(a => a.Name.StartsWith("x:")) .ToList(); - + foreach (var attr in attributes) { var val = n.GetAttribute(attr.Name); diff --git a/Htmt/AttributeParsers/IfAttributeParser.cs b/Htmt/AttributeParsers/IfAttributeParser.cs index df8ec00..be66b5f 100644 --- a/Htmt/AttributeParsers/IfAttributeParser.cs +++ b/Htmt/AttributeParsers/IfAttributeParser.cs @@ -6,7 +6,7 @@ namespace Htmt.AttributeParsers; public class IfAttributeParser : IAttributeParser { public string XTag => "//*[@x:if]"; - + public void Parse(XmlDocument xml, Dictionary data, XmlNodeList? nodes) { // No nodes found @@ -21,7 +21,7 @@ public void Parse(XmlDocument xml, Dictionary data, XmlNodeList var key = n.GetAttribute("x:if"); n.RemoveAttribute("x:if"); - + // if key is a single word, we just check for a truthy value if (!key.Contains(' ')) { @@ -51,12 +51,12 @@ public void Parse(XmlDocument xml, Dictionary data, XmlNodeList n.ParentNode?.RemoveChild(n); } } - + // if key contains multiple words, evaluate the expression with ExpressionValidator else { - var expression = new ExpressionValidator(key); - var result = expression.Validates(data); + var validator = new ExpressionBooleanValidator(key); + var result = validator.Validates(data); if (!result) { diff --git a/Htmt/AttributeParsers/UnlessAttributeParser.cs b/Htmt/AttributeParsers/UnlessAttributeParser.cs index b53f0f6..ef54031 100644 --- a/Htmt/AttributeParsers/UnlessAttributeParser.cs +++ b/Htmt/AttributeParsers/UnlessAttributeParser.cs @@ -6,7 +6,7 @@ namespace Htmt.AttributeParsers; public class UnlessAttributeParser : IAttributeParser { public string XTag => "//*[@x:unless]"; - + public void Parse(XmlDocument xml, Dictionary data, XmlNodeList? nodes) { // No nodes found @@ -21,7 +21,7 @@ public void Parse(XmlDocument xml, Dictionary data, XmlNodeList var key = n.GetAttribute("x:unless"); n.RemoveAttribute("x:unless"); - + // if key is a single word, we just check for a truthy value if (!key.Contains(' ')) { @@ -47,8 +47,8 @@ public void Parse(XmlDocument xml, Dictionary data, XmlNodeList // if key contains multiple words, evaluate the expression with ExpressionValidator else { - var expression = new ExpressionValidator(key); - var result = expression.Validates(data); + var validator = new ExpressionBooleanValidator(key); + var result = validator.Validates(data); if (result) { diff --git a/Htmt/ExpressionValidator.cs b/Htmt/ExpressionBooleanValidator.cs similarity index 93% rename from Htmt/ExpressionValidator.cs rename to Htmt/ExpressionBooleanValidator.cs index 743adc2..ac64085 100644 --- a/Htmt/ExpressionValidator.cs +++ b/Htmt/ExpressionBooleanValidator.cs @@ -3,7 +3,7 @@ namespace Htmt; -public class ExpressionValidator(string expression) +public class ExpressionBooleanValidator(string expression) { public bool Validates(Dictionary data) { @@ -14,27 +14,27 @@ private string Normalize(Dictionary data) { var evaluatedExpression = expression; var keyMatches = Regex.Matches(expression, """'(?[^']*)'|(?\w+)"""); - + foreach (Match match in keyMatches) { // if this is not a key, skip if (match.Groups["key"].Success == false) continue; - + var key = match.Groups["key"].Value; - + // skip if the key is an operator if (key is "is" or "and" or "or" or "not") continue; - + // skip if key is integer, double, float, boolean, null or string if (int.TryParse(key, out _)) continue; if (double.TryParse(key, out _)) continue; if (float.TryParse(key, out _)) continue; if (bool.TryParse(key, out _)) continue; if (key == "null") continue; - + var value = Helper.FindValueByKeys(data, key.Split('.')); var regex = new Regex($@"{key}"); - + // if value is bool, lowercase it if (value is bool b) { @@ -44,11 +44,11 @@ private string Normalize(Dictionary data) evaluatedExpression = regex.Replace(evaluatedExpression, value?.ToString() ?? "null", 1); } - + // remove single quotes from string values return Regex.Replace(evaluatedExpression, "'(.*?)'", "$1"); } - + private static bool EvaluateExp(string exp) { while (exp.Contains('(')) @@ -60,10 +60,10 @@ private static bool EvaluateExp(string exp) { throw new SyntaxErrorException("Invalid expression"); } - + var subExp = exp.Substring(openIndex + 1, closeIndex - openIndex - 1); var subResult = EvaluateSimpleExp(subExp); - + exp = exp.Substring(0, openIndex) + subResult.ToString().ToLower() + exp.Substring(closeIndex + 1); } @@ -83,10 +83,10 @@ private static bool EvaluateSimpleExp(string exp) { andResult &= EvaluateCondition(andPart.Trim()); } - + if (andResult) return true; } - + return false; } @@ -94,25 +94,25 @@ private static bool EvaluateCondition(string condition) { if (condition == "true") return true; if (condition == "false") return false; - + if (condition.Contains(" is ")) { var parts = condition.Split([" is "], StringSplitOptions.None); var key = parts[0].Trim(); var value = parts[1].Trim(); - + return key == value; } - + if (condition.Contains(" not ")) { var parts = condition.Split([" not "], StringSplitOptions.None); var key = parts[0].Trim(); var value = parts[1].Trim(); - + return key != value; } - + throw new SyntaxErrorException("Invalid condition"); } } \ No newline at end of file diff --git a/Htmt/ExpressionModifierParser.cs b/Htmt/ExpressionModifierParser.cs new file mode 100644 index 0000000..4a0ce6b --- /dev/null +++ b/Htmt/ExpressionModifierParser.cs @@ -0,0 +1,38 @@ +using System; + +namespace Htmt; + +public class ExpressionModifierParser +{ + public Dictionary Data { get; init; } = []; + + public IExpressionModifier[] ExpressionModifiers { get; init; } = []; + + public object? Parse(string expression) + { + var parts = expression.Split('|', StringSplitOptions.TrimEntries); + var key = parts[0]; + var value = Helper.FindValueByKeys(Data, key.Split('.')); + + // No expression modifiers found + if (parts.Length == 1) + { + return value; + } + + var modifier = parts[1]; + var modifierName = modifier.Split(':', StringSplitOptions.TrimEntries)[0]; + var modifierArgs = modifier.Contains(':') ? modifier.Split(':', StringSplitOptions.TrimEntries)[1] : null; + + // Find the modifier instance + var modifierInstance = ExpressionModifiers.FirstOrDefault(m => m.Name == modifierName); + + if (modifierInstance == null) + { + return value; + } + + // Off to the races. + return modifierInstance.Modify(value, modifierArgs); + } +} diff --git a/Htmt/ExpressionModifiers/DateExpressionModifier.cs b/Htmt/ExpressionModifiers/DateExpressionModifier.cs new file mode 100644 index 0000000..eea08e7 --- /dev/null +++ b/Htmt/ExpressionModifiers/DateExpressionModifier.cs @@ -0,0 +1,20 @@ +using System; + +namespace Htmt.ExpressionModifiers; + +public class DateExpressionModifier : IExpressionModifier +{ + public string Name => "date"; + + public object? Modify(object? value, string? args = null) + { + const string defaultFormat = "yyyy-MM-dd"; + + if (value is string s) + { + return !DateTime.TryParse(s, out var dtParsed) ? value : dtParsed.ToString(args ?? defaultFormat); + } + + return value is not DateTime dt ? value : dt.ToString(args ?? defaultFormat); + } +} diff --git a/Htmt/Helper.cs b/Htmt/Helper.cs index 479b6c3..bf676bc 100644 --- a/Htmt/Helper.cs +++ b/Htmt/Helper.cs @@ -1,6 +1,6 @@ using System.Globalization; using System.Text.RegularExpressions; -using System.Xml; +using Htmt.ExpressionModifiers; namespace Htmt; @@ -23,67 +23,82 @@ public partial class Helper switch (v) { case Dictionary dict: - { - var newKeys = keys.Skip(1).ToArray(); + { + var newKeys = keys.Skip(1).ToArray(); - data = dict; - keys = newKeys; - continue; - } + data = dict; + keys = newKeys; + continue; + } case Dictionary dict: - { - var newKeys = keys.Skip(1).ToArray(); + { + var newKeys = keys.Skip(1).ToArray(); - data = dict.ToDictionary(x => x.Key, object? (x) => x.Value); - keys = newKeys; - continue; - } + data = dict.ToDictionary(x => x.Key, object? (x) => x.Value); + keys = newKeys; + continue; + } case Dictionary dict: - { - var newKeys = keys.Skip(1).ToArray(); + { + var newKeys = keys.Skip(1).ToArray(); - data = dict.ToDictionary(x => x.Key, x => (object?) x.Value); - keys = newKeys; - continue; - } + data = dict.ToDictionary(x => x.Key, x => (object?)x.Value); + keys = newKeys; + continue; + } case Dictionary dict: - { - var newKeys = keys.Skip(1).ToArray(); - - data = dict.ToDictionary(x => x.Key, x => (object?) x.Value); - keys = newKeys; - continue; - } - + { + var newKeys = keys.Skip(1).ToArray(); + + data = dict.ToDictionary(x => x.Key, x => (object?)x.Value); + keys = newKeys; + continue; + } + default: return null; } } } - + [GeneratedRegex(@"(?\{.*?\})")] private static partial Regex WholeKeyRegex(); - + public static string ReplaceKeysWithData(string str, Dictionary data) { var matches = WholeKeyRegex().Matches(str).Select(x => x.Groups["name"].Value).ToArray(); - + foreach (var match in matches) { var strippedName = match[1..^1]; - var value = FindValueByKeys(data, strippedName.Split('.')); - - str = value switch + var modifiers = new IExpressionModifier[] { - string s => str.Replace(match, s), - int i => str.Replace(match, i.ToString()), - double d => str.Replace(match, d.ToString(CultureInfo.CurrentCulture)), - bool b => str.Replace(match, b.ToString()), - _ => str.Replace(match, "") + new DateExpressionModifier() }; + + var value = new ExpressionModifierParser { Data = data, ExpressionModifiers = modifiers }.Parse(strippedName); + + // print value + Console.WriteLine(value); + + if (value != null) + { + str = value switch + { + string s => str.Replace(match, s), + int i => str.Replace(match, i.ToString()), + double d => str.Replace(match, d.ToString(CultureInfo.CurrentCulture)), + bool b => str.Replace(match, b.ToString()), + _ => str.Replace(match, value.ToString()), + }; + } + else + { + str = str.Replace(match, ""); + } } - + return str; } } \ No newline at end of file diff --git a/Htmt/IExpressionModifier.cs b/Htmt/IExpressionModifier.cs new file mode 100644 index 0000000..e57ddc1 --- /dev/null +++ b/Htmt/IExpressionModifier.cs @@ -0,0 +1,10 @@ +using System; + +namespace Htmt; + +public interface IExpressionModifier +{ + public string Name { get; } + + public object? Modify(object? value, string? args = null); +} diff --git a/Htmt/Parser.cs b/Htmt/Parser.cs index 0701128..dcb309f 100644 --- a/Htmt/Parser.cs +++ b/Htmt/Parser.cs @@ -10,16 +10,16 @@ public partial class Parser public string Template { get; set; } = string.Empty; - public Dictionary Data { get; init; } = new(); + public Dictionary Data { get; init; } = []; public IAttributeParser[] AttributeParsers { get; init; } = []; - + private XmlNamespaceManager _nsManager = null!; - + private bool _isHtml; - + private string _docType = string.Empty; - + private readonly XmlReaderSettings _xmlSettings = new() { IgnoreWhitespace = true, @@ -28,29 +28,29 @@ public partial class Parser ValidationType = ValidationType.None, XmlResolver = null }; - + private const string HtmtNamespace = "http://www.w3.org/1999/xhtml"; private void Parse() { _nsManager = new XmlNamespaceManager(Xml.NameTable); _nsManager.AddNamespace("x", HtmtNamespace); - + if (IsHtml(Template)) { _isHtml = true; _docType = GetDoctype(Template); - + RemoveDoctype(); CloseVoidElements(); } - + TransformHtmlEntities(); - + var templateStr = $"{Template}"; using var reader = XmlReader.Create(new StringReader(templateStr), _xmlSettings); Xml.Load(reader); - + AddIdentifierToNodes(); RunAttributeParsers(); RemoveIdentifierFromNodes(); @@ -72,7 +72,7 @@ public static IAttributeParser[] DefaultAttributeParsers() new GenericValueAttributeParser(), ]; } - + /** * Detects if the template is an HTML document. */ @@ -80,13 +80,13 @@ private static bool IsHtml(string template) { var doctype = template.Trim().StartsWith("]*>", RegexOptions.IgnoreCase, "en-US")] private static partial Regex DocTypeRegex(); - + /** * Removes the doctype from the template to avoid issues with the XML parser. */ @@ -94,46 +94,46 @@ private void RemoveDoctype() { Template = DocTypeRegex().Replace(Template, string.Empty); } - + /** * Gets the doctype from the template, so it can be added back to the final HTML. */ private static string GetDoctype(string template) { var match = DocTypeRegex().Match(template); - + return match.Success ? match.Value : string.Empty; } - + private void CloseVoidElements() { var voidElements = new[] { - "area", - "base", - "br", - "col", + "area", + "base", + "br", + "col", "embed", - "hr", - "img", - "input", - "link", - "meta", - "param", - "source", - "track", + "hr", + "img", + "input", + "link", + "meta", + "param", + "source", + "track", "wbr" }; - + var regex = new Regex(@"(?<(" + string.Join('|', voidElements) + @")([^>]*?)>)", RegexOptions.IgnoreCase); - - foreach(Match match in regex.Matches(Template)) + + foreach (Match match in regex.Matches(Template)) { var element = match.Groups["el"].Value; - + // Already closed, skip if (element.EndsWith("/>")) continue; - + // replace with self-closing tag var newElement = element.Insert(element.Length - 1, "/"); Template = Template.Replace(element, newElement); @@ -142,7 +142,7 @@ private void CloseVoidElements() [GeneratedRegex(@"&(?\w+);")] private static partial Regex HtmlEntityRegex(); - + /** * Transforms HTML entities to their respective characters. * @@ -152,7 +152,7 @@ private void TransformHtmlEntities() { var entityRegex = HtmlEntityRegex(); var matches = entityRegex.Matches(Template); - + foreach (Match match in matches) { var entity = match.Groups["entity"].Value; @@ -161,74 +161,74 @@ private void TransformHtmlEntities() Template = Template.Replace(match.Value, replacement); } } - + /** * Parses the template and returns it as HTML. */ public string ToHtml() { Parse(); - + if (Xml.DocumentElement == null) return string.Empty; - + if (_isHtml) { return $"{_docType}{Xml.DocumentElement.FirstChild?.OuterXml}"; } - + return Xml.DocumentElement.FirstChild?.OuterXml ?? string.Empty; } - + /** * Parses the template and returns it as XML. */ public XmlNode ToXml() { Parse(); - + return Xml.DocumentElement?.FirstChild ?? Xml.CreateElement("root"); } - + private void RunAttributeParsers() { var parsers = AttributeParsers; - + if (parsers.Length == 0) { parsers = DefaultAttributeParsers(); } - - foreach(var parser in parsers) + + foreach (var parser in parsers) { var nodes = Xml.DocumentElement?.SelectNodes(parser.XTag, _nsManager); var clonedData = new Dictionary(Data); parser.Parse(Xml, clonedData, nodes); } - + // Remove all leftover attributes that start with x: var leftOverNodes = Xml.DocumentElement?.SelectNodes("//*[@*[starts-with(name(), 'x:')]]", _nsManager); - + if (leftOverNodes == null) return; - + foreach (var node in leftOverNodes.Cast()) { if (node is not XmlElement element) continue; - + var attributes = element.Attributes.Cast() .Where(a => a.Name.StartsWith("x:")) .ToList(); - + foreach (var attr in attributes) { element.RemoveAttribute(attr.Name); } } } - + private void AddIdentifierToNodes() { if (Xml.DocumentElement == null) return; - + var nodesToProcess = new Queue(Xml.DocumentElement.ChildNodes.Cast()); while (nodesToProcess.Count > 0) diff --git a/HtmtTests/AttributeParserTest.cs b/HtmtTests/AttributeParserTest.cs index 03c2312..b805f88 100644 --- a/HtmtTests/AttributeParserTest.cs +++ b/HtmtTests/AttributeParserTest.cs @@ -28,6 +28,39 @@ public void TestGenericValueAttributeParserWithouData() Assert.AreEqual("Click here", html); } + [TestMethod] + public void TestDateModifierParser() + { + const string template = "

"; + var data = new Dictionary { { "date", "2022-01-01" } }; + var parser = new Parser { Template = template, Data = data }; + var html = parser.ToHtml(); + + Assert.AreEqual("

2022

", html); + } + + [TestMethod] + public void TestDateModifierWithNoArgs() + { + const string template = "

"; + var data = new Dictionary { { "date", "2022-01-01" } }; + var parser = new Parser { Template = template, Data = data }; + var html = parser.ToHtml(); + + Assert.AreEqual("

2022-01-01

", html); + } + + [TestMethod] + public void TestDateModifierWithDateTimeVal() + { + const string template = "

"; + var data = new Dictionary { { "date", DateTime.Parse("2022-01-01") } }; + var parser = new Parser { Template = template, Data = data }; + var html = parser.ToHtml(); + + Assert.AreEqual("

2022

", html); + } + [TestMethod] public void TestInnerTextAttributeParser() { @@ -172,7 +205,7 @@ public void TestComplexExpressionIfAttributeParser() var data = new Dictionary { { "show", true }, { "title", "Hello, World!" } }; var parser = new Parser { Template = template, Data = data }; var html = parser.ToHtml(); - + Assert.AreEqual("

Hello, World!

", html); } @@ -268,7 +301,7 @@ public void TestUnlessEmptyDictionaryAttributeParser() Assert.AreEqual("

There are no items!

", html); } - + [TestMethod] public void TestComplexExpressionUnlessAttributeParser() { @@ -276,7 +309,7 @@ public void TestComplexExpressionUnlessAttributeParser() var data = new Dictionary { { "show", true }, { "title", "Hello, World!" } }; var parser = new Parser { Template = template, Data = data }; var html = parser.ToHtml(); - + Assert.AreEqual("", html); } @@ -300,7 +333,7 @@ public void TestInnerPartialAttributeParser() var data = new Dictionary { { "partial", partial } }; var parser = new Parser { Template = template, Data = data }; var html = parser.ToHtml(); - + Assert.AreEqual("

Hello, World!

", html); } @@ -312,7 +345,7 @@ public void TestInnerPartialAttributeParserWithData() var data = new Dictionary { { "partial", partial }, { "name", "World" } }; var parser = new Parser { Template = template, Data = data }; var html = parser.ToHtml(); - + Assert.AreEqual("

Hello, World!

", html); } @@ -324,10 +357,10 @@ public void TestInnerPartialAttributeParserWithHtmlEntities() var data = new Dictionary { { "partial", partial } }; var parser = new Parser { Template = template, Data = data }; var html = parser.ToHtml(); - + Assert.AreEqual("

This way →

", html); } - + [TestMethod] public void TestOuterPartialAttributeParser() { @@ -336,10 +369,10 @@ public void TestOuterPartialAttributeParser() var data = new Dictionary { { "partial", partial } }; var parser = new Parser { Template = template, Data = data }; var html = parser.ToHtml(); - + Assert.AreEqual("

Hello, World!

", html); } - + [TestMethod] public void TestOuterPartialAttributeParserWithData() { @@ -348,7 +381,7 @@ public void TestOuterPartialAttributeParserWithData() var data = new Dictionary { { "partial", partial }, { "name", "World" } }; var parser = new Parser { Template = template, Data = data }; var html = parser.ToHtml(); - + Assert.AreEqual("

Hello, World!

", html); } @@ -360,7 +393,7 @@ public void TestOuterPartialAttributeParserWithHtmlEntities() var data = new Dictionary { { "partial", partial } }; var parser = new Parser { Template = template, Data = data }; var html = parser.ToHtml(); - + Assert.AreEqual("

This way →

", html); } } \ No newline at end of file diff --git a/HtmtTests/ExpressionValidatorTest.cs b/HtmtTests/ExpressionValidatorTest.cs index e65d157..0fdbe75 100644 --- a/HtmtTests/ExpressionValidatorTest.cs +++ b/HtmtTests/ExpressionValidatorTest.cs @@ -8,9 +8,9 @@ public class ExpressionValidatorTest [TestMethod] public void TestSimpleOr() { - var returnsTrue = new ExpressionValidator("(1 is 1) or (2 is 3)").Validates(new Dictionary()); - var returnsFalse = new ExpressionValidator("(1 is 2) or (2 is 3)").Validates(new Dictionary()); - + var returnsTrue = new ExpressionBooleanValidator("(1 is 1) or (2 is 3)").Validates(new Dictionary()); + var returnsFalse = new ExpressionBooleanValidator("(1 is 2) or (2 is 3)").Validates(new Dictionary()); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } @@ -18,99 +18,99 @@ public void TestSimpleOr() [TestMethod] public void TestIntComparisons() { - var returnsTrue = new ExpressionValidator("test is 1").Validates(new Dictionary() { { "test", 1 } }); - var returnsFalse = new ExpressionValidator("test is 1").Validates(new Dictionary() { { "test", 2 } }); - + var returnsTrue = new ExpressionBooleanValidator("test is 1").Validates(new Dictionary() { { "test", 1 } }); + var returnsFalse = new ExpressionBooleanValidator("test is 1").Validates(new Dictionary() { { "test", 2 } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } - + [TestMethod] public void TestDoubleComparisons() { - var returnsTrue = new ExpressionValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.1 } }); - var returnsFalse = new ExpressionValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.2 } }); - + var returnsTrue = new ExpressionBooleanValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.1 } }); + var returnsFalse = new ExpressionBooleanValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.2 } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } - + [TestMethod] public void TestFloatComparisons() { - var returnsTrue = new ExpressionValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.1f } }); - var returnsFalse = new ExpressionValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.2f } }); - + var returnsTrue = new ExpressionBooleanValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.1f } }); + var returnsFalse = new ExpressionBooleanValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.2f } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } - + [TestMethod] public void TestStringComparisons() { - var returnsTrue = new ExpressionValidator("test is 'test'").Validates(new Dictionary() { { "test", "test" } }); - var returnsFalse = new ExpressionValidator("test is 'test'").Validates(new Dictionary() { { "test", "test2" } }); - + var returnsTrue = new ExpressionBooleanValidator("test is 'test'").Validates(new Dictionary() { { "test", "test" } }); + var returnsFalse = new ExpressionBooleanValidator("test is 'test'").Validates(new Dictionary() { { "test", "test2" } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } - + [TestMethod] public void TestBooleanComparisons() { - var returnsTrue = new ExpressionValidator("test is true").Validates(new Dictionary() { { "test", true } }); - var returnsFalse = new ExpressionValidator("test is true").Validates(new Dictionary() { { "test", false } }); - + var returnsTrue = new ExpressionBooleanValidator("test is true").Validates(new Dictionary() { { "test", true } }); + var returnsFalse = new ExpressionBooleanValidator("test is true").Validates(new Dictionary() { { "test", false } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } - + [TestMethod] public void TestNullComparisons() { - var returnsTrue = new ExpressionValidator("test is null").Validates(new Dictionary() { { "test", null } }); - var returnsFalse = new ExpressionValidator("test is null").Validates(new Dictionary() { { "test", "test" } }); - + var returnsTrue = new ExpressionBooleanValidator("test is null").Validates(new Dictionary() { { "test", null } }); + var returnsFalse = new ExpressionBooleanValidator("test is null").Validates(new Dictionary() { { "test", "test" } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } - + [TestMethod] public void TestAnd() { - var returnsTrue = new ExpressionValidator("(test is 1) and (test2 is 2)").Validates(new Dictionary() { { "test", 1 }, { "test2", 2 } }); - var returnsFalse = new ExpressionValidator("(test is 1) and (test2 is 2)").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 } }); - + var returnsTrue = new ExpressionBooleanValidator("(test is 1) and (test2 is 2)").Validates(new Dictionary() { { "test", 1 }, { "test2", 2 } }); + var returnsFalse = new ExpressionBooleanValidator("(test is 1) and (test2 is 2)").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } - + [TestMethod] public void TestComplexAndExpression() { - var returnsTrue = new ExpressionValidator("((test is 1) and (test2 is 2)) or (test3 is 3)").Validates(new Dictionary() { { "test", 1 }, { "test2", 2 }, { "test3", 3 } }); - var returnsFalse = new ExpressionValidator("((test is 1) and (test2 is 2))").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 } }); - + var returnsTrue = new ExpressionBooleanValidator("((test is 1) and (test2 is 2)) or (test3 is 3)").Validates(new Dictionary() { { "test", 1 }, { "test2", 2 }, { "test3", 3 } }); + var returnsFalse = new ExpressionBooleanValidator("((test is 1) and (test2 is 2))").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } - + [TestMethod] public void TestComplexOrExpression() { - var returnsTrue = new ExpressionValidator("((test is 1) or (test2 is 2)) and (test3 is 3)").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 }, { "test3", 3 } }); - var returnsFalse = new ExpressionValidator("((test is 1) or (test2 is 2))").Validates(new Dictionary() { { "test", 3 }, { "test2", 3 } }); - + var returnsTrue = new ExpressionBooleanValidator("((test is 1) or (test2 is 2)) and (test3 is 3)").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 }, { "test3", 3 } }); + var returnsFalse = new ExpressionBooleanValidator("((test is 1) or (test2 is 2))").Validates(new Dictionary() { { "test", 3 }, { "test2", 3 } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } - + [TestMethod] public void TestComplexExpression() { - var returnsTrue = new ExpressionValidator("((test is 1) or (test2 is 2)) and (test3 is 3)").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 }, { "test3", 3 } }); - var returnsFalse = new ExpressionValidator("((test is 1) or (test2 is 2))").Validates(new Dictionary() { { "test", 3 }, { "test2", 3 } }); - + var returnsTrue = new ExpressionBooleanValidator("((test is 1) or (test2 is 2)) and (test3 is 3)").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 }, { "test3", 3 } }); + var returnsFalse = new ExpressionBooleanValidator("((test is 1) or (test2 is 2))").Validates(new Dictionary() { { "test", 3 }, { "test2", 3 } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); } @@ -118,9 +118,9 @@ public void TestComplexExpression() [TestMethod] public void TestMultipleStringComparisons() { - var returnsTrue = new ExpressionValidator("(test is 'test') and (test2 is 'test2')").Validates(new Dictionary() { { "test", "test" }, { "test2", "test2" } }); - var returnsFalse = new ExpressionValidator("(test is 'test') and (test2 is 'test2')").Validates(new Dictionary() { { "test", "test" }, { "test2", "test3" } }); - + var returnsTrue = new ExpressionBooleanValidator("(test is 'test') and (test2 is 'test2')").Validates(new Dictionary() { { "test", "test" }, { "test2", "test2" } }); + var returnsFalse = new ExpressionBooleanValidator("(test is 'test') and (test2 is 'test2')").Validates(new Dictionary() { { "test", "test" }, { "test2", "test3" } }); + Assert.IsTrue(returnsTrue); Assert.IsFalse(returnsFalse); }