RangeBaseTests.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. using System;
  2. using System.ComponentModel;
  3. using System.Security.Cryptography.X509Certificates;
  4. using Avalonia.Controls.Primitives;
  5. using Avalonia.Controls.Templates;
  6. using Avalonia.Data;
  7. using Avalonia.Layout;
  8. using Avalonia.Markup.Data;
  9. using Avalonia.Styling;
  10. using Avalonia.UnitTests;
  11. using Xunit;
  12. namespace Avalonia.Controls.UnitTests.Primitives
  13. {
  14. public class RangeBaseTests : ScopedTestBase
  15. {
  16. [Fact]
  17. public void Maximum_Should_Be_Coerced_To_Minimum()
  18. {
  19. var target = new TestRange
  20. {
  21. Minimum = 100,
  22. Maximum = 50,
  23. };
  24. var root = new TestRoot(target);
  25. Assert.Equal(100, target.Minimum);
  26. Assert.Equal(100, target.Maximum);
  27. }
  28. [Fact]
  29. public void ChangingDataContextShouldNotChangeOldDataContext()
  30. {
  31. var viewModel = new RangeTestViewModel()
  32. {
  33. Minimum = -5000,
  34. Maximum = 5000,
  35. Value = 4000
  36. };
  37. var target = new TestRange
  38. {
  39. [!RangeBase.MinimumProperty] = new Binding(nameof(viewModel.Minimum)),
  40. [!RangeBase.MaximumProperty] = new Binding(nameof(viewModel.Maximum)),
  41. [!RangeBase.ValueProperty] = new Binding(nameof(viewModel.Value)),
  42. };
  43. var root = new TestRoot(target);
  44. target.DataContext = viewModel;
  45. target.DataContext = null;
  46. Assert.Equal(4000, viewModel.Value);
  47. Assert.Equal(-5000, viewModel.Minimum);
  48. Assert.Equal(5000, viewModel.Maximum);
  49. }
  50. [Fact]
  51. public void Value_Should_Be_Coerced_To_Range()
  52. {
  53. var target = new TestRange
  54. {
  55. Minimum = 0,
  56. Maximum = 50,
  57. Value = 100,
  58. };
  59. var root = new TestRoot(target);
  60. Assert.Equal(0, target.Minimum);
  61. Assert.Equal(50, target.Maximum);
  62. Assert.Equal(50, target.Value);
  63. }
  64. [Fact]
  65. public void Changing_Minimum_Should_Coerce_Value_And_Maximum()
  66. {
  67. var target = new TestRange
  68. {
  69. Minimum = 0,
  70. Maximum = 100,
  71. Value = 50,
  72. };
  73. var root = new TestRoot(target);
  74. target.Minimum = 200;
  75. Assert.Equal(200, target.Minimum);
  76. Assert.Equal(200, target.Maximum);
  77. Assert.Equal(200, target.Value);
  78. }
  79. [Fact]
  80. public void Changing_Maximum_Should_Coerce_Value()
  81. {
  82. var target = new TestRange
  83. {
  84. Minimum = 0,
  85. Maximum = 100,
  86. Value = 100,
  87. };
  88. var root = new TestRoot(target);
  89. target.Maximum = 50;
  90. Assert.Equal(0, target.Minimum);
  91. Assert.Equal(50, target.Maximum);
  92. Assert.Equal(50, target.Value);
  93. }
  94. [Theory]
  95. [InlineData(true)]
  96. [InlineData(false)]
  97. public void SetValue_Should_Not_Cause_StackOverflow(bool useXamlBinding)
  98. {
  99. var viewModel = new TestStackOverflowViewModel()
  100. {
  101. Value = 50
  102. };
  103. Track track = null;
  104. var target = new TestRange()
  105. {
  106. Template = new FuncControlTemplate<RangeBase>((c, scope) =>
  107. {
  108. track = new Track()
  109. {
  110. Width = 100,
  111. Orientation = Orientation.Horizontal,
  112. [~~Track.MinimumProperty] = c[~~RangeBase.MinimumProperty],
  113. [~~Track.MaximumProperty] = c[~~RangeBase.MaximumProperty],
  114. Name = "PART_Track",
  115. Thumb = new Thumb()
  116. }.RegisterInNameScope(scope);
  117. if (useXamlBinding)
  118. {
  119. track.Bind(Track.ValueProperty, new Binding("Value")
  120. {
  121. Mode = BindingMode.TwoWay,
  122. Source = c,
  123. Priority = BindingPriority.Style
  124. });
  125. }
  126. else
  127. {
  128. track[~~Track.ValueProperty] = c[~~RangeBase.ValueProperty];
  129. }
  130. return track;
  131. }),
  132. Minimum = 0,
  133. Maximum = 100,
  134. DataContext = viewModel
  135. };
  136. target.Bind(TestRange.ValueProperty, new Binding("Value") { Mode = BindingMode.TwoWay });
  137. target.ApplyTemplate();
  138. track.Measure(new Size(100, 0));
  139. track.Arrange(new Rect(0, 0, 100, 0));
  140. Assert.Equal(1, viewModel.SetterInvokedCount);
  141. // Issues #855 and #824 were causing a StackOverflowException at this point.
  142. target.Value = 51.001;
  143. Assert.Equal(2, viewModel.SetterInvokedCount);
  144. double expected = 51;
  145. Assert.Equal(expected, viewModel.Value);
  146. Assert.Equal(expected, target.Value);
  147. Assert.Equal(expected, track.Value);
  148. }
  149. [Fact]
  150. public void Coercion_Should_Not_Be_Done_During_Initialization()
  151. {
  152. var target = new TestRange();
  153. target.BeginInit();
  154. var root = new TestRoot(target);
  155. target.Minimum = 1;
  156. Assert.Equal(0, target.Value);
  157. target.Value = 50;
  158. target.EndInit();
  159. Assert.Equal(50, target.Value);
  160. }
  161. [Fact]
  162. public void Coercion_Should_Be_Done_After_Initialization()
  163. {
  164. var target = new TestRange();
  165. target.BeginInit();
  166. var root = new TestRoot(target);
  167. target.Minimum = 1;
  168. target.EndInit();
  169. Assert.Equal(1, target.Value);
  170. }
  171. private class TestRange : RangeBase
  172. {
  173. }
  174. private class TestStackOverflowViewModel : INotifyPropertyChanged
  175. {
  176. public int SetterInvokedCount { get; private set; }
  177. public const int MaxInvokedCount = 1000;
  178. private double _value;
  179. public event PropertyChangedEventHandler PropertyChanged;
  180. public double Value
  181. {
  182. get { return _value; }
  183. set
  184. {
  185. if (_value != value)
  186. {
  187. SetterInvokedCount++;
  188. if (SetterInvokedCount < MaxInvokedCount)
  189. {
  190. _value = (int)value;
  191. if (_value > 75) _value = 75;
  192. if (_value < 25) _value = 25;
  193. }
  194. else
  195. {
  196. _value = value;
  197. }
  198. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
  199. }
  200. }
  201. }
  202. }
  203. private class RangeTestViewModel
  204. {
  205. public double Minimum { get; set; }
  206. public double Maximum { get; set; }
  207. public double Value { get; set; }
  208. }
  209. }
  210. }