-
-
Notifications
You must be signed in to change notification settings - Fork 182
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented a variety of utilities for testing the core correctness o…
…f RX operators and streams, including notification sequencing and synchronization. (#797)
- Loading branch information
1 parent
d8c3ac6
commit ff8b94a
Showing
6 changed files
with
221 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System; | ||
|
||
namespace DynamicData.Tests.Utilities; | ||
|
||
internal static class RawAnonymousObservable | ||
{ | ||
public static RawAnonymousObservable<T> Create<T>(Func<IObserver<T>, IDisposable> onSubscribe) | ||
=> new(onSubscribe); | ||
} | ||
|
||
// Allows bypassing of safeguards implemented within Observable.Create<T>(), for testing. | ||
internal class RawAnonymousObservable<T> | ||
: IObservable<T> | ||
{ | ||
private readonly Func<IObserver<T>, IDisposable> _onSubscribe; | ||
|
||
public RawAnonymousObservable(Func<IObserver<T>, IDisposable> onSubscribe) | ||
=> _onSubscribe = onSubscribe; | ||
|
||
public IDisposable Subscribe(IObserver<T> observer) | ||
=> _onSubscribe.Invoke(observer); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using System; | ||
|
||
namespace DynamicData.Tests.Utilities; | ||
|
||
internal static class RawAnonymousObserver | ||
{ | ||
public static RawAnonymousObserver<T> Create<T>( | ||
Action<T> onNext, | ||
Action<Exception> onError, | ||
Action onCompleted) | ||
=> new( | ||
onNext: onNext, | ||
onError: onError, | ||
onCompleted: onCompleted); | ||
} | ||
|
||
// Allows bypassing of safeguards implemented within Observer.Create<T>(), for testing. | ||
internal class RawAnonymousObserver<T> | ||
: IObserver<T> | ||
{ | ||
private readonly Action _onCompleted; | ||
private readonly Action<Exception> _onError; | ||
private readonly Action<T> _onNext; | ||
|
||
public RawAnonymousObserver( | ||
Action<T> onNext, | ||
Action<Exception> onError, | ||
Action onCompleted) | ||
{ | ||
_onNext = onNext; | ||
_onError = onError; | ||
_onCompleted = onCompleted; | ||
} | ||
|
||
public void OnCompleted() | ||
=> _onCompleted.Invoke(); | ||
|
||
public void OnError(Exception error) | ||
=> _onError.Invoke(error); | ||
|
||
public void OnNext(T value) | ||
=> _onNext.Invoke(value); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Reactive; | ||
using System.Reactive.Concurrency; | ||
|
||
using Microsoft.Reactive.Testing; | ||
|
||
namespace DynamicData.Tests.Utilities; | ||
|
||
public static class TestableObserver | ||
{ | ||
public static TestableObserver<T> Create<T>(IScheduler? scheduler = null) | ||
=> new(scheduler ?? DefaultScheduler.Instance); | ||
} | ||
|
||
// Not using any existing Observer class, or Observer.Create<T>() to bypass normal RX safeguards, which prevent out-of-sequence notifications. | ||
public sealed class TestableObserver<T> | ||
: ITestableObserver<T> | ||
{ | ||
private readonly List<Recorded<Notification<T>>> _messages; | ||
private readonly IScheduler _scheduler; | ||
|
||
public TestableObserver(IScheduler scheduler) | ||
{ | ||
_messages = new(); | ||
_scheduler = scheduler; | ||
} | ||
|
||
public IList<Recorded<Notification<T>>> Messages | ||
=> _messages; | ||
|
||
void IObserver<T>.OnCompleted() | ||
=> _messages.Add(new( | ||
time: _scheduler.Now.Ticks, | ||
value: Notification.CreateOnCompleted<T>())); | ||
|
||
void IObserver<T>.OnError(Exception error) | ||
=> _messages.Add(new( | ||
time: _scheduler.Now.Ticks, | ||
value: Notification.CreateOnError<T>(error))); | ||
|
||
void IObserver<T>.OnNext(T value) | ||
=> _messages.Add(new( | ||
time: _scheduler.Now.Ticks, | ||
value: Notification.CreateOnNext(value))); | ||
} |
34 changes: 34 additions & 0 deletions
34
src/DynamicData.Tests/Utilities/TestableObserverExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reactive; | ||
|
||
using FluentAssertions; | ||
|
||
using Microsoft.Reactive.Testing; | ||
|
||
namespace DynamicData.Tests.Utilities; | ||
|
||
internal static class TestableObserverExtensions | ||
{ | ||
public static IEnumerable<Recorded<Notification<T>>> EnumerateInvalidNotifications<T>(this ITestableObserver<T> observer) | ||
=> observer.Messages | ||
.SkipWhile(message => message.Value.Kind is NotificationKind.OnNext) | ||
.Skip(1); | ||
|
||
public static IEnumerable<T> EnumerateRecordedValues<T>(this ITestableObserver<T> observer) | ||
=> observer.Messages | ||
.TakeWhile(message => message.Value.Kind is NotificationKind.OnNext) | ||
.Select(message => message.Value.Value); | ||
|
||
public static Exception? TryGetRecordedError<T>(this ITestableObserver<T> observer) | ||
=> observer.Messages | ||
.Where(message => message.Value.Kind is NotificationKind.OnError) | ||
.Select(message => message.Value.Exception) | ||
.FirstOrDefault(); | ||
|
||
public static bool TryGetRecordedCompletion<T>(this ITestableObserver<T> observer) | ||
=> observer.Messages | ||
.Where(message => message.Value.Kind is NotificationKind.OnCompleted) | ||
.Any(); | ||
} |
16 changes: 16 additions & 0 deletions
16
src/DynamicData.Tests/Utilities/UnsynchronizedNotificationException.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System; | ||
using System.Reactive; | ||
|
||
namespace DynamicData.Tests.Utilities; | ||
|
||
public class UnsynchronizedNotificationException<T> | ||
: Exception | ||
{ | ||
public UnsynchronizedNotificationException() | ||
: base("Unsynchronized notification received: Another notification is already being processed") | ||
{ } | ||
|
||
public required Notification<T> IncomingNotification { get; init; } | ||
|
||
public required Notification<T> PriorNotification { get; init; } | ||
} |