File: System\Windows\DurationConverter.Tests.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\tests\UnitTests\PresentationCore.Tests\PresentationCore.Tests.csproj (PresentationCore.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.ComponentModel.Design.Serialization;
using System.Globalization;
 
namespace System.Windows;
 
public sealed class DurationConverterTests
{
    [Theory]
    // Valid type
    [InlineData(true, typeof(string))]
    // Invalid types
    [InlineData(false, typeof(Duration))]
    [InlineData(false, typeof(TimeSpan))]
    [InlineData(false, typeof(InstanceDescriptor))]
    public void CanConvertFrom_ReturnsExpected(bool expected, Type sourceType)
    {
        DurationConverter converter = new();
 
        Assert.Equal(expected, converter.CanConvertFrom(sourceType));
    }
 
    [Theory]
    // Valid types
    [InlineData(true, typeof(string))]
    [InlineData(true, typeof(InstanceDescriptor))]
    // Invalid types
    [InlineData(false, typeof(Duration))]
    [InlineData(false, typeof(TimeSpan))]
    [InlineData(false, typeof(int))]
    [InlineData(false, typeof(long))]
    public void CanConvertTo_ReturnsExpected(bool expected, Type destinationType)
    {
        DurationConverter converter = new();
 
        Assert.Equal(expected, converter.CanConvertTo(destinationType));
    }
 
    [Theory]
    [MemberData(nameof(ConvertTo_ReturnsExpected_Data))]
    public void ConvertTo_ReturnsExpected(string expected, CultureInfo? culture, object value, bool checkTimeSpan)
    {
        DurationConverter converter = new();
 
        if (checkTimeSpan) // Framework sanity check to keep the Invariant assumption
            Assert.Equal(expected, TimeSpan.Parse(expected).ToString());
 
        Assert.Equal(expected, (string)converter.ConvertTo(null, culture, value, typeof(string)));
    }
 
    public static IEnumerable<object?[]> ConvertTo_ReturnsExpected_Data
    {
        get
        {
            yield return new object?[] { "Automatic", null, Duration.Automatic, false };
            yield return new object?[] { "Forever", null, Duration.Forever, false };
            // Because Duration uses TimeSpan.ToString() under the covers, which was Invariant up to NetFX 4, the Duration's ToString will always be Invariant
            yield return new object?[] { "17.22:10:15.4571230", CultureInfo.InvariantCulture, new Duration(new TimeSpan(17, 22, 10, 15, 457, 123)), true };
            yield return new object?[] { "17.22:10:15.4571230", new CultureInfo("ru-RU"), new Duration(new TimeSpan(17, 22, 10, 15, 457, 123)), true };
            // This is a special case, because original call was a base call, it does not throw for NULL but returns string.Empty
            yield return new object?[] { string.Empty, null, null, false };
        }
    }
 
    [Fact]
    public void ConvertTo_ThrowsArgumentNullException()
    {
        DurationConverter converter = new();
 
        // destinationType was NULL
        Assert.Throws<ArgumentNullException>(() => converter.ConvertTo(new Duration(new TimeSpan(17, 22, 10, 15, 457, 123)), destinationType: null!));
    }
 
    [Theory]
    [InlineData(typeof(int))]
    [InlineData(typeof(TimeSpan))]
    [InlineData(typeof(Duration))]
    [InlineData(typeof(DateTime))]
    [InlineData(typeof(TimeOnly))]
    [InlineData(typeof(DateOnly))]
    public void ConvertTo_ThrowsNotSupportedException(Type destinationType)
    {
        DurationConverter converter = new();
 
        // Supply of invalid destinationTypes
        Assert.Throws<NotSupportedException>(() => converter.ConvertTo(null, null, new Duration(new TimeSpan(17, 22, 10, 15, 457, 123)), destinationType));
    }
 
    [Theory]
    [MemberData(nameof(ConvertFrom_ReturnsExpected_TestData))]
    public void ConvertFrom_ReturnsExpected(Duration expected, CultureInfo? culture, object value)
    {
        DurationConverter converter = new();
 
        Assert.Equal(expected, (Duration)converter.ConvertFrom(null, culture, value));
    }
 
    public static IEnumerable<object?[]> ConvertFrom_ReturnsExpected_TestData
    {
        get
        {
            yield return new object?[] { Duration.Automatic, null, "Automatic" };
            yield return new object?[] { Duration.Forever, null, " Forever" };
            yield return new object?[] { new Duration(TimeSpan.FromTicks(6488853448000)), CultureInfo.InvariantCulture, "07:12:14:45.3448 " };
            yield return new object?[] { new Duration(TimeSpan.FromTicks(5624853448000)), new CultureInfo("ru-RU"), " 6:12:14:45,3448 " };
            // 6d
            yield return new object?[] { new Duration(TimeSpan.FromTicks(5184000000000)), CultureInfo.InvariantCulture, " 6 " };
            // 6h 12m
            yield return new object?[] { new Duration(TimeSpan.FromTicks(223200000000)), CultureInfo.InvariantCulture, " 6:12 " };
        }
    }
 
    [Theory]
    [MemberData(nameof(ConvertFrom_ThrowsFormatException_TestData))]
    public void ConvertFrom_ThrowsFormatException(CultureInfo? culture, object value)
    {
        DurationConverter converter = new();
 
        Assert.Throws<FormatException>(() => converter.ConvertFrom(null, culture, value));
    }
 
    public static IEnumerable<object?[]> ConvertFrom_ThrowsFormatException_TestData
    {
        get
        {
            // Invalid TimeSpan string specified
            yield return new object?[] { null, " á " };
            // Invalid TimeSpan string specified
            yield return new object?[] { new CultureInfo("ru-RU"), " á " };
            // Valid TimeSpan but wrong culture
            yield return new object?[] { CultureInfo.InvariantCulture, "       6:12:14:45,3448 " };
            // Valid TimeSpan but wrong culture
            yield return new object?[] { new CultureInfo("ru-RU"), "       6:12:14:45.3448 " };
        }
    }
 
    [Theory]
    [MemberData(nameof(ConvertFrom_NotSupportedException_TestData))]
    public void ConvertFrom_NotSupportedException(CultureInfo? culture, object value)
    {
        DurationConverter converter = new();
 
        Assert.Throws<NotSupportedException>(() => converter.ConvertFrom(null, culture, value));
    }
 
    public static IEnumerable<object?[]> ConvertFrom_NotSupportedException_TestData
    {
        get
        {
            // Input was null
            yield return new object?[] { null, null };
            // Wrong input type
            yield return new object?[] { null, 12345 };
            // Wrong input type with Culture
            yield return new object?[] { new CultureInfo("ru-RU"), 12345 };
        }
    }
}