Skip to content
Merged
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
19 changes: 15 additions & 4 deletions src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,13 +319,12 @@ private List<Expression> CollectExpressions(bool addSelf, Expression sourceExpre
{
case MemberExpression memberExpression:
expression = GetMemberExpression(memberExpression.Expression);
expressionRecognized = true;
expressionRecognized = expression != null;
break;

case MethodCallExpression methodCallExpression:
// FIX method without parameter: https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/432
expression = methodCallExpression.Arguments.FirstOrDefault();
expressionRecognized = true;
expression = GetMethodCallExpression(methodCallExpression);
expressionRecognized = expression != null;
break;

default:
Expand All @@ -341,5 +340,17 @@ private List<Expression> CollectExpressions(bool addSelf, Expression sourceExpre

return list;
}

private static Expression GetMethodCallExpression(MethodCallExpression methodCallExpression)
{
if (methodCallExpression.Object != null)
{
// Something like: "np(FooValue.Zero().Length)"
return methodCallExpression.Object;
}

// Something like: "np(MyClasses.FirstOrDefault())"
return methodCallExpression.Arguments.FirstOrDefault();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
using NFluent;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq.Dynamic.Core.CustomTypeProviders;
using System.Linq.Dynamic.Core.Exceptions;
using System.Linq.Dynamic.Core.Tests.Helpers.Models;
using System.Linq.Dynamic.Core.Tests.TestHelpers;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using FluentAssertions;
using NFluent;
using Xunit;
using User = System.Linq.Dynamic.Core.Tests.Helpers.Models.User;
using System.Linq.Dynamic.Core.Tests.TestHelpers;

namespace System.Linq.Dynamic.Core.Tests
{
public class DynamicExpressionParserTests
{
public class Foo
{
public Foo FooValue { get; set; }

public string Zero() => null;

public string One(int x) => null;

public string Two(int x, int y) => null;
}

private class MyClass
{
public List<string> MyStrings { get; set; }
Expand Down Expand Up @@ -291,15 +301,15 @@ public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQu
dynamic wrappedObj = constantExpression.Value;

var propertyInfo = wrappedObj.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public);
int value = (int) propertyInfo.GetValue(wrappedObj);
int value = (int)propertyInfo.GetValue(wrappedObj);

Check.That(value).IsEqualTo(42);
}

[Theory]
[InlineData("NullableIntValue", "42")]
[InlineData("NullableDoubleValue", "42.23")]
public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_ForNullableProperty_true(string propName, string valueString)
public void DynamicExpressionParser_ParseLambda_UseParameterizedNamesInDynamicQuery_ForNullableProperty_true(string propName, string valueString)
{
// Assign
var config = new ParsingConfig
Expand Down Expand Up @@ -1102,21 +1112,73 @@ public void DynamicExpressionParser_ParseLambda_SupportEnumerationStringComparis
Check.That(result).IsEqualTo(expectedResult);
}

[Fact]
public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_Zero_Arguments()
{
// Arrange
var expression = "np(FooValue.Zero().Length)";

// Act
var lambdaExpression = DynamicExpressionParser.ParseLambda(typeof(Foo), null, expression, new Foo());

// Assert
#if NET452
lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Zero() != null)), Convert(Param_0.FooValue.Zero().Length), null)");
#else
lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Zero() != null)), Convert(Param_0.FooValue.Zero().Length, Nullable`1), null)");
#endif
}

[Fact]
public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_One_Argument()
{
// Arrange
var expression = "np(FooValue.One(1).Length)";

// Act
var lambdaExpression = DynamicExpressionParser.ParseLambda(typeof(Foo), null, expression, new Foo());

// Assert
#if NET452
lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.One(1) != null)), Convert(Param_0.FooValue.One(1).Length), null)");
#else
lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.One(1) != null)), Convert(Param_0.FooValue.One(1).Length, Nullable`1), null)");
#endif
}

[Fact]
public void DynamicExpressionParser_ParseLambda_NullPropagation_InstanceMethod_Two_Arguments()
{
// Arrange
var expression = "np(FooValue.Two(1, 42).Length)";

// Act
var lambdaExpression = DynamicExpressionParser.ParseLambda(typeof(Foo), null, expression, new Foo());

// Assert
#if NET452
lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Two(1, 42) != null)), Convert(Param_0.FooValue.Two(1, 42).Length), null)");
#else
lambdaExpression.ToString().Should().Be("Param_0 => IIF((((Param_0 != null) AndAlso (Param_0.FooValue != null)) AndAlso (Param_0.FooValue.Two(1, 42) != null)), Convert(Param_0.FooValue.Two(1, 42).Length, Nullable`1), null)");
#endif
}

[Fact]
public void DynamicExpressionParser_ParseLambda_NullPropagation_MethodCallExpression()
{
// Arrange
var dataSource = new MyClass();
var myClass = new MyClass();
var dataSource = new { MyClasses = new[] { myClass, null } };

var expressionText = "np(MyClasses.FirstOrDefault())";

// Act
LambdaExpression expression = DynamicExpressionParser.ParseLambda(ParsingConfig.Default, dataSource.GetType(), typeof(MyClass), expressionText);
Delegate del = expression.Compile();
MyClass result = del.DynamicInvoke(dataSource) as MyClass;
var result = del.DynamicInvoke(dataSource) as MyClass;

// Assert
result.Should().BeNull();
result.Should().Be(myClass);
}

[Theory]
Expand Down
56 changes: 55 additions & 1 deletion test/System.Linq.Dynamic.Core.Tests/ExpressionTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Newtonsoft.Json.Linq;
using FluentAssertions;
using Newtonsoft.Json.Linq;
using NFluent;
using System.Collections.Generic;
using System.Dynamic;
Expand Down Expand Up @@ -49,6 +50,17 @@ public class TestObjectIdClass
public long ObjectId { get; set; }
}

public class Foo
{
public Foo FooValue { get; set; }

public string Zero() => null;

public string One(int x) => null;

public string Two(int x, int y) => null;
}

[Fact]
public void ExpressionTests_Add_Number()
{
Expand Down Expand Up @@ -1394,6 +1406,48 @@ public void ExpressionTests_NullPropagating(string test, string query)
Check.That(queryAsString).Equals(query);
}

[Fact]
public void ExpressionTests_NullPropagating_InstanceMethod_Zero_Arguments()
{
// Arrange 1
var expression = "np(FooValue.Zero().Length)";
var q = new[] { new Foo { FooValue = new Foo() } }.AsQueryable();

// Act 2
var result = q.Select(expression).FirstOrDefault() as int?;

// Assert 2
result.Should().BeNull();
}

[Fact]
public void ExpressionTests_NullPropagating_InstanceMethod_One_Argument()
{
// Arrange
var expression = "np(FooValue.One(1).Length)";
var q = new[] { new Foo { FooValue = new Foo() } }.AsQueryable();

// Act
var result = q.Select(expression).FirstOrDefault() as int?;

// Assert
result.Should().BeNull();
}

[Fact]
public void ExpressionTests_NullPropagating_InstanceMethod_Two_Arguments()
{
// Arrange
var expression = "np(FooValue.Two(1, 42).Length)";
var q = new[] { new Foo { FooValue = new Foo() } }.AsQueryable();

// Act
var result = q.Select(expression).FirstOrDefault() as int?;

// Assert
result.Should().BeNull();
}

[Fact]
public void ExpressionTests_NullPropagation_Method()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="NFluent" Version="2.7.0" />
<PackageReference Include="Moq" Version="4.13.1" />
<!--<PackageReference Include="ExpressionTreeToString" Version="3.1.47" />-->
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
Expand Down