File: ObjectModelRemoting\Helpers\ViewValidation.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.
 
#nullable disable
 
namespace Microsoft.Build.UnitTests.OM.ObjectModelRemoting
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Build.Construction;
    using Microsoft.Build.Evaluation;
    using Xunit;
 
    internal enum ObjectType
    {
        Real = 1,
        View = 2
    }
 
    internal class LinkPair<T>
    {
        public LinkPair(T view, T real)
        {
            ViewValidation.VerifyLinkedNotNull(view);
            ViewValidation.VerifyNotLinkedNotNull(real);
            this.View = view;
            this.Real = real;
        }
 
        public T Get(ObjectType type) => type == ObjectType.Real ? this.Real : this.View;
        public T View { get; }
        public T Real { get; }
 
        public void VerifyNotSame(LinkPair<T> other)
        {
            Assert.NotEqual((object)this.View, (object)other.View);
            Assert.NotEqual((object)this.Real, (object)other.Real);
        }
 
        public void VerifySame(LinkPair<T> other)
        {
            Assert.Equal((object)this.View, (object)other.View);
            Assert.Equal((object)this.Real, (object)other.Real);
        }
 
        public void VerifySetter(bool finalValue, Func<T, bool> getter, Action<T, bool> setter)
        {
            var current = getter(this.Real);
            Assert.Equal(current, getter(this.View));
 
            // set via the view
            setter(this.View, !current);
 
            Assert.Equal(!current, getter(this.View));
            Assert.Equal(!current, getter(this.Real));
 
            // set via the real.
            setter(this.Real, current);
 
            Assert.Equal(current, getter(this.View));
            Assert.Equal(current, getter(this.Real));
 
            setter(this.View, finalValue);
            Assert.Equal(finalValue, getter(this.View));
            Assert.Equal(finalValue, getter(this.Real));
        }
 
        public void VerifySetter(string newValue, Func<T, string> getter, Action<T, string> setter)
        {
            var newValue1 = newValue.Ver(1);
            var current = getter(this.Real);
            Assert.Equal(current, getter(this.View));
            Assert.NotEqual(current, newValue);
            Assert.NotEqual(current, newValue1);
 
            // set via the view
            setter(this.View, newValue1);
 
            Assert.Equal(newValue1, getter(this.View));
            Assert.Equal(newValue1, getter(this.Real));
 
            // set via the real.
            setter(this.Real, newValue);
 
            Assert.Equal(newValue, getter(this.View));
            Assert.Equal(newValue, getter(this.Real));
            this.Verify();
        }
 
        public virtual void Verify()
        {
            ViewValidation.VerifyFindType(this.View, this.Real);
        }
    }
 
    internal sealed class ValidationContext
    {
        public ValidationContext() { }
        public ValidationContext(ProjectPair pair) { this.Pair = pair; }
        public ProjectPair Pair { get; set; }
        public Action<ElementLocation, ElementLocation> ValidateLocation { get; set; }
    }
 
    internal static partial class ViewValidation
    {
        private static bool VerifyCheckType<T>(object view, object real, ValidationContext context, Action<T, T, ValidationContext> elementValidator)
        {
            if (view is T viewTypedXml)
            {
                Assert.True(real is T);
                elementValidator(viewTypedXml, (T)real, context);
                return true;
            }
            else
            {
                Assert.False(real is T);
                return false;
            }
        }
 
        // "Slow" Verify, probing all known link types
        public static void VerifyFindType(object view, object real, ValidationContext context = null)
        {
            if (view == null && real == null)
            {
                return;
            }
 
            VerifyLinkedNotNull(view);
            VerifyNotLinkedNotNull(real);
 
            // construction
            if (VerifyCheckType<ProjectMetadataElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectChooseElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectWhenElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectOtherwiseElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectTaskElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectOutputElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectUsingTaskBodyElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectUsingTaskParameterElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<UsingTaskParameterGroupElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectUsingTaskElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectTargetElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectRootElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectExtensionsElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectImportElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectImportGroupElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectItemDefinitionElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectItemDefinitionGroupElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectItemElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectItemGroupElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectPropertyElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectPropertyGroupElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectSdkElement>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectOnErrorElement>(view, real, context, Verify))
            {
                return;
            }
 
            // evaluation
            if (VerifyCheckType<ProjectProperty>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectMetadata>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectItemDefinition>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<ProjectItem>(view, real, context, Verify))
            {
                return;
            }
 
            if (VerifyCheckType<Project>(view, real, context, Verify))
            {
                return;
            }
 
            throw new NotImplementedException($"Unknown type:{view.GetType().Name}");
        }
 
        public static void VerifyMetadata(IEnumerable<KeyValuePair<string, string>> expected, Func<string, string> getMetadata, Func<string, bool> hasMetadata = null)
        {
            if (expected == null)
            {
                return;
            }
 
            foreach (var md in expected)
            {
                if (hasMetadata != null)
                {
                    Assert.True(hasMetadata(md.Key));
                }
 
                Assert.Equal(md.Value, getMetadata(md.Key));
            }
        }
 
        public static void Verify<T>(IEnumerable<T> viewCollection, IEnumerable<T> realCollection, Action<T, T, ValidationContext> validator, ValidationContext context = null)
        {
            if (viewCollection == null && realCollection == null)
            {
                return;
            }
 
            Assert.NotNull(viewCollection);
            Assert.NotNull(realCollection);
 
            var viewXmlList = viewCollection.ToList();
            var realXmlList = realCollection.ToList();
            Assert.Equal(realXmlList.Count, viewXmlList.Count);
            for (int i = 0; i < realXmlList.Count; i++)
            {
                validator(viewXmlList[i], realXmlList[i], context);
            }
        }
 
        public static void Verify<T>(IDictionary<string, T> viewCollection, IDictionary<string, T> realCollection, Action<T, T, ValidationContext> validator, ValidationContext context = null)
        {
            if (viewCollection == null && realCollection == null)
            {
                return;
            }
 
            Assert.NotNull(viewCollection);
            Assert.NotNull(realCollection);
 
            Assert.Equal(realCollection.Count, viewCollection.Count);
            foreach (var k in realCollection.Keys)
            {
                Assert.True(viewCollection.TryGetValue(k, out var vv));
                Assert.True(realCollection.TryGetValue(k, out var rv));
                validator(vv, rv, context);
            }
        }
 
        public static void Verify<T>(IEnumerable<T> viewXmlCollection, IEnumerable<T> realXmlCollection, ValidationContext context = null)
        {
            var viewXmlList = viewXmlCollection.ToList();
            var realXmlList = realXmlCollection.ToList();
            Assert.Equal(realXmlList.Count, viewXmlList.Count);
            for (int i = 0; i < realXmlList.Count; i++)
            {
                VerifyFindType(viewXmlList[i], realXmlList[i], context);
            }
        }
    }
}