Skip to content

Commit

Permalink
Bugfix/forbid null items (#706)
Browse files Browse the repository at this point in the history
* Update SDK version in global.json

* Add `where T : notnull` requirement to `Optional<T>`, and fix resultant warnings.
  • Loading branch information
PhilipCavanagh authored Jul 22, 2023
1 parent 9af334c commit a3eccd0
Show file tree
Hide file tree
Showing 201 changed files with 1,098 additions and 361 deletions.
14 changes: 10 additions & 4 deletions src/DynamicData.Tests/Cache/AutoRefreshFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,13 @@ public void AutoRefreshFromObservable()
[Fact]
public void MakeSelectMagicWorkWithObservable()
{
var initialItem = new IntHolder { Value = 1, Description = "Initial Description" };
var initialItem = new IntHolder(1, "Initial Description");

var sourceList = new SourceList<IntHolder>();
sourceList.Add(initialItem);

var descriptionStream = sourceList.Connect().AutoRefresh(intHolder => intHolder!.Description).Transform(intHolder => intHolder!.Description, true).Do(x => { }) // <--- Add break point here to check the overload fixes it
.Bind(out ReadOnlyObservableCollection<string?> resultCollection);
.Bind(out ReadOnlyObservableCollection<string> resultCollection);

using (descriptionStream.Subscribe())
{
Expand All @@ -109,11 +109,17 @@ public void MakeSelectMagicWorkWithObservable()

public class IntHolder : AbstractNotifyPropertyChanged
{
public string? _description_;
public string _description_;

public int _value;

public string? Description
public IntHolder(int value, string description)
{
_value = value;
_description_ = description;
}

public string Description
{
get => _description_;
set => SetAndRaise(ref _description_, value);
Expand Down
1 change: 1 addition & 0 deletions src/DynamicData.Tests/Cache/ObservableChangeSetFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ public void LoadsAndDisposeUsingDisposableAsync()

private void SubscribeAndAssert<TObject, TKey>(IObservable<IChangeSet<TObject, TKey>> observableChangeset, bool expectsError = false, Action<IObservableCache<TObject, TKey>>? checkContentAction = null)
where TKey : notnull
where TObject : notnull
{
Exception? error = null;
bool complete = false;
Expand Down
12 changes: 0 additions & 12 deletions src/DynamicData.Tests/Cache/TransformFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,6 @@ public void SameKeyChanges()
onlyItemInCache.Should().Be(lastTransformed, "Incorrect transform result");
}

[Fact]
public void TransformToNull()
{
using var source = new SourceCache<Person, string>(p => p.Name);
using var results = new ChangeSetAggregator<PersonWithGender?, string>(source.Connect().Transform((Func<Person, PersonWithGender?>)(p => null)));
source.AddOrUpdate(new Person("Adult1", 50));

results.Messages.Count.Should().Be(1, "Should be 1 updates");
results.Data.Count.Should().Be(1, "Should be 1 item in the cache");
results.Data.Items.First().Should().Be(null, "Should be same person");
}

[Fact]
public void Update()
{
Expand Down
13 changes: 0 additions & 13 deletions src/DynamicData.Tests/Cache/TransformFixtureParallel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,6 @@ public void SameKeyChanges()
onlyItemInCache.Should().Be(lastTransformed, "Incorrect transform result");
}

[Fact]
public void TransformToNull()
{
using var source = new SourceCache<Person, string>(p => p.Name);
using var results = new ChangeSetAggregator<PersonWithGender?, string>(source.Connect()
.Transform((Func<Person, PersonWithGender?>)(p => null), new ParallelisationOptions(ParallelType.Parallelise)));
source.AddOrUpdate(new Person("Adult1", 50));

results.Messages.Count.Should().Be(1, "Should be 1 updates");
results.Data.Count.Should().Be(1, "Should be 1 item in the cache");
results.Data.Items.First().Should().Be(null, "Should be same person");
}

[Fact]
public void Update()
{
Expand Down
1 change: 1 addition & 0 deletions src/DynamicData.Tests/List/CreationFixtures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public void Create()
}

private void SubscribeAndAssert<T>(IObservable<IChangeSet<T>> observableChangeset, bool expectsError = false)
where T : notnull
{
Exception? error = null;
bool complete = false;
Expand Down
2 changes: 1 addition & 1 deletion src/DynamicData.Tests/List/SortFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public ListItem(int number)
Number = number;
}

public int CompareTo([AllowNull] ListItem other) => DefaultComparer.Compare(this, other);
public int CompareTo(ListItem? other) => DefaultComparer.Compare(this, other);

}
}
Expand Down
13 changes: 0 additions & 13 deletions src/DynamicData.Tests/List/TransformFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,19 +117,6 @@ public void SameKeyChanges()
_results.Data.Count.Should().Be(10, "Should result in 10 records");
}

[Fact]
public void TransformToNull()
{
using var source = new SourceList<Person>();
using var results = new ChangeSetAggregator<PersonWithGender?>(source.Connect()
.Transform((Func<Person, PersonWithGender?>)(p => null)));
source.Add(new Person("Adult1", 50));

results.Messages.Count.Should().Be(1, "Should be 1 updates");
results.Data.Count.Should().Be(1, "Should be 1 item in the cache");
results.Data.Items.First().Should().Be(null, "Should be same person");
}

[Fact]
public void Update()
{
Expand Down
2 changes: 2 additions & 0 deletions src/DynamicData/Aggregation/AggregateEnumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace DynamicData.Aggregation;

internal class AggregateEnumerator<T> : IAggregateChangeSet<T>
where T : notnull
{
private readonly IChangeSet<T> _source;

Expand Down Expand Up @@ -64,6 +65,7 @@ IEnumerator IEnumerable.GetEnumerator()

[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "Same name, different generics.")]
internal class AggregateEnumerator<TObject, TKey> : IAggregateChangeSet<TObject>
where TObject : notnull
where TKey : notnull
{
private readonly IChangeSet<TObject, TKey> _source;
Expand Down
4 changes: 4 additions & 0 deletions src/DynamicData/Aggregation/AggregationEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static class AggregationEx
/// <param name="source">The source.</param>
/// <returns>The aggregated change set.</returns>
public static IObservable<IAggregateChangeSet<TObject>> ForAggregation<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source)
where TObject : notnull
where TKey : notnull
{
if (source is null)
Expand All @@ -39,6 +40,7 @@ public static IObservable<IAggregateChangeSet<TObject>> ForAggregation<TObject,
/// <param name="source">The source.</param>
/// <returns>The aggregated change set.</returns>
public static IObservable<IAggregateChangeSet<TObject>> ForAggregation<TObject>(this IObservable<IChangeSet<TObject>> source)
where TObject : notnull
{
if (source is null)
{
Expand Down Expand Up @@ -87,6 +89,7 @@ public static IObservable<T> InvalidateWhen<T, TTrigger>(this IObservable<T> sou
/// <param name="removeAction">The remove action.</param>
/// <returns>An observable with the accumulated value.</returns>
internal static IObservable<TResult> Accumulate<TObject, TResult>(this IObservable<IChangeSet<TObject>> source, TResult seed, Func<TObject, TResult> accessor, Func<TResult, TResult, TResult> addAction, Func<TResult, TResult, TResult> removeAction)
where TObject : notnull
{
return source.ForAggregation().Accumulate(seed, accessor, addAction, removeAction);
}
Expand All @@ -105,6 +108,7 @@ internal static IObservable<TResult> Accumulate<TObject, TResult>(this IObservab
/// <param name="removeAction">The remove action.</param>
/// <returns>An observable with the accumulated value.</returns>
internal static IObservable<TResult> Accumulate<TObject, TKey, TResult>(this IObservable<IChangeSet<TObject, TKey>> source, TResult seed, Func<TObject, TResult> accessor, Func<TResult, TResult, TResult> addAction, Func<TResult, TResult, TResult> removeAction)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Accumulate(seed, accessor, addAction, removeAction);
Expand Down
20 changes: 20 additions & 0 deletions src/DynamicData/Aggregation/AvgEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public static class AvgEx
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, int> valueSelector, int emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -42,6 +43,7 @@ public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, int?> valueSelector, int emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -59,6 +61,7 @@ public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, long> valueSelector, long emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -76,6 +79,7 @@ public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, long?> valueSelector, long emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -93,6 +97,7 @@ public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, double> valueSelector, double emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -110,6 +115,7 @@ public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, double?> valueSelector, double emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -127,6 +133,7 @@ public static IObservable<double> Avg<TObject, TKey>(this IObservable<IChangeSet
/// An observable of averages.
/// </returns>
public static IObservable<decimal> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, decimal> valueSelector, decimal emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -144,6 +151,7 @@ public static IObservable<decimal> Avg<TObject, TKey>(this IObservable<IChangeSe
/// An observable of averages.
/// </returns>
public static IObservable<decimal> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, decimal?> valueSelector, decimal emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -161,6 +169,7 @@ public static IObservable<decimal> Avg<TObject, TKey>(this IObservable<IChangeSe
/// An observable of averages.
/// </returns>
public static IObservable<float> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, float> valueSelector, float emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -178,6 +187,7 @@ public static IObservable<float> Avg<TObject, TKey>(this IObservable<IChangeSet<
/// An observable of averages.
/// </returns>
public static IObservable<float> Avg<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source, Func<TObject, float?> valueSelector, float emptyValue = 0)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
Expand All @@ -194,6 +204,7 @@ public static IObservable<float> Avg<TObject, TKey>(this IObservable<IChangeSet<
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, int> valueSelector, int emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand All @@ -209,6 +220,7 @@ public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source,
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, int?> valueSelector, int emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand All @@ -224,6 +236,7 @@ public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source,
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, long> valueSelector, long emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand All @@ -239,6 +252,7 @@ public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source,
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, long?> valueSelector, long emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand All @@ -254,6 +268,7 @@ public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source,
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, double> valueSelector, double emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand All @@ -269,6 +284,7 @@ public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source,
/// An observable of averages.
/// </returns>
public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, double?> valueSelector, double emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand All @@ -284,6 +300,7 @@ public static IObservable<double> Avg<T>(this IObservable<IChangeSet<T>> source,
/// An observable of averages.
/// </returns>
public static IObservable<decimal> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, decimal> valueSelector, decimal emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand All @@ -299,6 +316,7 @@ public static IObservable<decimal> Avg<T>(this IObservable<IChangeSet<T>> source
/// An observable of averages.
/// </returns>
public static IObservable<decimal> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, decimal?> valueSelector, decimal emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand All @@ -314,6 +332,7 @@ public static IObservable<decimal> Avg<T>(this IObservable<IChangeSet<T>> source
/// An observable of averages.
/// </returns>
public static IObservable<float> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, float> valueSelector, float emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand All @@ -329,6 +348,7 @@ public static IObservable<float> Avg<T>(this IObservable<IChangeSet<T>> source,
/// An observable of averages.
/// </returns>
public static IObservable<float> Avg<T>(this IObservable<IChangeSet<T>> source, Func<T, float?> valueSelector, float emptyValue = 0)
where T : notnull
{
return source.ForAggregation().Avg(valueSelector, emptyValue);
}
Expand Down
6 changes: 6 additions & 0 deletions src/DynamicData/Aggregation/CountEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public static class CountEx
/// <param name="source">The source.</param>
/// <returns>An observable which emits the count.</returns>
public static IObservable<int> Count<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Count();
Expand All @@ -32,6 +33,7 @@ public static IObservable<int> Count<TObject, TKey>(this IObservable<IChangeSet<
/// <param name="source">The source.</param>
/// <returns>An observable which emits the count.</returns>
public static IObservable<int> Count<TObject>(this IObservable<IChangeSet<TObject>> source)
where TObject : notnull
{
return source.ForAggregation().Count();
}
Expand Down Expand Up @@ -68,6 +70,7 @@ public static IObservable<int> Count<TObject>(this IObservable<IDistinctChangeSe
/// <param name="source">The source.</param>
/// <returns>An observable which emits the count.</returns>
public static IObservable<bool> IsEmpty<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Count().StartWith(0).Select(count => count == 0);
Expand All @@ -81,6 +84,7 @@ public static IObservable<bool> IsEmpty<TObject, TKey>(this IObservable<IChangeS
/// <param name="source">The source.</param>
/// <returns>An observable which emits the count.</returns>
public static IObservable<bool> IsEmpty<TObject>(this IObservable<IChangeSet<TObject>> source)
where TObject : notnull
{
return source.ForAggregation().Count().StartWith(0).Select(count => count == 0);
}
Expand All @@ -94,6 +98,7 @@ public static IObservable<bool> IsEmpty<TObject>(this IObservable<IChangeSet<TOb
/// <param name="source">The source.</param>
/// <returns>An observable which emits the count.</returns>
public static IObservable<bool> IsNotEmpty<TObject, TKey>(this IObservable<IChangeSet<TObject, TKey>> source)
where TObject : notnull
where TKey : notnull
{
return source.ForAggregation().Count().StartWith(0).Select(count => count > 0);
Expand All @@ -107,6 +112,7 @@ public static IObservable<bool> IsNotEmpty<TObject, TKey>(this IObservable<IChan
/// <param name="source">The source.</param>
/// <returns>An observable which emits the count.</returns>
public static IObservable<bool> IsNotEmpty<TObject>(this IObservable<IChangeSet<TObject>> source)
where TObject : notnull
{
return source.ForAggregation().Count().StartWith(0).Select(count => count > 0);
}
Expand Down
Loading

0 comments on commit a3eccd0

Please sign in to comment.