|
// 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.ComponentModel;
using Moq;
namespace System.Windows.Forms.Tests;
public class BindingSourceTests
{
[WinFormsFact]
public void Ctor_Default()
{
using SubBindingSource source = new();
Assert.True(source.AllowEdit);
Assert.True(source.AllowNew);
Assert.True(source.AllowRemove);
Assert.True(source.CanRaiseEvents);
Assert.Null(source.Container);
Assert.Empty(source);
Assert.Equal(0, source.CurrencyManager.Count);
Assert.Empty(source.CurrencyManager.Bindings);
Assert.Same(source.CurrencyManager.Bindings, source.CurrencyManager.Bindings);
Assert.Throws<IndexOutOfRangeException>(() => source.CurrencyManager.Current);
Assert.True(source.CurrencyManager.IsBindingSuspended);
Assert.Same(source, source.CurrencyManager.List);
Assert.Equal(-1, source.CurrencyManager.Position);
Assert.Same(source.CurrencyManager, source.CurrencyManager);
Assert.Null(source.Current);
Assert.Empty(source.DataMember);
Assert.Null(source.DataSource);
Assert.False(source.DesignMode);
Assert.NotNull(source.Events);
Assert.Same(source.Events, source.Events);
Assert.Null(source.Filter);
Assert.True(source.IsBindingSuspended);
Assert.False(source.IsFixedSize);
Assert.False(source.IsReadOnly);
Assert.False(source.IsSorted);
Assert.False(source.IsSynchronized);
Assert.Empty(source.List);
Assert.IsType<BindingList<object>>(source.List);
Assert.True(source.RaiseListChangedEvents);
Assert.Null(source.Site);
Assert.Null(source.Sort);
Assert.Empty(source.SortDescriptions);
Assert.Equal(ListSortDirection.Ascending, source.SortDirection);
Assert.Null(source.SortProperty);
Assert.False(source.SupportsAdvancedSorting);
Assert.True(source.SupportsChangeNotification);
Assert.False(source.SupportsFiltering);
Assert.False(source.SupportsSearching);
Assert.False(source.SupportsSorting);
Assert.Same(source.List.SyncRoot, source.SyncRoot);
}
public static IEnumerable<object[]> Ctor_Object_String_Null_TestData()
{
yield return new object[] { null, null, typeof(BindingList<object>) };
yield return new object[] { null, string.Empty, typeof(BindingList<object>) };
yield return new object[] { null, "dataMember", typeof(BindingList<object>) };
yield return new object[] { new DataClass { List = null }, nameof(DataClass.List), typeof(BindingList<int>) };
yield return new object[] { new DataClass { List = null }, nameof(DataClass.List), typeof(BindingList<int>) };
yield return new object[] { new ObjectDataClass { List = null }, nameof(ObjectDataClass.List), typeof(BindingList<object>) };
yield return new object[] { new ObjectDataClass { List = null }, nameof(ObjectDataClass.List).ToLowerInvariant(), typeof(BindingList<object>) };
}
[WinFormsTheory]
[MemberData(nameof(Ctor_Object_String_Null_TestData))]
public void Ctor_Object_String_Null(object dataSource, string dataMember, Type expectedType)
{
using SubBindingSource source = new(dataSource, dataMember);
Assert.True(source.AllowEdit);
Assert.True(source.AllowNew);
Assert.True(source.AllowRemove);
Assert.True(source.CanRaiseEvents);
Assert.Null(source.Container);
Assert.Empty(source);
Assert.Equal(0, source.CurrencyManager.Count);
Assert.Empty(source.CurrencyManager.Bindings);
Assert.Same(source.CurrencyManager.Bindings, source.CurrencyManager.Bindings);
Assert.Throws<IndexOutOfRangeException>(() => source.CurrencyManager.Current);
Assert.True(source.CurrencyManager.IsBindingSuspended);
Assert.Same(source, source.CurrencyManager.List);
Assert.Equal(-1, source.CurrencyManager.Position);
Assert.Same(source.CurrencyManager, source.CurrencyManager);
Assert.Null(source.Current);
Assert.Same(dataMember, source.DataMember);
Assert.Same(dataSource, source.DataSource);
Assert.False(source.DesignMode);
Assert.NotNull(source.Events);
Assert.Same(source.Events, source.Events);
Assert.Null(source.Filter);
Assert.True(source.IsBindingSuspended);
Assert.False(source.IsFixedSize);
Assert.False(source.IsReadOnly);
Assert.False(source.IsSorted);
Assert.False(source.IsSynchronized);
Assert.Empty(source.List);
Assert.IsType(expectedType, source.List);
Assert.True(source.RaiseListChangedEvents);
Assert.Null(source.Site);
Assert.Null(source.Sort);
Assert.Empty(source.SortDescriptions);
Assert.Equal(ListSortDirection.Ascending, source.SortDirection);
Assert.Null(source.SortProperty);
Assert.False(source.SupportsAdvancedSorting);
Assert.True(source.SupportsChangeNotification);
Assert.False(source.SupportsFiltering);
Assert.False(source.SupportsSearching);
Assert.False(source.SupportsSorting);
Assert.Same(source.List.SyncRoot, source.SyncRoot);
}
public static IEnumerable<object[]> Ctor_Object_String_Empty_TestData()
{
foreach (string dataMember in new string[] { null, string.Empty })
{
List<int> emptyList = [];
yield return new object[] { emptyList, dataMember, true, false, emptyList };
int[] emptyArray = Array.Empty<int>();
yield return new object[] { emptyArray, dataMember, false, true, emptyArray };
Mock<IListSource> mockEmptyListSource = new(MockBehavior.Strict);
mockEmptyListSource
.Setup(s => s.GetList())
.Returns(emptyList);
yield return new object[] { mockEmptyListSource.Object, dataMember, true, false, emptyList };
}
}
[WinFormsTheory]
[MemberData(nameof(Ctor_Object_String_Empty_TestData))]
public void Ctor_Object_String_Empty(object dataSource, string dataMember, bool expectedAllowRemove, bool expectedIsFixedSize, IList expected)
{
using SubBindingSource source = new(dataSource, dataMember);
Assert.True(source.AllowEdit);
Assert.False(source.AllowNew);
Assert.Equal(expectedAllowRemove, source.AllowRemove);
Assert.True(source.CanRaiseEvents);
Assert.Null(source.Container);
Assert.Equal(expected, source);
Assert.Equal(expected.Count, source.CurrencyManager.Count);
Assert.Empty(source.CurrencyManager.Bindings);
Assert.Same(source.CurrencyManager.Bindings, source.CurrencyManager.Bindings);
Assert.Throws<IndexOutOfRangeException>(() => source.CurrencyManager.Current);
Assert.True(source.CurrencyManager.IsBindingSuspended);
Assert.Same(source, source.CurrencyManager.List);
Assert.Equal(-1, source.CurrencyManager.Position);
Assert.Same(source.CurrencyManager, source.CurrencyManager);
Assert.Null(source.Current);
Assert.Same(dataMember, source.DataMember);
Assert.Same(dataSource, source.DataSource);
Assert.False(source.DesignMode);
Assert.NotNull(source.Events);
Assert.Same(source.Events, source.Events);
Assert.Null(source.Filter);
Assert.True(source.IsBindingSuspended);
Assert.Equal(expectedIsFixedSize, source.IsFixedSize);
Assert.False(source.IsReadOnly);
Assert.False(source.IsSorted);
Assert.False(source.IsSynchronized);
Assert.Same(expected, source.List);
Assert.True(source.RaiseListChangedEvents);
Assert.Null(source.Site);
Assert.Null(source.Sort);
Assert.Empty(source.SortDescriptions);
Assert.Equal(ListSortDirection.Ascending, source.SortDirection);
Assert.Null(source.SortProperty);
Assert.False(source.SupportsAdvancedSorting);
Assert.True(source.SupportsChangeNotification);
Assert.False(source.SupportsFiltering);
Assert.False(source.SupportsSearching);
Assert.False(source.SupportsSorting);
Assert.Same(source.List.SyncRoot, source.SyncRoot);
}
public static IEnumerable<object[]> Ctor_Object_String_TestData()
{
foreach (string dataMember in new string[] { null, string.Empty })
{
List<int> nonEmptyList = [1, 2, 3];
yield return new object[] { nonEmptyList, dataMember, true, false, true, false, false, false, nonEmptyList };
FixedSizeList<int> fixedSizeList = new() { 1, 2, 3 };
yield return new object[] { fixedSizeList, dataMember, true, false, false, true, false, false, fixedSizeList };
ReadOnlyList<int> readOnlyList = new() { 1, 2, 3 };
yield return new object[] { readOnlyList, dataMember, false, false, false, false, true, false, readOnlyList };
SynchronizedList<int> synchronizedList = new() { 1, 2, 3 };
yield return new object[] { synchronizedList, dataMember, true, false, true, false, false, true, synchronizedList };
int[] nonEmptyArray = [1, 2, 3];
yield return new object[] { nonEmptyArray, dataMember, true, false, false, true, false, false, nonEmptyArray };
Mock<IListSource> mockNonEmptyListSource = new(MockBehavior.Strict);
mockNonEmptyListSource
.Setup(s => s.GetList())
.Returns(nonEmptyList);
yield return new object[] { mockNonEmptyListSource.Object, dataMember, true, false, true, false, false, false, nonEmptyList };
}
List<int> list = [1, 2, 3];
DataClass listDataClass = new() { List = list };
yield return new object[] { listDataClass, nameof(DataClass.List), true, false, true, false, false, false, list };
yield return new object[] { listDataClass, nameof(DataClass.List).ToLowerInvariant(), true, false, true, false, false, false, list };
Mock<IListSource> mockListSource = new(MockBehavior.Strict);
mockListSource
.Setup(s => s.GetList())
.Returns(list);
ListSourceDataClass listSourceDataClass = new() { ListSource = mockListSource.Object };
yield return new object[] { listSourceDataClass, nameof(ListSourceDataClass.ListSource), true, false, true, false, false, false, list };
yield return new object[] { listSourceDataClass, nameof(ListSourceDataClass.ListSource).ToLowerInvariant(), true, false, true, false, false, false, list };
}
[WinFormsTheory]
[MemberData(nameof(Ctor_Object_String_TestData))]
public void Ctor_Object_String(object dataSource, string dataMember, bool expectedAllowEdit, bool expectedAllowNew, bool expectedAllowRemove, bool expectedIsFixedSize, bool expectedReadOnly, bool expectedIsSynchronized, IList expected)
{
using SubBindingSource source = new(dataSource, dataMember);
Assert.Equal(expectedAllowEdit, source.AllowEdit);
Assert.Equal(expectedAllowNew, source.AllowNew);
Assert.Equal(expectedAllowRemove, source.AllowRemove);
Assert.True(source.CanRaiseEvents);
Assert.Null(source.Container);
Assert.Equal(expected, source);
Assert.Equal(expected.Count, source.CurrencyManager.Count);
Assert.Empty(source.CurrencyManager.Bindings);
Assert.Same(source.CurrencyManager.Bindings, source.CurrencyManager.Bindings);
Assert.Equal(expected[0], source.CurrencyManager.Current);
Assert.False(source.CurrencyManager.IsBindingSuspended);
Assert.Same(source, source.CurrencyManager.List);
Assert.Equal(0, source.CurrencyManager.Position);
Assert.Same(source.CurrencyManager, source.CurrencyManager);
Assert.Equal(expected[0], source.Current);
Assert.Same(dataMember, source.DataMember);
Assert.Same(dataSource, source.DataSource);
Assert.False(source.DesignMode);
Assert.NotNull(source.Events);
Assert.Same(source.Events, source.Events);
Assert.Null(source.Filter);
Assert.False(source.IsBindingSuspended);
Assert.Equal(expectedIsFixedSize, source.IsFixedSize);
Assert.Equal(expectedReadOnly, source.IsReadOnly);
Assert.False(source.IsSorted);
Assert.Equal(expectedIsSynchronized, source.IsSynchronized);
Assert.Same(expected, source.List);
Assert.True(source.RaiseListChangedEvents);
Assert.Null(source.Site);
Assert.Null(source.Sort);
Assert.Empty(source.SortDescriptions);
Assert.Equal(ListSortDirection.Ascending, source.SortDirection);
Assert.Null(source.SortProperty);
Assert.False(source.SupportsAdvancedSorting);
Assert.True(source.SupportsChangeNotification);
Assert.False(source.SupportsFiltering);
Assert.False(source.SupportsSearching);
Assert.False(source.SupportsSorting);
Assert.Same(source.List.SyncRoot, source.SyncRoot);
}
public static IEnumerable<object[]> Ctor_Object_String_BindingList_TestData()
{
foreach (string dataMember in new string[] { null, string.Empty })
{
List<int> emptyList = [];
List<int> nonEmptyList = [1, 2, 3];
EnumerableWrapper<int> emptyEnumerable = new(emptyList);
yield return new object[] { emptyEnumerable, dataMember, true, false, true, false, false, false, new List<int>[] { emptyList }, typeof(BindingList<EnumerableWrapper<int>>) };
EnumerableWrapper<int> nonEmptyEnumerable = new(nonEmptyList);
yield return new object[] { nonEmptyEnumerable, dataMember, true, false, true, false, false, false, nonEmptyList, typeof(BindingList<int>) };
}
object o1 = new();
yield return new object[] { new ObjectDataClass { List = o1 }, nameof(ObjectDataClass.List), true, true, true, false, false, false, new BindingList<object> { o1 }, typeof(BindingList<object>) };
object o2 = new();
yield return new object[] { new ObjectDataClass { List = o2 }, nameof(ObjectDataClass.List).ToLowerInvariant(), true, true, true, false, false, false, new BindingList<object> { o2 }, typeof(BindingList<object>) };
yield return new object[] { new ObjectDataClass { List = 1 }, nameof(ObjectDataClass.List), true, true, true, false, false, false, new BindingList<int> { 1 }, typeof(BindingList<int>) };
yield return new object[] { new ObjectDataClass { List = 1 }, nameof(ObjectDataClass.List).ToLowerInvariant(), true, true, true, false, false, false, new BindingList<int> { 1 }, typeof(BindingList<int>) };
}
[WinFormsTheory]
[MemberData(nameof(Ctor_Object_String_BindingList_TestData))]
public void Ctor_Object_String_BindingList(object dataSource, string dataMember, bool expectedAllowEdit, bool expectedAllowNew, bool expectedAllowRemove, bool expectedIsFixedSize, bool expectedReadOnly, bool expectedIsSynchronized, IList expected, Type expectedType)
{
using SubBindingSource source = new(dataSource, dataMember);
Assert.Equal(expectedAllowEdit, source.AllowEdit);
Assert.Equal(expectedAllowNew, source.AllowNew);
Assert.Equal(expectedAllowRemove, source.AllowRemove);
Assert.True(source.CanRaiseEvents);
Assert.Null(source.Container);
Assert.Equal(expected, source);
Assert.Equal(expected.Count, source.CurrencyManager.Count);
Assert.Empty(source.CurrencyManager.Bindings);
Assert.Same(source.CurrencyManager.Bindings, source.CurrencyManager.Bindings);
Assert.Equal(expected[0], source.CurrencyManager.Current);
Assert.False(source.CurrencyManager.IsBindingSuspended);
Assert.Same(source, source.CurrencyManager.List);
Assert.Equal(0, source.CurrencyManager.Position);
Assert.Same(source.CurrencyManager, source.CurrencyManager);
Assert.Equal(expected[0], source.Current);
Assert.Same(dataMember, source.DataMember);
Assert.Same(dataSource, source.DataSource);
Assert.False(source.DesignMode);
Assert.NotNull(source.Events);
Assert.Same(source.Events, source.Events);
Assert.Null(source.Filter);
Assert.False(source.IsBindingSuspended);
Assert.Equal(expectedIsFixedSize, source.IsFixedSize);
Assert.Equal(expectedReadOnly, source.IsReadOnly);
Assert.False(source.IsSorted);
Assert.Equal(expectedIsSynchronized, source.IsSynchronized);
Assert.Equal(expected, source.List);
Assert.NotSame(expected, source.List);
Assert.IsType(expectedType, source.List);
Assert.True(source.RaiseListChangedEvents);
Assert.Null(source.Site);
Assert.Null(source.Sort);
Assert.Empty(source.SortDescriptions);
Assert.Equal(ListSortDirection.Ascending, source.SortDirection);
Assert.Null(source.SortProperty);
Assert.False(source.SupportsAdvancedSorting);
Assert.True(source.SupportsChangeNotification);
Assert.False(source.SupportsFiltering);
Assert.False(source.SupportsSearching);
Assert.False(source.SupportsSorting);
Assert.Same(source.List.SyncRoot, source.SyncRoot);
}
[WinFormsTheory]
[NullAndEmptyStringData]
public void Ctor_Object_String_IBindingList(string dataMember)
{
PropertyDescriptor sortProperty = TypeDescriptor.GetProperties(typeof(DataClass))[0];
object syncRoot = new();
Mock<IBindingList> mockList = new(MockBehavior.Strict);
mockList
.Setup(p => p.Count)
.Returns(0);
mockList
.Setup(p => p.AllowEdit)
.Returns(false);
mockList
.Setup(p => p.AllowNew)
.Returns(false);
mockList
.Setup(p => p.AllowRemove)
.Returns(false);
mockList
.Setup(p => p.GetEnumerator())
.Returns(new List<int>().GetEnumerator());
mockList
.Setup(p => p.IsFixedSize)
.Returns(false);
mockList
.Setup(p => p.IsReadOnly)
.Returns(false);
mockList
.Setup(p => p.IsSynchronized)
.Returns(false);
mockList
.Setup(p => p.IsSorted)
.Returns(true);
mockList
.Setup(p => p.SortDirection)
.Returns(ListSortDirection.Descending);
mockList
.Setup(p => p.SortProperty)
.Returns(sortProperty);
mockList
.Setup(p => p.SupportsChangeNotification)
.Returns(false);
mockList
.Setup(p => p.SupportsSearching)
.Returns(true);
mockList
.Setup(p => p.SupportsSorting)
.Returns(true);
mockList
.Setup(p => p.SyncRoot)
.Returns(syncRoot);
ListSortDescriptionCollection sortDescriptions = new();
var mockListView = mockList.As<IBindingListView>();
mockListView
.Setup(p => p.SortDescriptions)
.Returns(sortDescriptions);
mockListView
.Setup(p => p.SupportsAdvancedSorting)
.Returns(true);
mockListView
.Setup(p => p.SupportsFiltering)
.Returns(true);
using SubBindingSource source = new(mockList.Object, dataMember);
Assert.False(source.AllowEdit);
Assert.False(source.AllowNew);
Assert.False(source.AllowRemove);
Assert.True(source.CanRaiseEvents);
Assert.Null(source.Container);
Assert.Empty(source);
Assert.Equal(0, source.CurrencyManager.Count);
Assert.Empty(source.CurrencyManager.Bindings);
Assert.Same(source.CurrencyManager.Bindings, source.CurrencyManager.Bindings);
Assert.Throws<IndexOutOfRangeException>(() => source.CurrencyManager.Current);
Assert.True(source.CurrencyManager.IsBindingSuspended);
Assert.Same(source, source.CurrencyManager.List);
Assert.Equal(-1, source.CurrencyManager.Position);
Assert.Same(source.CurrencyManager, source.CurrencyManager);
Assert.Null(source.Current);
Assert.Same(dataMember, source.DataMember);
Assert.Same(mockList.Object, source.DataSource);
Assert.False(source.DesignMode);
Assert.NotNull(source.Events);
Assert.Same(source.Events, source.Events);
Assert.Null(source.Filter);
Assert.True(source.IsBindingSuspended);
Assert.False(source.IsFixedSize);
Assert.False(source.IsReadOnly);
Assert.True(source.IsSorted);
Assert.False(source.IsSynchronized);
Assert.Same(mockList.Object, source.List);
Assert.True(source.RaiseListChangedEvents);
Assert.Null(source.Site);
Assert.Null(source.Sort);
Assert.Same(sortDescriptions, source.SortDescriptions);
Assert.Equal(ListSortDirection.Descending, source.SortDirection);
Assert.Same(sortProperty, source.SortProperty);
Assert.True(source.SupportsAdvancedSorting);
Assert.True(source.SupportsChangeNotification);
Assert.True(source.SupportsFiltering);
Assert.True(source.SupportsSearching);
Assert.True(source.SupportsSorting);
Assert.Same(syncRoot, source.SyncRoot);
}
[WinFormsTheory]
[NullAndEmptyStringData]
public void Ctor_Object_String_ICurrencyManagerProvider(string dataMember)
{
Mock<ICurrencyManagerProvider> mockCurrencyManagerProvider = new(MockBehavior.Strict);
mockCurrencyManagerProvider
.Setup(p => p.CurrencyManager)
.Returns<CurrencyManager>(null)
.Verifiable();
using BindingSource source = new(mockCurrencyManagerProvider.Object, dataMember);
mockCurrencyManagerProvider.Verify(p => p.CurrencyManager, Times.Once());
}
[WinFormsTheory]
[InlineData(typeof(PrivateDefaultConstructor))]
[InlineData(typeof(NoDefaultConstructor))]
[InlineData(typeof(ThrowingDefaultConstructor))]
public void Ctor_InvalidDataSourceType_ThrowsNotSupportedException(Type dataSource)
{
Assert.Throws<NotSupportedException>(() => new BindingSource(dataSource, "dataMember"));
}
[WinFormsFact]
public void Ctor_NoSuchDataMember_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => new BindingSource(new DataClass(), "NoSuchProperty"));
}
[WinFormsFact]
public void Ctor_IContainer()
{
using Container container = new();
using SubBindingSource source = new(container);
Assert.True(source.AllowEdit);
Assert.True(source.AllowNew);
Assert.True(source.AllowRemove);
Assert.True(source.CanRaiseEvents);
Assert.Same(container, source.Container);
Assert.Empty(source);
Assert.Equal(0, source.CurrencyManager.Count);
Assert.Empty(source.CurrencyManager.Bindings);
Assert.Same(source.CurrencyManager.Bindings, source.CurrencyManager.Bindings);
Assert.Throws<IndexOutOfRangeException>(() => source.CurrencyManager.Current);
Assert.True(source.CurrencyManager.IsBindingSuspended);
Assert.Same(source, source.CurrencyManager.List);
Assert.Equal(-1, source.CurrencyManager.Position);
Assert.Same(source.CurrencyManager, source.CurrencyManager);
Assert.Null(source.Current);
Assert.Empty(source.DataMember);
Assert.Null(source.DataSource);
Assert.False(source.DesignMode);
Assert.NotNull(source.Events);
Assert.Same(source.Events, source.Events);
Assert.Null(source.Filter);
Assert.True(source.IsBindingSuspended);
Assert.False(source.IsFixedSize);
Assert.False(source.IsReadOnly);
Assert.False(source.IsSorted);
Assert.False(source.IsSynchronized);
Assert.Empty(source.List);
Assert.IsType<BindingList<object>>(source.List);
Assert.True(source.RaiseListChangedEvents);
Assert.NotNull(source.Site);
Assert.Null(source.Sort);
Assert.Empty(source.SortDescriptions);
Assert.Equal(ListSortDirection.Ascending, source.SortDirection);
Assert.Null(source.SortProperty);
Assert.False(source.SupportsAdvancedSorting);
Assert.True(source.SupportsChangeNotification);
Assert.False(source.SupportsFiltering);
Assert.False(source.SupportsSearching);
Assert.False(source.SupportsSorting);
Assert.Same(source.List.SyncRoot, source.SyncRoot);
}
[WinFormsFact]
public void Ctor_NullContainer_ThrowsArgumentNullException()
{
Assert.Throws<ArgumentNullException>("container", () => new SubBindingSource(null));
}
[WinFormsFact]
public void ISupportInitializeNotification_GetProperties_ReturnsExpected()
{
using BindingSource bindingSource = [];
ISupportInitializeNotification source = bindingSource;
Assert.True(source.IsInitialized);
}
[WinFormsFact]
public void BeginInitEndInit_Invoke_Success()
{
using BindingSource bindingSource = [];
ISupportInitializeNotification source = bindingSource;
source.BeginInit();
Assert.False(source.IsInitialized);
source.EndInit();
Assert.True(source.IsInitialized);
}
[WinFormsFact]
public void BeginInitEndInit_WithInitializedEvent_CallsEvent()
{
using BindingSource bindingSource = [];
ISupportInitializeNotification source = bindingSource;
int callCount = 0;
EventHandler handler = (sender, e) =>
{
callCount++;
Assert.Same(source, sender);
Assert.Equal(EventArgs.Empty, e);
};
source.Initialized += handler;
source.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(1, callCount);
source.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(2, callCount);
// Remove handler.
source.Initialized -= handler;
source.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(2, callCount);
}
[WinFormsFact]
public void BeginInitEndInit_WithDataSource_CallsEvent()
{
using BindingSource bindingSource = new(new DataSource(), nameof(DataSource.Member));
ISupportInitializeNotification source = bindingSource;
int callCount = 0;
EventHandler handler = (sender, e) =>
{
callCount++;
Assert.Same(source, sender);
Assert.Equal(EventArgs.Empty, e);
};
source.Initialized += handler;
source.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(1, callCount);
source.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(2, callCount);
}
[WinFormsFact]
public void BeginInitEndInit_WithISupportInitializeNotificationDataSource_WaitsForDataSourceInitialize()
{
ISupportInitializeNotificationDataSource dataSource = new() { IsInitializedResult = false };
using BindingSource bindingSource = new(dataSource, nameof(ISupportInitializeNotificationDataSource.Member));
ISupportInitializeNotification source = bindingSource;
int callCount = 0;
EventHandler handler = (sender, e) =>
{
callCount++;
Assert.Same(source, sender);
Assert.Equal(EventArgs.Empty, e);
};
source.Initialized += handler;
source.BeginInit();
Assert.False(source.IsInitialized);
Assert.Equal(0, callCount);
// Call the source init - should not initialize and should instead wait for
// the data source initialization.
source.EndInit();
Assert.False(source.IsInitialized);
Assert.Equal(0, callCount);
// Then, call the data source init.
dataSource.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(1, callCount);
// Call again.
source.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(1, callCount);
}
[WinFormsFact]
public void BeginInitEndInit_WithISupportInitializeNotificationDataSourceInitialized_DoesNotWaitForDataSourceInitialize()
{
ISupportInitializeNotificationDataSource dataSource = new() { IsInitializedResult = true };
using BindingSource bindingSource = new(dataSource, nameof(ISupportInitializeNotificationDataSource.Member));
ISupportInitializeNotification source = bindingSource;
int callCount = 0;
EventHandler handler = (sender, e) =>
{
callCount++;
Assert.Same(source, sender);
Assert.Equal(EventArgs.Empty, e);
};
source.Initialized += handler;
source.BeginInit();
Assert.False(source.IsInitialized);
Assert.Equal(0, callCount);
source.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(1, callCount);
// Call again.
source.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(2, callCount);
}
public static IEnumerable<object[]> BeginInitEndInit_SetDataSourceInInit_TestData()
{
yield return new object[] { null };
yield return new object[] { new DataSource() };
}
[WinFormsTheory]
[MemberData(nameof(BeginInitEndInit_SetDataSourceInInit_TestData))]
public void BeginInitEndInit_SetDataSourceInInit_Success(object newDataSource)
{
ISupportInitializeNotificationDataSource dataSource = new() { IsInitializedResult = false };
using BindingSource bindingSource = new(dataSource, nameof(ISupportInitializeNotificationDataSource.Member));
ISupportInitializeNotification source = bindingSource;
int callCount = 0;
EventHandler handler = (sender, e) =>
{
callCount++;
Assert.Same(source, sender);
Assert.Equal(EventArgs.Empty, e);
};
source.Initialized += handler;
dataSource.Initialized += (sender, e) =>
{
((BindingSource)source).DataSource = newDataSource;
};
source.BeginInit();
Assert.False(source.IsInitialized);
Assert.Equal(0, callCount);
// Call the source init - should not initialize and should instead wait for
// the data source initialization.
source.EndInit();
Assert.False(source.IsInitialized);
Assert.Equal(0, callCount);
// Then, call the data source init.
dataSource.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(1, callCount);
// Call again.
source.EndInit();
Assert.True(source.IsInitialized);
Assert.Equal(2, callCount);
}
private class FixedSizeList<T> : VirtualList<T>
{
public override bool IsFixedSize => true;
}
private class ReadOnlyList<T> : VirtualList<T>
{
public override bool IsReadOnly => true;
}
private class SynchronizedList<T> : VirtualList<T>
{
public override bool IsSynchronized => true;
}
private class VirtualList<T> : IList
{
private readonly List<T> _innerList = [];
public VirtualList()
{
}
IEnumerator IEnumerable.GetEnumerator() => _innerList.GetEnumerator();
public int Count => _innerList.Count;
public object SyncRoot => ((IList)_innerList).SyncRoot;
public virtual bool IsSynchronized => ((IList)_innerList).IsSynchronized;
public virtual bool IsReadOnly => ((IList)_innerList).IsReadOnly;
public virtual bool IsFixedSize => ((IList)_innerList).IsFixedSize;
public void Add(T item) => _innerList.Add(item);
public int Add(object item) => ((IList)_innerList).Add(item);
public void Clear() => _innerList.Clear();
public bool Contains(T item) => _innerList.Contains(item);
public bool Contains(object item) => ((IList)_innerList).Contains(item);
public void CopyTo(T[] array, int arrayIndex) => _innerList.CopyTo(array, arrayIndex);
public void CopyTo(Array array, int arrayIndex) => ((IList)_innerList).CopyTo(array, arrayIndex);
public bool Remove(T item) => _innerList.Remove(item);
public void Remove(object item) => ((IList)_innerList).Remove(item);
public T this[int index]
{
get => _innerList[index];
set => _innerList[index] = value;
}
object IList.this[int index]
{
get => ((IList)_innerList)[index];
set => ((IList)_innerList)[index] = value;
}
public int IndexOf(T item) => _innerList.IndexOf(item);
public int IndexOf(object item) => ((IList)_innerList).IndexOf(item);
public void Insert(int index, T item) => _innerList.Insert(index, item);
public void Insert(int index, object item) => ((IList)_innerList).Insert(index, item);
public void RemoveAt(int index) => _innerList.RemoveAt(index);
}
private class EnumerableWrapper<T> : IEnumerable<T>
{
private readonly IEnumerable<T> _innerEnumerable;
public EnumerableWrapper(IEnumerable<T> innerEnumerable)
{
_innerEnumerable = innerEnumerable;
}
public IEnumerator<T> GetEnumerator() => _innerEnumerable.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _innerEnumerable.GetEnumerator();
}
private class DataClass
{
public IList<int> List { get; set; }
}
private class EnumerableDataClass
{
public IEnumerable Enumerable { get; set; }
}
private class ListSourceDataClass
{
public IListSource ListSource { get; set; }
}
private class ObjectDataClass
{
public object List { get; set; }
}
private class SubBindingSource : BindingSource
{
public SubBindingSource() : base()
{
}
public SubBindingSource(object dataSource, string dataMember) : base(dataSource, dataMember)
{
}
public SubBindingSource(IContainer container) : base(container)
{
}
public new bool CanRaiseEvents => base.CanRaiseEvents;
public new bool DesignMode => base.DesignMode;
public new EventHandlerList Events => base.Events;
}
private class PrivateDefaultConstructor : List<int>, ITypedList
{
private PrivateDefaultConstructor() { }
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
throw new NotImplementedException();
}
public string GetListName(PropertyDescriptor[] listAccessors)
{
throw new NotImplementedException();
}
}
private class NoDefaultConstructor : List<int>, ITypedList
{
#pragma warning disable IDE0060 // Remove unused parameter
public NoDefaultConstructor(int i) { }
#pragma warning restore IDE0060
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
throw new NotImplementedException();
}
public string GetListName(PropertyDescriptor[] listAccessors)
{
throw new NotImplementedException();
}
}
private class ThrowingDefaultConstructor : List<int>, ITypedList
{
public ThrowingDefaultConstructor()
{
throw new DivideByZeroException();
}
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
throw new NotImplementedException();
}
public string GetListName(PropertyDescriptor[] listAccessors)
{
throw new NotImplementedException();
}
}
private class DataSource
{
public int Member { get; set; }
}
private class ISupportInitializeNotificationDataSource : ISupportInitializeNotification
{
public int Member { get; set; }
public bool IsInitializedResult { get; set; }
public bool IsInitialized => IsInitializedResult;
public event EventHandler Initialized;
public void BeginInit()
{
}
public void EndInit()
{
Initialized(this, null);
}
}
}
|