File: System\ComponentModel\GroupDescriptionTests.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\tests\UnitTests\WindowsBase.Tests\WindowsBase.Tests.csproj (WindowsBase.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.Collections;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
 
namespace System.ComponentModel.Tests;
 
public class GroupDescriptionTests
{
    [Fact]
    public void Ctor_Default()
    {
        var description = new SubGroupDescription();
        Assert.Null(description.CustomSort);
        Assert.Empty(description.GroupNames);
        Assert.Same(description.GroupNames, description.GroupNames);
        Assert.Empty(description.SortDescriptions);
        Assert.Same(description.SortDescriptions, description.SortDescriptions);
    }
 
    public static IEnumerable<object?[]> CustomSort_Set_TestData()
    {
        yield return new object?[] { null };
        yield return new object?[] { StringComparer.CurrentCulture };
    }
 
    [Theory]
    [MemberData(nameof(CustomSort_Set_TestData))]
    public void CustomSort_Set_GetReturnsExpected(IComparer? value)
    {
        var description = new SubGroupDescription
        {
            CustomSort = value
        };
        Assert.Same(value, description.CustomSort);
        Assert.Empty(description.SortDescriptions);
 
        // Set same.
        description.CustomSort = value;
        Assert.Same(value, description.CustomSort);
        Assert.Empty(description.SortDescriptions);
    }
 
    [Theory]
    [MemberData(nameof(CustomSort_Set_TestData))]
    public void CustomSort_SetNonNullOldValue_GetReturnsExpected(IComparer? value)
    {
        var description = new SubGroupDescription
        {
            CustomSort = StringComparer.Ordinal
        };
 
        description.CustomSort = value;
        Assert.Same(value, description.CustomSort);
        Assert.Empty(description.SortDescriptions);
 
        // Set same.
        description.CustomSort = value;
        Assert.Same(value, description.CustomSort);
        Assert.Empty(description.SortDescriptions);
    }
 
    [Theory]
    [MemberData(nameof(CustomSort_Set_TestData))]
    public void CustomSort_SetWithSortDescriptions_GetReturnsExpected(IComparer? value)
    {
        var description = new SubGroupDescription();
        description.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
 
        // Set.
        description.CustomSort = value;
        Assert.Same(value, description.CustomSort);
        Assert.Empty(description.SortDescriptions);
 
        // Set same.
        description.CustomSort = value;
        Assert.Same(value, description.CustomSort);
        Assert.Empty(description.SortDescriptions);
    }
 
    [Theory]
    [MemberData(nameof(CustomSort_Set_TestData))]
    public void CustomSort_SetWithEmptySortDescriptions_GetReturnsExpected(IComparer? value)
    {
        var description = new SubGroupDescription();
        Assert.Empty(description.SortDescriptions);
 
        // Set.
        description.CustomSort = value;
        Assert.Same(value, description.CustomSort);
        Assert.Empty(description.SortDescriptions);
 
        // Set same.
        description.CustomSort = value;
        Assert.Same(value, description.CustomSort);
        Assert.Empty(description.SortDescriptions);
    }
 
    [Fact]
    public void CustomSort_SetWithHandler_CallsPropertyChanged()
    {
        var description = new SubGroupDescription();
        int callCount = 0;
        PropertyChangedEventHandler handler = (sender, e) =>
        {
            Assert.Same(description, sender);
            Assert.Equal("CustomSort", e.PropertyName);
            callCount++;
        }; ;
        ((INotifyPropertyChanged)description).PropertyChanged += handler;
 
        // Set.
        description.CustomSort = StringComparer.CurrentCulture;
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
        Assert.Equal(1, callCount);
 
        // Set same.
        description.CustomSort = StringComparer.CurrentCulture;
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
        Assert.Equal(2, callCount);
 
        // Remove handler.
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
        description.CustomSort = null;
        Assert.Null(description.CustomSort);
        Assert.Equal(2, callCount);
    }
 
    [Fact]
    public void CustomSort_SetWithSortDescriptionsWithHandler_CallsPropertyChanged()
    {
        var description = new SubGroupDescription();
        description.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
 
        int callCount = 0;
        var properties = new List<string>();
        PropertyChangedEventHandler handler = (sender, e) =>
        {
            Assert.Same(description, sender);
            properties.Add(e.PropertyName!);
            callCount++;
        }; ;
        ((INotifyPropertyChanged)description).PropertyChanged += handler;
 
        // Set.
        description.CustomSort = StringComparer.CurrentCulture;
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
        Assert.Equal(2, callCount);
        Assert.Equal(new[] { "SortDescriptions", "CustomSort" }, properties);
 
        // Set same.
        description.CustomSort = StringComparer.CurrentCulture;
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
        Assert.Equal(3, callCount);
        Assert.Equal(new[] { "SortDescriptions", "CustomSort", "CustomSort" }, properties);
 
        // Remove handler.
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
        description.CustomSort = null;
        Assert.Null(description.CustomSort);
        Assert.Equal(3, callCount);
        Assert.Equal(new[] { "SortDescriptions", "CustomSort", "CustomSort" }, properties);
    }
 
    [Fact]
    public void CustomSort_SetWithEmptySortDescriptionsWithHandler_CallsPropertyChanged()
    {
        var description = new SubGroupDescription();
        Assert.Empty(description.SortDescriptions);
 
        int callCount = 0;
        var properties = new List<string>();
        PropertyChangedEventHandler handler = (sender, e) =>
        {
            Assert.Same(description, sender);
            properties.Add(e.PropertyName!);
            callCount++;
        }; ;
        ((INotifyPropertyChanged)description).PropertyChanged += handler;
 
        // Set.
        description.CustomSort = StringComparer.CurrentCulture;
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
        Assert.Equal(2, callCount);
        Assert.Equal(new[] { "SortDescriptions", "CustomSort" }, properties);
 
        // Set same.
        description.CustomSort = StringComparer.CurrentCulture;
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
        Assert.Equal(3, callCount);
        Assert.Equal(new[] { "SortDescriptions", "CustomSort", "CustomSort" }, properties);
 
        // Remove handler.
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
        description.CustomSort = null;
        Assert.Null(description.CustomSort);
        Assert.Equal(3, callCount);
        Assert.Equal(new[] { "SortDescriptions", "CustomSort", "CustomSort" }, properties);
    }
 
    [Fact]
    public void CustomSort_GetFirstTime_DoesNotCallPropertyChanged()
    {
        var description = new SubGroupDescription();
        int callCount = 0;
        ((INotifyPropertyChanged)description).PropertyChanged += (sender, e) => callCount++;
 
        // Get.
        Assert.Null(description.CustomSort);
        Assert.Equal(0, callCount);
 
        // Get again.
        Assert.Null(description.CustomSort);
        Assert.Equal(0, callCount);
    }
 
    [Fact]
    public void GroupNames_GetFirstTime_DoesNotCallPropertyChanged()
    {
        var description = new SubGroupDescription();
        int callCount = 0;
        ((INotifyPropertyChanged)description).PropertyChanged += (sender, e) => callCount++;
 
        // Get.
        ObservableCollection<object> collection = description.GroupNames;
        Assert.Empty(collection);
        Assert.Same(collection, description.GroupNames);
        Assert.Equal(0, callCount);
 
        // Get again.
        Assert.Empty(description.GroupNames);
        Assert.Equal(0, callCount);
    }
 
    [Fact]
    public void GroupNames_Change_CallsPropertyChanged()
    {
        var description = new SubGroupDescription();
        int callCount = 0;
        PropertyChangedEventHandler handler = (sender, e) =>
        {
            Assert.Same(description, sender);
            Assert.Equal("GroupNames", e.PropertyName);
            callCount++;
        };
        ((INotifyPropertyChanged)description).PropertyChanged += handler;
 
        // Clear.
        description.GroupNames.Clear();
        Assert.Empty(description.GroupNames);
        Assert.Equal(1, callCount);
 
        // Clear again.
        description.GroupNames.Clear();
        Assert.Empty(description.GroupNames);
        Assert.Equal(2, callCount);
 
        // Remove handler.
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
        description.GroupNames.Clear();
        Assert.Empty(description.GroupNames);
        Assert.Equal(2, callCount);
    }
 
    [Fact]
    public void GroupNames_ShouldSerialize_ReturnsExpected()
    {
        var description = new SubGroupDescription();
        PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(GroupDescription))[nameof(GroupDescription.GroupNames)]!;
        Assert.False(property.ShouldSerializeValue(description));
 
        Assert.Empty(description.GroupNames);
        Assert.False(property.ShouldSerializeValue(description));
 
        description.GroupNames.Add("Name");
        Assert.True(property.ShouldSerializeValue(description));
 
        description.GroupNames.Clear();
        Assert.False(property.ShouldSerializeValue(description));
    }
 
    [Fact]
    public void SortDescriptions_GetFirstTime_CallsPropertyChanged()
    {
        var description = new SubGroupDescription();
        int callCount = 0;
        ((INotifyPropertyChanged)description).PropertyChanged += (sender, e) =>
        {
            Assert.Same(description, sender);
            Assert.Equal("SortDescriptions", e.PropertyName);
            callCount++;
        };
 
        // Get.
        SortDescriptionCollection collection = description.SortDescriptions;
        Assert.Empty(collection);
        Assert.Same(collection, description.SortDescriptions);
        Assert.Equal(1, callCount);
 
        // Get again.
        Assert.Empty(description.SortDescriptions);
        Assert.Equal(1, callCount);
    }
 
    [Fact]
    public void SortDescriptions_GetFirstTimeWithCustomSort_CallsPropertyChanged()
    {
        var description = new SubGroupDescription
        {
            CustomSort = StringComparer.CurrentCulture
        };
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
 
        int callCount = 0;
        ((INotifyPropertyChanged)description).PropertyChanged += (sender, e) =>
        {
            Assert.Same(description, sender);
            Assert.Equal("SortDescriptions", e.PropertyName);
            callCount++;
        };
 
        // Get.
        SortDescriptionCollection collection = description.SortDescriptions;
        Assert.Empty(collection);
        Assert.Same(collection, description.SortDescriptions);
        Assert.Equal(1, callCount);
 
        // Get again.
        Assert.Empty(description.SortDescriptions);
        Assert.Equal(1, callCount);
    }
 
    [Fact]
    public void SortDescriptions_GetRemovedHandler_DoesNotCallPropertyChanged()
    {
        var description = new SubGroupDescription();
        int callCount = 0;
        PropertyChangedEventHandler handler = (sender, e) => callCount++;
        ((INotifyPropertyChanged)description).PropertyChanged += handler;
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
 
        // Get.
        SortDescriptionCollection collection = description.SortDescriptions;
        Assert.Empty(collection);
        Assert.Same(collection, description.SortDescriptions);
        Assert.Equal(0, callCount);
 
        // Get again.
        Assert.Empty(description.SortDescriptions);
        Assert.Equal(0, callCount);
    }
 
    [Fact]
    public void SortDescriptions_ChangeCount_ClearsCustomSort()
    {
        var description = new SubGroupDescription();
        var description1 = new SortDescription("Name1", ListSortDirection.Ascending);
        _ = new SortDescription("Name2", ListSortDirection.Ascending);
 
        description.CustomSort = StringComparer.CurrentCulture;
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
 
        // Add.
        description.SortDescriptions.Add(description1);
        Assert.Equal(new[] { description1 }, description.SortDescriptions.Cast<SortDescription>());
        Assert.Null(description.CustomSort);
    }
 
    [Fact]
    public void SortDescriptions_ChangeNoCount_DoesNotClearCustomSort()
    {
        var description = new SubGroupDescription();
        _ = new SortDescription("Name1", ListSortDirection.Ascending);
        _ = new SortDescription("Name2", ListSortDirection.Ascending);
 
        description.CustomSort = StringComparer.CurrentCulture;
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
 
        // Clear.
        description.SortDescriptions.Clear();
        Assert.Empty(description.SortDescriptions);
        Assert.Equal(StringComparer.CurrentCulture, description.CustomSort);
    }
 
    [Fact]
    public void SortDescriptions_Change_CallsPropertyChanged()
    {
        var description = new SubGroupDescription();
        var description1 = new SortDescription("Name1", ListSortDirection.Ascending);
        var description2 = new SortDescription("Name2", ListSortDirection.Ascending);
        Assert.Empty(description.SortDescriptions);
 
        int callCount = 0;
        PropertyChangedEventHandler handler = (sender, e) =>
        {
            Assert.Same(description, sender);
            Assert.Equal("SortDescriptions", e.PropertyName);
            callCount++;
        };
        ((INotifyPropertyChanged)description).PropertyChanged += handler;
 
        // Add.
        description.SortDescriptions.Add(description1);
        Assert.Equal(new[] { description1 }, description.SortDescriptions.Cast<SortDescription>());
        Assert.Null(description.CustomSort);
        Assert.Equal(1, callCount);
 
        // Clear.
        description.SortDescriptions.Clear();
        Assert.Empty(description.SortDescriptions);
        Assert.Null(description.CustomSort);
        Assert.Equal(2, callCount);
 
        // Remove handler.
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
        description.SortDescriptions.Add(description2);
        Assert.Equal(new[] { description2 }, description.SortDescriptions.Cast<SortDescription>());
        Assert.Null(description.CustomSort);
        Assert.Equal(2, callCount);
    }
 
    [Fact]
    public void SortDescriptions_ChangeWithCustomSort_CallsPropertyChanged()
    {
        var description = new SubGroupDescription();
        var description1 = new SortDescription("Name1", ListSortDirection.Ascending);
        var description2 = new SortDescription("Name2", ListSortDirection.Ascending);
        description.CustomSort = StringComparer.CurrentCulture;
        Assert.Empty(description.SortDescriptions);
 
        int callCount = 0;
        var properties = new List<string>();
        PropertyChangedEventHandler handler = (sender, e) =>
        {
            Assert.Same(description, sender);
            properties.Add(e.PropertyName!);
            callCount++;
        };
        ((INotifyPropertyChanged)description).PropertyChanged += handler;
 
        // Add.
        description.SortDescriptions.Add(description1);
        Assert.Equal(new[] { description1 }, description.SortDescriptions.Cast<SortDescription>());
        Assert.Null(description.CustomSort);
        Assert.Equal(2, callCount);
        Assert.Equal(new[] { "CustomSort", "SortDescriptions" }, properties);
 
        // Clear.
        description.SortDescriptions.Clear();
        Assert.Empty(description.SortDescriptions);
        Assert.Null(description.CustomSort);
        Assert.Equal(3, callCount);
        Assert.Equal(new[] { "CustomSort", "SortDescriptions", "SortDescriptions" }, properties);
 
        // Remove handler.
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
        description.SortDescriptions.Add(description2);
        Assert.Equal(new[] { description2 }, description.SortDescriptions.Cast<SortDescription>());
        Assert.Null(description.CustomSort);
        Assert.Equal(3, callCount);
        Assert.Equal(new[] { "CustomSort", "SortDescriptions", "SortDescriptions" }, properties);
    }
 
    [Fact]
    public void SortDescriptions_ShouldSerialize_ReturnsExpected()
    {
        var description = new SubGroupDescription();
        PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(GroupDescription))[nameof(GroupDescription.SortDescriptions)]!;
        Assert.False(property.ShouldSerializeValue(description));
 
        Assert.Empty(description.SortDescriptions);
        Assert.False(property.ShouldSerializeValue(description));
 
        description.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
        Assert.True(property.ShouldSerializeValue(description));
 
        description.SortDescriptions.Clear();
        Assert.False(property.ShouldSerializeValue(description));
    }
 
    [Fact]
    public void PropertyChanged_INotifyPropertyChangedAddRemove_Success()
    {
        INotifyPropertyChanged description = new SubGroupDescription();
 
        int callCount = 0;
        PropertyChangedEventHandler handler = (s, e) => callCount++;
        ((INotifyPropertyChanged)description).PropertyChanged += handler;
        Assert.Equal(0, callCount);
 
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
        Assert.Equal(0, callCount);
 
        // Remove non existent.
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
        Assert.Equal(0, callCount);
 
        // Add null.
        ((INotifyPropertyChanged)description).PropertyChanged += null;
        Assert.Equal(0, callCount);
 
        // Remove null.
        ((INotifyPropertyChanged)description).PropertyChanged -= null;
        Assert.Equal(0, callCount);
    }
 
    public static IEnumerable<object?[]> NamesMatch_TestData()
    {
        yield return new object?[] { null, null, true };
 
        var obj = new object();
        yield return new object?[] { obj, obj, true };
        yield return new object?[] { obj, new object(), false };
        yield return new object?[] { obj, null, false };
        yield return new object?[] { null, null, true };
        yield return new object?[] { null, new object(), false };
    }
 
    [Theory]
    [MemberData(nameof(NamesMatch_TestData))]
    public void NamesMatch_Invoke_ReturnsExpected(object? groupName1, object? groupName2, bool expected)
    {
        var description = new SubGroupDescription();
        Assert.Equal(expected, description.NamesMatch(groupName1, groupName2));
    }
 
    public static IEnumerable<object?[]> OnPropertyChanged_TestData()
    {
        yield return new object?[] { new PropertyChangedEventArgs("Name") };
        yield return new object?[] { null };
    }
 
    [Theory]
    [MemberData(nameof(OnPropertyChanged_TestData))]
    public void OnPropertyChanged_Invoke_CallsPropertyChangedEvent(PropertyChangedEventArgs eventArgs)
    {
        var description = new SubGroupDescription();
        int callCount = 0;
        PropertyChangedEventHandler handler = (sender, e) =>
        {
            Assert.Same(description, sender);
            Assert.Same(eventArgs, e);
            callCount++;
        };
 
        // Call with handler.
        ((INotifyPropertyChanged)description).PropertyChanged += handler;
        description.OnPropertyChanged(eventArgs);
        Assert.Equal(1, callCount);
 
        // Remove handler.
        ((INotifyPropertyChanged)description).PropertyChanged -= handler;
        description.OnPropertyChanged(eventArgs);
        Assert.Equal(1, callCount);
    }
 
    [Fact]
    public void ShouldSerializeGroupNames_Invoke_ReturnsExpected()
    {
        var description = new SubGroupDescription();
        _ = TypeDescriptor.GetProperties(typeof(GroupDescription))[nameof(GroupDescription.GroupNames)]!;
        Assert.False(description.ShouldSerializeGroupNames());
 
        Assert.Empty(description.GroupNames);
        Assert.False(description.ShouldSerializeGroupNames());
 
        description.GroupNames.Add("Name");
        Assert.True(description.ShouldSerializeGroupNames());
 
        description.GroupNames.Clear();
        Assert.False(description.ShouldSerializeGroupNames());
    }
 
    [Fact]
    public void ShouldSerializeGroupNames_Invoke_DoesNotCallPropertyChanged()
    {
        var description = new SubGroupDescription();
        int callCount = 0;
        ((INotifyPropertyChanged)description).PropertyChanged += (sender, e) => callCount++;
 
        Assert.False(description.ShouldSerializeGroupNames());
        Assert.Equal(0, callCount);
    }
 
    [Fact]
    public void ShouldSerializeSortDescriptions_Invoke_ReturnsExpected()
    {
        var description = new SubGroupDescription();
        Assert.False(description.ShouldSerializeSortDescriptions());
 
        Assert.Empty(description.SortDescriptions);
        Assert.False(description.ShouldSerializeSortDescriptions());
 
        description.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
        Assert.True(description.ShouldSerializeSortDescriptions());
 
        description.SortDescriptions.Clear();
        Assert.False(description.ShouldSerializeSortDescriptions());
    }
 
    [Fact]
    public void ShouldSerializeSortDescriptions_Invoke_DoesNotCallPropertyChanged()
    {
        var description = new SubGroupDescription();
        int callCount = 0;
        ((INotifyPropertyChanged)description).PropertyChanged += (sender, e) => callCount++;
 
        Assert.False(description.ShouldSerializeSortDescriptions());
        Assert.Equal(0, callCount);
    }
 
    private class SubGroupDescription : GroupDescription
    {
        public SubGroupDescription() : base()
        {
        }
 
        public override object GroupNameFromItem(object item, int level, CultureInfo culture)
            => throw new NotImplementedException();
 
        public new void OnPropertyChanged(PropertyChangedEventArgs e) => base.OnPropertyChanged(e);
    }
}