PriorityValueTests.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // -----------------------------------------------------------------------
  2. // <copyright file="PriorityValueTests.cs" company="Steven Kirk">
  3. // Copyright 2013 MIT Licence. See licence.md for more information.
  4. // </copyright>
  5. // -----------------------------------------------------------------------
  6. namespace Perspex.Base.UnitTests
  7. {
  8. using System;
  9. using System.Linq;
  10. using System.Reactive.Linq;
  11. using System.Reactive.Subjects;
  12. using Xunit;
  13. public class PriorityValueTests
  14. {
  15. [Fact]
  16. public void Initial_Value_Should_Be_UnsetValue()
  17. {
  18. var target = new PriorityValue("Test", typeof(string));
  19. Assert.Same(PerspexProperty.UnsetValue, target.Value);
  20. }
  21. [Fact]
  22. public void First_Binding_Sets_Value()
  23. {
  24. var target = new PriorityValue("Test", typeof(string));
  25. target.Add(this.Single("foo"), 0);
  26. Assert.Equal("foo", target.Value);
  27. }
  28. [Fact]
  29. public void Changing_Binding_Should_Set_Value()
  30. {
  31. var target = new PriorityValue("Test", typeof(string));
  32. var subject = new BehaviorSubject<string>("foo");
  33. target.Add(subject, 0);
  34. Assert.Equal("foo", target.Value);
  35. subject.OnNext("bar");
  36. Assert.Equal("bar", target.Value);
  37. }
  38. [Fact]
  39. public void Setting_Direct_Value_Should_Override_Binding()
  40. {
  41. var target = new PriorityValue("Test", typeof(string));
  42. target.Add(this.Single("foo"), 0);
  43. target.SetDirectValue("bar", 0);
  44. Assert.Equal("bar", target.Value);
  45. }
  46. [Fact]
  47. public void Binding_Firing_Should_Override_Direct_Value()
  48. {
  49. var target = new PriorityValue("Test", typeof(string));
  50. var source = new BehaviorSubject<object>("initial");
  51. target.Add(source, 0);
  52. Assert.Equal("initial", target.Value);
  53. target.SetDirectValue("first", 0);
  54. Assert.Equal("first", target.Value);
  55. source.OnNext("second");
  56. Assert.Equal("second", target.Value);
  57. }
  58. [Fact]
  59. public void Earlier_Binding_Firing_Should_Override_Later_Priority_0()
  60. {
  61. var target = new PriorityValue("Test", typeof(string));
  62. var nonActive = new BehaviorSubject<object>("na");
  63. var source = new BehaviorSubject<object>("initial");
  64. target.Add(nonActive, 0);
  65. target.Add(source, 0);
  66. Assert.Equal("initial", target.Value);
  67. target.SetDirectValue("first", 0);
  68. Assert.Equal("first", target.Value);
  69. nonActive.OnNext("second");
  70. Assert.Equal("second", target.Value);
  71. }
  72. [Fact]
  73. public void Earlier_Binding_Firing_Should_Not_Override_Later_Priority_1()
  74. {
  75. var target = new PriorityValue("Test", typeof(string));
  76. var nonActive = new BehaviorSubject<object>("na");
  77. var source = new BehaviorSubject<object>("initial");
  78. target.Add(nonActive, 1);
  79. target.Add(source, 1);
  80. Assert.Equal("initial", target.Value);
  81. target.SetDirectValue("first", 1);
  82. Assert.Equal("first", target.Value);
  83. nonActive.OnNext("second");
  84. Assert.Equal("first", target.Value);
  85. }
  86. [Fact]
  87. public void Binding_Completing_Should_Revert_To_Direct_Value()
  88. {
  89. var target = new PriorityValue("Test", typeof(string));
  90. var source = new BehaviorSubject<object>("initial");
  91. target.Add(source, 0);
  92. Assert.Equal("initial", target.Value);
  93. target.SetDirectValue("first", 0);
  94. Assert.Equal("first", target.Value);
  95. source.OnNext("second");
  96. Assert.Equal("second", target.Value);
  97. source.OnCompleted();
  98. Assert.Equal("first", target.Value);
  99. }
  100. [Fact]
  101. public void Binding_With_Lower_Priority_Has_Precedence()
  102. {
  103. var target = new PriorityValue("Test", typeof(string));
  104. target.Add(this.Single("foo"), 1);
  105. target.Add(this.Single("bar"), 0);
  106. target.Add(this.Single("baz"), 1);
  107. Assert.Equal("bar", target.Value);
  108. }
  109. [Fact]
  110. public void Later_Binding_With_Same_Priority_Should_Take_Precedence()
  111. {
  112. var target = new PriorityValue("Test", typeof(string));
  113. target.Add(this.Single("foo"), 1);
  114. target.Add(this.Single("bar"), 0);
  115. target.Add(this.Single("baz"), 0);
  116. target.Add(this.Single("qux"), 1);
  117. Assert.Equal("baz", target.Value);
  118. }
  119. [Fact]
  120. public void Changing_Binding_With_Lower_Priority_Should_Set_Not_Value()
  121. {
  122. var target = new PriorityValue("Test", typeof(string));
  123. var subject = new BehaviorSubject<string>("bar");
  124. target.Add(this.Single("foo"), 0);
  125. target.Add(subject, 1);
  126. Assert.Equal("foo", target.Value);
  127. subject.OnNext("baz");
  128. Assert.Equal("foo", target.Value);
  129. }
  130. [Fact]
  131. public void UnsetValue_Should_Fall_Back_To_Next_Binding()
  132. {
  133. var target = new PriorityValue("Test", typeof(string));
  134. var subject = new BehaviorSubject<object>("bar");
  135. target.Add(subject, 0);
  136. target.Add(this.Single("foo"), 1);
  137. Assert.Equal("bar", target.Value);
  138. subject.OnNext(PerspexProperty.UnsetValue);
  139. Assert.Equal("foo", target.Value);
  140. }
  141. [Fact]
  142. public void Adding_Value_Should_Call_OnNext()
  143. {
  144. var target = new PriorityValue("Test", typeof(string));
  145. bool called = false;
  146. target.Changed.Subscribe(value => called = value.Item1 == PerspexProperty.UnsetValue && (string)value.Item2 == "foo");
  147. target.Add(this.Single("foo"), 0);
  148. Assert.True(called);
  149. }
  150. [Fact]
  151. public void Changing_Value_Should_Call_OnNext()
  152. {
  153. var target = new PriorityValue("Test", typeof(string));
  154. var subject = new BehaviorSubject<object>("foo");
  155. bool called = false;
  156. target.Add(subject, 0);
  157. target.Changed.Subscribe(value => called = (string)value.Item1 == "foo" && (string)value.Item2 == "bar");
  158. subject.OnNext("bar");
  159. Assert.True(called);
  160. }
  161. [Fact]
  162. public void Disposing_A_Binding_Should_Revert_To_Next_Value()
  163. {
  164. var target = new PriorityValue("Test", typeof(string));
  165. target.Add(this.Single("foo"), 0);
  166. var disposable = target.Add(this.Single("bar"), 0);
  167. Assert.Equal("bar", target.Value);
  168. disposable.Dispose();
  169. Assert.Equal("foo", target.Value);
  170. }
  171. [Fact]
  172. public void Disposing_A_Binding_Should_Remove_BindingEntry()
  173. {
  174. var target = new PriorityValue("Test", typeof(string));
  175. target.Add(this.Single("foo"), 0);
  176. var disposable = target.Add(this.Single("bar"), 0);
  177. Assert.Equal(2, target.GetBindings().Count());
  178. disposable.Dispose();
  179. Assert.Equal(1, target.GetBindings().Count());
  180. }
  181. [Fact]
  182. public void Completing_A_Binding_Should_Revert_To_Previous_Binding()
  183. {
  184. var target = new PriorityValue("Test", typeof(string));
  185. var source = new BehaviorSubject<object>("bar");
  186. target.Add(this.Single("foo"), 0);
  187. target.Add(source, 0);
  188. Assert.Equal("bar", target.Value);
  189. source.OnCompleted();
  190. Assert.Equal("foo", target.Value);
  191. }
  192. [Fact]
  193. public void Completing_A_Binding_Should_Revert_To_Lower_Priority()
  194. {
  195. var target = new PriorityValue("Test", typeof(string));
  196. var source = new BehaviorSubject<object>("bar");
  197. target.Add(this.Single("foo"), 1);
  198. target.Add(source, 0);
  199. Assert.Equal("bar", target.Value);
  200. source.OnCompleted();
  201. Assert.Equal("foo", target.Value);
  202. }
  203. [Fact]
  204. public void Completing_A_Binding_Should_Remove_BindingEntry()
  205. {
  206. var target = new PriorityValue("Test", typeof(string));
  207. var subject = new BehaviorSubject<object>("bar");
  208. target.Add(this.Single("foo"), 0);
  209. target.Add(subject, 0);
  210. Assert.Equal(2, target.GetBindings().Count());
  211. subject.OnCompleted();
  212. Assert.Equal(1, target.GetBindings().Count());
  213. }
  214. [Fact]
  215. public void Direct_Value_Should_Be_Coerced()
  216. {
  217. var target = new PriorityValue("Test", typeof(int), x => Math.Min((int)x, 10));
  218. target.SetDirectValue(5, 0);
  219. Assert.Equal(5, target.Value);
  220. target.SetDirectValue(15, 0);
  221. Assert.Equal(10, target.Value);
  222. }
  223. [Fact]
  224. public void Bound_Value_Should_Be_Coerced()
  225. {
  226. var target = new PriorityValue("Test", typeof(int), x => Math.Min((int)x, 10));
  227. var source = new Subject<object>();
  228. target.Add(source, 0);
  229. source.OnNext(5);
  230. Assert.Equal(5, target.Value);
  231. source.OnNext(15);
  232. Assert.Equal(10, target.Value);
  233. }
  234. [Fact]
  235. public void Revalidate_Should_ReCoerce_Value()
  236. {
  237. var max = 10;
  238. var target = new PriorityValue("Test", typeof(int), x => Math.Min((int)x, max));
  239. var source = new Subject<object>();
  240. target.Add(source, 0);
  241. source.OnNext(5);
  242. Assert.Equal(5, target.Value);
  243. source.OnNext(15);
  244. Assert.Equal(10, target.Value);
  245. max = 12;
  246. target.Revalidate();
  247. Assert.Equal(12, target.Value);
  248. }
  249. /// <summary>
  250. /// Returns an observable that returns a single value but does not complete.
  251. /// </summary>
  252. /// <typeparam name="T">The type of the observable.</typeparam>
  253. /// <param name="value">The value.</param>
  254. /// <returns>The observable.</returns>
  255. private IObservable<T> Single<T>(T value)
  256. {
  257. return Observable.Never<T>().StartWith(value);
  258. }
  259. }
  260. }