PriorityValueTests.cs 10 KB

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