// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#if NETFRAMEWORK

using AwesomeAssertions;

using TestFramework.ForTestingMSTest;

using static MSTestAdapter.PlatformServices.UnitTests.Utilities.AppDomainUtilitiesTests;

namespace MSTestAdapter.PlatformServices.UnitTests.Utilities;

public class XmlUtilitiesTests : TestContainer
{
    private readonly TestableXmlUtilities _testableXmlUtilities = new();

    public void AddAssemblyRedirectionShouldAddRedirectionToAnEmptyXml()
    {
        _testableXmlUtilities.ConfigXml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>";
        AssemblyName assemblyName = Assembly.GetExecutingAssembly().GetName();

        byte[] configBytes = _testableXmlUtilities.AddAssemblyRedirection(
            "foo.xml",
            assemblyName,
            "99.99.99.99",
            assemblyName.Version.ToString());

        // Assert.
        string expectedXml = $$"""
            <?xml version="1.0" encoding="utf-8"?>
            <configuration>
                <runtime>
                    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                        <dependentAssembly>
                            <assemblyIdentity name="MSTestAdapter.PlatformServices.UnitTests" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
                            <bindingRedirect oldVersion="99.99.99.99" newVersion="{{assemblyName.Version}}" />
                        </dependentAssembly>
                    </assemblyBinding>
                </runtime>
            </configuration>
            """;
        var doc = new XmlDocument();
        doc.LoadXml(expectedXml);
        byte[] expectedConfigBytes;

        using (var ms = new MemoryStream())
        {
            doc.Save(ms);
            expectedConfigBytes = ms.ToArray();
        }

        configBytes.SequenceEqual(expectedConfigBytes).Should().BeTrue();
    }

    public void AddAssemblyRedirectionShouldAddRedirectionToAnEmptyConfig()
    {
        _testableXmlUtilities.ConfigXml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
<configuration>
</configuration>";
        AssemblyName assemblyName = Assembly.GetExecutingAssembly().GetName();

        byte[] configBytes = _testableXmlUtilities.AddAssemblyRedirection(
            "foo.xml",
            assemblyName,
            "99.99.99.99",
            assemblyName.Version.ToString());

        // Assert.
        string expectedXml = $$"""
            <?xml version="1.0" encoding="utf-8"?>
            <configuration>
                <runtime>
                    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                        <dependentAssembly>
                            <assemblyIdentity name="MSTestAdapter.PlatformServices.UnitTests" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
                            <bindingRedirect oldVersion="99.99.99.99" newVersion="{{assemblyName.Version}}" />
                        </dependentAssembly>
                    </assemblyBinding>
                </runtime>
            </configuration>
            """;
        var doc = new XmlDocument();
        doc.LoadXml(expectedXml);
        byte[] expectedConfigBytes;

        using (var ms = new MemoryStream())
        {
            doc.Save(ms);
            expectedConfigBytes = ms.ToArray();
        }

        configBytes.SequenceEqual(expectedConfigBytes).Should().BeTrue();
    }

    public void AddAssemblyRedirectionShouldAddRedirectionToAConfigWithARuntimeSectionOnly()
    {
        _testableXmlUtilities.ConfigXml = @"<?xml version=""1.0"" encoding=""utf-8"" ?>
<configuration>
<runtime>
</runtime>
</configuration>";
        AssemblyName assemblyName = Assembly.GetExecutingAssembly().GetName();

        byte[] configBytes = _testableXmlUtilities.AddAssemblyRedirection(
            "foo.xml",
            assemblyName,
            "99.99.99.99",
            assemblyName.Version.ToString());

        // Assert.
        string expectedXml = $$"""
            <?xml version="1.0" encoding="utf-8"?>
            <configuration>
                <runtime>
                    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                        <dependentAssembly>
                            <assemblyIdentity name="MSTestAdapter.PlatformServices.UnitTests" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
                            <bindingRedirect oldVersion="99.99.99.99" newVersion="{{assemblyName.Version}}" />
                        </dependentAssembly>
                    </assemblyBinding>
                </runtime>
            </configuration>
            """;
        var doc = new XmlDocument();
#pragma warning disable CA3075 // Insecure DTD processing in XML
        doc.LoadXml(expectedXml);
#pragma warning restore CA3075 // Insecure DTD processing in XML
        byte[] expectedConfigBytes;

        using (var ms = new MemoryStream())
        {
            doc.Save(ms);
            expectedConfigBytes = ms.ToArray();
        }

        configBytes.SequenceEqual(expectedConfigBytes).Should().BeTrue();
    }

    public void AddAssemblyRedirectionShouldAddRedirectionToAConfigWithRedirections()
    {
        _testableXmlUtilities.ConfigXml = """
            <?xml version="1.0" encoding="utf-8" ?>
            <configuration>
                <runtime>
                    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                        <dependentAssembly>
                            <assemblyIdentity name="Random.UnitTests" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
                            <bindingRedirect oldVersion="99.99.99.99" newVersion="14.0.0.0" />
                        </dependentAssembly>
                    </assemblyBinding>
                </runtime>
            </configuration>
            """;
        AssemblyName assemblyName = Assembly.GetExecutingAssembly().GetName();

        byte[] configBytes = _testableXmlUtilities.AddAssemblyRedirection(
            "foo.xml",
            assemblyName,
            "99.99.99.99",
            assemblyName.Version.ToString());

        // Assert.
        string expectedXml = $$"""
            <?xml version="1.0" encoding="utf-8"?>
            <configuration>
                <runtime>
                    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
                        <dependentAssembly>
                            <assemblyIdentity name="Random.UnitTests" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
                            <bindingRedirect oldVersion="99.99.99.99" newVersion="14.0.0.0" />
                        </dependentAssembly>
                        <dependentAssembly>
                            <assemblyIdentity name="MSTestAdapter.PlatformServices.UnitTests" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
                            <bindingRedirect oldVersion="99.99.99.99" newVersion="{{assemblyName.Version}}" />
                        </dependentAssembly>
                    </assemblyBinding>
                </runtime>
            </configuration>
            """;
        var doc = new XmlDocument();
        doc.LoadXml(expectedXml);
        byte[] expectedConfigBytes;

        using (var ms = new MemoryStream())
        {
            doc.Save(ms);
            expectedConfigBytes = ms.ToArray();
        }

        configBytes.SequenceEqual(expectedConfigBytes).Should().BeTrue();
    }
}
#endif
