File: System\Xaml\XamlSchemaContextTests.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\tests\UnitTests\System.Xaml.Tests\System.Xaml.Tests.csproj (System.Xaml.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Windows.Markup;
using System.Xaml.Schema;
using System.Xaml.Tests.Common;
using Xunit;
 
namespace System.Xaml.Tests;
 
public class XamlSchemaContextTests
{
    [Fact]
    public void Ctor_Default()
    {
        var context = new XamlSchemaContext();
        Assert.False(context.SupportMarkupExtensionsWithDuplicateArity);
        Assert.False(context.FullyQualifyAssemblyNamesInClrNamespaces);
        Assert.Null(context.ReferenceAssemblies);
    }
 
    public static IEnumerable<object?[]> Ctor_XamlSchemaContextSettings_TestData()
    {
        yield return new object?[] { null, false, false };
        yield return new object?[]
        {
            new XamlSchemaContextSettings
            {
                SupportMarkupExtensionsWithDuplicateArity = true,
                FullyQualifyAssemblyNamesInClrNamespaces = true
            }, true, true
        };
    }
 
    [Theory]
    [MemberData(nameof(Ctor_XamlSchemaContextSettings_TestData))]
    public void Ctor_XamlSchemaContextSettings(XamlSchemaContextSettings settings, bool expectdSupportMarkupExtensionsWithDuplicateArity, bool expectedFullyQualifyAssemblyNamesInClrNamespaces)
    {
        var context = new XamlSchemaContext(settings);
        Assert.Equal(expectdSupportMarkupExtensionsWithDuplicateArity, context.SupportMarkupExtensionsWithDuplicateArity);
        Assert.Equal(expectedFullyQualifyAssemblyNamesInClrNamespaces, context.FullyQualifyAssemblyNamesInClrNamespaces);
        Assert.Null(context.ReferenceAssemblies);
    }
 
    public static IEnumerable<object?[]> Ctor_ReferencedAssemblies_TestData()
    {
        yield return new object?[] { null };
        yield return new object?[] { Array.Empty<Assembly>() };
        yield return new object?[] { new Assembly?[] { typeof(XamlSchemaContextSettings).Assembly, typeof(int).Assembly, null } };
    }
 
    [Theory]
    [MemberData(nameof(Ctor_ReferencedAssemblies_TestData))]
    public void Ctor_ReferencedAssemblies(IEnumerable<Assembly> referenceAssemblies)
    {
        var context = new XamlSchemaContext(referenceAssemblies);
        Assert.False(context.SupportMarkupExtensionsWithDuplicateArity);
        Assert.False(context.FullyQualifyAssemblyNamesInClrNamespaces);
        Assert.Equal(referenceAssemblies, context.ReferenceAssemblies);
        if (referenceAssemblies != null)
        {
            Assert.NotSame(referenceAssemblies, context.ReferenceAssemblies);
        }
    }
 
    public static IEnumerable<object?[]> Ctor_XamlSchemaContextSettings_ReferenceAssemblies_TestData()
    {
        yield return new object?[] { null, null, false, false };
        yield return new object?[]
        {
            new XamlSchemaContextSettings
            {
                SupportMarkupExtensionsWithDuplicateArity = true,
                FullyQualifyAssemblyNamesInClrNamespaces = true
            }, new Assembly?[] { typeof(XamlSchemaContextSettings).Assembly, typeof(int).Assembly, null }, true, true
        };
        yield return new object?[] { null, Array.Empty<Assembly>(), false, false };
    }
 
    [Theory]
    [MemberData(nameof(Ctor_XamlSchemaContextSettings_ReferenceAssemblies_TestData))]
    public void Ctor_XamlSchemaContextSettings_ReferenceAssemblies(XamlSchemaContextSettings settings, IEnumerable<Assembly> referenceAssemblies, bool expectdSupportMarkupExtensionsWithDuplicateArity, bool expectedFullyQualifyAssemblyNamesInClrNamespaces)
    {
        var context = new XamlSchemaContext(referenceAssemblies, settings);
        Assert.Equal(expectdSupportMarkupExtensionsWithDuplicateArity, context.SupportMarkupExtensionsWithDuplicateArity);
        Assert.Equal(expectedFullyQualifyAssemblyNamesInClrNamespaces, context.FullyQualifyAssemblyNamesInClrNamespaces);
        Assert.Equal(referenceAssemblies, context.ReferenceAssemblies);
        if (referenceAssemblies != null)
        {
            Assert.NotSame(referenceAssemblies, context.ReferenceAssemblies);
        }
    }
 
    [Theory]
    [InlineData("", "p")]
    [InlineData("namespace", "p")]
    [InlineData("http://schemas.microsoft.com/winfx/2006/xaml", "x")]
    [InlineData("clr-namespace:", "local")]
    [InlineData("clr-namespace:namespace", "local")]
    [InlineData("clr-namespace:namespace;assembly=", "local")]
    [InlineData("clr-namespace:namespace;assembly=assemblyName", "n")]
    [InlineData("clr-namespace:..;assembly=assemblyName", "local")]
    [InlineData("clr-namespace:;assembly=assemblyName", "local")]
    [InlineData("clr-namespace:namespace.sub.type;assembly=assemblyName", "nst")]
    [InlineData("clr-namespace:NAMESPACE.SUB.type;assembly=assemblyName", "nst")]
    [InlineData("clr-namespace:x;assembly=assemblyName", "p")]
    [InlineData("clr-namespace:x.n;assembly=assemblyName", "xn")]
    [InlineData("clr-namespace:x.m.l;assembly=assemblyName", "p")]
    [InlineData("clr-namespace:x.m.l.s;assembly=assemblyName", "xmls")]
    [InlineData("clr-namespace", "p")]
    [InlineData("other-namespace:", "p")]
    [InlineData(":", "p")]
    [InlineData("clr-namespace:namespace;", "p")]
    [InlineData("clr-namespace:namespace;assembly", "p")]
    [InlineData("clr-namespace:namespace;other-assembly=assemblyName", "p")]
    public void GetPreferredPrefix_Invoke_ReturnsExpected(string xmlns, string expected)
    {
        var context = new XamlSchemaContext();
        Assert.Equal(expected, context.GetPreferredPrefix(xmlns));
        Assert.Equal(expected, context.GetPreferredPrefix(xmlns));
    }
 
    [Theory]
    [InlineData("namespace", "prefix")]
    [InlineData("doubleNamespace1", "doublePrefix")]
    [InlineData("doubleNamespace2", "doublePrefix")]
    [InlineData("sameNamespace", "prefix1")]
    [InlineData("other", "p")]
    [InlineData("longerAssemblyNamespace", "longerAssemblyPrefix")]
    [InlineData("shorterAssemblyNamespace", "shorterAssemblyPrefi")]
    [InlineData("greaterAssemblyNamespace", "greaterAssemblyPrefix1")]
    [InlineData("lesserAssemblyNamespace", "lesserAssemblyPrefix1")]
    public void GetPreferredPrefix_OverridenCustomPrefixes_Success(string xmlns, string expected)
    {
        var assembly1 = new CustomAssembly(typeof(XamlTypeTests).Assembly)
        {
            GetCustomAttributesMap = new Dictionary<Type, object?[]?>
            {
                {
                    typeof(XmlnsPrefixAttribute),
                    new Attribute[]
                    {
                        new XmlnsPrefixAttribute("namespace", "prefix"),
                        new XmlnsPrefixAttribute("doubleNamespace1", "doublePrefix"),
                        new XmlnsPrefixAttribute("doubleNamespace2", "doublePrefix"),
                        new XmlnsPrefixAttribute("sameNamespace", "prefix1"),
                        new XmlnsPrefixAttribute("sameNamespace", "prefix2"),
                        new XmlnsPrefixAttribute("longerAssemblyNamespace", "longerAssemblyPrefix"),
                        new XmlnsPrefixAttribute("shorterAssemblyNamespace", "shorterAssemblyPrefix"),
                        new XmlnsPrefixAttribute("greaterAssemblyNamespace", "greaterAssemblyPrefix2"),
                        new XmlnsPrefixAttribute("lesserAssemblyNamespace", "lesserAssemblyPrefix1")
                    }
                }
            }
        };
        var assembly2 = new CustomAssembly(typeof(XamlTypeTests).Assembly)
        {
            GetCustomAttributesMap = new Dictionary<Type, object?[]?>
            {
                {
                    typeof(XmlnsPrefixAttribute),
                    new Attribute[]
                    {
                        new XmlnsPrefixAttribute("longerAssemblyNamespace", "longerAssemblyPrefix2"),
                        new XmlnsPrefixAttribute("shorterAssemblyNamespace", "shorterAssemblyPrefi"),
                        new XmlnsPrefixAttribute("greaterAssemblyNamespace", "greaterAssemblyPrefix1"),
                        new XmlnsPrefixAttribute("lesserAssemblyNamespace", "lesserAssemblyPrefix2"),
                    }
                }
            }
        };
        var context = new XamlSchemaContext(new Assembly[] { assembly1, assembly2 });
        Assert.Equal(expected, context.GetPreferredPrefix(xmlns));
        Assert.Equal(expected, context.GetPreferredPrefix(xmlns));
    }
 
    [Fact]
    public void GetPreferredPrefix_NewAssemblySinceLastCall_Success()
    {
        var context = new XamlSchemaContext();
        Assert.Equal("p", context.GetPreferredPrefix("noSuchNamespace"));
 
        AssemblyBuilder _ = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Name"), AssemblyBuilderAccess.Run, new CustomAttributeBuilder[]
        {
            new CustomAttributeBuilder(
                typeof(XmlnsPrefixAttribute).GetConstructors()[0],
                new object[] { "loadedNamespace", "loadedPrefix" }
            )
        });
        Assert.Equal("loadedPrefix", context.GetPreferredPrefix("loadedNamespace"));
    }
 
    [Theory]
    [InlineData("namespace", "prefix")]
    [InlineData("doubleNamespace1", "doublePrefix")]
    [InlineData("doubleNamespace2", "doublePrefix")]
    [InlineData("sameNamespace", "prefix1")]
    [InlineData("other", "p")]
    public void GetPreferredPrefix_OverridenCustomPrefixesReflectionOnly_Success(string xmlns, string expected)
    {
        ConstructorInfo constructor = typeof(XmlnsPrefixAttribute).GetConstructors()[0];
        var assemblyWithPrefix = new CustomAssembly(typeof(XamlTypeTests).Assembly)
        {
            ReflectionOnlyResult = true,
            GetCustomAttributesDataResult = new CustomAttributeData[]
            {
                new CustomCustomAttributeData
                {
                    ConstructorResult = constructor,
                    ConstructorArgumentsResult = new CustomAttributeTypedArgument[]
                    {
                        new CustomAttributeTypedArgument(typeof(string), "namespace"),
                        new CustomAttributeTypedArgument(typeof(string), "prefix")
                    }
                },
                new CustomCustomAttributeData
                {
                    ConstructorResult = constructor,
                    ConstructorArgumentsResult = new CustomAttributeTypedArgument[]
                    {
                        new CustomAttributeTypedArgument(typeof(string), "doubleNamespace1"),
                        new CustomAttributeTypedArgument(typeof(string), "doublePrefix")
                    }
                },
                new CustomCustomAttributeData
                {
                    ConstructorResult = constructor,
                    ConstructorArgumentsResult = new CustomAttributeTypedArgument[]
                    {
                        new CustomAttributeTypedArgument(typeof(string), "doubleNamespace2"),
                        new CustomAttributeTypedArgument(typeof(string), "doublePrefix")
                    }
                },
                new CustomCustomAttributeData
                {
                    ConstructorResult = constructor,
                    ConstructorArgumentsResult = new CustomAttributeTypedArgument[]
                    {
                        new CustomAttributeTypedArgument(typeof(string), "sameNamespace"),
                        new CustomAttributeTypedArgument(typeof(string), "prefix1")
                    }
                },
                new CustomCustomAttributeData
                {
                    ConstructorResult = constructor,
                    ConstructorArgumentsResult = new CustomAttributeTypedArgument[]
                    {
                        new CustomAttributeTypedArgument(typeof(string), "sameNamespace"),
                        new CustomAttributeTypedArgument(typeof(string), "prefix1")
                    }
                },
            }
        };
        var context = new XamlSchemaContext(new Assembly[] { assemblyWithPrefix });
        Assert.Equal(expected, context.GetPreferredPrefix(xmlns));
    }
 
    [Fact]
    public void GetPreferredPrefix_NullValueInReferencedAssemblies_ReturnsExpected()
    {
        var context = new XamlSchemaContext(new Assembly?[] { null });
        Assert.Equal("p", context.GetPreferredPrefix("prefix"));
    }
 
    [Fact]
    public void GetPreferredPrefix_NullXmlns_ThrowsArgumentNullException()
    {
        var context = new XamlSchemaContext();
        Assert.Throws<ArgumentNullException>("xmlns", () => context.GetPreferredPrefix(null));
    }
 
    public static IEnumerable<object[]> GetPreferredPrefix_InvalidXmlnsPrefixAttribute_TestData()
    {
        yield return new object[]
        {
            new CustomAttributeTypedArgument[]
            {
                new CustomAttributeTypedArgument(typeof(string), null),
                new CustomAttributeTypedArgument(typeof(string), "prefix")
            }
        };
        yield return new object[]
        {
            new CustomAttributeTypedArgument[]
            {
                new CustomAttributeTypedArgument(typeof(string), ""),
                new CustomAttributeTypedArgument(typeof(string), "prefix")
            }
        };
        yield return new object[]
        {
            new CustomAttributeTypedArgument[]
            {
                new CustomAttributeTypedArgument(typeof(string), "xmlNamespace"),
                new CustomAttributeTypedArgument(typeof(string), null)
            }
        };
        yield return new object[]
        {
            new CustomAttributeTypedArgument[]
            {
                new CustomAttributeTypedArgument(typeof(string), "xmlNamespace"),
                new CustomAttributeTypedArgument(typeof(string), "")
            }
        };
    }
 
    [Theory]
    [MemberData(nameof(GetPreferredPrefix_InvalidXmlnsPrefixAttribute_TestData))]
    public void GetPreferredPrefix_InvalidXmlnsPrefixAttribute_ThrowsXamlSchemaException(CustomAttributeTypedArgument[] arguments)
    {
        var assembly = new CustomAssembly(typeof(XamlTypeTests).Assembly)
        {
            ReflectionOnlyResult = true,
            GetCustomAttributesDataResult = new CustomAttributeData[]
            {
                new CustomCustomAttributeData
                {
                    ConstructorResult = typeof(XmlnsPrefixAttribute).GetConstructors()[0],
                    ConstructorArgumentsResult = arguments
                }
            }
        };
        var context = new XamlSchemaContext(new Assembly[] { assembly });
        Assert.Throws<XamlSchemaException>(() => context.GetPreferredPrefix("xmlns"));
    }
 
    [Fact]
    public void GetPreferredPrefix_NullAttributeResult_ThrowsNullReferenceException()
    {
        var assembly = new CustomAssembly(typeof(XamlTypeTests).Assembly)
        {
            GetCustomAttributesMap = new Dictionary<Type, object?[]?>
            {
                { typeof(XmlnsPrefixAttribute), null }
            }
        };
        var context = new XamlSchemaContext(new Assembly[] { assembly });
        Assert.Throws<NullReferenceException>(() => context.GetPreferredPrefix("xmlns"));
    }
 
    [Fact]
    public void GetPreferredPrefix_InvalidAttributeResultType_ThrowsInvalidCastException()
    {
        var assembly = new CustomAssembly(typeof(XamlTypeTests).Assembly)
        {
            GetCustomAttributesMap = new Dictionary<Type, object?[]?>
            {
                { typeof(XmlnsPrefixAttribute), new object[] { new XmlnsDefinitionAttribute("xmlNamespace", "clrNamespace") } }
            }
        };
        var context = new XamlSchemaContext(new Assembly[] { assembly });
        Assert.Throws<InvalidCastException>(() => context.GetPreferredPrefix("xmlns"));
    }
 
    [Fact]
    public void GetPreferredPrefix_NullItemInAttributeResult_ThrowsNullReferenceException()
    {
        var assembly = new CustomAssembly(typeof(XamlTypeTests).Assembly)
        {
            GetCustomAttributesMap = new Dictionary<Type, object?[]?>
            {
                { typeof(XmlnsPrefixAttribute), new Attribute?[] { null } }
            }
        };
        var context = new XamlSchemaContext(new Assembly[] { assembly });
        Assert.Throws<NullReferenceException>(() => context.GetPreferredPrefix("xmlns"));
    }
 
    [Fact]
    public void GetPreferredPrefix_InvalidTypeItemInAttributeResult_ThrowsInvalidCastException()
    {
        var assembly = new CustomAssembly(typeof(XamlTypeTests).Assembly)
        {
            GetCustomAttributesMap = new Dictionary<Type, object?[]?>
            {
                { typeof(XmlnsDefinitionAttribute), new Attribute[] { new AttributeUsageAttribute(AttributeTargets.All) } }
            }
        };
        var context = new XamlSchemaContext(new Assembly[] { assembly });
        Assert.Throws<InvalidCastException>(() => context.GetPreferredPrefix("xmlns"));
    }
 
    public static IEnumerable<object?[]> GetXamlDirective_TestData()
    {
        const string XamlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml";
        const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
 
        yield return new object?[] { XamlNamespace, "AsyncRecords", XamlLanguage.AsyncRecords };
        yield return new object?[] { XamlNamespace, "Arguments", XamlLanguage.Arguments };
        yield return new object?[] { XamlNamespace, "Class", XamlLanguage.Class };
        yield return new object?[] { XamlNamespace, "ClassModifier", XamlLanguage.ClassModifier };
        yield return new object?[] { XamlNamespace, "Code", XamlLanguage.Code };
        yield return new object?[] { XamlNamespace, "ConnectionId", XamlLanguage.ConnectionId };
        yield return new object?[] { XamlNamespace, "FactoryMethod", XamlLanguage.FactoryMethod };
        yield return new object?[] { XamlNamespace, "FieldModifier", XamlLanguage.FieldModifier };
        yield return new object?[] { XamlNamespace, "_Initialization", XamlLanguage.Initialization };
        yield return new object?[] { XamlNamespace, "_Items", XamlLanguage.Items };
        yield return new object?[] { XamlNamespace, "Key", XamlLanguage.Key };
        yield return new object?[] { XamlNamespace, "Members", XamlLanguage.Members };
        yield return new object?[] { XamlNamespace, "ClassAttributes", XamlLanguage.ClassAttributes };
        yield return new object?[] { XamlNamespace, "Name", XamlLanguage.Name };
        yield return new object?[] { XamlNamespace, "_PositionalParameters", XamlLanguage.PositionalParameters };
        yield return new object?[] { XamlNamespace, "Shared", XamlLanguage.Shared };
        yield return new object?[] { XamlNamespace, "Subclass", XamlLanguage.Subclass };
        yield return new object?[] { XamlNamespace, "SynchronousMode", XamlLanguage.SynchronousMode };
        yield return new object?[] { XamlNamespace, "TypeArguments", XamlLanguage.TypeArguments };
        yield return new object?[] { XamlNamespace, "Uid", XamlLanguage.Uid };
        yield return new object?[] { XamlNamespace, "_UnknownContent", XamlLanguage.UnknownContent };
        yield return new object?[] { XamlNamespace, "name", null };
        yield return new object?[] { XamlNamespace, "Base", null };
        yield return new object?[] { XamlNamespace, "Language", null };
        yield return new object?[] { XamlNamespace, "Space", null };
        yield return new object?[] { XamlNamespace, "NoSuchDirective", null };
        yield return new object?[] { XamlNamespace, "", null };
 
        yield return new object?[] { XmlNamespace, "base", XamlLanguage.Base };
        yield return new object?[] { XmlNamespace, "lang", XamlLanguage.Lang };
        yield return new object?[] { XmlNamespace, "space", XamlLanguage.Space };
        yield return new object?[] { XmlNamespace, "Base", null };
        yield return new object?[] { XmlNamespace, "NoSuchDirective", null };
        yield return new object?[] { XmlNamespace, "", null };
 
        yield return new object?[] { "NoSuchNamespace", "Name", null };
    }
 
    [Theory]
    [MemberData(nameof(GetXamlDirective_TestData))]
    public void GetXamlDirective_Invoke_ReturnsExpected(string xamlNamespace, string name, XamlDirective expected)
    {
        var context = new XamlSchemaContext();
        Assert.Equal(expected, context.GetXamlDirective(xamlNamespace, name));
    }
 
    public static IEnumerable<object?[]> GetXamlType_XamlTypeName_TestData()
    {
        const string XamlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml";
        static string Name(Assembly assembly) => new AssemblyName(assembly.FullName!).Name!;
 
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Array"),
            new XamlType(typeof(ArrayExtension), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "ArrayExtension"),
            new XamlType(typeof(ArrayExtension), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Member"),
            new XamlType(typeof(MemberDefinition), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Null"),
            new XamlType(typeof(NullExtension), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "NullExtension"),
            new XamlType(typeof(NullExtension), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Property"),
            new XamlType(typeof(PropertyDefinition), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Reference"),
            new XamlType(typeof(Reference), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "ReferenceExtension"),
            new XamlType(typeof(Reference), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Static"),
            new XamlType(typeof(StaticExtension), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "StaticExtension"),
            new XamlType(typeof(StaticExtension), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Type"),
            new XamlType(typeof(TypeExtension), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "TypeExtension"),
            new XamlType(typeof(TypeExtension), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "String"),
            new XamlType(typeof(string), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Double"),
            new XamlType(typeof(double), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Int16"),
            new XamlType(typeof(short), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Int32"),
            new XamlType(typeof(int), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Int64"),
            new XamlType(typeof(long), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Boolean"),
            new XamlType(typeof(bool), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "XData"),
            new XamlType(typeof(XData), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Object"),
            new XamlType(typeof(object), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Char"),
            new XamlType(typeof(char), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Single"),
            new XamlType(typeof(float), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Byte"),
            new XamlType(typeof(byte), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Decimal"),
            new XamlType(typeof(decimal), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Uri"),
            new XamlType(typeof(Uri), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "TimeSpan"),
            new XamlType(typeof(TimeSpan), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "double"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName(XamlNamespace, "Name"),
            null
        };
 
        // Valid assembly.
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + typeof(int).Assembly.FullName, "Int32"),
            new XamlType(typeof(int), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + Name(typeof(int).Assembly), "Int32"),
            new XamlType(typeof(int), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Xaml.Tests;assembly=" + typeof(XamlSchemaContextTests).Assembly.FullName, "XamlSchemaContextTests"),
            new XamlType(typeof(XamlSchemaContextTests), new XamlSchemaContext())
        };
 
        // Type arguments.
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Collections.Generic;assembly=" + Name(typeof(List<>).Assembly), "List", new XamlTypeName[]
            {
                new XamlTypeName("clr-namespace:System;assembly=" + Name(typeof(int).Assembly), "Int32")
            }),
            new XamlType(typeof(List<int>), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Collections.Generic;assembly=" + Name(typeof(List<>).Assembly), "List[]", new XamlTypeName[]
            {
                new XamlTypeName("clr-namespace:System;assembly=" + Name(typeof(int).Assembly), "Int32")
            }),
            new XamlType(typeof(List<int>[]), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Collections.Generic;assembly=" + Name(typeof(List<>).Assembly), "List[][,]", new XamlTypeName[]
            {
                new XamlTypeName("clr-namespace:System;assembly=" + Name(typeof(int).Assembly), "Int32")
            }),
            new XamlType(typeof(List<int>[,][]), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Collections.Generic;assembly=" + Name(typeof(List<>).Assembly), "List[ ] [ , ]", new XamlTypeName[]
            {
                new XamlTypeName("clr-namespace:System;assembly=" + Name(typeof(int).Assembly), "Int32")
            }),
            new XamlType(typeof(List<int>[,][]), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Collections.Generic;assembly=" + Name(typeof(List<>).Assembly), "List[,  ,]", new XamlTypeName[]
            {
                new XamlTypeName("clr-namespace:System;assembly=" + Name(typeof(int).Assembly), "Int32")
            }),
            new XamlType(typeof(List<int>[,,]), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Collections.Generic;assembly=" + Name(typeof(List<>).Assembly), "NoSuchType", new XamlTypeName[]
            {
                new XamlTypeName("clr-namespace:System;assembly=" + Name(typeof(int).Assembly), "Int32")
            }),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Collections.Generic;assembly=" + Name(typeof(List<>).Assembly), "List", new XamlTypeName[]
            {
                new XamlTypeName("clr-namespace:System;assembly=" + Name(typeof(int).Assembly), "NoSuchType")
            }),
            null
        };
 
        foreach (string invalidArrayName in new string[] { "List[", "List[,", "List[invalid]", "List[[]", "List]", "List,", "List[] ", "List[],", "List[]]", "List[]]invalid", "List[][" })
        {
            yield return new object?[]
            {
                new XamlTypeName("clr-namespace:System.Collections.Generic;assembly=" + Name(typeof(List<>).Assembly), invalidArrayName, new XamlTypeName[]
                {
                    new XamlTypeName("clr-namespace:System;assembly=" + Name(typeof(int).Assembly), "Int32")
                }),
                null
            };
        }
 
        // Nested type.
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Xaml.Tests;assembly=" + typeof(XamlSchemaContextTests).Assembly.FullName, "XamlSchemaContextTests+PublicNestedClass"),
            new XamlType(typeof(PublicNestedClass), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Xaml.Tests;assembly=" + typeof(XamlSchemaContextTests).Assembly.FullName, "XamlSchemaContextTests+PrivateNestedClass"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Xaml.Tests;assembly=" + typeof(XamlSchemaContextTests).Assembly.FullName, "XamlSchemaContextTests+PublicNestedClass+PublicClass"),
            new XamlType(typeof(PublicNestedClass.PublicClass), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Xaml.Tests;assembly=" + typeof(XamlSchemaContextTests).Assembly.FullName, "XamlSchemaContextTests+PublicNestedClass+PrivateClass"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Xaml.Tests;assembly=" + typeof(XamlSchemaContextTests).Assembly.FullName, "XamlSchemaContextTests+PrivateNestedClass+PublicClass"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Xaml.Tests;assembly=" + typeof(XamlSchemaContextTests).Assembly.FullName, "XamlSchemaContextTests+PrivateNestedClass+PublicClass"),
            null
        };
 
        // System.Xaml assemnbly.
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Xaml;assembly=" + typeof(XamlLanguage).Assembly.FullName, "XamlType"),
            new XamlType(typeof(XamlType), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup;assembly=" + typeof(XamlLanguage).Assembly.FullName, "MemberDefinition"),
            new XamlType(typeof(MemberDefinition), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup;assembly=" + typeof(XamlLanguage).Assembly.FullName, "Member"),
            new XamlType(typeof(MemberDefinition), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup.Sub;assembly=" + typeof(XamlLanguage).Assembly.FullName, "Member"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup;assembly=" + typeof(int).Assembly.FullName, "Member"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup;assembly=" + typeof(XamlLanguage).Assembly.FullName, "PropertyDefinition"),
            new XamlType(typeof(PropertyDefinition), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup;assembly=" + typeof(XamlLanguage).Assembly.FullName, "Property"),
            new XamlType(typeof(PropertyDefinition), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup.Sub;assembly=" + typeof(XamlLanguage).Assembly.FullName, "Property"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup;assembly=" + typeof(int).Assembly.FullName, "Property"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup;assembly=" + typeof(XamlLanguage).Assembly.FullName, "AmbientAttribute"),
            new XamlType(typeof(AmbientAttribute), new XamlSchemaContext())
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Windows.Markup;assembly=" + typeof(XamlLanguage).Assembly.FullName, "NoSuchType"),
            null
        };
    
        // Invalid assembly.
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System", "Int32"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=", "Int32"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=NoSuchAssembly", "Int32"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=NoSuchAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e", "Int32"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:;assembly=" + Name(typeof(int).Assembly), "Int32"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System.Inner;assembly=" + Name(typeof(int).Assembly), "Int32"),
            null
        };
 
        yield return new object?[]
        {
            new XamlTypeName("", ""),
            null
        };
    }
 
    [Theory]
    [MemberData(nameof(GetXamlType_XamlTypeName_TestData))]
    public void GetXamlType_TypeName_ReturnsExpected(XamlTypeName xamlTypeName, XamlType expected)
    {
        var context = new XamlSchemaContext();
        XamlType actual = context.GetXamlType(xamlTypeName);
        Assert.Equal(expected, actual);
        Assert.Same(actual, context.GetXamlType(xamlTypeName));
    }
 
    [Theory]
    [MemberData(nameof(GetXamlType_XamlTypeName_TestData))]
    public void GetXamlType_TypeNameFullyQualifyAssemblyNamesInClrNamespaces_ReturnsExpected(XamlTypeName xamlTypeName, XamlType expected)
    {
        var settings = new XamlSchemaContextSettings
        {
            FullyQualifyAssemblyNamesInClrNamespaces = true
        };
        var context = new XamlSchemaContext(settings);
        XamlType actual = context.GetXamlType(xamlTypeName);
        Assert.Equal(expected, actual);
    }
 
    [Fact]
    public void GetXamlType_OverridenGetXamlTypeType_ReturnsNull()
    {
        var context = new CustomXamlSchemaContext
        {
            GetXamlTypeAction = type =>
            {
                Assert.Equal(typeof(int), type);
                return null!;
            }
        };
        var xamlTypeName = new XamlTypeName("clr-namespace:System;assembly=" + typeof(int).Assembly.FullName, "Int32");
        Assert.Null(context.GetXamlType(xamlTypeName));
    }
 
    [Fact]
    public void GetXamlType_OverridenGetXamlTypeGenericType_ReturnsNull()
    {
        var context = new CustomXamlSchemaContext
        {
            GetXamlTypeAction = type => null!
        };
        var xamlTypeName = new XamlTypeName("clr-namespace:System.Collections.Generic;assembly=" + typeof(List<int>).Assembly.FullName, "List", new XamlTypeName[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + typeof(int).Assembly.FullName, "Int32")
        });
        Assert.Null(context.GetXamlType(xamlTypeName));
    }
    
    public static IEnumerable<object?[]> GetXamlType_ReferencesAssemblies_TestData()
    {
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + typeof(int).Assembly.FullName, "Int32"),
            new XamlType(typeof(int), new XamlSchemaContext())
        };
 
        var noVersionAssemblyName = new AssemblyName(typeof(int).Assembly.FullName!)
        {
            Version = null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + noVersionAssemblyName.FullName, "Int32"),
            new XamlType(typeof(int), new XamlSchemaContext())
        };
 
        var noCultureAssemblyName = new AssemblyName(typeof(int).Assembly.FullName!)
        {
            CultureInfo = null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + noCultureAssemblyName.FullName, "Int32"),
            new XamlType(typeof(int), new XamlSchemaContext())
        };
 
        var noPublicKeyTokenAssemblyName = new AssemblyName(typeof(int).Assembly.FullName!);
        noPublicKeyTokenAssemblyName.SetPublicKeyToken(null);
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + noPublicKeyTokenAssemblyName.FullName, "Int32"),
            new XamlType(typeof(int), new XamlSchemaContext())
        };
 
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=NoSuchAssembly", "Int32"),
            null
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=NoSuchAssembly, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e", "Int32"),
            null
        };
 
        var incorrectVersionAssemblyName = new AssemblyName(typeof(int).Assembly.FullName!)
        {
            Version = new Version(1, 2, 3, 4)
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + incorrectVersionAssemblyName.FullName, "Int32"),
            null
        };
 
        var incorrectCultureAssemblyName = new AssemblyName(typeof(int).Assembly.FullName!)
        {
            CultureInfo = new CultureInfo("en")
        };
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + incorrectCultureAssemblyName.FullName, "Int32"),
            null
        };
 
        var incorrectPublicKeyToken = new AssemblyName(typeof(int).Assembly.FullName!);
        incorrectPublicKeyToken.SetPublicKeyToken(new AssemblyName(typeof(XamlSchemaContextTests).Assembly.FullName!).GetPublicKeyToken());
        yield return new object?[]
        {
            new XamlTypeName("clr-namespace:System;assembly=" + incorrectPublicKeyToken.FullName, "Int32"),
            null
        };
    }
 
    [Theory]
    [MemberData(nameof(GetXamlType_ReferencesAssemblies_TestData))]
    public void GetXamlType_ReferencesAssemblies_Success(XamlTypeName xamlTypeName, XamlType expected)
    {
        var context = new XamlSchemaContext(new Assembly[] { typeof(int).Assembly });
        XamlType actual = context.GetXamlType(xamlTypeName);
        Assert.Equal(expected, actual);
    }
 
    [Fact]
    public void GetXamlType_NullValueInReferencedAssemblies_ThrowsNullReferenceException()
    {
        var context = new XamlSchemaContext(new Assembly?[] { null });
        var type = new XamlTypeName("clr-namespace:System;assembly=" + typeof(int).Assembly.FullName, "Int32");
        Assert.Throws<NullReferenceException>(() => context.GetXamlType(type));
    }
 
    [Fact]
    public void GetXamlType_NullXamlNamespace_ThrowsArgumentNullException()
    {
        var context = new XamlSchemaContext();
        Assert.Throws<ArgumentNullException>("xamlNamespace", () => context.GetXamlDirective(null, "name"));
    }
 
    [Fact]
    public void GetXamlType_NullName_ThrowsArgumentNullException()
    {
        var context = new XamlSchemaContext();
        Assert.Throws<ArgumentNullException>("name", () => context.GetXamlDirective("xamlNamespace", null));
    }
 
    [Fact]
    public void GetXamlType_NullXamlTypeName_ThrowsArgumentNullException()
    {
        var context = new XamlSchemaContext();
        Assert.Throws<ArgumentNullException>("xamlTypeName", () => context.GetXamlType((XamlTypeName)null!));
    }
 
    [Fact]
    public void GetXamlType_NullXamlTypeNameNamespace_ThrowsArgumentException()
    {
        var context = new XamlSchemaContext();
        Assert.Throws<ArgumentException>("xamlTypeName", () => context.GetXamlType(new XamlTypeName(null, "name")));
    }
 
    [Fact]
    public void GetXamlType_NullXamlTypeNameName_ThrowsArgumentException()
    {
        var context = new XamlSchemaContext();
        Assert.Throws<ArgumentException>("xamlTypeName", () => context.GetXamlType(new XamlTypeName("xamlNamespace", null)));
    }
 
    [Fact]
    public void GetXamlType_NullXamlTypeNameTypeArgument_ThrowsArgumentException()
    {
        var context = new XamlSchemaContext();
        var xamlTypeName = new XamlTypeName("xamlNamespace", "name", new XamlTypeName?[] { null });
        // TODO: paramName.
        Assert.Throws<ArgumentException>(() => context.GetXamlType(xamlTypeName));
    }
 
    [Theory]
    [InlineData(typeof(int), "Int32")]
    [InlineData(typeof(MemberDefinition), "Member")]
    [InlineData(typeof(PropertyDefinition), "Property")]
    public void GetXamlType_Invoke_ReturnsExpected(Type underlyingType, string expectedName)
    {
        var context = new XamlSchemaContext();
        XamlType type = context.GetXamlType(underlyingType);
        Assert.Equal(new XamlType(underlyingType, new XamlSchemaContext()), type);
        Assert.Same(type, context.GetXamlType(underlyingType));
        Assert.Equal(expectedName, type.Name);
        Assert.Equal(underlyingType, type.UnderlyingType);
    }
 
    [Fact]
    public void GetXamlType_NullXamlType_ThrowsNullReferenceException()
    {
        var context = new XamlSchemaContext();
        Assert.Throws<ArgumentNullException>("type", () => context.GetXamlType((Type)null!));
    }
 
#pragma warning disable CA1052 // Static holder types should be Static or NotInheritable
    public class PublicNestedClass
    {
        public class PublicClass { }
        private class PrivateClass { }
    }
 
    private class PrivateNestedClass
    {
        public class PublicClass { }
        private class PrivateClass { }   
    }
    
    private class CustomXamlSchemaContext : XamlSchemaContext
    {
        public Func<Type, XamlType>? GetXamlTypeAction { get; set; }
 
        public override XamlType GetXamlType(Type type)
        {
            if (GetXamlTypeAction is null)
            {
                throw new NotImplementedException();
            }
 
            return GetXamlTypeAction(type);
        }
    }
    
    public class CustomCustomAttributeData : CustomAttributeData
    {
        public ConstructorInfo? ConstructorResult { get; set; }
        public override ConstructorInfo Constructor => ConstructorResult!;
 
        public IList<CustomAttributeTypedArgument>? ConstructorArgumentsResult { get; set; }
        public override IList<CustomAttributeTypedArgument> ConstructorArguments => ConstructorArgumentsResult!;
    }
#pragma warning restore CA1052 // Static holder types should be Static or NotInheritable
}