File: System\Xaml\Replacements\TypeTypeConverterTests.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.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Windows.Markup;
using Xunit;
 
namespace System.Xaml.Replacements.Tests;
 
public class TypeTypeConverterTests
{
    [Theory]
    [InlineData(null, false)]
    [InlineData(typeof(string), true)]
    [InlineData(typeof(int), false)]
    [InlineData(typeof(InstanceDescriptor), false)]
    public void CanConvertFrom_Invoke_ReturnsExpected(Type? sourceType, bool expected)
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        Assert.Equal(expected, converter.CanConvertFrom(sourceType!));
    }
 
    [Fact]
    public void ConvertFrom_ValidContextService_ReturnsExpected()
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        var context = new CustomTypeDescriptorContext
        {
            GetServiceAction = serviceType =>
            {
                Assert.Equal(typeof(IXamlTypeResolver), serviceType);
                return new CustomXamlTypeResolver
                {
                    ResolveAction = qualifiedTypeName =>
                    {
                        Assert.Equal("value", qualifiedTypeName);
                        return typeof(int);
                    }
                };
            }
        };
        Assert.Equal(typeof(int), converter.ConvertFrom(context, null, "value"));
    }
 
    [Theory]
    [InlineData(null)]
    [InlineData(1)]
    public void ConvertFrom_InvalidIXamlTypeResolverService_ThrowsNotSupportedException(object? service)
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        var context = new CustomTypeDescriptorContext
        {
            GetServiceAction = serviceType =>
            {
                Assert.Equal(typeof(IXamlTypeResolver), serviceType);
                return service;
            }
        };
        Assert.Throws<NotSupportedException>(() => converter.ConvertFrom(context, null, "value"));
    }
 
    [Fact]
    public void ConvertFrom_NullContext_ThrowsNotSupportedException()
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        Assert.Throws<NotSupportedException>(() => converter.ConvertFrom("value"));
    }
 
    [Theory]
    [InlineData(1)]
    [InlineData(null)]
    public void ConvertFrom_InvalidObject_ThrowsNotSupportedException(object? value)
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        Assert.Throws<NotSupportedException>(() => converter.ConvertFrom(value!));
        Assert.Throws<NotSupportedException>(() => converter.ConvertFrom(new CustomTypeDescriptorContext(), null, value!));
    }
 
    [Theory]
    [InlineData(null, false)]
    [InlineData(typeof(string), true)]
    [InlineData(typeof(int), false)]
    [InlineData(typeof(InstanceDescriptor), false)]
    public void CanConvertTo_Invoke_ReturnsExpected(Type? sourceType, bool expected)
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        Assert.Equal(expected, converter.CanConvertTo(sourceType));
    }
 
    [Fact]
    public void ConvertTo_ValidContextService_ReturnsExpected()
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        var context = new CustomTypeDescriptorContext
        {
            GetServiceAction = serviceType =>
            {
                if (serviceType == typeof(IXamlSchemaContextProvider))
                {
                    return new CustomXamlSchemaContextProvider
                    {
                        SchemaContextResult = new XamlSchemaContext()
                    };
                }
                else if (serviceType == typeof(INamespacePrefixLookup))
                {
                    return new CustomNamespacePrefixLookup
                    {
                        LookupPrefixAction = ns =>
                        {
                            Assert.Equal("http://schemas.microsoft.com/winfx/2006/xaml", ns);
                            return "prefix";
                        }
                    };
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
        };
        Assert.Equal("prefix:Int32", converter.ConvertTo(context, null, typeof(int), typeof(string)));
    }
 
    [Fact]
    public void ConvertTo_CustomGetTypeContextService_ReturnsExpected()
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        var context = new CustomTypeDescriptorContext
        {
            GetServiceAction = serviceType =>
            {
                if (serviceType == typeof(IXamlSchemaContextProvider))
                {
                    return new CustomXamlSchemaContextProvider
                    {
                        SchemaContextResult = new CustomXamlSchemaContext
                        {
                            GetXamlTypeAction = (type) => new XamlType(typeof(short), new XamlSchemaContext())
                        }
                    };
                }
                else if (serviceType == typeof(INamespacePrefixLookup))
                {
                    return new CustomNamespacePrefixLookup
                    {
                        LookupPrefixAction = ns =>
                        {
                            Assert.Equal("http://schemas.microsoft.com/winfx/2006/xaml", ns);
                            return "prefix";
                        }
                    };
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
        };
        Assert.Equal("prefix:Int16", converter.ConvertTo(context, null, typeof(int), typeof(string)));
    }
 
    [Fact]
    public void ConvertTo_NullGetXamlTypeResult_ReturnsExpected()
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        var context = new CustomTypeDescriptorContext
        {
            GetServiceAction = serviceType =>
            {
                Assert.Equal(typeof(IXamlSchemaContextProvider), serviceType);
                return new CustomXamlSchemaContextProvider
                {
                    SchemaContextResult = new CustomXamlSchemaContext
                    {
                        GetXamlTypeAction = type => null!
                    }
                };
            }
        };
        Assert.Equal(typeof(int).ToString(), converter.ConvertTo(context, null, typeof(int), typeof(string)));
    }
 
    public static IEnumerable<object?[]> ConvertTo_InvalidIXamlSchemaContextProvider_TestData()
    {
        yield return new object?[] { null };
        yield return new object?[] { 1 };
        yield return new object?[] { new CustomXamlSchemaContextProvider() };
    }
 
    [Theory]
    [MemberData(nameof(ConvertTo_InvalidIXamlSchemaContextProvider_TestData))]
    public void ConvertTo_InvalidIXamlSchemaContextProvider_ReturnsExpected(object service)
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        var context = new CustomTypeDescriptorContext
        {
            GetServiceAction = serviceType =>
            {
                Assert.Equal(typeof(IXamlSchemaContextProvider), serviceType);
                return service;
            }
        };
        Assert.Equal(typeof(int).ToString(), converter.ConvertTo(context, null, typeof(int), typeof(string)));
    }
 
    [Theory]
    [InlineData(null)]
    [InlineData(1)]
    public void ConvertTo_InvalidINamespacePrefixLookup_ReturnsExpected(object? service)
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        var context = new CustomTypeDescriptorContext
        {
            GetServiceAction = serviceType =>
            {
                if (serviceType == typeof(IXamlSchemaContextProvider))
                {
                    return new CustomXamlSchemaContextProvider
                    {
                        SchemaContextResult = new XamlSchemaContext()
                    };
                }
                else if (serviceType == typeof(INamespacePrefixLookup))
                {
                    return service;
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
        };
 
        var expectedType = new XamlType(typeof(int), new XamlSchemaContext());
        Assert.Equal(expectedType.ToString(), converter.ConvertTo(context, null, typeof(int), typeof(string)));
    }
    
    [Theory]
    [InlineData("notType")]
    [InlineData(null)]
    public void ConvertTo_NotType_ReturnsExpected(object? value)
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        Assert.Equal(value ?? string.Empty, converter.ConvertTo(value, typeof(string)));
        Assert.Equal(value ?? string.Empty, converter.ConvertTo(new CustomTypeDescriptorContext(), null, value, typeof(string)));
    }
    
    [Theory]
    [InlineData(typeof(int))]
    public void ConvertTo_InvalidType_ThrowsNotSupportedException(Type destinationType)
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        Assert.Throws<NotSupportedException>(() => converter.ConvertTo(typeof(int), destinationType));
        Assert.Throws<NotSupportedException>(() => converter.ConvertTo(new CustomTypeDescriptorContext(), null, typeof(int), destinationType));
    }
 
    [Fact]
    public void ConvertTo_NullDestinationType_ThrowsArgumentNullException()
    {
        var type = new XamlType(typeof(Type), new XamlSchemaContext());
        TypeConverter converter = type.TypeConverter.ConverterInstance;
        Assert.Throws<ArgumentNullException>("destinationType", () => converter.ConvertTo(typeof(int), null!));
    }
    
    private class CustomTypeDescriptorContext : ITypeDescriptorContext
    {
        public IContainer Container => throw new NotImplementedException();
 
        public object Instance => throw new NotImplementedException();
 
        public PropertyDescriptor PropertyDescriptor => throw new NotImplementedException();
 
        public Func<Type, object?>? GetServiceAction { get; set; }
 
        public object? GetService(Type serviceType)
        {
            if (GetServiceAction is null)
            {
                throw new NotImplementedException();
            }
 
            return GetServiceAction(serviceType);
        }
 
        public void OnComponentChanged() => throw new NotImplementedException();
 
        public bool OnComponentChanging() => throw new NotImplementedException();
    }
    
    private class CustomXamlSchemaContextProvider : IXamlSchemaContextProvider
    {
        public XamlSchemaContext? SchemaContextResult { get; set; }
 
        public XamlSchemaContext? SchemaContext => SchemaContextResult;
    }
 
    private class CustomNamespacePrefixLookup : INamespacePrefixLookup
    {
        public Func<string, string>? LookupPrefixAction { get; set; }
 
        public string LookupPrefix(string ns)
        {
            if (LookupPrefixAction is null)
            {
                throw new NotImplementedException();
            }
 
            return LookupPrefixAction(ns);
        }
    }
 
    private class CustomXamlTypeResolver : IXamlTypeResolver
    {
        public Func<string, Type>? ResolveAction { get; set; }
 
        public Type Resolve(string qualifiedTypeName)
        {
            if (ResolveAction is null)
            {
                throw new NotImplementedException();
            }
 
            return ResolveAction(qualifiedTypeName);
        }
    }
    
    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);
        }
    }
}