Skip to content

Commit

Permalink
Adding ternary operator support and improving common error message.
Browse files Browse the repository at this point in the history
  • Loading branch information
cdibbs committed Jan 6, 2019
1 parent 74a6687 commit 442336a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 5 deletions.
43 changes: 43 additions & 0 deletions Linq2Ldap.Core.Tests/FilterCompiler/LDAPFilterCompilerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using System.Text;
using Linq2Ldap.Core.FilterCompiler;
using Linq2Ldap.Core.FilterCompiler.Models;
using Linq2Ldap.Core.FilterParser;
using Linq2Ldap.Core.Models;
using Linq2Ldap.Core.Proxies;
using Xunit;

namespace Linq2Ldap.Core.Tests.FilterCompiler
Expand Down Expand Up @@ -129,6 +131,47 @@ public void Compile_EscapesValues() {
var result = FilterCompiler.Compile(e);
Assert.Equal(@"(cn=must\2aescape\5cthis\28please\29)", result);
}

[InlineData("one", "onediff", "two", "twodiff", "three", "threediff", false)]
[InlineData("one", "onediff", "two", "twodiff", "three", "three", true)]
[InlineData("one", "one", "two", "twodiff", "three", "threediff", false)]
[InlineData("one", "one", "two", "two", "three", "threediff", true)]
[InlineData("one", "one", "two", "two", "three", "three", true)]
[InlineData("one", "onediff", "two", "two", "three", "threediff", false)]
[InlineData("one", "onediff", "two", "two", "three", "three", true)]
[Theory]
public void Compile_ConvertsTernaryToBooleanAlgebra(
string a, string b, string c, string d, string e, string f, bool expected)
{
Expression<Func<TestLdapModel, bool>> expr
= (TestLdapModel m) => m["a"] == b ? m["c"] == d : m["e"] == f;
var comp = FilterCompiler.Compile(expr);
var parsed = new LdapFilterParser().Parse<TestLdapModel>(comp);

var model = new TestLdapModel()
{
Attributes = new EntryAttributeDictionary()
{
{ "a", new AttributeValueList(a) },
{ "c", new AttributeValueList(c) },
{ "e", new AttributeValueList(e) }
}
};

var ternResult = expr.Compile()(model);
var parsedResult = parsed.Compile()(model);
Assert.Equal(expected, ternResult);
Assert.Equal(expected, parsedResult);
}

[Fact]
public void Compile_ThrowsSensibleErrorForTwoAttrComparison()
{
Expression<Func<TestLdapModel, bool>> expr = e => e["a"] == e["b"];
var ex = Assert.Throws<InvalidOperationException>(() => FilterCompiler.Compile(expr));
Assert.Contains("Right side", ex.Message);
Assert.Contains("must be a constant", ex.Message);
}
}

public class TestUser : TestLdapModel
Expand Down
27 changes: 22 additions & 5 deletions Linq2Ldap.Core/FilterCompiler/CompilerCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,28 @@ public string ExpressionToString(Expression expr, IReadOnlyCollection<ParameterE
return _Negate(_MaybeStringCompareToExpr(expr, p, /* not */ "=")
?? _ComparisonExprToString(expr, p, /* not */ "="));

// Low-priority/do not implement:
case ExpressionType.Conditional: /* ternary */
return _TernaryToBooleanAlgebra(expr, p);

// Low-priority/do not implement:
default:
throw new NotImplementedException(
$"Linq-to-LDAP not implemented for {expr.NodeType}. \n"
+ "Use local variables to remove algebraic expressions and method calls, \n"
+ "and reduce Linq expression complexity to boolean algebra and \n"
+ ".Contains/.StartsWith/.EndsWith string ops.");
+ "and reduce Linq expression complexity to boolean algebra and string ops.\n"
+ "Please see the Linq2Ldap project site.");
}
}

private string _TernaryToBooleanAlgebra(Expression expr, IReadOnlyCollection<ParameterExpression> p)
{
var tern = expr as ConditionalExpression;
var test = ExpressionToString(tern.Test, p);
var whenTrue = ExpressionToString(tern.IfTrue, p);
var whenFalse = ExpressionToString(tern.IfFalse, p);
return $"(|(&{test}{whenTrue})(&(!{test}){whenFalse}))";
}

internal string _CallExprToString(
Expression expr, IReadOnlyCollection<ParameterExpression> p)
{
Expand Down Expand Up @@ -249,8 +260,14 @@ internal string _ComparisonExprToString(
var trueRight = e.Right;

var left = ExpressionToString(trueLeft, p);
var right = EvalExpr(trueRight, p);
return $"({left}{op}{right})";
try
{
var right = EvalExpr(trueRight, p);
return $"({left}{op}{right})";
} catch (NotImplementedException ex)
{
throw new InvalidOperationException($"Right side of LDAP comparison must be a constant.");
}
}

internal string _MaybeStringCompareToExpr(
Expand Down

0 comments on commit 442336a

Please sign in to comment.