File: Definition\EditingElementsReferencedByOrReferences_Tests.cs
Web Access
Project: ..\..\..\src\Build.OM.UnitTests\Microsoft.Build.Engine.OM.UnitTests.csproj (Microsoft.Build.Engine.OM.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.Build.Evaluation;
using Xunit;
 
#nullable disable
 
namespace Microsoft.Build.UnitTests.OM.Definition
{
    /// <summary>
    /// Tests around editing elements that are referenced by others or the ones that references others.
    /// </summary>
    public class EditingElementsReferencedByOrReferences_Tests
    {
        /// <summary>
        /// Changes the item type on an item used with the at operator.
        /// </summary>
        [Fact]
        public void ChangeItemTypeInReferencedItem()
        {
            Project project = GetProject(
@"<Project>
  <ItemGroup>
    <I Include=""X"" />
    <I Include=""@(I);Y"" />
  </ItemGroup>
</Project>");
 
            ProjectItem item = project.GetItems("I").Where(i => i.UnevaluatedInclude == "X").First();
            item.ItemType = "J";
 
            string expected =
@"<Project>
  <ItemGroup>
    <J Include=""X"" />
    <I Include=""@(I);Y"" />
  </ItemGroup>
</Project>";
 
            Helpers.VerifyAssertProjectContent(expected, project.Xml, false);
 
            project.ReevaluateIfNecessary();
            IEnumerable<ProjectItem> items = project.GetItems("I");
 
            Assert.Single(items); // "Wrong number of items after changing type"
            Assert.Equal("Y", items.First().EvaluatedInclude); // "Wrong evaluated include after changing type"
        }
 
        /// <summary>
        /// Removes an item in a ; separated list. It blows up the list.
        /// </summary>
        [Fact]
        public void RemoveItemInList()
        {
            Project project = GetProject(
@"<Project>
  <ItemGroup>
    <I Include=""X"" />
    <I Include=""@(I);Y;Z"" />
  </ItemGroup>
</Project>");
 
            ProjectItem item = project.GetItems("I").Where(i => i.EvaluatedInclude == "Y").First();
            project.RemoveItem(item);
 
            string expected =
@"<Project>
  <ItemGroup>
    <I Include=""X"" />
    <I Include=""X"" />
    <I Include=""Z"" />
  </ItemGroup>
</Project>";
 
            Helpers.VerifyAssertProjectContent(expected, project.Xml, false);
        }
 
        /// <summary>
        /// Renames an item in a ; separated list. It blows up the list.
        /// </summary>
        [Fact]
        public void RenameItemInList()
        {
            Project project = GetProject(
@"<Project>
  <ItemGroup>
    <I Include=""X"" />
    <I Include=""@(I);Y"" />
  </ItemGroup>
</Project>");
 
            ProjectItem item = project.GetItems("I").Where(i => i.EvaluatedInclude == "Y").First();
            item.Rename("Z");
 
            string expected =
@"<Project>
  <ItemGroup>
    <I Include=""X"" />
    <I Include=""X"" />
    <I Include=""Z"" />
  </ItemGroup>
</Project>";
 
            Helpers.VerifyAssertProjectContent(expected, project.Xml, false);
        }
 
        /// <summary>
        /// Removes metadata duplicated in item.
        /// </summary>
        [Fact]
        public void RemoveMetadata1()
        {
            Project project = GetProject(
@"<Project>
  <ItemDefinitionGroup>
    <I>
      <M>A</M>
    </I>
  </ItemDefinitionGroup>
  <ItemGroup>
    <I Include=""X"">
      <M>%(M);B</M>
      <M>%(M);C</M>
    </I>
    <I Include=""Y"">
      <M>%(M);D</M>
    </I>
  </ItemGroup>
</Project>");
 
            ProjectItem item1 = project.GetItems("I").Where(i => i.EvaluatedInclude == "X").First();
            Assert.Equal("A;B;C", item1.GetMetadataValue("M")); // "Invalid metadata at start"
 
            ProjectItem item2 = project.GetItems("I").Where(i => i.EvaluatedInclude == "Y").First();
            Assert.Equal("A;D", item2.GetMetadataValue("M")); // "Invalid metadata at start"
 
            item1.RemoveMetadata("M");
 
            string expected =
@"<Project>
  <ItemDefinitionGroup>
    <I>
      <M>A</M>
    </I>
  </ItemDefinitionGroup>
  <ItemGroup>
    <I Include=""X"">
      <M>%(M);B</M>
    </I>
    <I Include=""Y"">
      <M>%(M);D</M>
    </I>
  </ItemGroup>
</Project>";
            Helpers.VerifyAssertProjectContent(expected, project.Xml, false);
        }
 
        /// <summary>
        /// Removes duplicated metadata and checks evaluation.
        /// </summary>
        [Fact]
        public void RemoveMetadata2()
        {
            Project project = GetProject(
@"<Project>
  <ItemDefinitionGroup>
    <I>
      <M>A</M>
    </I>
  </ItemDefinitionGroup>
  <ItemGroup>
    <I Include=""X"">
      <M>%(M);B</M>
      <M>%(M);C</M>
    </I>
    <I Include=""Y"">
      <M>%(M);D</M>
    </I>
  </ItemGroup>
</Project>");
 
            ProjectItem item1 = project.GetItems("I").Where(i => i.EvaluatedInclude == "X").First();
            item1.RemoveMetadata("M");
 
            string expected =
@"<Project>
  <ItemDefinitionGroup>
    <I>
      <M>A</M>
    </I>
  </ItemDefinitionGroup>
  <ItemGroup>
    <I Include=""X"">
      <M>%(M);B</M>
    </I>
    <I Include=""Y"">
      <M>%(M);D</M>
    </I>
  </ItemGroup>
</Project>";
            Helpers.VerifyAssertProjectContent(expected, project.Xml, false);
 
            project.ReevaluateIfNecessary();
            item1 = project.GetItems("I").Where(i => i.EvaluatedInclude == "X").First();
            Assert.Equal("A;B", item1.GetMetadataValue("M")); // "Invalid metadata after first removal"
            ProjectItem item2 = project.GetItems("I").Where(i => i.EvaluatedInclude == "Y").First();
            Assert.Equal("A;D", item2.GetMetadataValue("M")); // "Invalid metadata after first removal"
        }
 
        /// <summary>
        /// Removes metadata but still keep inherited one from item definition.
        /// </summary>
        [Fact]
        public void RemoveMetadata3()
        {
            Project project = GetProject(
        @"<Project>
  <ItemDefinitionGroup>
    <I>
      <M>A</M>
    </I>
  </ItemDefinitionGroup>
  <ItemGroup>
    <I Include=""X"">
      <M>%(M);B</M>
      <M>%(M);C</M>
    </I>
    <I Include=""Y"">
      <M>%(M);D</M>
    </I>
  </ItemGroup>
</Project>");
 
            ProjectItem item1 = project.GetItems("I").Where(i => i.EvaluatedInclude == "X").First();
            item1.RemoveMetadata("M");
 
            project.ReevaluateIfNecessary();
            ProjectItem item2 = project.GetItems("I").Where(i => i.EvaluatedInclude == "Y").First();
            item2.RemoveMetadata("M");
 
            string expected =
@"<Project>
  <ItemDefinitionGroup>
    <I>
      <M>A</M>
    </I>
  </ItemDefinitionGroup>
  <ItemGroup>
    <I Include=""X"">
      <M>%(M);B</M>
    </I>
    <I Include=""Y"" />
  </ItemGroup>
</Project>";
            Helpers.VerifyAssertProjectContent(expected, project.Xml, false);
 
            project.ReevaluateIfNecessary();
            item1 = project.GetItems("I").Where(i => i.EvaluatedInclude == "X").First();
            Assert.Equal("A;B", item1.GetMetadataValue("M")); // "Invalid metadata after second removal"
            item2 = project.GetItems("I").Where(i => i.EvaluatedInclude == "Y").First();
            Assert.Equal("A", item2.GetMetadataValue("M")); // "Invalid metadata after second removal"
        }
 
        /// <summary>
        /// Removes metadata referenced with % qualification.
        /// </summary>
        [Fact]
        public void RemoveReferencedMetadata()
        {
            Project project = GetProject(
@"<Project>
  <ItemGroup>
    <I Include=""i"">
      <M>m</M>
      <N>%(I.M)</N>
    </I>
  </ItemGroup>
</Project>");
 
            ProjectItem item = project.GetItems("I").First();
            Assert.Equal("m", item.GetMetadataValue("N")); // "Wrong metadata value at startup"
 
            item.RemoveMetadata("M");
 
            string expected =
@"<Project>
  <ItemGroup>
    <I Include=""i"">
      <N>%(I.M)</N>
    </I>
  </ItemGroup>
</Project>";
            Helpers.VerifyAssertProjectContent(expected, project.Xml, false);
 
            project.ReevaluateIfNecessary();
            item = project.GetItems("I").First();
            ProjectMetadata metadata = item.GetMetadata("N");
 
            Assert.Equal("%(I.M)", metadata.UnevaluatedValue); // "Unevaluated value is wrong"
            Assert.Equal(String.Empty, metadata.EvaluatedValue); // "Evaluated value is wrong"
        }
 
        /// <summary>
        /// Removes duplicated property.
        /// </summary>
        [Fact]
        public void RemoveProperty()
        {
            Project project = GetProject(
@"<Project>
  <PropertyGroup>
    <P>A</P>
    <P>$(P)B</P>
  </PropertyGroup>
</Project>");
 
            ProjectProperty property = project.GetProperty("P");
            project.RemoveProperty(property);
 
            string expected =
@"<Project>
  <PropertyGroup>
    <P>A</P>
  </PropertyGroup>
</Project>";
 
            Helpers.VerifyAssertProjectContent(expected, project.Xml, false);
        }
 
        /// <summary>
        /// Creates a new project the given contents.
        /// </summary>
        /// <param name="contents">The contents for the project.</param>
        /// <returns>The project contents.</returns>
        private Project GetProject(string contents)
        {
            using ProjectFromString projectFromString = new(contents);
            Project project = projectFromString.Project;
            return project;
        }
    }
}