HalfSerializerTest.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Reactive;
  7. using Microsoft.VisualStudio.TestTools.UnitTesting;
  8. using Assert = Xunit.Assert;
  9. namespace ReactiveTests.Tests
  10. {
  11. [TestClass]
  12. public class HalfSerializerTest
  13. {
  14. #pragma warning disable IDE0044 // Spurious suggestion to add readonly. Not appropriate because this is passed by ref
  15. private int _wip;
  16. #pragma warning restore IDE0044
  17. private Exception _error;
  18. private readonly Consumer _consumer = new();
  19. [TestMethod]
  20. public void HalfSerializer_OnNext()
  21. {
  22. HalfSerializer.ForwardOnNext(_consumer, 1, ref _wip, ref _error);
  23. Assert.Equal(0, _wip);
  24. Assert.Null(_error);
  25. Assert.Equal(1, _consumer.Items.Count);
  26. Assert.Equal(1, _consumer.Items[0]);
  27. Assert.Equal(0, _consumer.Done);
  28. Assert.Null(_consumer.Exc);
  29. }
  30. [TestMethod]
  31. public void HalfSerializer_OnError()
  32. {
  33. var ex = new InvalidOperationException();
  34. HalfSerializer.ForwardOnError(_consumer, ex, ref _wip, ref _error);
  35. Assert.Equal(1, _wip);
  36. Assert.Equal(_error, ExceptionHelper.Terminated);
  37. HalfSerializer.ForwardOnNext(_consumer, 2, ref _wip, ref _error);
  38. Assert.Equal(0, _consumer.Items.Count);
  39. Assert.Equal(0, _consumer.Done);
  40. Assert.Equal(ex, _consumer.Exc);
  41. }
  42. [TestMethod]
  43. public void HalfSerializer_OnError_Ignore_Further_Events()
  44. {
  45. var ex = new InvalidOperationException();
  46. HalfSerializer.ForwardOnError(_consumer, ex, ref _wip, ref _error);
  47. Assert.Equal(1, _wip);
  48. Assert.Equal(_error, ExceptionHelper.Terminated);
  49. HalfSerializer.ForwardOnNext(_consumer, 2, ref _wip, ref _error);
  50. var ex2 = new NotSupportedException();
  51. HalfSerializer.ForwardOnError(_consumer, ex2, ref _wip, ref _error);
  52. HalfSerializer.ForwardOnCompleted(_consumer, ref _wip, ref _error);
  53. Assert.Equal(0, _consumer.Items.Count);
  54. Assert.Equal(0, _consumer.Done);
  55. Assert.Equal(ex, _consumer.Exc);
  56. }
  57. [TestMethod]
  58. public void HalfSerializer_OnCompleted()
  59. {
  60. HalfSerializer.ForwardOnCompleted(_consumer, ref _wip, ref _error);
  61. Assert.Equal(1, _wip);
  62. Assert.Equal(_error, ExceptionHelper.Terminated);
  63. HalfSerializer.ForwardOnNext(_consumer, 2, ref _wip, ref _error);
  64. Assert.Equal(0, _consumer.Items.Count);
  65. Assert.Equal(1, _consumer.Done);
  66. Assert.Null(_consumer.Exc);
  67. }
  68. [TestMethod]
  69. public void HalfSerializer_OnCompleted_Ignore_Further_Events()
  70. {
  71. HalfSerializer.ForwardOnCompleted(_consumer, ref _wip, ref _error);
  72. Assert.Equal(1, _wip);
  73. Assert.Equal(_error, ExceptionHelper.Terminated);
  74. HalfSerializer.ForwardOnNext(_consumer, 2, ref _wip, ref _error);
  75. var ex2 = new NotSupportedException();
  76. HalfSerializer.ForwardOnError(_consumer, ex2, ref _wip, ref _error);
  77. HalfSerializer.ForwardOnCompleted(_consumer, ref _wip, ref _error);
  78. Assert.Equal(0, _consumer.Items.Count);
  79. Assert.Equal(1, _consumer.Done);
  80. Assert.Null(_consumer.Exc);
  81. }
  82. // Practically simulates concurrent invocation of the HalfSerializer methods
  83. [TestMethod]
  84. public void HalfSerializer_OnNext_Reentrant_Error()
  85. {
  86. var c = new ReentrantConsumer(this, true);
  87. HalfSerializer.ForwardOnNext(c, 1, ref _wip, ref _error);
  88. Assert.Equal(1, _wip);
  89. Assert.Equal(_error, ExceptionHelper.Terminated);
  90. Assert.Equal(1, _consumer.Items.Count);
  91. Assert.Equal(1, _consumer.Items[0]);
  92. Assert.Equal(0, _consumer.Done);
  93. Assert.Equal(c.X, _consumer.Exc);
  94. }
  95. // Practically simulates concurrent invocation of the HalfSerializer methods
  96. [TestMethod]
  97. public void HalfSerializer_OnNext_Reentrant_OnCompleted()
  98. {
  99. var c = new ReentrantConsumer(this, false);
  100. HalfSerializer.ForwardOnNext(c, 1, ref _wip, ref _error);
  101. Assert.Equal(1, _wip);
  102. Assert.Equal(_error, ExceptionHelper.Terminated);
  103. Assert.Equal(1, _consumer.Items.Count);
  104. Assert.Equal(1, _consumer.Items[0]);
  105. Assert.Equal(1, _consumer.Done);
  106. Assert.Null(_consumer.Exc);
  107. }
  108. private sealed class Consumer : ISink<int>
  109. {
  110. internal List<int> Items = [];
  111. internal int Done;
  112. internal Exception Exc;
  113. public void ForwardOnCompleted()
  114. {
  115. Done++;
  116. }
  117. public void ForwardOnError(Exception error)
  118. {
  119. Exc = error;
  120. }
  121. public void ForwardOnNext(int value)
  122. {
  123. Items.Add(value);
  124. }
  125. }
  126. private sealed class ReentrantConsumer : ISink<int>
  127. {
  128. private readonly HalfSerializerTest _parent;
  129. private readonly bool _errorReenter;
  130. internal readonly Exception X = new IndexOutOfRangeException();
  131. public ReentrantConsumer(HalfSerializerTest parent, bool errorReenter)
  132. {
  133. _parent = parent;
  134. _errorReenter = errorReenter;
  135. }
  136. public void ForwardOnCompleted()
  137. {
  138. _parent._consumer.ForwardOnCompleted();
  139. }
  140. public void ForwardOnError(Exception error)
  141. {
  142. _parent._consumer.ForwardOnError(error);
  143. }
  144. public void ForwardOnNext(int value)
  145. {
  146. _parent._consumer.ForwardOnNext(value);
  147. if (_errorReenter)
  148. {
  149. HalfSerializer.ForwardOnError(this, X, ref _parent._wip, ref _parent._error);
  150. }
  151. else
  152. {
  153. HalfSerializer.ForwardOnCompleted(this, ref _parent._wip, ref _parent._error);
  154. }
  155. }
  156. }
  157. }
  158. }