diff options
Diffstat (limited to 'Xamarin.Forms.Core.UnitTests/ListProxyTests.cs')
-rw-r--r-- | Xamarin.Forms.Core.UnitTests/ListProxyTests.cs | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/Xamarin.Forms.Core.UnitTests/ListProxyTests.cs b/Xamarin.Forms.Core.UnitTests/ListProxyTests.cs new file mode 100644 index 00000000..6fa85d2c --- /dev/null +++ b/Xamarin.Forms.Core.UnitTests/ListProxyTests.cs @@ -0,0 +1,426 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; + +namespace Xamarin.Forms.Core.UnitTests +{ + [TestFixture] + public class ListProxyTests : BaseTestFixture + { + [SetUp] + public override void Setup() + { + base.Setup (); + Device.PlatformServices = new MockPlatformServices (); + } + + [TearDown] + public override void TearDown() + { + base.TearDown (); + Device.PlatformServices = null; + } + + [Test] + public void ListCount() + { + var list = new List<string> { "foo", "bar" }; + var proxy = new ListProxy (list); + + Assert.AreEqual (list.Count, proxy.Count); + list.Add ("baz"); + Assert.AreEqual (list.Count, proxy.Count); + } + + [Test] + public void CollectionCount() + { + var list = new Collection<string> { "foo", "bar" }; + var proxy = new ListProxy (list); + + Assert.AreEqual (list.Count, proxy.Count); + list.Add ("baz"); + Assert.AreEqual (list.Count, proxy.Count); + } + + [Test] + [Description ("Count should ensure that the window is created if neccessary")] + public void EnumerableInitialCount() + { + var enumerable = Enumerable.Range (0, 100); + var proxy = new ListProxy (enumerable, 10); + + Assert.AreEqual (10, proxy.Count); + } + + [Test] + public void EnumerableCount() + { + var enumerable = Enumerable.Range (0, 100); + var proxy = new ListProxy (enumerable, 10); + + int changed = 0; + proxy.CountChanged += (o, e) => changed++; + + var enumerator = proxy.GetEnumerator(); + enumerator.MoveNext(); + + Assert.AreEqual (10, proxy.Count); + Assert.AreEqual (1, changed); + + enumerator.MoveNext(); + + Assert.AreEqual (10, proxy.Count); + Assert.AreEqual (1, changed); + + while (enumerator.MoveNext()) { + } + + enumerator.Dispose(); + + Assert.AreEqual (100, proxy.Count); + Assert.AreEqual (19, changed); + + using (enumerator = proxy.GetEnumerator()) { + + Assert.AreEqual (100, proxy.Count); + + while (enumerator.MoveNext()) + Assert.AreEqual (100, proxy.Count); + + Assert.AreEqual (100, proxy.Count); + } + + Assert.AreEqual (19, changed); + } + + [Test] + public void InsideWindowSize() + { + var numbers = Enumerable.Range (0, 100); + var proxy = new ListProxy (numbers, 10); + + int i = (int)proxy[5]; + Assert.That (i, Is.EqualTo (5)); + } + + [Test] + public void IndexOutsideWindowSize() + { + var numbers = Enumerable.Range (0, 100); + var proxy = new ListProxy (numbers, 10); + + int i = (int)proxy[50]; + Assert.That (i, Is.EqualTo (50)); + } + + [Test] + public void IndexInsideToOutsideWindowSize() + { + var numbers = Enumerable.Range (0, 100); + var proxy = new ListProxy (numbers, 10); + + int i = (int)proxy[5]; + Assert.That (i, Is.EqualTo (5)); + + i = (int)proxy[50]; + Assert.That (i, Is.EqualTo (50)); + } + + [Test] + public void IndexOutsideToPreWindowSize() + { + var numbers = Enumerable.Range (0, 100); + var proxy = new ListProxy (numbers, 10); + + int i = (int)proxy[50]; + Assert.That (i, Is.EqualTo (50)); + + i = (int)proxy[5]; + Assert.That (i, Is.EqualTo (5)); + } + + [Test] + public void EnumerableIndexOutOfRange() + { + var numbers = Enumerable.Range (0, 100); + var proxy = new ListProxy (numbers); + + Assert.That (() => proxy[100], Throws.InstanceOf<ArgumentOutOfRangeException>()); + } + + class IntCollection + : ICollection + { + readonly List<int> ints; + + public IntCollection (IEnumerable<int> ints) + { + this.ints = ints.ToList(); + } + + public IEnumerator GetEnumerator() + { + return ints.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void CopyTo (Array array, int index) + { + throw new NotImplementedException(); + } + + public int Count { get { return ints.Count; }} + + public object SyncRoot + { + get { throw new NotImplementedException(); } + } + + public bool IsSynchronized + { + get { throw new NotImplementedException(); } + } + + public bool IsReadOnly { get { return true; } } + } + + [Test] + public void CollectionIndexOutOfRange() + { + var numbers = new IntCollection (Enumerable.Range (0, 100)); + var proxy = new ListProxy (numbers); + + Assert.That (() => proxy[100], Throws.InstanceOf<ArgumentOutOfRangeException>()); + } + + [Test] + public void ListIndexOutOfRange() + { + var numbers = Enumerable.Range (0, 100).ToList(); + var proxy = new ListProxy (numbers); + + Assert.That (() => proxy[100], Throws.InstanceOf<ArgumentOutOfRangeException>()); + } + + [Test] + public void CollectionChangedWhileEnumerating() + { + var c = new ObservableCollection<string> { "foo", "bar" }; + var p = new ListProxy (c); + + IEnumerator<object> e = p.GetEnumerator(); + Assert.IsTrue (e.MoveNext(), "Initial MoveNext() failed, test can't continue"); + + c.Add ("baz"); + + Assert.That (() => e.MoveNext(), Throws.InvalidOperationException, + "MoveNext did not throw an exception when the underlying collection had changed"); + } + + [Test] + public void SynchronizedCollectionAccess() + { + var collection = new ObservableCollection<string> { "foo" }; + var context = new object(); + + var list = new ListProxy (collection); + + bool executed = false; + BindingBase.EnableCollectionSynchronization (collection, context, (enumerable, o, method, access) => { + executed = true; + Assert.AreSame (collection, enumerable); + Assert.AreSame (context, o); + Assert.IsNotNull (method); + Assert.IsFalse (access); + + lock (enumerable) + method(); + }); + + object value = list[0]; + + Assert.IsTrue (executed, "Callback was not executed"); + } + + [Test] + public void SynchronizedCollectionAdd() + { + bool invoked = false; + Device.PlatformServices = new MockPlatformServices (invokeOnMainThread: action => { + invoked = true; + action(); + }); + + var collection = new ObservableCollection<string> { "foo" }; + var context = new object(); + + var list = new ListProxy (collection); + + Assert.IsFalse (invoked, "An invoke shouldn't be executed just setting up ListProxy"); + + bool executed = false; + BindingBase.EnableCollectionSynchronization (collection, context, (enumerable, o, method, access) => { + executed = true; + Assert.AreSame (collection, enumerable); + Assert.AreSame (context, o); + Assert.IsNotNull (method); + Assert.IsFalse (access); + + lock (enumerable) + method(); + }); + + var mre = new ManualResetEvent (false); + + Task.Factory.StartNew (() => { + lock (collection) + collection.Add ("foo"); + + mre.Set(); + }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + + mre.WaitOne (5000); + + Assert.IsTrue (executed, "Callback was not executed"); + Assert.IsTrue (invoked, "Callback was not executed on the UI thread"); + } + + [Test] + public void ClearEnumerable() + { + var proxy = new ListProxy (Enumerable.Range (0, 100)); + var enumerator = proxy.GetEnumerator(); + enumerator.MoveNext(); + enumerator.MoveNext(); + + proxy.Clear(); + + Assert.AreEqual (100, proxy.Count); + Assert.That (() => enumerator.MoveNext(), Throws.InvalidOperationException); + } + + [Test] + public void ClearCollection() + { + var proxy = new ListProxy (new IntCollection (Enumerable.Range (0, 100))); + var enumerator = proxy.GetEnumerator(); + enumerator.MoveNext(); + enumerator.MoveNext(); + + proxy.Clear(); + + Assert.AreEqual (100, proxy.Count); + Assert.That (() => enumerator.MoveNext(), Throws.InvalidOperationException); + } + + [Test] + public void ClearList() + { + var proxy = new ListProxy (Enumerable.Range (0, 100).ToList()); + var enumerator = proxy.GetEnumerator(); + enumerator.MoveNext(); + enumerator.MoveNext(); + + proxy.Clear(); + + Assert.AreEqual (100, proxy.Count); + Assert.That (() => enumerator.MoveNext(), Throws.InvalidOperationException); + } + + [Test] + public void IndexOfValueTypeNonList() + { + var proxy = new ListProxy (Enumerable.Range (0, 100)); + Assert.AreEqual (1, proxy.IndexOf (1)); + } + + [Test] + public void EnumeratorForEnumerable() + { + var proxy = new ListProxy (Enumerable.Range (0, 2)); + + var enumerator = proxy.GetEnumerator(); + Assert.That (enumerator.Current, Is.Null); + Assert.That (enumerator.MoveNext(), Is.True); + Assert.That (enumerator.Current, Is.EqualTo (0)); + Assert.That (enumerator.MoveNext(), Is.True); + Assert.That (enumerator.Current, Is.EqualTo (1)); + Assert.That (enumerator.MoveNext(), Is.False); + } + + [Test] + public void ProxyIsWeaklyHeldByINotifyCollectionChanged() + { + ObservableCollection<string> collection = new ObservableCollection<string>(); + + WeakReference weakProxy = null; + + int i = 0; + Action create = null; + create = () => { + if (i++ < 1024) { + create(); + return; + } + + var proxy = new ListProxy (collection); + weakProxy = new WeakReference (proxy); + }; + + create(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + + Assert.That (weakProxy.IsAlive, Is.False); + } + + [Test] + public void IEnumerableAddDoesNotReport0() + { + var custom = new CustomINCC(); + custom.Add ("test"); + custom.Add ("test2"); + + var proxy = new ListProxy (custom); + Assert.That (proxy.Count, Is.EqualTo (2)); + + custom.Add ("testing"); + Assert.That (proxy.Count, Is.EqualTo (3)); + } + + class CustomINCC : IEnumerable<string>, INotifyCollectionChanged + { + public event NotifyCollectionChangedEventHandler CollectionChanged; + List<string> Items = new List<string> (); + + public void Add (string s) + { + Items.Add(s); + if (CollectionChanged != null) + CollectionChanged (this, new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Add, s)); + } + + public IEnumerator<string> GetEnumerator () + { + return Items.GetEnumerator (); + } + IEnumerator IEnumerable.GetEnumerator () + { + return Items.GetEnumerator (); + } + } + } +} |