| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 | // Licensed to the .NET Foundation under one or more agreements.// The .NET Foundation licenses this file to you under the MIT License.// See the LICENSE file in the project root for more information. using System;using System.Collections.Generic;using System.Linq;using System.Reactive.Concurrency;using System.Reactive.Linq;using System.Threading;using Microsoft.Reactive.Testing;using Microsoft.VisualStudio.TestTools.UnitTesting;using Assert = Xunit.Assert;namespace ReactiveTests.Tests{    [TestClass]    public class FromEventTest : ReactiveTest    {        [TestMethod]        public void FromEvent_ArgumentChecking()        {            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(default, h => { }, h => { }));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, default, h => { }));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, h => { }, default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(default, h => { }));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => { }, default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(default, h => { }));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(h => { }, default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(default, h => { }));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(h => { }, default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(default, h => { }, h => { }, Scheduler.Default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, default, h => { }, Scheduler.Default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, h => { }, default, Scheduler.Default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => h, h => { }, h => { }, default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(default, h => { }, Scheduler.Default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => { }, default, Scheduler.Default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<Action<int>, int>(h => { }, h => { }, default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(default, h => { }, Scheduler.Default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(h => { }, default, Scheduler.Default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent<int>(h => { }, h => { }, default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(default, h => { }, Scheduler.Default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(h => { }, default, Scheduler.Default));            ReactiveAssert.Throws<ArgumentNullException>(() => Observable.FromEvent(h => { }, h => { }, default));        }        [TestMethod]        public void FromEvent_Action()        {            var fe = new FromEvent();            var xs = Observable.FromEvent(h => fe.A += h, h => fe.A -= h);            fe.OnA();            var n = 0;            var d = xs.Subscribe(_ => n++);            fe.OnA();            fe.OnA();            d.Dispose();            fe.OnA();            Assert.Equal(2, n);        }        [TestMethod]        public void FromEvent_ActionOfInt()        {            var fe = new FromEvent();            var xs = Observable.FromEvent<int>(h => fe.B += h, h => fe.B -= h);            fe.OnB(1);            var n = 0;            var d = xs.Subscribe(x => n += x);            fe.OnB(2);            fe.OnB(3);            d.Dispose();            fe.OnB(4);            Assert.Equal(2 + 3, n);        }        [TestMethod]        public void FromEvent_ActionOfInt_SpecifiedExplicitly()        {            var fe = new FromEvent();            var xs = Observable.FromEvent<Action<int>, int>(h => fe.B += h, h => fe.B -= h);            fe.OnB(1);            var n = 0;            var d = xs.Subscribe(x => n += x);            fe.OnB(2);            fe.OnB(3);            d.Dispose();            fe.OnB(4);            Assert.Equal(2 + 3, n);        }        [TestMethod]        public void FromEvent_ActionOfInt_SpecifiedExplicitly_TrivialConversion()        {            var fe = new FromEvent();            var xs = Observable.FromEvent<Action<int>, int>(h => h, h => fe.B += h, h => fe.B -= h);            fe.OnB(1);            var n = 0;            var d = xs.Subscribe(x => n += x);            fe.OnB(2);            fe.OnB(3);            d.Dispose();            fe.OnB(4);            Assert.Equal(2 + 3, n);        }        [TestMethod]        public void FromEvent_MyAction()        {            var fe = new FromEvent();            var xs = Observable.FromEvent<MyAction, int>(h => new MyAction(h), h => fe.C += h, h => fe.C -= h);            fe.OnC(1);            var n = 0;            var d = xs.Subscribe(x => n += x);            fe.OnC(2);            fe.OnC(3);            d.Dispose();            fe.OnC(4);            Assert.Equal(2 + 3, n);        }        #region Rx v2.0 behavior        [TestMethod]        public void FromEvent_ImplicitPublish()        {            var src = new MyEventSource();            var addCount = 0;            var remCount = 0;            var xs = Observable.FromEventPattern<MyEventArgs>(h => { addCount++; src.Bar += h; }, h => { src.Bar -= h; remCount++; }, Scheduler.Immediate);            Assert.Equal(0, addCount);            Assert.Equal(0, remCount);            src.OnBar(41);            var fst = new List<int>();            var d1 = xs.Subscribe(e => fst.Add(e.EventArgs.Value));            Assert.Equal(1, addCount);            Assert.Equal(0, remCount);            src.OnBar(42);            Assert.True(fst.SequenceEqual([42]));            d1.Dispose();            Assert.Equal(1, addCount);            Assert.Equal(1, remCount);            var snd = new List<int>();            var d2 = xs.Subscribe(e => snd.Add(e.EventArgs.Value));            Assert.Equal(2, addCount);            Assert.Equal(1, remCount);            src.OnBar(43);            Assert.True(fst.SequenceEqual([42]));            Assert.True(snd.SequenceEqual([43]));            var thd = new List<int>();            var d3 = xs.Subscribe(e => thd.Add(e.EventArgs.Value));            Assert.Equal(2, addCount);            Assert.Equal(1, remCount);            src.OnBar(44);            Assert.True(fst.SequenceEqual([42]));            Assert.True(snd.SequenceEqual([43, 44]));            Assert.True(thd.SequenceEqual([44]));            d2.Dispose();            Assert.Equal(2, addCount);            Assert.Equal(1, remCount);            src.OnBar(45);            Assert.True(fst.SequenceEqual([42]));            Assert.True(snd.SequenceEqual([43, 44]));            Assert.True(thd.SequenceEqual([44, 45]));            d3.Dispose();            Assert.Equal(2, addCount);            Assert.Equal(2, remCount);            src.OnBar(46);            Assert.True(fst.SequenceEqual([42]));            Assert.True(snd.SequenceEqual([43, 44]));            Assert.True(thd.SequenceEqual([44, 45]));        }        [TestMethod]        public void FromEvent_SynchronizationContext()        {            var beforeSubscribeNull = false;            var afterSubscribeNull = false;            var subscribeOnCtx = false;            var fstNext = false;            var sndNext = false;            var thdNext = false;            var beforeDisposeNull = false;            var afterDisposeNull = false;            var disposeOnCtx = false;            RunWithContext(new MyEventSyncCtx(), ctx =>            {                var src = new MyEventSource();                var addCtx = default(SynchronizationContext);                var remCtx = default(SynchronizationContext);                var addEvt = new ManualResetEvent(false);                var remEvt = new ManualResetEvent(false);                var xs = Observable.FromEventPattern<MyEventArgs>(h => { addCtx = SynchronizationContext.Current; src.Bar += h; addEvt.Set(); }, h => { remCtx = SynchronizationContext.Current; src.Bar -= h; remEvt.Set(); });                Assert.Null(addCtx);                Assert.Null(remCtx);                var d = default(IDisposable);                var res = new List<int>();                var s = new Thread(() =>                {                    beforeSubscribeNull = SynchronizationContext.Current is null;                    d = xs.Subscribe(e => res.Add(e.EventArgs.Value));                    afterSubscribeNull = SynchronizationContext.Current is null;                });                s.Start();                s.Join();                addEvt.WaitOne();                subscribeOnCtx = ReferenceEquals(addCtx, ctx);                src.OnBar(42);                fstNext = res.SequenceEqual([42]);                src.OnBar(43);                sndNext = res.SequenceEqual([42, 43]);                var u = new Thread(() =>                {                    beforeDisposeNull = SynchronizationContext.Current is null;                    d.Dispose();                    afterDisposeNull = SynchronizationContext.Current is null;                });                u.Start();                u.Join();                remEvt.WaitOne();                disposeOnCtx = ReferenceEquals(remCtx, ctx);                src.OnBar(44);                thdNext = res.SequenceEqual([42, 43]);            });            Assert.True(beforeSubscribeNull);            Assert.True(subscribeOnCtx);            Assert.True(afterSubscribeNull);            Assert.True(fstNext);            Assert.True(sndNext);            Assert.True(thdNext);            Assert.True(beforeDisposeNull);            Assert.True(disposeOnCtx);            Assert.True(afterDisposeNull);        }        private void RunWithContext<T>(T ctx, Action<T> run)            where T : SynchronizationContext        {            var t = new Thread(() =>            {                SynchronizationContext.SetSynchronizationContext(ctx);                run(ctx);            });            t.Start();            t.Join();        }        [TestMethod]        public void FromEvent_Scheduler1()        {            RunWithScheduler((s, add, remove) => Observable.FromEvent<MyEventArgs>(h => { add(); }, h => { remove(); }, s));        }        [TestMethod]        public void FromEvent_Scheduler2()        {            RunWithScheduler((s, add, remove) => Observable.FromEvent(h => { add(); }, h => { remove(); }, s));        }        [TestMethod]        public void FromEvent_Scheduler3()        {            RunWithScheduler((s, add, remove) => Observable.FromEvent<Action<MyEventArgs>, MyEventArgs>(h => { add(); }, h => { remove(); }, s));        }        [TestMethod]        public void FromEvent_Scheduler4()        {            RunWithScheduler((s, add, remove) => Observable.FromEvent<Action, MyEventArgs>(h => () => { }, h => { add(); }, h => { remove(); }, s));        }        private void RunWithScheduler<T>(Func<IScheduler, Action, Action, IObservable<T>> run)        {            var n = 0;            var a = 0;            var r = 0;            var s = new MyEventScheduler(() => n++);            var add = new Action(() => a++);            var rem = new Action(() => r++);            var xs = run(s, add, rem);            Assert.Equal(0, n);            Assert.Equal(0, a);            Assert.Equal(0, r);            var d1 = xs.Subscribe();            Assert.Equal(1, n);            Assert.Equal(1, a);            Assert.Equal(0, r);            var d2 = xs.Subscribe();            Assert.Equal(1, n);            Assert.Equal(1, a);            Assert.Equal(0, r);            d1.Dispose();            Assert.Equal(1, n);            Assert.Equal(1, a);            Assert.Equal(0, r);            d2.Dispose();            Assert.Equal(2, n);            Assert.Equal(1, a);            Assert.Equal(1, r);        }        #endregion    }}
 |