summaryrefslogtreecommitdiff
path: root/external/rx/Rx/NET/Source/Microsoft.Reactive.Testing/ReactiveTest.cs
blob: 45d8424647342f1f2a1a50f73644cafeba0e0eaa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

using System;
using System.Reactive;

namespace Microsoft.Reactive.Testing
{
    /// <summary>
    /// Base class to write unit tests for applications and libraries built using Reactive Extensions.
    /// </summary>
    public class ReactiveTest
    {
        /// <summary>
        /// Default virtual time used for creation of observable sequences in <see cref="ReactiveTest"/>-based unit tests.
        /// </summary>
        public const long Created = 100;
        
        /// <summary>
        /// Default virtual time used to subscribe to observable sequences in <see cref="ReactiveTest"/>-based unit tests.
        /// </summary>
        public const long Subscribed = 200;

        /// <summary>
        /// Default virtual time used to dispose subscriptions in <see cref="ReactiveTest"/>-based unit tests.
        /// </summary>
        public const long Disposed = 1000;

        /// <summary>
        /// Factory method for an OnNext notification record at a given time with a given value.
        /// </summary>
        /// <typeparam name="T">The element type for the resulting notification object.</typeparam>
        /// <param name="ticks">Recorded virtual time the OnNext notification occurs.</param>
        /// <param name="value">Recorded value stored in the OnNext notification.</param>
        /// <returns>Recorded OnNext notification.</returns>
        public static Recorded<Notification<T>> OnNext<T>(long ticks, T value)
        {
            return new Recorded<Notification<T>>(ticks, Notification.CreateOnNext<T>(value));
        }

        /// <summary>
        /// Factory method for writing an assert that checks for an OnNext notification record at a given time, using the specified predicate to check the value.
        /// </summary>
        /// <typeparam name="T">The element type for the resulting notification object.</typeparam>
        /// <param name="ticks">Recorded virtual time the OnNext notification occurs.</param>
        /// <param name="predicate">Predicate function to check the OnNext notification value against an expected value.</param>
        /// <returns>Recorded OnNext notification with a predicate to assert a given value.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="predicate"/> is null.</exception>
        public static Recorded<Notification<T>> OnNext<T>(long ticks, Func<T, bool> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException("predicate");

            return new Recorded<Notification<T>>(ticks, new OnNextPredicate<T>(predicate));
        }

        /// <summary>
        /// Factory method for an OnCompleted notification record at a given time.
        /// </summary>
        /// <typeparam name="T">The element type for the resulting notification object.</typeparam>
        /// <param name="ticks">Recorded virtual time the OnCompleted notification occurs.</param>
        /// <returns>Recorded OnCompleted notification.</returns>
        public static Recorded<Notification<T>> OnCompleted<T>(long ticks)
        {
            return new Recorded<Notification<T>>(ticks, Notification.CreateOnCompleted<T>());
        }

        /// <summary>
        /// Factory method for an OnCompleted notification record at a given time, using inference to determine the type of <typeparamref name="T"/>.
        /// </summary>
        /// <typeparam name="T">The element type for the resulting notification object.</typeparam>
        /// <param name="ticks">Recorded virtual time the OnCompleted notification occurs.</param>
        /// <param name="witness">Object solely used to infer the type of the <typeparamref name="T"/> type parameter. This parameter is typically used when creating a sequence of anonymously typed elements.</param>
        /// <returns>Recorded OnCompleted notification.</returns>
        public static Recorded<Notification<T>> OnCompleted<T>(long ticks, T witness)
        {
            return new Recorded<Notification<T>>(ticks, Notification.CreateOnCompleted<T>());
        }

        /// <summary>
        /// Factory method for an OnError notification record at a given time with a given error.
        /// </summary>
        /// <typeparam name="T">The element type for the resulting notification object.</typeparam>
        /// <param name="ticks">Recorded virtual time the OnError notification occurs.</param>
        /// <param name="exception">Recorded exception stored in the OnError notification.</param>
        /// <returns>Recorded OnError notification.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="exception"/> is null.</exception>
        public static Recorded<Notification<T>> OnError<T>(long ticks, Exception exception)
        {
            if (exception == null)
                throw new ArgumentNullException("exception");

            return new Recorded<Notification<T>>(ticks, Notification.CreateOnError<T>(exception));
        }

        /// <summary>
        /// Factory method for writing an assert that checks for an OnError notification record at a given time, using the specified predicate to check the exception.
        /// </summary>
        /// <typeparam name="T">The element type for the resulting notification object.</typeparam>
        /// <param name="ticks">Recorded virtual time the OnError notification occurs.</param>
        /// <param name="predicate">Predicate function to check the OnError notification value against an expected exception.</param>
        /// <returns>Recorded OnError notification with a predicate to assert a given exception.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="predicate"/> is null.</exception>
        public static Recorded<Notification<T>> OnError<T>(long ticks, Func<Exception, bool> predicate)
        {
            if (predicate == null)
                throw new ArgumentNullException("predicate");

            return new Recorded<Notification<T>>(ticks, new OnErrorPredicate<T>(predicate));
        }
        
        /// <summary>
        /// Factory method for an OnError notification record at a given time with a given error, using inference to determine the type of <typeparamref name="T"/>.
        /// </summary>
        /// <typeparam name="T">The element type for the resulting notification object.</typeparam>
        /// <param name="ticks">Recorded virtual time the OnError notification occurs.</param>
        /// <param name="exception">Recorded exception stored in the OnError notification.</param>
        /// <param name="witness">Object solely used to infer the type of the <typeparamref name="T"/> type parameter. This parameter is typically used when creating a sequence of anonymously typed elements.</param>
        /// <returns>Recorded OnError notification.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="exception"/> is null.</exception>
        public static Recorded<Notification<T>> OnError<T>(long ticks, Exception exception, T witness)
        {
            if (exception == null)
                throw new ArgumentNullException("exception");

            return new Recorded<Notification<T>>(ticks, Notification.CreateOnError<T>(exception));
        }

        /// <summary>
        /// Factory method for writing an assert that checks for an OnError notification record at a given time, using the specified predicate to check the exception and inference to determine the type of <typeparamref name="T"/>.
        /// </summary>
        /// <typeparam name="T">The element type for the resulting notification object.</typeparam>
        /// <param name="ticks">Recorded virtual time the OnError notification occurs.</param>
        /// <param name="predicate">Predicate function to check the OnError notification value against an expected exception.</param>
        /// <param name="witness">Object solely used to infer the type of the <typeparamref name="T"/> type parameter. This parameter is typically used when creating a sequence of anonymously typed elements.</param>
        /// <returns>Recorded OnError notification with a predicate to assert a given exception.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="predicate"/> is null.</exception>
        public static Recorded<Notification<T>> OnError<T>(long ticks, Func<Exception, bool> predicate, T witness)
        {
            if (predicate == null)
                throw new ArgumentNullException("predicate");

            return new Recorded<Notification<T>>(ticks, new OnErrorPredicate<T>(predicate));
        }

        /// <summary>
        /// Factory method for a subscription record based on a given subscription and disposal time.
        /// </summary>
        /// <param name="start">Virtual time indicating when the subscription was created.</param>
        /// <param name="end">Virtual time indicating when the subscription was disposed.</param>
        /// <returns>Subscription object.</returns>
        public static Subscription Subscribe(long start, long end)
        {
            return new Subscription(start, end);
        }

        /// <summary>
        /// Factory method for a subscription record based on a given subscription time.
        /// </summary>
        /// <param name="start">Virtual time indicating when the subscription was created.</param>
        /// <returns>Subscription object.</returns>
        public static Subscription Subscribe(long start)
        {
            return new Subscription(start);
        }

        #region Predicate-based notification assert helper classes

        class OnNextPredicate<T> : PredicateNotification<T>
        {
            private readonly Func<T, bool> _predicate;

            public OnNextPredicate(Func<T, bool> predicate)
            {
                _predicate = predicate;
            }

            public override bool Equals(Notification<T> other)
            {
                if (Object.ReferenceEquals(this, other))
                    return true;
                if (Object.ReferenceEquals(other, null))
                    return false;
                if (other.Kind != NotificationKind.OnNext)
                    return false;

                return _predicate(other.Value);
            }
        }

        class OnErrorPredicate<T> : PredicateNotification<T>
        {
            private readonly Func<Exception, bool> _predicate;

            public OnErrorPredicate(Func<Exception, bool> predicate)
            {
                _predicate = predicate;
            }

            public override bool Equals(Notification<T> other)
            {
                if (Object.ReferenceEquals(this, other))
                    return true;
                if (Object.ReferenceEquals(other, null))
                    return false;
                if (other.Kind != NotificationKind.OnError)
                    return false;

                return _predicate(other.Exception);
            }
        }

        abstract class PredicateNotification<T> : Notification<T>
        {
            #region Non-implemented members (by design)

            public override T Value
            {
                get { throw new NotSupportedException(); }
            }

            public override bool HasValue
            {
                get { throw new NotSupportedException(); }
            }

            public override Exception Exception
            {
                get { throw new NotSupportedException(); }
            }

            public override NotificationKind Kind
            {
                get { throw new NotSupportedException(); }
            }

            public override void Accept(IObserver<T> observer)
            {
                throw new NotSupportedException();
            }

            public override TResult Accept<TResult>(IObserver<T, TResult> observer)
            {
                throw new NotSupportedException();
            }

            public override void Accept(Action<T> onNext, Action<Exception> onError, Action onCompleted)
            {
                throw new NotSupportedException();
            }

            public override TResult Accept<TResult>(Func<T, TResult> onNext, Func<Exception, TResult> onError, Func<TResult> onCompleted)
            {
                throw new NotSupportedException();
            }

            #endregion
        }

        #endregion
    }
}