1053 lines
38 KiB
C#
1053 lines
38 KiB
C#
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
namespace ProductivityApiUnitTests
|
|
{
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Data.Entity;
|
|
using System.Data.Entity.Infrastructure;
|
|
using System.Data.Entity.Internal;
|
|
using System.Data.Entity.Internal.Linq;
|
|
using System.Data.Entity.Resources;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Xml.Linq;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
/// <summary>
|
|
/// Unit tests for data binding and DbSet.Local.
|
|
/// </summary>
|
|
public class DatabindingTests : TestBase
|
|
{
|
|
#region Test subjects
|
|
|
|
private class ListElement
|
|
{
|
|
public ListElement()
|
|
{
|
|
}
|
|
|
|
public ListElement(int i)
|
|
{
|
|
Int = i;
|
|
NullableInt = i;
|
|
String = i.ToString();
|
|
XNode = new XText(i.ToString());
|
|
Random = new Random();
|
|
ByteArray = new[] { (byte)i, (byte)i, (byte)i, (byte)i };
|
|
}
|
|
|
|
public static implicit operator ListElement(int i)
|
|
{
|
|
return new ListElement(i);
|
|
}
|
|
|
|
public int Int { get; set; }
|
|
public int? NullableInt { get; set; }
|
|
public string String { get; set; }
|
|
public XNode XNode { get; set; }
|
|
public Random Random { get; set; }
|
|
public byte[] ByteArray { get; set; }
|
|
|
|
public static PropertyDescriptor Property(string name)
|
|
{
|
|
return TypeDescriptor.GetProperties(typeof(ListElement))[name];
|
|
}
|
|
}
|
|
|
|
private class DerivedListElement : ListElement
|
|
{
|
|
public DerivedListElement()
|
|
{
|
|
}
|
|
|
|
public DerivedListElement(int i)
|
|
: base(i)
|
|
{
|
|
}
|
|
}
|
|
|
|
private class ListElementComparer : IEqualityComparer<ListElement>
|
|
{
|
|
public bool Equals(ListElement x, ListElement y)
|
|
{
|
|
return x.Int == y.Int;
|
|
}
|
|
|
|
public int GetHashCode(ListElement obj)
|
|
{
|
|
return obj.Int;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SortableBindingList tests
|
|
|
|
private void SortTest(string property, ListSortDirection direction)
|
|
{
|
|
var list = new List<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
4,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var sortedList = direction == ListSortDirection.Ascending
|
|
? new List<ListElement>
|
|
{
|
|
1,
|
|
1,
|
|
3,
|
|
4,
|
|
5,
|
|
9
|
|
}
|
|
: new List<ListElement>
|
|
{
|
|
9,
|
|
5,
|
|
4,
|
|
3,
|
|
1,
|
|
1
|
|
};
|
|
|
|
var bindingList = new SortableBindingList<ListElement>(list);
|
|
|
|
((IBindingList)bindingList).ApplySort(ListElement.Property(property), direction);
|
|
|
|
Assert.True(list.SequenceEqual(sortedList, new ListElementComparer()));
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_ascending_using_IComparable_on_value_type()
|
|
{
|
|
SortTest("Int", ListSortDirection.Ascending);
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_ascending_using_IComparable_on_nullable_value_type()
|
|
{
|
|
SortTest("NullableInt", ListSortDirection.Ascending);
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_ascending_using_IComparable_on_reference_type()
|
|
{
|
|
SortTest("String", ListSortDirection.Ascending);
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_descending_using_IComparable_on_value_type()
|
|
{
|
|
SortTest("Int", ListSortDirection.Descending);
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_descending_using_IComparable_on_nullable_value_type()
|
|
{
|
|
SortTest("NullableInt", ListSortDirection.Descending);
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_descending_using_IComparable_on_reference_type()
|
|
{
|
|
SortTest("String", ListSortDirection.Descending);
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_ascending_for_XNode_using_ToString()
|
|
{
|
|
SortTest("XNode", ListSortDirection.Ascending);
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_descending_for_XNode_using_ToString()
|
|
{
|
|
SortTest("XNode", ListSortDirection.Descending);
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_does_not_sort_for_non_XNode_that_does_not_implement_IComparable()
|
|
{
|
|
var list = new List<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
4,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var unsortedList = new List<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
4,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var bindingList = new SortableBindingList<ListElement>(list);
|
|
|
|
((IBindingList)bindingList).ApplySort(ListElement.Property("Random"), ListSortDirection.Ascending);
|
|
|
|
Assert.True(list.SequenceEqual(unsortedList, new ListElementComparer()));
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_does_not_sort_for_byte_arrays()
|
|
{
|
|
var list = new List<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
4,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var unsortedList = new List<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
4,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var bindingList = new SortableBindingList<ListElement>(list);
|
|
|
|
((IBindingList)bindingList).ApplySort(ListElement.Property("ByteArray"), ListSortDirection.Descending);
|
|
|
|
Assert.True(list.SequenceEqual(unsortedList, new ListElementComparer()));
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_when_list_contains_derived_objects()
|
|
{
|
|
var list = new List<ListElement>
|
|
{
|
|
new DerivedListElement(3),
|
|
new DerivedListElement(1),
|
|
new DerivedListElement(4)
|
|
};
|
|
var sortedList = new List<ListElement>
|
|
{
|
|
new DerivedListElement(1),
|
|
new DerivedListElement(3),
|
|
new DerivedListElement(4)
|
|
};
|
|
|
|
var bindingList = new SortableBindingList<ListElement>(list);
|
|
|
|
((IBindingList)bindingList).ApplySort(ListElement.Property("Int"), ListSortDirection.Ascending);
|
|
|
|
Assert.True(list.SequenceEqual(sortedList, new ListElementComparer()));
|
|
}
|
|
|
|
[Fact]
|
|
public void SortableBindingList_can_sort_when_list_is_of_derived_type()
|
|
{
|
|
var list = new List<DerivedListElement>
|
|
{
|
|
new DerivedListElement(3),
|
|
new DerivedListElement(1),
|
|
new DerivedListElement(4)
|
|
};
|
|
var sortedList = new List<DerivedListElement>
|
|
{
|
|
new DerivedListElement(1),
|
|
new DerivedListElement(3),
|
|
new DerivedListElement(4)
|
|
};
|
|
|
|
var bindingList = new SortableBindingList<DerivedListElement>(list);
|
|
|
|
((IBindingList)bindingList).ApplySort(ListElement.Property("Int"), ListSortDirection.Ascending);
|
|
|
|
Assert.True(list.SequenceEqual(sortedList, new ListElementComparer()));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ObservableBackedBindingList tests
|
|
|
|
[Fact]
|
|
public void Items_added_to_ObservableCollection_are_added_to_binding_list()
|
|
{
|
|
var oc = new ObservableCollection<ListElement>();
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
var item = new ListElement(1);
|
|
oc.Add(item);
|
|
|
|
Assert.True(obbl.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_removed_from_ObservableCollection_are_removed_from_binding_list()
|
|
{
|
|
var item = new ListElement(4);
|
|
var oc = new ObservableCollection<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
item,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
oc.Remove(item);
|
|
|
|
Assert.False(obbl.Contains(item));
|
|
Assert.Equal(5, obbl.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_replaced_in_the_ObservableCollection_are_replaced_in_the_binding_list()
|
|
{
|
|
var item = new ListElement(4);
|
|
var oc = new ObservableCollection<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
item,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
var newItem = new ListElement(-4);
|
|
oc[2] = newItem;
|
|
|
|
Assert.False(obbl.Contains(item));
|
|
Assert.True(obbl.Contains(newItem));
|
|
Assert.Equal(6, obbl.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_cleared_in_the_ObservableCollection_are_cleared_in_the_binding_list()
|
|
{
|
|
var oc = new ObservableCollection<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
4,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
oc.Clear();
|
|
|
|
Assert.Equal(0, obbl.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void Adding_duplicate_item_to_the_ObservableCollection_adds_duplicate_to_the_binding_list()
|
|
{
|
|
var item = new ListElement(4);
|
|
var oc = new ObservableCollection<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
item,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
oc.Add(item);
|
|
|
|
Assert.Equal(7, obbl.Count);
|
|
Assert.Equal(2, obbl.Count(i => ReferenceEquals(i, item)));
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_added_to_the_binding_list_are_added_to_the_ObservableCollection()
|
|
{
|
|
var oc = new ObservableCollection<ListElement>();
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
var item = new ListElement(7);
|
|
obbl.Add(item);
|
|
|
|
Assert.True(oc.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_added_to_the_binding_list_with_AddNew_are_added_to_the_ObservableCollection()
|
|
{
|
|
var oc = new ObservableCollection<ListElement>();
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
var item = obbl.AddNew();
|
|
obbl.EndNew(0);
|
|
|
|
Assert.True(oc.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_canceled_during_AddNew_are_not_added_to_the_ObservableCollection()
|
|
{
|
|
var oc = new ObservableCollection<ListElement>();
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
var item = obbl.AddNew();
|
|
obbl.CancelNew(0);
|
|
|
|
Assert.False(oc.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_inserted_into_the_binding_list_are_added_to_the_ObservableCollection()
|
|
{
|
|
var oc = new ObservableCollection<ListElement>();
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
var item = new ListElement(7);
|
|
obbl.Insert(0, item);
|
|
|
|
Assert.True(oc.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_set_in_the_binding_list_are_replaced_in_the_ObservableCollection()
|
|
{
|
|
var item = new ListElement(4);
|
|
var oc = new ObservableCollection<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
item,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
var newItem = new ListElement(7);
|
|
obbl[2] = newItem;
|
|
|
|
Assert.True(oc.Contains(newItem));
|
|
Assert.False(oc.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_removed_from_the_binding_list_are_removed_from_the_ObservableCollection()
|
|
{
|
|
var item = new ListElement(4);
|
|
var oc = new ObservableCollection<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
item,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
obbl.Remove(item);
|
|
|
|
Assert.False(oc.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_removed_by_index_from_the_binding_list_are_removed_from_the_ObservableCollection()
|
|
{
|
|
var item = new ListElement(4);
|
|
var oc = new ObservableCollection<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
item,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
obbl.RemoveAt(2);
|
|
|
|
Assert.False(oc.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Items_cleared_from_the_binding_list_are_cleared_from_the_ObservableCollection()
|
|
{
|
|
var oc = new ObservableCollection<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
4,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
obbl.Clear();
|
|
|
|
Assert.Equal(0, oc.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void Adding_duplicate_item_to_the_binding_list_adds_duplicate_to_the_ObservableCollection()
|
|
{
|
|
var item = new ListElement(4);
|
|
var oc = new ObservableCollection<ListElement>
|
|
{
|
|
3,
|
|
1,
|
|
item,
|
|
1,
|
|
5,
|
|
9
|
|
};
|
|
var obbl = new ObservableBackedBindingList<ListElement>(oc);
|
|
|
|
obbl.Add(item);
|
|
|
|
Assert.Equal(7, oc.Count);
|
|
Assert.Equal(2, oc.Count(i => ReferenceEquals(i, item)));
|
|
}
|
|
|
|
[Fact]
|
|
public void Attempt_to_AddNew_for_abstract_type_works_if_AddingNew_event_is_used_to_create_new_object()
|
|
{
|
|
var obbl = new ObservableBackedBindingList<XNode>(new ObservableCollection<XNode>());
|
|
var item = new XText("Some Value");
|
|
|
|
obbl.AddingNew += (s, e) => e.NewObject = item;
|
|
obbl.AddNew();
|
|
obbl.EndNew(0);
|
|
|
|
Assert.True(obbl.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Attempt_to_AddNew_for_abstract_type_throws_if_AddingNew_event_is_not_used()
|
|
{
|
|
var obbl = new ObservableBackedBindingList<XNode>(new ObservableCollection<XNode>());
|
|
|
|
const BindingFlags bindingAttr = BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance;
|
|
Assert.Equal(
|
|
GenerateException(() => Activator.CreateInstance(typeof(XNode), bindingAttr, null, null, null)).Message,
|
|
Assert.Throws<MissingMethodException>(() => obbl.AddNew()).Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void Attempt_to_AddNew_for_type_without_parameterless_constructor_works_if_AddingNew_event_is_used_to_create_new_object()
|
|
{
|
|
var obbl = new ObservableBackedBindingList<XText>(new ObservableCollection<XText>());
|
|
var item = new XText("Some Value");
|
|
|
|
obbl.AddingNew += (s, e) => e.NewObject = item;
|
|
obbl.AddNew();
|
|
obbl.EndNew(0);
|
|
|
|
Assert.True(obbl.Contains(item));
|
|
}
|
|
|
|
[Fact]
|
|
public void Attempt_to_AddNew_for_type_without_parameterless_constructor_throws_if_AddingNew_event_is_not_used()
|
|
{
|
|
var obbl = new ObservableBackedBindingList<XText>(new ObservableCollection<XText>());
|
|
|
|
const BindingFlags bindingAttr = BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance;
|
|
Assert.Equal(
|
|
GenerateException(() => Activator.CreateInstance(typeof(XText), bindingAttr, null, null, null)).Message,
|
|
Assert.Throws<MissingMethodException>(() => obbl.AddNew()).Message);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DbLocalView tests
|
|
|
|
private Mock<InternalContextForMock> CreateMockedInternalContext(
|
|
Mock<IDbSet<FakeEntity>> mockDbSet, IList<FakeEntity> entities = null)
|
|
{
|
|
entities = entities ?? new List<FakeEntity>();
|
|
var mockInternalContext = new Mock<InternalContextForMock>();
|
|
mockInternalContext.Setup(i => i.GetLocalEntities<FakeEntity>()).Returns(entities);
|
|
mockInternalContext.Setup(i => i.Set<FakeEntity>()).Returns(mockDbSet.Object);
|
|
mockInternalContext.Setup(i => i.EntityInContextAndNotDeleted(It.Is<FakeEntity>(e => entities.Contains(e))));
|
|
return mockInternalContext;
|
|
}
|
|
|
|
private DbLocalView<FakeEntity> CreateLocalView(Mock<IDbSet<FakeEntity>> mockDbSet, IList<FakeEntity> entities = null)
|
|
{
|
|
return new DbLocalView<FakeEntity>(CreateMockedInternalContext(mockDbSet, entities).Object);
|
|
}
|
|
|
|
[Fact]
|
|
public void DbLocalView_is_initialized_with_entities_from_the_context()
|
|
{
|
|
var entities = new List<FakeEntity>
|
|
{
|
|
new FakeEntity(),
|
|
new FakeEntity()
|
|
};
|
|
var localView = CreateLocalView(new Mock<IDbSet<FakeEntity>>(), entities);
|
|
|
|
Assert.Equal(2, localView.Count);
|
|
Assert.True(localView.Contains(entities[0]));
|
|
Assert.True(localView.Contains(entities[1]));
|
|
}
|
|
|
|
[Fact]
|
|
public void Adding_entity_to_DbLocalView_adds_entity_to_DbSet()
|
|
{
|
|
var mockDbSet = new Mock<IDbSet<FakeEntity>>();
|
|
var localView = CreateLocalView(mockDbSet);
|
|
|
|
var entity = new FakeEntity();
|
|
localView.Add(entity);
|
|
|
|
mockDbSet.Verify(s => s.Add(entity), Times.Once());
|
|
}
|
|
|
|
[Fact]
|
|
public void Removing_entity_from_DbLocalView_removes_entity_from_DbSet()
|
|
{
|
|
var entity = new FakeEntity();
|
|
var mockDbSet = new Mock<IDbSet<FakeEntity>>();
|
|
var localView = CreateLocalView(
|
|
mockDbSet, new List<FakeEntity>
|
|
{
|
|
entity
|
|
});
|
|
|
|
localView.Remove(entity);
|
|
|
|
mockDbSet.Verify(s => s.Remove(entity), Times.Once());
|
|
}
|
|
|
|
[Fact]
|
|
public void Replacing_entity_in_DbLocalView_adds_an_entity_and_removes_an_entity_from_DbSet()
|
|
{
|
|
var entity = new FakeEntity();
|
|
var mockDbSet = new Mock<IDbSet<FakeEntity>>();
|
|
var localView = CreateLocalView(
|
|
mockDbSet, new List<FakeEntity>
|
|
{
|
|
entity
|
|
});
|
|
|
|
var newEntity = new FakeEntity();
|
|
localView[0] = newEntity;
|
|
|
|
mockDbSet.Verify(s => s.Remove(entity), Times.Once());
|
|
mockDbSet.Verify(s => s.Add(newEntity), Times.Once());
|
|
}
|
|
|
|
[Fact]
|
|
public void Moving_an_entity_in_DbLocalView_is_ignored()
|
|
{
|
|
var entities = new List<FakeEntity>
|
|
{
|
|
new FakeEntity(),
|
|
new FakeEntity()
|
|
};
|
|
var mockDbSet = new Mock<IDbSet<FakeEntity>>();
|
|
var localView = CreateLocalView(mockDbSet, entities);
|
|
|
|
localView.Move(0, 1);
|
|
|
|
mockDbSet.Verify(s => s.Remove(It.IsAny<FakeEntity>()), Times.Never());
|
|
mockDbSet.Verify(s => s.Add(It.IsAny<FakeEntity>()), Times.Never());
|
|
}
|
|
|
|
[Fact]
|
|
public void Adding_entity_to_DbLocalView_that_is_already_in_state_manager_is_ignored()
|
|
{
|
|
var entity = new FakeEntity();
|
|
var mockDbSet = new Mock<IDbSet<FakeEntity>>();
|
|
var localView = CreateLocalView(
|
|
mockDbSet, new List<FakeEntity>
|
|
{
|
|
entity
|
|
});
|
|
|
|
localView.Add(entity);
|
|
|
|
mockDbSet.Verify(s => s.Add(It.IsAny<FakeEntity>()), Times.Never());
|
|
}
|
|
|
|
[Fact]
|
|
public void BindingList_obtained_from_DbLocalView_is_cached()
|
|
{
|
|
var localView = CreateLocalView(new Mock<IDbSet<FakeEntity>>());
|
|
|
|
var bindingList = localView.BindingList;
|
|
Assert.NotNull(bindingList);
|
|
|
|
var bindingListAgain = localView.BindingList;
|
|
Assert.Same(bindingList, bindingListAgain);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindingList_obtaibed_from_DbLocalView_stays_in_sync_with_the_local_view()
|
|
{
|
|
var entities = new List<FakeEntity>
|
|
{
|
|
new FakeEntity(),
|
|
new FakeEntity()
|
|
};
|
|
var localView = CreateLocalView(new Mock<IDbSet<FakeEntity>>(), entities);
|
|
|
|
var bindingList = localView.BindingList;
|
|
Assert.Equal(2, bindingList.Count);
|
|
|
|
localView.Add(new FakeEntity());
|
|
Assert.Equal(3, bindingList.Count);
|
|
|
|
localView.Remove(entities[0]);
|
|
Assert.Equal(2, bindingList.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void DbLocalView_stays_in_sync_with_BindingList_obtaibed_from_it()
|
|
{
|
|
var entities = new List<FakeEntity>
|
|
{
|
|
new FakeEntity(),
|
|
new FakeEntity()
|
|
};
|
|
var localView = CreateLocalView(new Mock<IDbSet<FakeEntity>>(), entities);
|
|
|
|
var bindingList = localView.BindingList;
|
|
Assert.Equal(2, bindingList.Count);
|
|
|
|
bindingList.Add(new FakeEntity());
|
|
Assert.Equal(3, localView.Count);
|
|
|
|
bindingList.Remove(entities[0]);
|
|
Assert.Equal(2, localView.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void Clear_on_DbLocalView_removes_all_items_from_DbSet()
|
|
{
|
|
var entities = new List<FakeEntity>
|
|
{
|
|
new FakeEntity(),
|
|
new FakeEntity()
|
|
};
|
|
var mockDbSet = new Mock<IDbSet<FakeEntity>>();
|
|
var localView = CreateLocalView(mockDbSet, entities);
|
|
|
|
localView.Clear();
|
|
|
|
Assert.Equal(0, localView.Count);
|
|
mockDbSet.Verify(s => s.Remove(It.IsAny<FakeEntity>()), Times.Exactly(2));
|
|
}
|
|
|
|
[Fact]
|
|
public void Attempted_adds_of_duplicates_to_DbLocalView_are_ignored()
|
|
{
|
|
var entities = new List<FakeEntity>
|
|
{
|
|
new FakeEntity()
|
|
};
|
|
var mockDbSet = new Mock<IDbSet<FakeEntity>>();
|
|
var localView = CreateLocalView(mockDbSet, entities);
|
|
|
|
localView.Add(entities[0]);
|
|
|
|
Assert.Equal(1, localView.Count);
|
|
mockDbSet.Verify(s => s.Add(It.IsAny<FakeEntity>()), Times.Never());
|
|
}
|
|
|
|
[Fact]
|
|
public void State_manager_Remove_event_causes_entity_to_be_removed_from_DbLocalView()
|
|
{
|
|
var entity = new FakeEntity();
|
|
var mockInternalContext = CreateMockedInternalContext(
|
|
new Mock<IDbSet<FakeEntity>>(), new List<FakeEntity>
|
|
{
|
|
entity
|
|
});
|
|
|
|
CollectionChangeEventHandler stateManagerChanged = null;
|
|
mockInternalContext.Setup(i => i.RegisterObjectStateManagerChangedEvent(It.IsAny<CollectionChangeEventHandler>())).
|
|
Callback<CollectionChangeEventHandler>(h => stateManagerChanged = h);
|
|
|
|
var localView = new DbLocalView<FakeEntity>(mockInternalContext.Object);
|
|
|
|
stateManagerChanged.Invoke(null, new CollectionChangeEventArgs(CollectionChangeAction.Remove, entity));
|
|
|
|
Assert.False(localView.Contains(entity));
|
|
}
|
|
|
|
[Fact]
|
|
public void State_manager_Remove_event_for_entity_not_in_DbLocalView_is_ignored()
|
|
{
|
|
var mockInternalContext = CreateMockedInternalContext(new Mock<IDbSet<FakeEntity>>());
|
|
|
|
CollectionChangeEventHandler stateManagerChanged = null;
|
|
mockInternalContext.Setup(i => i.RegisterObjectStateManagerChangedEvent(It.IsAny<CollectionChangeEventHandler>())).
|
|
Callback<CollectionChangeEventHandler>(h => stateManagerChanged = h);
|
|
|
|
new DbLocalView<FakeEntity>(mockInternalContext.Object);
|
|
|
|
stateManagerChanged.Invoke(null, new CollectionChangeEventArgs(CollectionChangeAction.Remove, new FakeEntity()));
|
|
}
|
|
|
|
[Fact]
|
|
public void State_manager_Remove_event_for_entity_of_wrong_type_for_DbLocalView_is_ignored()
|
|
{
|
|
var mockInternalContext = CreateMockedInternalContext(new Mock<IDbSet<FakeEntity>>());
|
|
|
|
CollectionChangeEventHandler stateManagerChanged = null;
|
|
mockInternalContext.Setup(i => i.RegisterObjectStateManagerChangedEvent(It.IsAny<CollectionChangeEventHandler>())).
|
|
Callback<CollectionChangeEventHandler>(h => stateManagerChanged = h);
|
|
|
|
new DbLocalView<FakeEntity>(mockInternalContext.Object);
|
|
|
|
stateManagerChanged.Invoke(null, new CollectionChangeEventArgs(CollectionChangeAction.Remove, "Wrong Type"));
|
|
}
|
|
|
|
[Fact]
|
|
public void State_manager_Add_event_causes_entity_to_be_added_to_DbLocalView()
|
|
{
|
|
var mockInternalContext = CreateMockedInternalContext(new Mock<IDbSet<FakeEntity>>());
|
|
|
|
CollectionChangeEventHandler stateManagerChanged = null;
|
|
mockInternalContext.Setup(i => i.RegisterObjectStateManagerChangedEvent(It.IsAny<CollectionChangeEventHandler>())).
|
|
Callback<CollectionChangeEventHandler>(h => stateManagerChanged = h);
|
|
|
|
var localView = new DbLocalView<FakeEntity>(mockInternalContext.Object);
|
|
|
|
var entity = new FakeEntity();
|
|
stateManagerChanged.Invoke(null, new CollectionChangeEventArgs(CollectionChangeAction.Add, entity));
|
|
|
|
Assert.True(localView.Contains(entity));
|
|
}
|
|
|
|
[Fact]
|
|
public void State_manager_Add_event_for_entity_already_in_DbLocalView_is_ignored()
|
|
{
|
|
var entity = new FakeEntity();
|
|
var mockInternalContext = CreateMockedInternalContext(
|
|
new Mock<IDbSet<FakeEntity>>(), new List<FakeEntity>
|
|
{
|
|
entity
|
|
});
|
|
|
|
CollectionChangeEventHandler stateManagerChanged = null;
|
|
mockInternalContext.Setup(i => i.RegisterObjectStateManagerChangedEvent(It.IsAny<CollectionChangeEventHandler>())).
|
|
Callback<CollectionChangeEventHandler>(h => stateManagerChanged = h);
|
|
|
|
var localView = new DbLocalView<FakeEntity>(mockInternalContext.Object);
|
|
|
|
stateManagerChanged.Invoke(null, new CollectionChangeEventArgs(CollectionChangeAction.Add, entity));
|
|
|
|
Assert.Equal(1, localView.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void State_manager_Add_event_for_entity_of_wrong_type_for_DbLocalView_is_ignored()
|
|
{
|
|
var mockInternalContext = CreateMockedInternalContext(new Mock<IDbSet<FakeEntity>>());
|
|
|
|
CollectionChangeEventHandler stateManagerChanged = null;
|
|
mockInternalContext.Setup(i => i.RegisterObjectStateManagerChangedEvent(It.IsAny<CollectionChangeEventHandler>())).
|
|
Callback<CollectionChangeEventHandler>(h => stateManagerChanged = h);
|
|
|
|
var localView = new DbLocalView<FakeEntity>(mockInternalContext.Object);
|
|
|
|
stateManagerChanged.Invoke(null, new CollectionChangeEventArgs(CollectionChangeAction.Add, "Wrong Type"));
|
|
|
|
Assert.Equal(0, localView.Count);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ToBindingList tests
|
|
|
|
[Fact]
|
|
public void ToBindingList_throws_when_given_null_ObservableCollection()
|
|
{
|
|
Assert.Equal(
|
|
"source",
|
|
Assert.Throws<ArgumentNullException>(() => ObservableCollectionExtensions.ToBindingList<FakeEntity>(null)).ParamName);
|
|
}
|
|
|
|
[Fact]
|
|
public void ToBindingList_returns_the_cached_BindingList_when_called_with_DbLocalView()
|
|
{
|
|
var localView = CreateLocalView(new Mock<IDbSet<FakeEntity>>());
|
|
|
|
var bindingList = localView.ToBindingList();
|
|
Assert.NotNull(bindingList);
|
|
|
|
var bindingListAgain = localView.ToBindingList();
|
|
Assert.Same(bindingList, bindingListAgain);
|
|
}
|
|
|
|
[Fact]
|
|
public void ToBindingList_returns_a_new_binding_list_each_time_when_called_on_non_DbLocalView_ObervableCollections()
|
|
{
|
|
var oc = new ObservableCollection<FakeEntity>();
|
|
|
|
var bindingList = oc.ToBindingList();
|
|
Assert.NotNull(bindingList);
|
|
|
|
var bindingListAgain = oc.ToBindingList();
|
|
Assert.NotNull(bindingListAgain);
|
|
Assert.NotSame(bindingList, bindingListAgain);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ObservableListSource tests
|
|
|
|
[Fact]
|
|
public void ObservableListSource_exposes_ObervableCollection_parameterless_constructor()
|
|
{
|
|
var ols = new ObservableListSource<FakeEntity>();
|
|
Assert.Equal(0, ols.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void ObservableListSource_exposes_ObervableCollection_IEnumerable_constructor()
|
|
{
|
|
IEnumerable<FakeEntity> entities = new[] { new FakeEntity(), new FakeEntity() };
|
|
var ols = new ObservableListSource<FakeEntity>(entities);
|
|
Assert.Equal(2, ols.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void ObservableListSource_exposes_ObervableCollection_List_constructor()
|
|
{
|
|
var entities = new List<FakeEntity>
|
|
{
|
|
new FakeEntity(),
|
|
new FakeEntity()
|
|
};
|
|
var ols = new ObservableListSource<FakeEntity>(entities);
|
|
Assert.Equal(2, ols.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void ObservableListSource_ContainsListCollection_returns_false()
|
|
{
|
|
Assert.False(((IListSource)new ObservableListSource<FakeEntity>()).ContainsListCollection);
|
|
}
|
|
|
|
[Fact]
|
|
public void ObservableListSource_GetList_returns_BindingList_attached_to_the_ObservableCollection()
|
|
{
|
|
var ols = new ObservableListSource<FakeEntity>
|
|
{
|
|
new FakeEntity(),
|
|
new FakeEntity()
|
|
};
|
|
var bindingList = ((IListSource)ols).GetList();
|
|
|
|
Assert.Equal(2, bindingList.Count);
|
|
|
|
ols.Add(new FakeEntity());
|
|
Assert.Equal(3, bindingList.Count);
|
|
|
|
ols.Remove(ols[0]);
|
|
Assert.Equal(2, bindingList.Count);
|
|
|
|
bindingList.Add(new FakeEntity());
|
|
Assert.Equal(3, ols.Count);
|
|
|
|
bindingList.RemoveAt(0);
|
|
Assert.Equal(2, ols.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void The_BindingList_returned_from_ObservableListSource_GetList_is_cached()
|
|
{
|
|
var ols = new ObservableListSource<FakeEntity>();
|
|
var bindingList = ((IListSource)ols).GetList();
|
|
|
|
Assert.Same(bindingList, ((IListSource)ols).GetList());
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DbQuery as IListSource tests
|
|
|
|
[Fact]
|
|
public void DbQuery_ContainsListCollection_returns_false()
|
|
{
|
|
var fakeQuery = new DbQuery<FakeEntity>(new Mock<IInternalQuery<FakeEntity>>().Object);
|
|
|
|
Assert.False(((IListSource)fakeQuery).ContainsListCollection);
|
|
}
|
|
|
|
[Fact]
|
|
public void Non_generic_DbQuery_ContainsListCollection_returns_false()
|
|
{
|
|
var fakeQuery = new InternalDbQuery<FakeEntity>(new Mock<IInternalQuery<FakeEntity>>().Object);
|
|
|
|
Assert.False(((IListSource)fakeQuery).ContainsListCollection);
|
|
}
|
|
|
|
[Fact]
|
|
public void DbQuery_GetList_throws_indicating_that_binding_to_queries_is_not_allowed()
|
|
{
|
|
var fakeQuery = new DbQuery<FakeEntity>(new Mock<IInternalQuery<FakeEntity>>().Object);
|
|
|
|
Assert.Equal(
|
|
Strings.DbQuery_BindingToDbQueryNotSupported,
|
|
Assert.Throws<NotSupportedException>(() => ((IListSource)fakeQuery).GetList()).Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void Non_generic_DbQuery_GetList_throws_indicating_that_binding_to_queries_is_not_allowed()
|
|
{
|
|
var fakeQuery = new InternalDbQuery<FakeEntity>(new Mock<IInternalQuery<FakeEntity>>().Object);
|
|
|
|
Assert.Equal(
|
|
Strings.DbQuery_BindingToDbQueryNotSupported,
|
|
Assert.Throws<NotSupportedException>(() => ((IListSource)fakeQuery).GetList()).Message);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Load tests
|
|
|
|
[Fact]
|
|
public void Load_throws_when_given_null_query()
|
|
{
|
|
Assert.Equal("source", Assert.Throws<ArgumentNullException>(() => IQueryableExtensions.Load(null)).ParamName);
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_enumerates_the_query()
|
|
{
|
|
var count = 0;
|
|
var mockEnumerator = new Mock<IEnumerator<FakeEntity>>();
|
|
var mockQuery = new Mock<IList<FakeEntity>>();
|
|
mockQuery.Setup(q => q.GetEnumerator()).Returns(mockEnumerator.Object);
|
|
mockEnumerator.Setup(e => e.MoveNext()).Returns(() => count++ < 5 ? true : false);
|
|
|
|
mockQuery.Object.AsQueryable().Load();
|
|
|
|
mockEnumerator.Verify(e => e.MoveNext(), Times.Exactly(6));
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|