TextBoxTests_DataValidation.cs 5.6 KB

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