ArgumentValidationTest.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Reactive;
  8. using System.Reactive.Concurrency;
  9. using System.Reactive.Disposables;
  10. using System.Reactive.Joins;
  11. using System.Reactive.Linq;
  12. using System.Reactive.Subjects;
  13. using System.Reflection;
  14. using System.Text;
  15. using System.Threading;
  16. using System.Threading.Tasks;
  17. using Xunit;
  18. namespace ReactiveTests.Tests
  19. {
  20. /// <summary>
  21. /// Check if the Observable operator methods perform the proper
  22. /// argument validations en-masse with reflective checks.
  23. /// </summary>
  24. public class ArgumentValidationTest
  25. {
  26. #region + Default values for the generic types +
  27. /// <summary>
  28. /// Contains a map of various types, represented
  29. /// as strings generated via <see cref="TypeNameOf(Type)"/>,
  30. /// mapped to a value.
  31. /// </summary>
  32. static Dictionary<string, object> _defaultValues;
  33. /// <summary>
  34. /// Prepare the default instances for various types used
  35. /// throughout Rx.NET.
  36. /// </summary>
  37. static ArgumentValidationTest()
  38. {
  39. _defaultValues = new Dictionary<string, object>();
  40. _defaultValues.Add("IObservable`1[Object]", Observable.Return(new object()));
  41. _defaultValues.Add("IObservable`1[Int32]", Observable.Return(1));
  42. _defaultValues.Add("IObservable`1[Task`1[Int32]]", Observable.Return(Task.FromResult(1)));
  43. _defaultValues.Add("IObservable`1[Notification`1[Int32]]", Observable.Return(Notification.CreateOnNext(1)));
  44. _defaultValues.Add("IObservable`1[Int64]", Observable.Return(1L));
  45. _defaultValues.Add("IObservable`1[Double]", Observable.Return(1.0));
  46. _defaultValues.Add("IObservable`1[Single]", Observable.Return(1.0f));
  47. _defaultValues.Add("IObservable`1[Decimal]", Observable.Return(1.0m));
  48. _defaultValues.Add("IObservable`1[Nullable`1[Int32]]", Observable.Return<int?>(1));
  49. _defaultValues.Add("IObservable`1[Nullable`1[Int64]]", Observable.Return<long?>(1L));
  50. _defaultValues.Add("IObservable`1[Nullable`1[Double]]", Observable.Return<double?>(1.0));
  51. _defaultValues.Add("IObservable`1[Nullable`1[Single]]", Observable.Return<float?>(1.0f));
  52. _defaultValues.Add("IObservable`1[Nullable`1[Decimal]]", Observable.Return<decimal?>(1.0m));
  53. _defaultValues.Add("IObservable`1[IObservable`1[Int32]]", Observable.Return(Observable.Return(1)));
  54. _defaultValues.Add("IObservable`1[][Int32]", new[] { Observable.Return(1) });
  55. _defaultValues.Add("IConnectableObservable`1[Int32]", Observable.Return(1).Publish());
  56. _defaultValues.Add("Int32", 1);
  57. _defaultValues.Add("Int64", 1L);
  58. _defaultValues.Add("IScheduler", Scheduler.Immediate);
  59. _defaultValues.Add("TimeSpan", TimeSpan.FromMilliseconds(1));
  60. _defaultValues.Add("DateTimeOffset", DateTimeOffset.Now);
  61. _defaultValues.Add("Object", new object());
  62. _defaultValues.Add("Exception", new Exception());
  63. _defaultValues.Add("String", "String");
  64. _defaultValues.Add("IDictionary`2[Int32, IObservable`1[Int32]]", new Dictionary<int, IObservable<int>>());
  65. _defaultValues.Add("Type", typeof(object));
  66. _defaultValues.Add("Int32[]", new[] { 1 });
  67. _defaultValues.Add("ISubject`1[Int32]", new Subject<int>());
  68. _defaultValues.Add("ISubject`2[Int32, Int32]", new Subject<int>());
  69. _defaultValues.Add("IEnumerable`1[Int32]", new[] { 1 });
  70. _defaultValues.Add("IEnumerable`1[IObservable`1[Int32]]", new[] { Observable.Return(1) });
  71. _defaultValues.Add("SynchronizationContext", SynchronizationContext.Current);
  72. _defaultValues.Add("IEqualityComparer`1[Int32]", EqualityComparer<int>.Default);
  73. _defaultValues.Add("IComparer`1[Int32]", Comparer<int>.Default);
  74. _defaultValues.Add("IObserver`1[Int32]", Observer.Create<int>(v => { }));
  75. _defaultValues.Add("CancellationToken", new CancellationToken());
  76. _defaultValues.Add("Action", new Action(() => { }));
  77. _defaultValues.Add("Action`1[Int32]", new Action<int>(v => { }));
  78. _defaultValues.Add("Action`1[Exception]", new Action<Exception>(v => { }));
  79. _defaultValues.Add("Action`1[IDisposable]", new Action<IDisposable>(v => { }));
  80. _defaultValues.Add("Action`1[EventHandler]", new Action<EventHandler>(v => { }));
  81. _defaultValues.Add("Action`1[EventHandler`1[Int32]]", new Action<EventHandler<int>>(v => { }));
  82. _defaultValues.Add("Action`1[Action`1[Int32]]", new Action<Action<int>>(v => { }));
  83. _defaultValues.Add("Action`1[Action]", new Action<Action>(v => { }));
  84. _defaultValues.Add("Action`1[IAsyncResult]", new Action<IAsyncResult>(v => { }));
  85. _defaultValues.Add("Action`2[Int32, Int32]", new Action<int, int>((v, u) => { }));
  86. _defaultValues.Add("Func`1[Boolean]", new Func<bool>(() => true));
  87. _defaultValues.Add("Func`1[Int32]", new Func<int>(() => 1));
  88. _defaultValues.Add("Func`1[IObservable`1[Int32]]", new Func<IObservable<int>>(() => Observable.Return(1)));
  89. _defaultValues.Add("Func`1[ISubject`2[Int32, Int32]]", new Func<ISubject<int, int>>(() => new Subject<int>()));
  90. _defaultValues.Add("Func`1[Task`1[IObservable`1[Int32]]]", new Func<Task<IObservable<int>>>(() => Task.FromResult(Observable.Return(1))));
  91. _defaultValues.Add("Func`1[IDisposable]", new Func<IDisposable>(() => Disposable.Empty));
  92. _defaultValues.Add("Func`1[Task]", new Func<Task>(() => Task.FromResult(1)));
  93. _defaultValues.Add("Func`1[Task`1[Int32]]", new Func<Task<int>>(() => Task.FromResult(1)));
  94. _defaultValues.Add("Func`1[IEnumerable`1[IObservable`1[Object]]]", new Func<IEnumerable<IObservable<object>>>(() => new[] { Observable.Return((object)1) }));
  95. _defaultValues.Add("Func`2[Int32, IObservable`1[Int32]]", new Func<int, IObservable<int>>(v => Observable.Return(v)));
  96. _defaultValues.Add("Func`2[Exception, IObservable`1[Int32]]", new Func<Exception, IObservable<int>>(v => Observable.Return(1)));
  97. _defaultValues.Add("Func`2[Int32, Task`1[Int32]]", new Func<int, Task<int>>(v => Task.FromResult(v)));
  98. _defaultValues.Add("Func`2[Int32, Int32]", new Func<int, int>(v => v));
  99. _defaultValues.Add("Func`2[Int32, IEnumerable`1[Int32]]", new Func<int, IEnumerable<int>>(v => new[] { v }));
  100. _defaultValues.Add("Func`2[Int32, Boolean]", new Func<int, bool>(v => true));
  101. _defaultValues.Add("Func`2[Int32, TimeSpan]", new Func<int, TimeSpan>(v => TimeSpan.FromMilliseconds(1)));
  102. _defaultValues.Add("Func`2[Int32, DateTimeOffset]", new Func<int, DateTimeOffset>(v => DateTimeOffset.Now));
  103. _defaultValues.Add("Func`2[IList`1[Int32], Int32]", new Func<IList<int>, int>(v => v.Count));
  104. _defaultValues.Add("Func`2[Int32, Nullable`1[Double]]", new Func<int, double?>(v => v));
  105. _defaultValues.Add("Func`2[Int32, Nullable`1[Single]]", new Func<int, float?>(v => v));
  106. _defaultValues.Add("Func`2[Int32, Nullable`1[Int32]]", new Func<int, int?>(v => v));
  107. _defaultValues.Add("Func`2[Int32, Nullable`1[Decimal]]", new Func<int, decimal?>(v => v));
  108. _defaultValues.Add("Func`2[Int32, Nullable`1[Int64]]", new Func<int, long?>(v => v));
  109. _defaultValues.Add("Func`2[Int32, Double]", new Func<int, double>(v => v));
  110. _defaultValues.Add("Func`2[Int32, Single]", new Func<int, float>(v => v));
  111. _defaultValues.Add("Func`2[Int32, Decimal]", new Func<int, decimal>(v => v));
  112. _defaultValues.Add("Func`2[Int32, Int64]", new Func<int, long>(v => v));
  113. _defaultValues.Add("Func`2[IObservable`1[Object], IObservable`1[Int32]]", new Func<IObservable<object>, IObservable<int>>(v => v.Select(w => 1)));
  114. _defaultValues.Add("Func`2[IObservable`1[Exception], IObservable`1[Int32]]", new Func<IObservable<Exception>, IObservable<int>>(v => v.Select(w => 1)));
  115. _defaultValues.Add("Func`2[IGroupedObservable`2[Int32, Int32], IObservable`1[Int32]]", new Func<IGroupedObservable<int, int>, IObservable<int>>(v => v));
  116. _defaultValues.Add("Func`2[IObservable`1[Int32], IObservable`1[Int32]]", new Func<IObservable<int>, IObservable<int>>(v => v.Select(w => 1)));
  117. _defaultValues.Add("Func`2[CancellationToken, Task`1[IObservable`1[Int32]]]", new Func<CancellationToken, Task<IObservable<int>>>(v => Task.FromResult(Observable.Return(1))));
  118. _defaultValues.Add("Func`2[IDisposable, Task`1[IObservable`1[Int32]]]", new Func<IDisposable, Task<IObservable<int>>>(v => Task.FromResult(Observable.Return(1))));
  119. _defaultValues.Add("Func`2[IDisposable, IObservable`1[Int32]]", new Func<IDisposable, IObservable<int>>(v => Observable.Return(1)));
  120. _defaultValues.Add("Func`2[CancellationToken, Task`1[IDisposable]]", new Func<CancellationToken, Task<IDisposable>>(v => Task.FromResult(Disposable.Empty)));
  121. _defaultValues.Add("Func`2[EventHandler`1[Int32], Int32]", new Func<EventHandler<int>, int>(v => 1));
  122. _defaultValues.Add("Func`2[Action`1[Int32], Int32]", new Func<Action<int>, int>(v => 1));
  123. _defaultValues.Add("Func`2[IObserver`1[Int32], IDisposable]", new Func<IObserver<int>, IDisposable>(v => Disposable.Empty));
  124. _defaultValues.Add("Func`2[IObserver`1[Int32], Action]", new Func<IObserver<int>, Action>(v => () => { }));
  125. _defaultValues.Add("Func`2[IObserver`1[Int32], Task]", new Func<IObserver<int>, Task>(v => Task.FromResult(1)));
  126. _defaultValues.Add("Func`2[IObserver`1[Int32], Task`1[IDisposable]]", new Func<IObserver<int>, Task<IDisposable>>(v => Task.FromResult(Disposable.Empty)));
  127. _defaultValues.Add("Func`2[IObserver`1[Int32], Task`1[Action]]", new Func<IObserver<int>, Task<Action>>(v => Task.FromResult<Action>(() => { })));
  128. _defaultValues.Add("Func`2[CancellationToken, Task]", new Func<CancellationToken, Task>(v => Task.FromResult(1)));
  129. _defaultValues.Add("Func`2[CancellationToken, Task`1[Int32]]", new Func<CancellationToken, Task<int>>(v => Task.FromResult(1)));
  130. _defaultValues.Add("Func`2[IAsyncResult, Int32]", new Func<IAsyncResult, int>(v => 1));
  131. _defaultValues.Add("Func`2[IObserver`1[Int32], IEnumerable`1[IObservable`1[Object]]]", new Func<IObserver<int>, IEnumerable<IObservable<object>>>(v => new[] { Observable.Return((object)1) }));
  132. _defaultValues.Add("Func`2[IObservable`1[Int32], Int32]", new Func<IObservable<int>, int>(v => 1));
  133. _defaultValues.Add("Func`3[Int32, Int32, IObservable`1[Int32]]", new Func<int, int, IObservable<int>>((v, u) => Observable.Return(v + u)));
  134. _defaultValues.Add("Func`3[Int32, Int32, Task`1[Int32]]", new Func<int, int, Task<int>>((v, u) => Task.FromResult(v + u)));
  135. _defaultValues.Add("Func`3[Int32, CancellationToken, Task`1[Int32]]", new Func<int, CancellationToken, Task<int>>((v, u) => Task.FromResult(v)));
  136. _defaultValues.Add("Func`3[Int32, Int32, Int32]", new Func<int, int, int>((v, u) => v + u));
  137. _defaultValues.Add("Func`3[Int32, Int32, IEnumerable`1[Int32]]", new Func<int, int, IEnumerable<int>>((v, u) => new[] { v, u }));
  138. _defaultValues.Add("Func`3[Int32, Int32, Boolean]", new Func<int, int, bool>((v, u) => true));
  139. _defaultValues.Add("Func`3[Int32, IObservable`1[Int32], Int32]", new Func<int, IObservable<int>, int>((v, u) => v));
  140. _defaultValues.Add("Func`3[IDisposable, CancellationToken, Task`1[IObservable`1[Int32]]]", new Func<IDisposable, CancellationToken, Task<IObservable<int>>>((v, u) => Task.FromResult(Observable.Return(1))));
  141. _defaultValues.Add("Func`3[IObserver`1[Int32], CancellationToken, Task]", new Func<IObserver<int>, CancellationToken, Task>((v, w) => Task.FromResult(1)));
  142. _defaultValues.Add("Func`3[IObserver`1[Int32], CancellationToken, Task`1[IDisposable]]", new Func<IObserver<int>, CancellationToken, Task<IDisposable>>((v, w) => Task.FromResult(Disposable.Empty)));
  143. _defaultValues.Add("Func`3[IObserver`1[Int32], CancellationToken, Task`1[Action]]", new Func<IObserver<int>, CancellationToken, Task<Action>>((v, w) => Task.FromResult<Action>(() => { })));
  144. _defaultValues.Add("Func`3[AsyncCallback, Object, IAsyncResult]", new Func<AsyncCallback, object, IAsyncResult>((v, w) => null));
  145. _defaultValues.Add("Func`4[Int32, Int32, CancellationToken, Task`1[Int32]]", new Func<int, int, CancellationToken, Task<int>>((v, u, w) => Task.FromResult(v)));
  146. _defaultValues.Add("Func`4[Int32, Int32, Int32, Int32]", new Func<int, int, int, int>((v1, v2, v3) => v1 + v2 + v3));
  147. _defaultValues.Add("Func`4[Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, AsyncCallback, object, IAsyncResult>((v, w, x) => null));
  148. _defaultValues.Add("Func`5[Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int>((v1, v2, v3, v4) => v1 + v2 + v3 + v4));
  149. _defaultValues.Add("Func`6[Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int>((v1, v2, v3, v4, v5) => v1 + v2 + v3 + v4 + v5));
  150. _defaultValues.Add("Func`7[Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6) => v1 + v2 + v3 + v4 + v5 + v6));
  151. _defaultValues.Add("Func`8[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7) => v1 + v2 + v3 + v4 + v5 + v6 + v7));
  152. _defaultValues.Add("Func`9[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8) => v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8));
  153. _defaultValues.Add("Func`10[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9) => v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9));
  154. _defaultValues.Add("Func`11[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10));
  155. _defaultValues.Add("Func`12[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11));
  156. _defaultValues.Add("Func`13[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12));
  157. _defaultValues.Add("Func`14[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) => v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12 + v13));
  158. _defaultValues.Add("Func`15[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) => v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12 + v13 + v14));
  159. _defaultValues.Add("Func`16[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) => v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12 + v13 + v14 + v15));
  160. _defaultValues.Add("Func`17[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Func<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) => v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8 + v9 + v10 + v11 + v12 + v13 + v14 + v15 + v16));
  161. _defaultValues.Add("Plan`1[][Int32]", new Plan<int>[] {
  162. Observable.Return(1).Then(v => v)
  163. });
  164. _defaultValues.Add("IEnumerable`1[Plan`1[Int32]]", new Plan<int>[] {
  165. Observable.Return(1).Then(v => v)
  166. });
  167. _defaultValues.Add("Action`3[Int32, Int32, Int32]", new Action<int, int, int>((v1, v2, v3) => { }));
  168. _defaultValues.Add("Action`4[Int32, Int32, Int32, Int32]", new Action<int, int, int, int>((v1, v2, v3, v4) => { }));
  169. _defaultValues.Add("Action`5[Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int>((v1, v2, v3, v4, v5) => { }));
  170. _defaultValues.Add("Action`6[Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6) => { }));
  171. _defaultValues.Add("Action`7[Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7) => { }));
  172. _defaultValues.Add("Action`8[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8) => { }));
  173. _defaultValues.Add("Action`9[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9) => { }));
  174. _defaultValues.Add("Action`10[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => { }));
  175. _defaultValues.Add("Action`11[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => { }));
  176. _defaultValues.Add("Action`12[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => { }));
  177. _defaultValues.Add("Action`13[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) => { }));
  178. _defaultValues.Add("Action`14[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) => { }));
  179. _defaultValues.Add("Action`15[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) => { }));
  180. _defaultValues.Add("Action`16[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32]", new Action<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) => { }));
  181. _defaultValues.Add("Func`5[Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4) => null));
  182. _defaultValues.Add("Func`6[Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5) => null));
  183. _defaultValues.Add("Func`7[Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6) => null));
  184. _defaultValues.Add("Func`8[Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7) => null));
  185. _defaultValues.Add("Func`9[Int32, Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7, v8) => null));
  186. _defaultValues.Add("Func`10[Int32, Int32, Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7, v8, v9) => null));
  187. _defaultValues.Add("Func`11[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) => null));
  188. _defaultValues.Add("Func`12[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) => null));
  189. _defaultValues.Add("Func`13[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) => null));
  190. _defaultValues.Add("Func`14[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, int, int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) => null));
  191. _defaultValues.Add("Func`15[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, int, int, int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) => null));
  192. _defaultValues.Add("Func`16[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, int, int, int, int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) => null));
  193. _defaultValues.Add("Func`17[Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, AsyncCallback, Object, IAsyncResult]", new Func<int, int, int, int, int, int, int, int, int, int, int, int, int, int, AsyncCallback, object, IAsyncResult>((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) => null));
  194. }
  195. #endregion
  196. [Fact]
  197. public void Verify_Observable()
  198. {
  199. VerifyClass(typeof(Observable));
  200. }
  201. [Fact]
  202. public void Verify_ObservableEx()
  203. {
  204. VerifyClass(typeof(ObservableEx));
  205. }
  206. #region + Verification method +
  207. /// <summary>
  208. /// Verify that public static members of the class
  209. /// check for nulls in their arguments as
  210. /// well as when invoking Subscribe with null.
  211. /// </summary>
  212. /// <param name="type">The type to verify.</param>
  213. static void VerifyClass(Type type)
  214. {
  215. foreach (var method in type.GetMethods())
  216. {
  217. // public static only (skip methods like Equals)
  218. if (!method.IsPublic || !method.IsStatic)
  219. {
  220. continue;
  221. }
  222. var m = default(MethodInfo);
  223. // Is this a generic method?
  224. if (method.IsGenericMethodDefinition)
  225. {
  226. // we need to specialize it to concrete types
  227. // for the reflective call to work
  228. // get the type arguments
  229. var ga = method.GetGenericArguments();
  230. var targs = new Type[ga.Length];
  231. // fill in the type arguments
  232. for (int k = 0; k < targs.Length; k++)
  233. {
  234. // watch out for type constrains
  235. // the default typeof(int) will not work when
  236. // exception or IDisposable is required at minimum
  237. var gac = ga[k].GetGenericParameterConstraints();
  238. // no type constraints
  239. if (gac.Length == 0)
  240. {
  241. targs[k] = typeof(int);
  242. }
  243. else if (gac[0] == typeof(Exception))
  244. {
  245. targs[k] = typeof(Exception);
  246. }
  247. else if (gac[0] == typeof(IDisposable))
  248. {
  249. targs[k] = typeof(IDisposable);
  250. }
  251. else
  252. {
  253. // If we get here, a new rule should be added above
  254. throw new Exception("Unknown constraint: " + gac + "\r\n" + method);
  255. }
  256. }
  257. // generate a specialized method with the concrete generic arguments
  258. try
  259. {
  260. m = method.MakeGenericMethod(targs);
  261. }
  262. catch (Exception ex)
  263. {
  264. throw new Exception("MakeGenericMethod threw: " + method, ex);
  265. }
  266. } else
  267. {
  268. // non generic method, we can invoke this directly
  269. m = method;
  270. }
  271. var args = m.GetParameters();
  272. // for each parameter of the (generic) method
  273. for (int i = 0; i < args.Length; i++)
  274. {
  275. // prepare a pattern for the method invocation
  276. var margs = new object[args.Length];
  277. // some arguments can be null, often indicated with a default == null marker
  278. // this tracks this case and forgives for not throwing an ArgumentNullException
  279. var argumentCanBeNull = true;
  280. // for each argument index
  281. // with the loop i, this creates an N x N matrix where in each row, one argument is null
  282. for (int j = 0; j < args.Length; j++)
  283. {
  284. // figure out the type of the argument
  285. var pt = args[j].ParameterType;
  286. // by using some type naming convention as string
  287. var paramTypeName = TypeNameOf(pt);
  288. // classes, interfaces, arrays and abstract markers can be null
  289. // for the diagonal entries of the test matrix
  290. if (j == i && (pt.IsClass || pt.IsInterface || pt.IsArray || pt.IsAbstract))
  291. {
  292. margs[j] = null;
  293. // check if the argument can be actually
  294. argumentCanBeNull = args[j].HasDefaultValue && args[j].DefaultValue == null;
  295. }
  296. else
  297. {
  298. // this argument is not tested for null or is not a null type
  299. // find the default instance for it
  300. if (_defaultValues.ContainsKey(paramTypeName))
  301. {
  302. margs[j] = _defaultValues[paramTypeName];
  303. }
  304. else
  305. {
  306. // default values have to be instantiated in _defaultValues for
  307. // each possible generic type arguments.
  308. // this will indicate what concrete instance value is missing.
  309. throw new Exception("Default instance not found for: " + paramTypeName + "\r\n\r\n" + m);
  310. }
  311. }
  312. }
  313. // assume it threw
  314. var thrown = true;
  315. var obj = default(object);
  316. try
  317. {
  318. obj = m.Invoke(null, margs);
  319. thrown = false;
  320. }
  321. catch (ArgumentNullException)
  322. {
  323. // expected exception, just in case
  324. }
  325. catch (Exception ex)
  326. {
  327. // reflection wraps the actual exception, let's unwrap it
  328. if (!(ex.InnerException is ArgumentNullException))
  329. {
  330. throw new Exception("Method threw: " + method + " @ " + i, ex);
  331. }
  332. }
  333. // if the call didn't throw and the argument being tested isn't defaulted to null, throw
  334. if (!thrown && !argumentCanBeNull)
  335. {
  336. throw new Exception("Should have thrown: " + method + " @ " + i);
  337. }
  338. // if the call didn't throw and returned a null object, throw
  339. // no operators should return null
  340. if (obj == null && !thrown) {
  341. throw new NullReferenceException("null return: " + method + " @ " + i);
  342. }
  343. }
  344. // Now check the same method with valid arguments but
  345. // Subscribe(null) if it returns an IObservable subclass
  346. if (m.ReturnType.Name.Equals("IObservable`1")
  347. || m.ReturnType.Name.Equals("IConnectableObservable`1"))
  348. {
  349. // these will fail other argument validation with the defaults, skip them
  350. if (m.Name.Equals("FromEventPattern"))
  351. {
  352. continue;
  353. }
  354. // prepare method arguments
  355. var margs = new object[args.Length];
  356. for (int j = 0; j < args.Length; j++)
  357. {
  358. var pt = args[j].ParameterType;
  359. var paramTypeName = TypeNameOf(pt);
  360. if (_defaultValues.ContainsKey(paramTypeName))
  361. {
  362. margs[j] = _defaultValues[paramTypeName];
  363. }
  364. else
  365. {
  366. // default values have to be instantiated in _defaultValues for
  367. // each possible generic type arguments.
  368. // this will indicate what concrete instance value is missing.
  369. //
  370. // it may fail independently of the null test above because
  371. // the particular type is non-nullable thus skipped above
  372. // or was the solo argument and it got never tested with a non-null
  373. // value
  374. throw new Exception("Default instance not found (Subscribe(null) check): " + paramTypeName + "\r\n\r\n" + m);
  375. }
  376. }
  377. // Assume it throws
  378. var thrown = true;
  379. try
  380. {
  381. var o = m.Invoke(null, margs) as IObservable<int>;
  382. // Should not return null, but would be mistaken for
  383. // throwing because of Subscribe(null)
  384. if (o != null) {
  385. o.Subscribe(null);
  386. thrown = false;
  387. }
  388. }
  389. catch (ArgumentNullException)
  390. {
  391. // expected
  392. }
  393. catch (Exception ex)
  394. {
  395. // Unexpected exception
  396. // Maybe some other validation failed inside the method call
  397. // Consider skipping this method (set)
  398. //
  399. // Otherwise, the operator may run with the null IObserver
  400. // for a while and crash later.
  401. throw new Exception("Method threw (Subscribe(null) check): " + m, ex);
  402. }
  403. // If it didn't throw, report it
  404. if (!thrown)
  405. {
  406. throw new Exception("Should have thrown (Subscribe(null) check): " + m);
  407. }
  408. }
  409. }
  410. }
  411. /// <summary>
  412. /// Generate a string representation of a possibly generic type
  413. /// that is not verbose (i.e, no "System." everywhere).
  414. /// </summary>
  415. /// <param name="type">The type to get a string representation</param>
  416. /// <returns>The string representation of a possibly generic type</returns>
  417. static string TypeNameOf(Type type)
  418. {
  419. var ga = type.GetGenericArguments();
  420. if (ga.Length == 0)
  421. {
  422. return type.Name;
  423. }
  424. return type.Name + "[" + string.Join(", ", ga.Select(t => TypeNameOf(t)).ToArray()) + "]";
  425. }
  426. #endregion
  427. }
  428. }