public void SortingTestWithFilterBetween6And12() { var source = new Subject<Thing>(); var col = new TrackingCollection<Thing>( source, OrderedComparer<Thing>.OrderByDescending(x => x.UpdatedAt).Compare, (item, position, list) => item.UpdatedAt.Minute >= 6 && item.UpdatedAt.Minute <= 12); col.ProcessingDelay = TimeSpan.Zero; var count = 0; var expectedCount = 0; var evt = new ManualResetEvent(false); col.Subscribe(t => { if (++count == expectedCount) evt.Set(); }, () => { }); // testing ADD expectedCount = 1; // add a thing with UpdatedAt=0:0:10 Add(source, GetThing(1, 10)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(1, 10), }); // testing ADD // add another thing with UpdatedAt=0:0:2 expectedCount = 2; Add(source, GetThing(2, 2)); evt.WaitOne(); evt.Reset(); // check that list has {0:0:10,0:0:2} CollectionAssert.AreEqual(col, new List<Thing> { GetThing(1, 10), }); // testing MOVE // replace thing with UpdatedAt=0:0:2 to UpdatedAt=0:0:12 expectedCount = 3; Add(source, GetThing(2, 12)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(2, 12), GetThing(1, 10), }); // testing INSERT expectedCount = 4; Add(source, GetThing(3, 11)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(2, 12), GetThing(3, 11), GetThing(1, 10), }); // testing INSERT expectedCount = 7; Add(source, GetThing(4, 5)); Add(source, GetThing(5, 14)); Add(source, GetThing(6, 13)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(2, 12), GetThing(3, 11), GetThing(1, 10), }); // testing MOVE from top to middle expectedCount = 8; Add(source, GetThing(5, 5)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(2, 12), GetThing(3, 11), GetThing(1, 10), }); // testing MOVE from top to bottom expectedCount = 9; Add(source, GetThing(6, 4)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(2, 12), GetThing(3, 11), GetThing(1, 10), }); // testing MOVE from bottom to top expectedCount = 10; Add(source, GetThing(6, 14)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(2, 12), GetThing(3, 11), GetThing(1, 10), }); // testing MOVE from middle bottom to middle top expectedCount = 11; Add(source, GetThing(3, 14)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(2, 12), GetThing(1, 10), }); // testing MOVE from middle top to middle bottom expectedCount = 12; Add(source, GetThing(2, 9)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(1, 10), GetThing(2, 9), }); // testing MOVE from middle bottom to middle top more than 1 position expectedCount = 13; Add(source, GetThing(5, 12)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(5, 12), GetThing(1, 10), GetThing(2, 9), }); expectedCount = 14; col.RemoveItem(GetThing(1, 10)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(5, 12), GetThing(2, 9), }); col.Dispose(); }
public void DisposingThrows() { var col = new TrackingCollection<Thing>(Observable.Empty<Thing>()); col.Dispose(); Assert.Throws<ObjectDisposedException>(() => col.SetFilter(null)); Assert.Throws<ObjectDisposedException>(() => col.SetComparer(null)); Assert.Throws<ObjectDisposedException>(() => col.Subscribe()); Assert.Throws<ObjectDisposedException>(() => col.AddItem(GetThing(1))); Assert.Throws<ObjectDisposedException>(() => col.RemoveItem(GetThing(1))); }
public void NoChangingAfterDisposed2() { var col = new TrackingCollection<Thing>(Observable.Never<Thing>(), OrderedComparer<Thing>.OrderByDescending(x => x.UpdatedAt).Compare); col.Dispose(); Assert.Throws<ObjectDisposedException>(() => col.RemoveItem(new Thing())); }
public void Removing() { var source = new Subject<Thing>(); var col = new TrackingCollection<Thing>( source, OrderedComparer<Thing>.OrderBy(x => x.UpdatedAt).Compare, (item, position, list) => (position > 2 && position < 5) || (position > 6 && position < 8)) { ProcessingDelay = TimeSpan.Zero }; var count = 0; var expectedCount = 0; var evt = new ManualResetEvent(false); col.Subscribe(t => { if (++count == expectedCount) evt.Set(); }, () => { }); expectedCount = 11; Add(source, GetThing(0, 0)); Add(source, GetThing(1, 1)); Add(source, GetThing(2, 2)); Add(source, GetThing(3, 3)); Add(source, GetThing(4, 4)); Add(source, GetThing(5, 5)); Add(source, GetThing(6, 6)); Add(source, GetThing(7, 7)); Add(source, GetThing(8, 8)); Add(source, GetThing(9, 9)); Add(source, GetThing(10, 10)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(3, 3), GetThing(4, 4), GetThing(7, 7), }); expectedCount = 12; col.RemoveItem(GetThing(2)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(4, 4), GetThing(5, 5), GetThing(8, 8), }); expectedCount = 13; col.RemoveItem(GetThing(5)); evt.WaitOne(); evt.Reset(); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(4, 4), GetThing(6, 6), GetThing(9, 9), }); col.SetFilter(null); expectedCount = 14; col.RemoveItem(GetThing(100)); // this one won't result in a new element from the observable col.RemoveItem(GetThing(10)); evt.WaitOne(); evt.Reset(); Assert.AreEqual(8, col.Count); CollectionAssert.AreEqual(col, new List<Thing> { GetThing(0, 0), GetThing(1, 1), GetThing(3, 3), GetThing(4, 4), GetThing(6, 6), GetThing(7, 7), GetThing(8, 8), GetThing(9, 9), }); col.Dispose(); }
public ITrackingCollection <IPullRequestModel> GetPullRequests(ISimpleRepositoryModel repo) { // Since the api to list pull requests returns all the data for each pr, cache each pr in its own entry // and also cache an index that contains all the keys for each pr. This way we can fetch prs in bulk // but also individually without duplicating information. We store things in a custom observable collection // that checks whether an item is being updated (coming from the live stream after being retrieved from cache) // and replaces it instead of appending, so items get refreshed in-place as they come in. var keyobs = GetUserFromCache() .Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}|pr", user.Login, repo.Name)); var col = new TrackingCollection <IPullRequestModel>(); var source = Observable.Defer(() => keyobs .SelectMany(key => hostCache.GetAndFetchLatestFromIndex(key, () => apiClient.GetPullRequestsForRepository(repo.CloneUrl.Owner, repo.CloneUrl.RepositoryName) .Select(PullRequestCacheItem.Create), item => col.RemoveItem(Create(item)), TimeSpan.FromMinutes(5), TimeSpan.FromDays(1)) ) .Select(Create) ); col.Listen(source); return(col); }
public void RemovingWithNoObservableSetThrows() { ITrackingCollection<Thing> col = new TrackingCollection<Thing>(); Assert.Throws<InvalidOperationException>(() => col.RemoveItem(new Thing())); }
public void RemovingFirstItemWithFilterWorks() { var source = new Subject<Thing>(); ITrackingCollection<Thing> col = new TrackingCollection<Thing>( Observable.Range(0, 5).Select(x => GetThing(x, x)), OrderedComparer<Thing>.OrderBy(x => x.UpdatedAt).Compare, (item, position, list) => true); col.ProcessingDelay = TimeSpan.Zero; var count = 0; var expectedCount = 5; var evt = new ManualResetEvent(false); col.Subscribe(t => { if (++count == expectedCount) evt.Set(); }, () => { }); Assert.True(evt.WaitOne(40)); evt.Reset(); expectedCount = 6; col.RemoveItem(GetThing(0)); Assert.True(evt.WaitOne(40)); evt.Reset(); CollectionAssert.AreEqual(col, Enumerable.Range(1, 4).Select(x => GetThing(x, x))); col.Dispose(); }
public ITrackingCollection<IPullRequestModel> GetPullRequests(ISimpleRepositoryModel repo) { // Since the api to list pull requests returns all the data for each pr, cache each pr in its own entry // and also cache an index that contains all the keys for each pr. This way we can fetch prs in bulk // but also individually without duplicating information. We store things in a custom observable collection // that checks whether an item is being updated (coming from the live stream after being retrieved from cache) // and replaces it instead of appending, so items get refreshed in-place as they come in. var keyobs = GetUserFromCache() .Select(user => string.Format(CultureInfo.InvariantCulture, "{0}|{1}|pr", user.Login, repo.Name)); var col = new TrackingCollection<IPullRequestModel>(); var source = Observable.Defer(() => keyobs .SelectMany(key => hostCache.GetAndFetchLatestFromIndex(key, () => apiClient.GetPullRequestsForRepository(repo.CloneUrl.Owner, repo.CloneUrl.RepositoryName) .Select(PullRequestCacheItem.Create), item => col.RemoveItem(Create(item)), TimeSpan.FromMinutes(5), TimeSpan.FromDays(1)) ) .Select(Create) ); col.Listen(source); return col; }