Support ItemDefinitionGroup in Choose/When#7979
Conversation
|
Hello, assuming the repo owners would like to take this change, they will ask for unit test coverage too. |
src/Build.UnitTests/Parser_Tests.cs
Outdated
| MockLogger ml = ObjectModelHelpers.BuildProjectExpectSuccess(@" | ||
| <Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`> | ||
| <Choose> | ||
| <When Condition=` '$(OutputType)'=='Library' `> |
There was a problem hiding this comment.
I would expect tests that
-verify that the IDG works, and isn't ignored
-verify that multiple IDG are supported and they are processed top to bottom
-this for multiple When, as well as Otherwise
There was a problem hiding this comment.
I think testing the same way as ItemGroup might cover all the scenarios. That could be a start.
There was a problem hiding this comment.
Also put in some PropertyGroup and ItemGroup in there. Everything is evaluated in passes -- normally, all properties, then all IDG, then all items. each pass can "see" the previous, even if the elements were "lower" in the project file. So if there are PG and IG in here, whatever the ordering, the IG should see the IDG.
This comment is now wrong:
msbuild/src/Build/Evaluation/Evaluator.cs
Line 1495 in 5d102ae
it's certainly important to verify that the IDG are "working" inside Choose.
There was a problem hiding this comment.
@danmoseley Should we add PropertyGroup and ItemGroup in the project definition, and verify the itemdefinitiongroup works there in the test?
There was a problem hiding this comment.
/// We enter here in both the property and item passes, since Chooses can contain both.
Will remove this line or update to "We enter here in the property, itemDefinition, and item passes, since Chooses can contain all of them" ?
There was a problem hiding this comment.
@danmoseley Should we add PropertyGroup and ItemGroup in the project definition, and verify the itemdefinitiongroup works there in the test?
Sorry I'm not sure what you mean. Yes, I would expect tests that verify the IDG work, including consuming property expressions
There was a problem hiding this comment.
There's some confusion here, so I'll just lay out roughly what I'd want the test to look like:
Project
Choose
When
ItemGroup
ItemDefinitionGroup
PropertyGroup
Otherwise
ItemDefinitionGroup
PropertyGroup
ItemGroup
For each ItemDefinitionGroup, PropertyGroup, and ItemGroup, there should be things actually defined in it, so like for a PropertyGroup:
<PropertyGroup>
<Foo>bar</Foo>
</PropertyGroupThat's important because you can have something that parses without throwing an error but doesn't actually work, and you want to verify that it works.
So then you also want to make sure each of the Property/Item/ItemDefinitionGroups that you'd expected to execute actually did execute. It would be good to do that for both the When and the Otherwise case, so a Theory with one case for each would be appropriate here.
Is that clearer? (And I'm guessing that hits what you wanted, right danmoseley?)
There was a problem hiding this comment.
@danmoseley I have updated the test case, please have a look. Any suggestions, please let me know. Thank you.
There was a problem hiding this comment.
This looks much closer to what I'd expect, but the When and Otherwise conditions are currently identical. That means we don't know if it's following the When, Otherwise, or both. It would be good to disentangle those.
There was a problem hiding this comment.
Add one condition to distinguish when it is following when or otherwise
| /// Initialize a parented ProjectItemDefinitionGroupElement | ||
| /// </summary> | ||
| internal ProjectItemDefinitionGroupElement(XmlElement xmlElement, ProjectRootElement parent, ProjectRootElement containingProject) | ||
| internal ProjectItemDefinitionGroupElement(XmlElement xmlElement, ProjectElementContainer parent, ProjectRootElement containingProject) |
There was a problem hiding this comment.
We should probably add a check to make sure the parent isn't a Target, since we still reject ItemDefinitionGroups under targets.
There was a problem hiding this comment.
In the function ParseProjectTargetElement,there is
msbuild/src/Build/Evaluation/ProjectParser.cs
Lines 629 to 631 in cc3db35
| { | ||
| var projectContent = $@" | ||
| <Project ToolsVersion= `msbuilddefaulttoolsversion` xmlns= `msbuildnamespace`> | ||
| <Choose> |
There was a problem hiding this comment.
This might be out of topic but the only child element that doesn't support Condition attribute is Choose. Is it on purpose? I find myself, on some occasions, needing to add a conditional attribute to the Choose element itself.
If I don't have that option, the code kinda becomes error prone and cumbersome.
For Example
<Choose Condition="'$(RootCheck)' == 'true'">
<When Condition="'$(ActualCheck)' == 'value1'">
</When>
<When Condition="'$(ActualCheck)' == 'value2'">
</When>
<Otherwise>
</Otherwise>
</Choose>is better, less repetitive and less error prone than the following...
<Choose>
<When Condition="'$(RootCheck)' == 'true' AND '$(ActualCheck)' == 'value1'">
</When>
<When Condition="'$(RootCheck)' == 'true' AND '$(ActualCheck)' == 'value2'">
</When>
<Otherwise Condition="'$(RootCheck)' == 'true'">
</Otherwise>
</Choose>There was a problem hiding this comment.
This test is for the ItemDefinitionGroup supported under choose/when and choose/otherwise, and not for the choose when or otherwise condition expression testing. So, didn't add condition expression for the Choose.
There was a problem hiding this comment.
only child element that doesn't support Condition attribute is Choose. Is it on purpose?
Reaching back over 15 years .. no particular reason, it just didn't occur to anyone. I don't see why it couldn't be added if they want it.
There was a problem hiding this comment.
only child element that doesn't support Condition attribute is Choose. Is it on purpose?
This should be on purpose from this test case
There was a problem hiding this comment.
@JaynieBai Nice Find... Thanks for looking it up.
Seems on purpose but WHY? Instead of supporting it, they made sure it didn't. Still, WHY? I'm puzzled.
I need this badly. Any chance that this can be allowed?
There was a problem hiding this comment.
I'm not sure either. @Forgind @rainersigwald Do you know anything about this?
There was a problem hiding this comment.
I said why 🙂 I implemented it. It just didn't occur to me at the time that it would be useful. Today I see no reason why it can't be added.
There was a problem hiding this comment.
It just didn't occur to me at the time that it would be useful.
So, were you one of devs who worked on MSBuild? 😲 I thought you were just speaking for the team. Sorry If I misunderstood you. 😥
Today I see no reason why it can't be added.
Thank you!
There was a problem hiding this comment.
Ha.. no problem. Yes, but I don't speak for the current team. I work on ASPNET now. My knowledge is historical.
There was a problem hiding this comment.
@Nirmal4G, as far as I'm concerned, you're free to file a bug to add conditions as an option. My first impulse is that we'd treat it the same as ItemDefinitionGroups: if you want to implement it, and you do it properly, we can take it, but we aren't likely to prioritize it. But file the bug first so we can have an official team opinion.
Forgind
left a comment
There was a problem hiding this comment.
Thanks for taking care of this!
| var project = ObjectModelHelpers.CreateInMemoryProject(projectContent); | ||
|
|
||
| var projectItem = project.GetItems("A").FirstOrDefault(); | ||
| Assert.Equal("bar", projectItem.EvaluatedInclude); |
There was a problem hiding this comment.
nit:
We're trying to use Shouldly for new tests, but I'm not blocking on that.
|
Thanks @JaynieBai! |
Fixes #5436
Context
Changes Made
There is a significant error in the original Constuctor ProjectItemDefinitionGroupElement(XmlElement xmlElement, ProjectRootElement parent, ProjectRootElement containingProject). The second parameter and third parameter types are the same. Fix the constructor bug and parse ItemDefinationGroup in when and otherwise.
Testing
Add one test SupportItemDefinationGroupInWhenOtherwise()
Notes