Skip to content

Commit b78629f

Browse files
OlegNadymovStefH
authored andcommitted
Fix for parsing Guid and string in the same condition (#200)
* Fix for ParseLambda with itType and resultType: correct order of arguments * Add references for missing classes * Fix for missing classes: UserState and UserProfileDetails * Small update on unit-test (no need to check for `DoesNotThrow`) * add comment to appveyor * Only run SonarScanner on master branch * APPVEYOR_REPO_BRANCH * APPVEYOR_PULL_REQUEST_NUMBER * No working unit test for inner double quotes * Fix for inner double quotes * Using {} * Fix for parsing Guid and string in the same condition * FIxes after review * Fixes after review: just add comments and remove empty lines after bracket * Fix for parsing expression with custom types with implicit convertions * Use "string" instead of "var" * Remove empty line * Fix for LessGreater (<>) parsing. * Fix for unit test * Changes according to review
1 parent b31d36f commit b78629f

File tree

4 files changed

+207
-6
lines changed

4 files changed

+207
-6
lines changed

src/System.Linq.Dynamic.Core/Parser/ExpressionHelper.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,13 @@ public static Expression OptimizeStringForEqualityIfPossible(string text, Type t
188188

189189
static MethodInfo GetStaticMethod(string methodName, Expression left, Expression right)
190190
{
191-
return left.Type.GetMethod(methodName, new[] { left.Type, right.Type });
191+
var methodInfo = left.Type.GetMethod(methodName, new[] {left.Type, right.Type});
192+
if (methodInfo == null)
193+
{
194+
methodInfo = right.Type.GetMethod(methodName, new[] {left.Type, right.Type});
195+
}
196+
197+
return methodInfo;
192198
}
193199

194200
static Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right)

src/System.Linq.Dynamic.Core/Parser/ExpressionParser.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ Expression ParseComparisonOperator()
443443
Token op = _textParser.CurrentToken;
444444
_textParser.NextToken();
445445
Expression right = ParseShiftOperator();
446-
bool isEquality = op.Id == TokenId.Equal || op.Id == TokenId.DoubleEqual || op.Id == TokenId.ExclamationEqual;
446+
bool isEquality = op.Id == TokenId.Equal || op.Id == TokenId.DoubleEqual || op.Id == TokenId.ExclamationEqual || op.Id == TokenId.LessGreater;
447447

448448
if (isEquality && (!left.Type.GetTypeInfo().IsValueType && !right.Type.GetTypeInfo().IsValueType || left.Type == typeof(Guid) && right.Type == typeof(Guid)))
449449
{

src/System.Linq.Dynamic.Core/Parser/SupportedOperands/IEqualitySignatures.cs

+6-4
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ internal interface IEqualitySignatures : IRelationalSignatures
1313

1414
void F(Guid x, Guid y);
1515
void F(Guid? x, Guid? y);
16-
void F(Guid x, string y);
17-
void F(Guid? x, string y);
18-
void F(string x, Guid y);
19-
void F(string x, Guid? y);
16+
17+
// Disabled 4 lines below because of : https://github.com/StefH/System.Linq.Dynamic.Core/pull/200
18+
//void F(Guid x, string y);
19+
//void F(Guid? x, string y);
20+
//void F(string x, Guid y);
21+
//void F(string x, Guid? y);
2022
}
2123
}

test/System.Linq.Dynamic.Core.Tests/DynamicExpressionParserTests.cs

+193
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,57 @@ public class CustomClassWithStaticMethod
3737
public static int GetAge(int x) => x;
3838
}
3939

40+
public class CustomTextClass
41+
{
42+
public CustomTextClass(string origin)
43+
{
44+
Origin = origin;
45+
}
46+
47+
public string Origin { get; }
48+
49+
public static implicit operator string(CustomTextClass customTextValue)
50+
{
51+
return customTextValue?.Origin;
52+
}
53+
54+
public static implicit operator CustomTextClass(string origin)
55+
{
56+
return new CustomTextClass(origin);
57+
}
58+
59+
public override string ToString()
60+
{
61+
return Origin;
62+
}
63+
}
64+
65+
public class TextHolder
66+
{
67+
public TextHolder(string name, CustomTextClass note)
68+
{
69+
Name = name;
70+
Note = note;
71+
}
72+
73+
public string Name { get; }
74+
75+
public CustomTextClass Note { get; }
76+
77+
public override string ToString()
78+
{
79+
return Name + " (" + Note + ")";
80+
}
81+
}
82+
83+
public static class StaticHelper
84+
{
85+
public static Guid? GetGuid(string name)
86+
{
87+
return Guid.NewGuid();
88+
}
89+
}
90+
4091
private class TestCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
4192
{
4293
private HashSet<Type> _customTypes;
@@ -50,6 +101,7 @@ public virtual HashSet<Type> GetCustomTypes()
50101

51102
_customTypes = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly }));
52103
_customTypes.Add(typeof(CustomClassWithStaticMethod));
104+
_customTypes.Add(typeof(StaticHelper));
53105
return _customTypes;
54106
}
55107
}
@@ -452,5 +504,146 @@ public void ParseLambda_With_InnerStringLiteral()
452504
object result = del.DynamicInvoke(String.Empty);
453505
Check.That(result).IsEqualTo(originalTrueValue);
454506
}
507+
508+
[Fact]
509+
public void ParseLambda_With_Guid_Equals_Null()
510+
{
511+
// Arrange
512+
var user = new User();
513+
Guid guidEmpty = Guid.Empty;
514+
Guid someId = Guid.NewGuid();
515+
string expressionText = $"iif(@0.Id == null, @0.Id == Guid.Parse(\"{someId}\"), Id == Id)";
516+
517+
// Act
518+
var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user);
519+
var boolLambda = lambda as Expression<Func<User, bool>>;
520+
Assert.NotNull(boolLambda);
521+
522+
var del = lambda.Compile();
523+
bool result = (bool) del.DynamicInvoke(user);
524+
525+
// Assert
526+
Assert.True(result);
527+
}
528+
529+
[Fact]
530+
public void ParseLambda_With_Null_Equals_Guid()
531+
{
532+
// Arrange
533+
var user = new User();
534+
Guid guidEmpty = Guid.Empty;
535+
Guid someId = Guid.NewGuid();
536+
string expressionText = $"iif(null == @0.Id, @0.Id == Guid.Parse(\"{someId}\"), Id == Id)";
537+
538+
// Act
539+
var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user);
540+
var boolLambda = lambda as Expression<Func<User, bool>>;
541+
Assert.NotNull(boolLambda);
542+
543+
var del = lambda.Compile();
544+
bool result = (bool) del.DynamicInvoke(user);
545+
546+
// Assert
547+
Assert.True(result);
548+
}
549+
550+
[Fact]
551+
public void ParseLambda_With_Guid_Equals_String()
552+
{
553+
// Arrange
554+
Guid someId = Guid.NewGuid();
555+
Guid anotherId = Guid.NewGuid();
556+
var user = new User();
557+
user.Id = someId;
558+
Guid guidEmpty = Guid.Empty;
559+
string expressionText = $"iif(@0.Id == \"{someId}\", Guid.Parse(\"{guidEmpty}\"), Guid.Parse(\"{anotherId}\"))";
560+
561+
// Act
562+
var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user);
563+
var guidLambda = lambda as Expression<Func<User, Guid>>;
564+
Assert.NotNull(guidLambda);
565+
566+
var del = lambda.Compile();
567+
Guid result = (Guid) del.DynamicInvoke(user);
568+
569+
// Assert
570+
Assert.Equal(guidEmpty, result);
571+
}
572+
573+
[Fact]
574+
public void ParseLambda_With_Concat_String_CustomType()
575+
{
576+
// Arrange
577+
string name = "name1";
578+
string note = "note1";
579+
var textHolder = new TextHolder(name, note);
580+
string expressionText = "Name + \" (\" + Note + \")\"";
581+
582+
// Act 1
583+
var lambda = DynamicExpressionParser.ParseLambda(typeof(TextHolder), null, expressionText, textHolder);
584+
var stringLambda = lambda as Expression<Func<TextHolder, string>>;
585+
586+
// Assert 1
587+
Assert.NotNull(stringLambda);
588+
589+
// Act 2
590+
var del = lambda.Compile();
591+
string result = (string) del.DynamicInvoke(textHolder);
592+
593+
// Assert 2
594+
Assert.Equal("name1 (note1)", result);
595+
}
596+
597+
[Fact]
598+
public void ParseLambda_With_Concat_CustomType_String()
599+
{
600+
// Arrange
601+
string name = "name1";
602+
string note = "note1";
603+
var textHolder = new TextHolder(name, note);
604+
string expressionText = "Note + \" (\" + Name + \")\"";
605+
606+
// Act 1
607+
var lambda = DynamicExpressionParser.ParseLambda(typeof(TextHolder), null, expressionText, textHolder);
608+
var stringLambda = lambda as Expression<Func<TextHolder, string>>;
609+
610+
// Assert 1
611+
Assert.NotNull(stringLambda);
612+
613+
// Act 2
614+
var del = lambda.Compile();
615+
string result = (string) del.DynamicInvoke(textHolder);
616+
617+
// Assert 2
618+
Assert.Equal("note1 (name1)", result);
619+
}
620+
621+
[Fact]
622+
public void ParseLambda_Operator_Less_Greater_With_Guids()
623+
{
624+
var config = new ParsingConfig
625+
{
626+
CustomTypeProvider = new TestCustomTypeProvider()
627+
};
628+
629+
// Arrange
630+
Guid someId = Guid.NewGuid();
631+
Guid anotherId = Guid.NewGuid();
632+
var user = new User();
633+
user.Id = someId;
634+
Guid guidEmpty = Guid.Empty;
635+
string expressionText = $"iif(@0.Id == StaticHelper.GetGuid(\"name\"), Guid.Parse(\"{guidEmpty}\"), Guid.Parse(\"{anotherId}\"))";
636+
637+
// Act
638+
var lambda = DynamicExpressionParser.ParseLambda(config, typeof(User), null, expressionText, user);
639+
var guidLambda = lambda as Expression<Func<User, Guid>>;
640+
Assert.NotNull(guidLambda);
641+
642+
var del = lambda.Compile();
643+
Guid result = (Guid) del.DynamicInvoke(user);
644+
645+
// Assert
646+
Assert.Equal(anotherId, result);
647+
}
455648
}
456649
}

0 commit comments

Comments
 (0)