diff --git a/libraries/AdaptiveExpressions/ExpressionFunctions.cs b/libraries/AdaptiveExpressions/ExpressionFunctions.cs index 6a6c7e0b4f..7e7bd8ef9e 100644 --- a/libraries/AdaptiveExpressions/ExpressionFunctions.cs +++ b/libraries/AdaptiveExpressions/ExpressionFunctions.cs @@ -2990,7 +2990,7 @@ private static IDictionary GetStandardFunctions() if (args.Count == 1) { inputStr = ParseStringOrNull(args[0]); - } + } else { inputStr = ParseStringOrNull(args[0]); @@ -3745,7 +3745,6 @@ private static IDictionary GetStandardFunctions() // Conversions new ExpressionEvaluator(ExpressionType.Float, Apply(args => (float)Convert.ToDouble(args[0])), ReturnType.Number, ValidateUnary), new ExpressionEvaluator(ExpressionType.Int, Apply(args => (int)Convert.ToInt64(args[0])), ReturnType.Number, ValidateUnary), - new ExpressionEvaluator(ExpressionType.Array, Apply(args => new[] { args[0] }, VerifyString), ReturnType.Object, ValidateUnary), new ExpressionEvaluator(ExpressionType.Binary, Apply(args => ExpressionFunctions.ToBinary(args[0]), VerifyString), ReturnType.String, ValidateUnary), new ExpressionEvaluator(ExpressionType.Base64, Apply(args => Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(args[0])), VerifyString), ReturnType.String, ValidateUnary), new ExpressionEvaluator(ExpressionType.Base64ToBinary, Apply(args => ExpressionFunctions.ToBinary(args[0]), VerifyString), ReturnType.String, ValidateUnary), @@ -3908,6 +3907,58 @@ private static IDictionary GetStandardFunctions() }), ReturnType.Boolean, ValidateIsMatch), + + //Type Checking Functions + new ExpressionEvaluator( + ExpressionType.IsString, + Apply(args => args[0].GetType() == typeof(string)), + ReturnType.Boolean, + ValidateUnary), + new ExpressionEvaluator( + ExpressionType.IsInteger, + Apply(args => Extensions.IsNumber(args[0]) && args[0] % 1 == 0), + ReturnType.Boolean, + ValidateUnary), + new ExpressionEvaluator( + ExpressionType.IsFloat, + Apply(args => Extensions.IsNumber(args[0]) && args[0] % 1 != 0), + ReturnType.Boolean, + ValidateUnary), + new ExpressionEvaluator( + ExpressionType.IsArray, + Apply(args => TryParseList(args[0], out IList _)), + ReturnType.Boolean, + ValidateUnary), + new ExpressionEvaluator( + ExpressionType.IsObject, + Apply(args => !(args[0] is JValue) && args[0].GetType().IsValueType == false && args[0].GetType() != typeof(string)), + ReturnType.Boolean, + ValidateUnary), + new ExpressionEvaluator( + ExpressionType.IsBoolean, + Apply(args => args[0] is bool), + ReturnType.Boolean, + ValidateUnary), + new ExpressionEvaluator( + ExpressionType.IsDateTime, + Apply( + args => + { + if (args[0] is string) + { + object value = null; + string error = null; + (value, error) = ParseISOTimestamp(args[0] as string); + if (error == null) + { + return true; + } + } + + return false; + }), + ReturnType.Boolean, + ValidateUnary), }; var eval = new ExpressionEvaluator(ExpressionType.Optional, (expression, state) => throw new NotImplementedException(), ReturnType.Boolean, ExpressionFunctions.ValidateUnaryBoolean); diff --git a/libraries/AdaptiveExpressions/ExpressionType.cs b/libraries/AdaptiveExpressions/ExpressionType.cs index b16dfb3eb9..13d69fb757 100644 --- a/libraries/AdaptiveExpressions/ExpressionType.cs +++ b/libraries/AdaptiveExpressions/ExpressionType.cs @@ -105,7 +105,6 @@ public static class ExpressionType public const string Int = "int"; public const string String = "string"; public const string Bool = "bool"; - public const string Array = "array"; public const string Binary = "binary"; public const string Base64 = "base64"; public const string Base64ToBinary = "base64ToBinary"; @@ -150,8 +149,17 @@ public static class ExpressionType // Regular expression public const string IsMatch = "isMatch"; + //Type Checking + public const string IsInteger = "isInteger"; + public const string IsFloat = "isFloat"; + public const string IsString = "isString"; + public const string IsArray = "isArray"; + public const string IsObject = "isObject"; + public const string IsBoolean = "isBoolean"; + public const string IsDateTime = "isDateTime"; + // trigger tree - + /// /// Mark a sub-expression as optional. /// diff --git a/tests/AdaptiveExpressions.Tests/BadExpressionTests.cs b/tests/AdaptiveExpressions.Tests/BadExpressionTests.cs index 6c3d6dbd25..3b9d900049 100644 --- a/tests/AdaptiveExpressions.Tests/BadExpressionTests.cs +++ b/tests/AdaptiveExpressions.Tests/BadExpressionTests.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using AdaptiveExpressions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json.Linq; namespace AdaptiveExpressions.Tests { @@ -359,6 +360,16 @@ public class BadExpressionTests Test("isMatch('abC', '^[a-z+$')"), // bad regular expression #endregion +#region Type Checking + Test("isString(hello, hello)"), // should have 1 parameter + Test("isInteger(2, 3)"), // should have 1 parameter + Test("isFloat(1.2, 3.1)"), // should have 1 parameter + Test("isArray(createArray(1,2,3), 1)"), // should have 1 parameter + Test("isObejct(emptyJObject, hello)"), // should have 1 parameter + Test("isDateTime('2018-03-15T13:00:00.000Z', hello)"), // should have 1 parameter + Test("isBoolean(false, false)"), // should have 1 parameter +#endregion + #region SetPathToValue tests Test("setPathToValue(2+3, 4)"), // Not a real path Test("setPathToValue(a)"), // Missing value @@ -412,6 +423,7 @@ public void Evaluate(string exp) hello = "hello", world = "world", istrue = true, + emptyJObject = new JObject(), bag = new { three = 3.0, diff --git a/tests/AdaptiveExpressions.Tests/ExpressionParserTests.cs b/tests/AdaptiveExpressions.Tests/ExpressionParserTests.cs index 2621736db1..0833de4842 100644 --- a/tests/AdaptiveExpressions.Tests/ExpressionParserTests.cs +++ b/tests/AdaptiveExpressions.Tests/ExpressionParserTests.cs @@ -539,7 +539,6 @@ public class ExpressionParserTests Test("bool('hi')", true), Test("createArray('h', 'e', 'l', 'l', 'o')", new List { "h", "e", "l", "l", "o" }), Test("createArray(1, bool(0), string(bool(1)), float('10'))", new List { 1, true, "true", 10.0f }), - Test("array('hello')", new List { "hello" }), Test("binary(hello)", "0110100001100101011011000110110001101111"), Test("length(binary(hello))", 40), Test("base64(hello)", "aGVsbG8="), @@ -786,6 +785,24 @@ public class ExpressionParserTests Test(@"isMatch('1', '\\d{1}')", true), // "\d" (match [0-9]) #endregion + #region type checking + Test("isString('abc')", true), + Test("isString(123)", false), + Test("isInteger('abc')", false), + Test("isInteger(123)", true), + Test("isFloat('abc')", false), + Test("isFloat(123.234)", true), + Test("isArray(createArray(1,2,3))", true), + Test("isArray(123.234)", false), + Test("isObject(emptyJObject)", true), + Test("isObject(dialog)", true), + Test("isObject(123.234)", false), + Test("isBoolean(2 + 3)", false), + Test("isBoolean(2 > 1)", true), + Test("isDateTime(2 + 3)", false), + Test("isDateTime(timestamp)", true), + #endregion + #region Empty expression Test(string.Empty, string.Empty), Test(string.Empty, string.Empty),