Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Source/Expressive.Tests/ExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ public void RelationalTests()
Assert.AreEqual(true, new Expression("1 <= 2").Evaluate());
Assert.AreEqual(false, new Expression("7 < 2").Evaluate());
Assert.AreEqual(true, new Expression("1 < 2").Evaluate());
Assert.AreEqual(true, new Expression("[var1] < 1").Evaluate(new Dictionary<string, object> { ["var1"] = null}));
Assert.AreEqual(false, new Expression("[var1] > 1").Evaluate(new Dictionary<string, object> { ["var1"] = null}));
Assert.AreEqual(false, new Expression("[var1] < 1", ExpressiveOptions.Strict).Evaluate(new Dictionary<string, object> { ["var1"] = null}));
Assert.AreEqual(false, new Expression("[var1] > 1", ExpressiveOptions.Strict).Evaluate(new Dictionary<string, object> { ["var1"] = null}));

// Dates can be parsed to string.
Assert.AreEqual(true, new Expression("[date1] == '2016-01-01'").Evaluate(new Dictionary<string, object> { ["date1"] = new DateTime(2016, 01, 01) }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public static class GreaterThanExpressionTests
[TestCase(1.001, 1.001, false)]
[TestCase(1, 1.00, false)]
[TestCase(1.00, 1, false)]
[TestCase(null, 1, false)]
[TestCase(1, null, true)]
public static void TestEvaluate(object lhs, object rhs, object expectedValue)
{
var expression = new GreaterThanExpression(
Expand All @@ -35,5 +37,20 @@ public static void TestEvaluate(object lhs, object rhs, object expectedValue)

Assert.That(expression.Evaluate(null), Is.EqualTo(expectedValue));
}

[TestCase(null, 1, false)]
[TestCase(1, null, false)]
[TestCase(null, null, false)]
[TestCase(null, "abc", false)]
[TestCase("abc", null, false)]
public static void TestEvaluateWithStrictMode(object lhs, object rhs, object expectedValue)
{
var expression = new GreaterThanExpression(
Mock.Of<IExpression>(e => e.Evaluate(It.IsAny<IDictionary<string, object>>()) == lhs),
Mock.Of<IExpression>(e => e.Evaluate(It.IsAny<IDictionary<string, object>>()) == rhs),
new Context(ExpressiveOptions.Strict));

Assert.That(expression.Evaluate(null), Is.EqualTo(expectedValue));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public static class GreaterThanOrEqualExpressionTests
[TestCase(1.001, 1.001, true)]
[TestCase(1, 1.00, true)]
[TestCase(1.00, 1, true)]
[TestCase(null, 1, false)]
[TestCase(1, null, true)]
public static void TestEvaluate(object lhs, object rhs, object expectedValue)
{
var expression = new GreaterThanOrEqualExpression(
Expand All @@ -35,5 +37,20 @@ public static void TestEvaluate(object lhs, object rhs, object expectedValue)

Assert.That(expression.Evaluate(null), Is.EqualTo(expectedValue));
}

[TestCase(null, 1, false)]
[TestCase(1, null, false)]
[TestCase(null, null, true)]
[TestCase(null, "abc", false)]
[TestCase("abc", null, false)]
public static void TestEvaluateWithStrictMode(object lhs, object rhs, object expectedValue)
{
var expression = new GreaterThanOrEqualExpression(
Mock.Of<IExpression>(e => e.Evaluate(It.IsAny<IDictionary<string, object>>()) == lhs),
Mock.Of<IExpression>(e => e.Evaluate(It.IsAny<IDictionary<string, object>>()) == rhs),
new Context(ExpressiveOptions.Strict));

Assert.That(expression.Evaluate(null), Is.EqualTo(expectedValue));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public static class LessThanExpressionTests
[TestCase(1.001, 1.001, false)]
[TestCase(1, 1.00, false)]
[TestCase(1.00, 1, false)]
[TestCase(null, 1, true)]
[TestCase(1, null, false)]
public static void TestEvaluate(object lhs, object rhs, object expectedValue)
{
var expression = new LessThanExpression(
Expand All @@ -35,5 +37,20 @@ public static void TestEvaluate(object lhs, object rhs, object expectedValue)

Assert.That(expression.Evaluate(null), Is.EqualTo(expectedValue));
}

[TestCase(null, 1, false)]
[TestCase(1, null, false)]
[TestCase(null, null, false)]
[TestCase(null, "abc", false)]
[TestCase("abc", null, false)]
public static void TestEvaluateWithStrictMode(object lhs, object rhs, object expectedValue)
{
var expression = new LessThanExpression(
Mock.Of<IExpression>(e => e.Evaluate(It.IsAny<IDictionary<string, object>>()) == lhs),
Mock.Of<IExpression>(e => e.Evaluate(It.IsAny<IDictionary<string, object>>()) == rhs),
new Context(ExpressiveOptions.Strict));

Assert.That(expression.Evaluate(null), Is.EqualTo(expectedValue));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public static class LessThanOrEqualExpressionTests
[TestCase(1.001, 1.001, true)]
[TestCase(1, 1.00, true)]
[TestCase(1.00, 1, true)]
[TestCase(null, 1, true)]
[TestCase(1, null, false)]
public static void TestEvaluate(object lhs, object rhs, object expectedValue)
{
var expression = new LessThanOrEqualExpression(
Expand All @@ -35,5 +37,21 @@ public static void TestEvaluate(object lhs, object rhs, object expectedValue)

Assert.That(expression.Evaluate(null), Is.EqualTo(expectedValue));
}

[TestCase(null, 1, false)]
[TestCase(1, null, false)]
[TestCase(null, null, true)]
[TestCase(null, "abc", false)]
[TestCase("abc", null, false)]
public static void TestEvaluateWithStrictMode(object lhs, object rhs, object expectedValue)
{
var expression = new LessThanOrEqualExpression(
Mock.Of<IExpression>(e => e.Evaluate(It.IsAny<IDictionary<string, object>>()) == lhs),
Mock.Of<IExpression>(e => e.Evaluate(It.IsAny<IDictionary<string, object>>()) == rhs),
new Context(ExpressiveOptions.Strict));

Assert.That(expression.Evaluate(null), Is.EqualTo(expectedValue));
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,28 @@ public GreaterThanExpression(IExpression lhs, IExpression rhs, Context context)

#region BinaryExpressionBase Members

protected override object EvaluateImpl(object lhsResult, IExpression rightHandSide, IDictionary<string, object> variables) =>
Comparison.CompareUsingMostPreciseType(lhsResult, rightHandSide.Evaluate(variables), this.Context) > 0;
protected override object EvaluateImpl(object lhsResult, IExpression rightHandSide, IDictionary<string, object> variables)
{
object rhsResult = null;

if (Context.Options.HasFlag(ExpressiveOptions.Strict))
{
if (lhsResult is null)
{
return false;
}

rhsResult = rightHandSide.Evaluate(variables);

// If we got here then the lhsResult is not null.
if (rhsResult is null)
{
return false;
}
}

return Comparison.CompareUsingMostPreciseType(lhsResult, rhsResult ?? rightHandSide.Evaluate(variables), this.Context) > 0;
}

#endregion
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,25 @@ public GreaterThanOrEqualExpression(IExpression lhs, IExpression rhs, Context co

#region BinaryExpressionBase Members

protected override object EvaluateImpl(object lhsResult, IExpression rightHandSide, IDictionary<string, object> variables) =>
Comparison.CompareUsingMostPreciseType(lhsResult, rightHandSide.Evaluate(variables), this.Context) >= 0;
protected override object EvaluateImpl(object lhsResult, IExpression rightHandSide, IDictionary<string, object> variables)
{
object rhsResult = rightHandSide.Evaluate(variables);

if (Context.Options.HasFlag(ExpressiveOptions.Strict))
{
if (lhsResult is null && rhsResult is null)
{
return true;
}

if (lhsResult is null || rhsResult is null)
{
return false;
}
}

return Comparison.CompareUsingMostPreciseType(lhsResult, rhsResult, this.Context) >= 0;
}

#endregion
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,28 @@ public LessThanExpression(IExpression lhs, IExpression rhs, Context context) : b

#region BinaryExpressionBase Members

protected override object EvaluateImpl(object lhsResult, IExpression rightHandSide, IDictionary<string, object> variables) =>
Comparison.CompareUsingMostPreciseType(lhsResult, rightHandSide.Evaluate(variables), this.Context) < 0;
protected override object EvaluateImpl(object lhsResult, IExpression rightHandSide, IDictionary<string, object> variables)
{
object rhsResult = null;

if (Context.Options.HasFlag(ExpressiveOptions.Strict))
{
if (lhsResult is null)
{
return false;
}

rhsResult = rightHandSide.Evaluate(variables);

// If we got here then the lhsResult is not null.
if (rhsResult is null)
{
return false;
}
}

return Comparison.CompareUsingMostPreciseType(lhsResult, rhsResult ?? rightHandSide.Evaluate(variables), this.Context) < 0;
}

#endregion
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,25 @@ public LessThanOrEqualExpression(IExpression lhs, IExpression rhs, Context conte

#region BinaryExpressionBase Members

protected override object EvaluateImpl(object lhsResult, IExpression rightHandSide, IDictionary<string, object> variables) =>
Comparison.CompareUsingMostPreciseType(lhsResult, rightHandSide.Evaluate(variables), this.Context) <= 0;
protected override object EvaluateImpl(object lhsResult, IExpression rightHandSide, IDictionary<string, object> variables)
{
object rhsResult = rightHandSide.Evaluate(variables);

if (Context.Options.HasFlag(ExpressiveOptions.Strict))
{
if (lhsResult is null && rhsResult is null)
{
return true;
}

if (lhsResult is null || rhsResult is null)
{
return false;
}
}

return Comparison.CompareUsingMostPreciseType(lhsResult, rhsResult, this.Context) <= 0;
}

#endregion
}
Expand Down
9 changes: 8 additions & 1 deletion Source/Expressive/ExpressiveOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,18 @@ public enum ExpressiveOptions
/// </summary>
IgnoreCaseAll = IgnoreCaseForParsing | IgnoreCaseForEquality,

/// <summary>
/// Specifies we're using strict mode for comparison
/// `False` will be returned if value `null` is a side expression for most of cases
/// e.g.: (null &lt; 1) = False; (null &gt; 1) = False; (null &gt; "abc") = False; (null &lt; "abc") = False;
/// </summary>
Strict = 64,

/// <summary>
/// All options are used.
/// </summary>
#pragma warning disable 618 // As it is our own warning this is safe enough until we actually get rid
All = IgnoreCase | NoCache | RoundAwayFromZero | IgnoreCaseAll
All = IgnoreCase | NoCache | RoundAwayFromZero | IgnoreCaseAll | Strict
#pragma warning restore 618
}
}