Skip to content

Commit

Permalink
Improve Expression with adding type checking functions (#3581)
Browse files Browse the repository at this point in the history
* init

* add test cases

* add bad expression tests

* fix comments

* fix
  • Loading branch information
cosmicshuai committed Mar 17, 2020
1 parent 9e6d2b6 commit c033715
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 5 deletions.
55 changes: 53 additions & 2 deletions libraries/AdaptiveExpressions/ExpressionFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2990,7 +2990,7 @@ private static IDictionary<string, ExpressionEvaluator> GetStandardFunctions()
if (args.Count == 1)
{
inputStr = ParseStringOrNull(args[0]);
}
}
else
{
inputStr = ParseStringOrNull(args[0]);
Expand Down Expand Up @@ -3745,7 +3745,6 @@ private static IDictionary<string, ExpressionEvaluator> 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),
Expand Down Expand Up @@ -3908,6 +3907,58 @@ private static IDictionary<string, ExpressionEvaluator> 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);
Expand Down
12 changes: 10 additions & 2 deletions libraries/AdaptiveExpressions/ExpressionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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

/// <summary>
/// Mark a sub-expression as optional.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions tests/AdaptiveExpressions.Tests/BadExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Diagnostics;
using AdaptiveExpressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;

namespace AdaptiveExpressions.Tests
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -412,6 +423,7 @@ public void Evaluate(string exp)
hello = "hello",
world = "world",
istrue = true,
emptyJObject = new JObject(),
bag = new
{
three = 3.0,
Expand Down
19 changes: 18 additions & 1 deletion tests/AdaptiveExpressions.Tests/ExpressionParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,6 @@ public class ExpressionParserTests
Test("bool('hi')", true),
Test("createArray('h', 'e', 'l', 'l', 'o')", new List<object> { "h", "e", "l", "l", "o" }),
Test("createArray(1, bool(0), string(bool(1)), float('10'))", new List<object> { 1, true, "true", 10.0f }),
Test("array('hello')", new List<object> { "hello" }),
Test("binary(hello)", "0110100001100101011011000110110001101111"),
Test("length(binary(hello))", 40),
Test("base64(hello)", "aGVsbG8="),
Expand Down Expand Up @@ -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),
Expand Down

0 comments on commit c033715

Please sign in to comment.