Skip to content

Commit 2c32489

Browse files
dwcullopRolandPheasant
andauthoredSep 4, 2024··
Fix for GroupOnObservable OnCompleted handling (#938)
* GroupOnObservable Fix (and Unit Tests) * Remove extra tests --------- Co-authored-by: Roland Pheasant <roland_pheasant@hotmail.com>
1 parent 55002ae commit 2c32489

File tree

2 files changed

+23
-10
lines changed

2 files changed

+23
-10
lines changed
 

‎src/DynamicData.Tests/Cache/GroupOnObservableFixture.cs

+19-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Linq;
3+
using System.Reactive;
34
using System.Reactive.Linq;
5+
using System.Reactive.Subjects;
46
using System.Threading.Tasks;
57

68
using Bogus;
@@ -30,12 +32,14 @@ public class GroupOnObservableFixture : IDisposable
3032
private readonly SourceCache<Person, string> _cache = new (p => p.UniqueKey);
3133
private readonly ChangeSetAggregator<Person, string> _results;
3234
private readonly GroupChangeSetAggregator<Person, string, Color> _groupResults;
35+
private readonly Subject<Unit> _grouperShutdown;
3336
private readonly Faker<Person> _faker;
3437
private readonly Randomizer _randomizer = new(0x3141_5926);
3538

3639
public GroupOnObservableFixture()
3740
{
3841
_faker = Fakers.Person.Clone().WithSeed(_randomizer);
42+
_grouperShutdown = new();
3943
_results = _cache.Connect().AsAggregator();
4044
_groupResults = _cache.Connect().GroupOnObservable(CreateFavoriteColorObservable).AsAggregator();
4145
}
@@ -179,7 +183,7 @@ public void GroupingSequenceCompletesWhenEmpty()
179183
}
180184

181185
[Fact]
182-
public void AllSequencesCompleteWhenSourceIsDisposed()
186+
public void AllSequencesShouldCompleteWhenSourceAndGroupingObservablesComplete()
183187
{
184188
// Arrange
185189
_cache.AddOrUpdate(_faker.Generate(InitialCount));
@@ -190,6 +194,7 @@ public void AllSequencesCompleteWhenSourceIsDisposed()
190194

191195
// Act
192196
_cache.Dispose();
197+
_grouperShutdown.OnNext(Unit.Default);
193198

194199
// Assert
195200
results.IsCompleted.Should().BeTrue();
@@ -243,9 +248,11 @@ public async Task ResultsContainsCorrectRegroupedValuesAsync()
243248
}
244249

245250
[Theory]
246-
[InlineData(false)]
247-
[InlineData(true)]
248-
public void ResultCompletesOnlyWhenSourceCompletes(bool completeSource)
251+
[InlineData(false, false)]
252+
[InlineData(true, false)]
253+
[InlineData(false, true)]
254+
[InlineData(true, true)]
255+
public void ResultCompletesOnlyWhenSourceAndAllGroupingObservablesComplete(bool completeSource, bool completeGroups)
249256
{
250257
// Arrange
251258
_cache.AddOrUpdate(_faker.Generate(InitialCount));
@@ -255,10 +262,14 @@ public void ResultCompletesOnlyWhenSourceCompletes(bool completeSource)
255262
{
256263
_cache.Dispose();
257264
}
265+
if (completeGroups)
266+
{
267+
_grouperShutdown.OnNext(Unit.Default);
268+
}
258269

259270
// Assert
260271
_results.IsCompleted.Should().Be(completeSource);
261-
_groupResults.IsCompleted.Should().Be(completeSource);
272+
_groupResults.IsCompleted.Should().Be(completeGroups && completeSource);
262273
}
263274

264275
[Fact]
@@ -311,6 +322,7 @@ public void Dispose()
311322
_groupResults.Dispose();
312323
_results.Dispose();
313324
_cache.Dispose();
325+
_grouperShutdown.Dispose();
314326
}
315327

316328
private void RandomFavoriteColorChange()
@@ -342,6 +354,6 @@ private static void VerifyGroupingResults(ISourceCache<Person, string> cache, Ch
342354
groupResults.Groups.Items.ForEach(group => group.Data.Count.Should().BeGreaterThan(0, "Empty groups should be removed"));
343355
}
344356

345-
private static IObservable<Color> CreateFavoriteColorObservable(Person person, string key) =>
346-
person.WhenPropertyChanged(p => p.FavoriteColor).Select(change => change.Value);
357+
private IObservable<Color> CreateFavoriteColorObservable(Person person, string key) =>
358+
person.WhenPropertyChanged(p => p.FavoriteColor).Select(change => change.Value).TakeUntil(_grouperShutdown);
347359
}

‎src/DynamicData/Cache/Internal/GroupOnObservable.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ IObservable<TGroupKey> CreateGroupObservable(TObject item, TKey key) =>
4242
// Next process the Grouping observables created for each item
4343
var subMergeMany = shared
4444
.MergeMany(CreateGroupObservable)
45-
.SubscribeSafe(onError: observer.OnError);
45+
.SubscribeSafe(
46+
onError: observer.OnError,
47+
onCompleted: observer.OnCompleted);
4648

4749
// Finally, emit the results
4850
var subResults = shared
@@ -52,8 +54,7 @@ IObservable<TGroupKey> CreateGroupObservable(TObject item, TKey key) =>
5254
grouper.EmitChanges(observer);
5355
parentUpdate = false;
5456
},
55-
onError: observer.OnError,
56-
onCompleted: observer.OnCompleted);
57+
onError: observer.OnError);
5758

5859
return new CompositeDisposable(shared.Connect(), subMergeMany, subChanges, grouper);
5960
});

0 commit comments

Comments
 (0)
Please sign in to comment.