|
@@ -3,10 +3,13 @@
|
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
|
|
using System;
|
|
|
+using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Reactive;
|
|
|
+using System.Reactive.Disposables;
|
|
|
using System.Reactive.Linq;
|
|
|
+using System.Reactive.Subjects;
|
|
|
using System.Threading;
|
|
|
using Microsoft.Reactive.Testing;
|
|
|
using ReactiveTests.Dummies;
|
|
@@ -4054,6 +4057,113 @@ namespace ReactiveTests.Tests
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ [Fact]
|
|
|
+ public void ZipWithEnumerable_NoAsyncDisposeOnMoveNext()
|
|
|
+ {
|
|
|
+ var source = new Subject<int>();
|
|
|
+
|
|
|
+ var disposable = new SingleAssignmentDisposable();
|
|
|
+
|
|
|
+ var other = new MoveNextDisposeDetectEnumerable(disposable, true);
|
|
|
+
|
|
|
+ disposable.Disposable = source.Zip(other, (a, b) => a + b).Subscribe();
|
|
|
+
|
|
|
+ source.OnNext(1);
|
|
|
+
|
|
|
+ Assert.True(other.IsDisposed);
|
|
|
+ Assert.False(other.DisposedWhileMoveNext);
|
|
|
+ Assert.False(other.DisposedWhileCurrent);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void ZipWithEnumerable_NoAsyncDisposeOnCurrent()
|
|
|
+ {
|
|
|
+ var source = new Subject<int>();
|
|
|
+
|
|
|
+ var disposable = new SingleAssignmentDisposable();
|
|
|
+
|
|
|
+ var other = new MoveNextDisposeDetectEnumerable(disposable, false);
|
|
|
+
|
|
|
+ disposable.Disposable = source.Zip(other, (a, b) => a + b).Subscribe();
|
|
|
+
|
|
|
+ source.OnNext(1);
|
|
|
+
|
|
|
+ Assert.True(other.IsDisposed);
|
|
|
+ Assert.False(other.DisposedWhileMoveNext);
|
|
|
+ Assert.False(other.DisposedWhileCurrent);
|
|
|
+ }
|
|
|
+
|
|
|
+ private class MoveNextDisposeDetectEnumerable : IEnumerable<int>, IEnumerator<int>
|
|
|
+ {
|
|
|
+ readonly IDisposable _disposable;
|
|
|
+
|
|
|
+ readonly bool _disposeOnMoveNext;
|
|
|
+
|
|
|
+ private bool _moveNextRunning;
|
|
|
+
|
|
|
+ private bool _currentRunning;
|
|
|
+
|
|
|
+ internal bool DisposedWhileMoveNext;
|
|
|
+
|
|
|
+ internal bool DisposedWhileCurrent;
|
|
|
+
|
|
|
+ internal bool IsDisposed;
|
|
|
+
|
|
|
+ internal MoveNextDisposeDetectEnumerable(IDisposable disposable, bool disposeOnMoveNext)
|
|
|
+ {
|
|
|
+ _disposable = disposable;
|
|
|
+ _disposeOnMoveNext = disposeOnMoveNext;
|
|
|
+ }
|
|
|
+ public int Current
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ _currentRunning = true;
|
|
|
+ if (!_disposeOnMoveNext)
|
|
|
+ {
|
|
|
+ _disposable.Dispose();
|
|
|
+ }
|
|
|
+ _currentRunning = false;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ object IEnumerator.Current => Current;
|
|
|
+
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ DisposedWhileMoveNext = _moveNextRunning;
|
|
|
+ DisposedWhileCurrent = _currentRunning;
|
|
|
+ IsDisposed = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public IEnumerator<int> GetEnumerator()
|
|
|
+ {
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool MoveNext()
|
|
|
+ {
|
|
|
+ _moveNextRunning = true;
|
|
|
+ if (_disposeOnMoveNext)
|
|
|
+ {
|
|
|
+ _disposable.Dispose();
|
|
|
+ }
|
|
|
+ _moveNextRunning = false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Reset()
|
|
|
+ {
|
|
|
+ throw new NotSupportedException();
|
|
|
+ }
|
|
|
+
|
|
|
+ IEnumerator IEnumerable.GetEnumerator()
|
|
|
+ {
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private IEnumerable<int> EnumerableNever(ManualResetEvent evt)
|
|
|
{
|
|
|
evt.WaitOne();
|