TextBoxTests_DataValidation.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Linq;
  6. using Avalonia.Controls.Presenters;
  7. using Avalonia.Controls.Templates;
  8. using Avalonia.Data;
  9. using Avalonia.Headless;
  10. using Avalonia.Markup.Data;
  11. using Avalonia.Platform;
  12. using Avalonia.UnitTests;
  13. using Moq;
  14. using Xunit;
  15. namespace Avalonia.Controls.UnitTests
  16. {
  17. public class TextBoxTests_DataValidation
  18. {
  19. [Fact]
  20. public void Setter_Exceptions_Should_Set_Error_Pseudoclass()
  21. {
  22. using (UnitTestApplication.Start(Services))
  23. {
  24. var target = new TextBox
  25. {
  26. DataContext = new ExceptionTest(),
  27. [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay),
  28. Template = CreateTemplate(),
  29. };
  30. target.ApplyTemplate();
  31. Assert.DoesNotContain(":error", target.Classes);
  32. target.Text = "20";
  33. Assert.Contains(":error", target.Classes);
  34. target.Text = "1";
  35. Assert.DoesNotContain(":error", target.Classes);
  36. }
  37. }
  38. [Fact]
  39. public void Setter_Exceptions_Should_Set_DataValidationErrors_Errors()
  40. {
  41. using (UnitTestApplication.Start(Services))
  42. {
  43. var target = new TextBox
  44. {
  45. DataContext = new ExceptionTest(),
  46. [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay),
  47. Template = CreateTemplate(),
  48. };
  49. target.ApplyTemplate();
  50. Assert.Null(DataValidationErrors.GetErrors(target));
  51. target.Text = "20";
  52. IEnumerable<object> errors = DataValidationErrors.GetErrors(target);
  53. Assert.Single(errors);
  54. Assert.IsType<InvalidOperationException>(errors.Single());
  55. target.Text = "1";
  56. Assert.Null(DataValidationErrors.GetErrors(target));
  57. }
  58. }
  59. [Fact]
  60. public void Setter_Exceptions_Should_Set_DataValidationErrors_HasErrors()
  61. {
  62. using (UnitTestApplication.Start(Services))
  63. {
  64. var target = new TextBox
  65. {
  66. DataContext = new ExceptionTest(),
  67. [!TextBox.TextProperty] = new Binding(nameof(ExceptionTest.LessThan10), BindingMode.TwoWay),
  68. Template = CreateTemplate(),
  69. };
  70. target.ApplyTemplate();
  71. Assert.False(DataValidationErrors.GetHasErrors(target));
  72. target.Text = "20";
  73. Assert.True(DataValidationErrors.GetHasErrors(target));
  74. target.Text = "1";
  75. Assert.False(DataValidationErrors.GetHasErrors(target));
  76. }
  77. }
  78. private static TestServices Services => TestServices.MockThreadingInterface.With(
  79. standardCursorFactory: Mock.Of<ICursorFactory>(),
  80. textShaperImpl: new HeadlessTextShaperStub(),
  81. fontManagerImpl: new HeadlessFontManagerStub());
  82. private static IControlTemplate CreateTemplate()
  83. {
  84. return new FuncControlTemplate<TextBox>((control, scope) =>
  85. new TextPresenter
  86. {
  87. Name = "PART_TextPresenter",
  88. [!!TextPresenter.TextProperty] = new Binding
  89. {
  90. Path = "Text",
  91. Mode = BindingMode.TwoWay,
  92. Priority = BindingPriority.Template,
  93. RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
  94. },
  95. }.RegisterInNameScope(scope));
  96. }
  97. private class ExceptionTest
  98. {
  99. private int _lessThan10;
  100. public int LessThan10
  101. {
  102. get { return _lessThan10; }
  103. set
  104. {
  105. if (value < 10)
  106. {
  107. _lessThan10 = value;
  108. }
  109. else
  110. {
  111. throw new InvalidOperationException("More than 10.");
  112. }
  113. }
  114. }
  115. }
  116. private class IndeiTest : INotifyDataErrorInfo
  117. {
  118. private int _lessThan10;
  119. private Dictionary<string, IList<string>> _errors = new Dictionary<string, IList<string>>();
  120. public int LessThan10
  121. {
  122. get { return _lessThan10; }
  123. set
  124. {
  125. if (value < 10)
  126. {
  127. _lessThan10 = value;
  128. _errors.Remove(nameof(LessThan10));
  129. ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(LessThan10)));
  130. }
  131. else
  132. {
  133. _errors[nameof(LessThan10)] = new[] { "More than 10" };
  134. ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(LessThan10)));
  135. }
  136. }
  137. }
  138. public bool HasErrors => _lessThan10 >= 10;
  139. public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
  140. public IEnumerable GetErrors(string propertyName)
  141. {
  142. IList<string> result;
  143. _errors.TryGetValue(propertyName, out result);
  144. return result;
  145. }
  146. }
  147. }
  148. }