Skip to content
Open
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
30 changes: 30 additions & 0 deletions src/Build.UnitTests/Evaluation/Expander_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5268,5 +5268,35 @@ public void PropertyFunctionRegisterBuildCheck()
logger.AllBuildEvents.Count.ShouldBe(1);
}
}

/// <summary>
/// Test for issue where chained item functions with empty results incorrectly evaluate as non-empty in conditions
/// </summary>
[Fact]
public void ChainedItemFunctionEmptyResultInCondition()
{
string content = @"
<Project>
<Target Name='Test'>
<ItemGroup>
<TestItem Include='Test1' Foo='Bar' />
<TestItem Include='Test2' />
</ItemGroup>

<!-- This should be empty because Test1 has Foo='Bar', not 'Baz' -->
<PropertyGroup Condition=""'@(TestItem->WithMetadataValue('Identity', 'Test1')->WithMetadataValue('Foo', 'Baz'))' == ''"">
<EmptyResult>TRUE</EmptyResult>
</PropertyGroup>

<Message Text='EmptyResult=$(EmptyResult)' Importance='high' />
</Target>
</Project>
";

MockLogger log = Helpers.BuildProjectWithNewOMExpectSuccess(content);

// The chained WithMetadataValue should return empty, so the condition should be true and EmptyResult should be set
log.AssertLogContains("EmptyResult=TRUE");
}
}
}
20 changes: 12 additions & 8 deletions src/Build/Evaluation/Expander.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2021,21 +2021,25 @@ internal static List<KeyValuePair<string, S>> Transform<S>(
break;
}

// If we have another transform, swap the source and transform lists.
if (i < captures.Count - 1)
{
(transformedItems, sourceItems) = (sourceItems, transformedItems);
transformedItems.Clear();
}
}

// Check for break on non-empty only after ALL transforms are complete
if ((options & ExpanderOptions.BreakOnNotEmpty) != 0)
{
foreach (KeyValuePair<string, S> itemTuple in transformedItems)
{
if (!string.IsNullOrEmpty(itemTuple.Key) && (options & ExpanderOptions.BreakOnNotEmpty) != 0)
if (!string.IsNullOrEmpty(itemTuple.Key))
{
brokeEarly = true;
return transformedItems; // break out early
}
}

// If we have another transform, swap the source and transform lists.
if (i < captures.Count - 1)
{
(transformedItems, sourceItems) = (sourceItems, transformedItems);
transformedItems.Clear();
}
}

brokeEarly = false;
Expand Down