-
-
Notifications
You must be signed in to change notification settings - Fork 231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix for parsing Guid and string in the same condition #200
Conversation
Codecov Report
@@ Coverage Diff @@
## master #200 +/- ##
==========================================
+ Coverage 82.53% 82.55% +0.02%
==========================================
Files 37 37
Lines 3676 3681 +5
Branches 503 504 +1
==========================================
+ Hits 3034 3039 +5
- Misses 498 502 +4
+ Partials 144 140 -4
Continue to review full report at Codecov.
|
Hi @StefH ! |
Hello @OlegNadymov , Thanks for this PR, I'll check and review in some time. 1] Unit tests are fine (see https://ci.appveyor.com/project/StefH/system-linq-dynamic-core/build/1.0.8.643)
2] CodeFactor complains, therefore you see a red cross there. |
@@ -452,5 +454,39 @@ public void ParseLambda_With_InnerStringLiteral() | |||
object result = del.DynamicInvoke(String.Empty); | |||
Check.That(result).IsEqualTo(originalTrueValue); | |||
} | |||
|
|||
[Fact] | |||
public void ParseLambda_With_If_Guid_Null() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use // Arrange
, // Act
and // Assert
flow (take a look at other tests).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was done!
[Fact] | ||
public void ParseLambda_With_If_Guid_Null() | ||
{ | ||
var objContext = new User(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
user
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was done!
public void ParseLambda_With_If_Guid_Null() | ||
{ | ||
var objContext = new User(); | ||
var guidEmpty = Guid.Empty; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For clarity, I mostly / always use real definitions for simple types. So use Guid
here.
Only for complex types, I use var.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was done!
var objContext = new User(); | ||
var guidEmpty = Guid.Empty; | ||
var someId = Guid.NewGuid(); | ||
var expressionText = $"iif(@0.{nameof(objContext.Id)} == null, @0.{nameof(objContext.Id)} == Guid.Parse(\"{someId}\"), {nameof(objContext.Id)}={nameof(objContext.Id)})"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was done!
@@ -452,5 +454,39 @@ public void ParseLambda_With_InnerStringLiteral() | |||
object result = del.DynamicInvoke(String.Empty); | |||
Check.That(result).IsEqualTo(originalTrueValue); | |||
} | |||
|
|||
[Fact] | |||
public void ParseLambda_With_If_Guid_Null() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be Iif
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was done!
var objContext = new User(); | ||
var guidEmpty = Guid.Empty; | ||
var someId = Guid.NewGuid(); | ||
var expressionText = $"iif(@0.{nameof(objContext.Id)} == null, @0.{nameof(objContext.Id)} == Guid.Parse(\"{someId}\"), {nameof(objContext.Id)}={nameof(objContext.Id)})"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For readability I would just type the expressionText string as simple as possible, so just:
$"iif(@0.Id == null, @0.Id == Guid.Parse(\"{someId}\"), Id=Id)";
And actually I wonder if this is ok?
Wouldn't the last statement set a value?
Like:
$"iif(@0.Id == null, @0.Id == Guid.Parse(\"{someId}\"), Id)";
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it would not. This expression should have boolean result. So "Id == Id"
is kind of true result. It's part of query for our ORM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's correct expression:
string expressionText = $"iif(@0.Id == null, @0.Id == Guid.Parse(\"{someId}\"), Id == Id)";
@@ -452,5 +454,39 @@ public void ParseLambda_With_InnerStringLiteral() | |||
object result = del.DynamicInvoke(String.Empty); | |||
Check.That(result).IsEqualTo(originalTrueValue); | |||
} | |||
|
|||
[Fact] | |||
public void ParseLambda_With_If_Guid_Null() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better text like: Guid_Equals_Null
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was done!
} | ||
|
||
[Fact] | ||
public void ParseLambda_With_If_Null_Guid() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comments as defined on other method also apply here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was done!
//void F(Guid x, string y); | ||
//void F(Guid? x, string y); | ||
|
||
// Disabled 2 lines below according to unit test ParseLambda_With_If_Null_Guid |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would think that removing this code would actually break unit-tests? Or do you say that this logic was wrong from the beginning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion logic was wrong from the start.
It's like the issue #19
I've added unit test ParseLambda_With_Guid_Equals_String
for demonstrate that Guid
plus String
works without these lines (at least in condition part).
@StefH, |
@StefH all changes according to your review were done! |
CodeFactor found multiple issues last seen at 6213fd1: An opening curly bracket must not be followed by a blank line.test\System.Linq.Dynamic.Core.Tests\DynamicExpressionParserTests.cs:13 The code must not contain multiple blank lines in a row.test\System.Linq.Dynamic.Core.Tests\DynamicExpressionParserTests.cs:15 |
Small issues:
|
string expressionText = $"iif(@0.Id == \"{someId}\", Guid.Parse(\"{guidEmpty}\"), Guid.Parse(\"{anotherId}\"))"; | ||
|
||
var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not also check here on:
var boolLambda = lambda as Expression<Func<User, bool>>;
Assert.NotNull(boolLambda);
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I've added it:
var guidLambda = lambda as Expression<Func<User, Guid>>;
Assert.NotNull(guidLambda);
Ok! Now I got that you mean about // Arrange , // Act and // Assert. // Act
var lambda = DynamicExpressionParser.ParseLambda(typeof(User), null, expressionText, user);
var guidLambda = lambda as Expression<Func<User, Guid>>;
Assert.NotNull(guidLambda);
var del = lambda.Compile();
Guid result = (Guid) del.DynamicInvoke(user);
// Assert
Assert.Equal(guidEmpty, result); As you can see here the first |
@StefH Do I need mention you in my each comment? Or you get notifications about new comments anyway. |
@OlegNadymov No need to mention me in the comments. |
for now it's ok. |
Ok! I'll do it like you said with several Act1, Act2 in next PRs |
@StefH, what about this PR? |
I will merge this weekend and create new nuget. |
Ok! Then I'll add one more change for this PR. |
And one more change for LessGreater parsing. |
Maybe it's best to revert the last changes you did for LessGreater (unit test fail?). And create a new PR for this. |
I've fixed unit test. It was problem with custom static type |
Do you want that I create new PR? Or I can leave it here. In case with new PR, I need to create new branch for new PR because the current branch is using for this open PR. Do I understand correctly? |
OK, keep in same branch. I'll check the new code in some time... |
OK! Thank you! I'm looking forward to reviewing my changes. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added some comments, please take a look.
And I think I need to restructure the test class a bit in the future to make clear what's tested.
var user = new User(); | ||
user.Id = someId; | ||
Guid guidEmpty = Guid.Empty; | ||
string expressionText = $"iif(@0.Id == StaticHelper.GetGuid(\"name\"), Guid.Parse(\"{guidEmpty}\"), Guid.Parse(\"{anotherId}\"))"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why introduce the StaticHelper
class here if you only want to test the <>
operator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This expression with Guid constant
instead of Guid method
was worked correctly before these changes. Therefore for represent bug with method
I've introduced StaticHelper
with GetGuid
method. Or do you mean why I didn't create this class like as local class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that the <> was not working at all. But I understand from your comment that this was only not working in specific flows?
In that case your test looks good.
Maybe you could add some more comments to explain this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The <>
was working with constant only.
Your ExpressionParser
has this condition (line 494):
else if ((constantExpr = right as ConstantExpression) != null && constantExpr.Value is string && (typeConverter = TypeConverterFactory.GetConverter(left.Type)) != null)
{
right = Expression.Constant(typeConverter.ConvertFromInvariantString((string)constantExpr.Value), left.Type);
}
Therefore if right
epxression is ConstantExpression
then the <> will be working.
But for non-constant and for different types (e.g. Guid
and Guid?
) will be executed this code (line 531):
CheckAndPromoteOperands(isEquality ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), op.Text, ref left, ref right, op.Pos);
And before my changes the variable isEquality
was false
. Therefore into method CheckAndPromoteOperands
passed argument type as typeof(IRelationalSignatures)
. But type typeof(IRelationalSignatures)
doesn't have conversion between Guid
and Guid?
.
Moreover for the !=
this case was working because for the !=
the variable isEquality
was true:
bool isEquality = op.Id == TokenId.Equal || op.Id == TokenId.DoubleEqual || op.Id == TokenId.ExclamationEqual;
TokenId.ExclamationEqual
is equal to the !=
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, thanks for the detailed explanation.
void F(string x, Guid y); | ||
void F(string x, Guid? y); | ||
|
||
// Disabled 2 lines below according to unit test ParseLambda_With_Guid_Equals_Null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change comment to:
// Disabled 4 lines below because of : https://github.com/StefH/System.Linq.Dynamic.Core/pull/200
//void F(Guid x, string y);
//void F(Guid? x, string y);
//void F(string x, Guid y);
//void F(string x, Guid? y);
string name = "name1"; | ||
string note = "note1"; | ||
var textHolder = new TextHolder(name, note); | ||
string expressionText = $"Name + \" (\" + Note + \")\""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to use $ here I think ? It's just a normal string.
string name = "name1"; | ||
string note = "note1"; | ||
var textHolder = new TextHolder(name, note); | ||
string expressionText = $"Note + \" (\" + Name + \")\""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to use $ here I think ? It's just a normal string.
} | ||
|
||
[Fact] | ||
public void ParseLambda_With_Less_Greater() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to ParseLambda_Operator_Less_Greater_With_Guids
?
All review's changes were done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
Thank you for merge! And please nuget. |
1.0.8.17 is added to NuGet |
@StefH Thanks! |
Plus fix for parsing expression with custom types with implicit convertions