ExpressionObserverBuilderTests_Negation.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using System;
  2. using System.Collections;
  3. using System.ComponentModel;
  4. using System.Reactive.Linq;
  5. using System.Threading.Tasks;
  6. using Avalonia.Data;
  7. using Avalonia.Markup.Parsers;
  8. using Xunit;
  9. namespace Avalonia.Markup.UnitTests.Parsers
  10. {
  11. public class ExpressionObserverBuilderTests_Negation
  12. {
  13. [Fact]
  14. public async Task Should_Negate_0()
  15. {
  16. var data = new { Foo = 0 };
  17. var target = ExpressionObserverBuilder.Build(data, "!Foo");
  18. var result = await target.Take(1);
  19. Assert.True((bool)result);
  20. GC.KeepAlive(data);
  21. }
  22. [Fact]
  23. public async Task Should_Negate_1()
  24. {
  25. var data = new { Foo = 1 };
  26. var target = ExpressionObserverBuilder.Build(data, "!Foo");
  27. var result = await target.Take(1);
  28. Assert.False((bool)result);
  29. GC.KeepAlive(data);
  30. }
  31. [Fact]
  32. public async Task Should_Negate_False_String()
  33. {
  34. var data = new { Foo = "false" };
  35. var target = ExpressionObserverBuilder.Build(data, "!Foo");
  36. var result = await target.Take(1);
  37. Assert.True((bool)result);
  38. GC.KeepAlive(data);
  39. }
  40. [Fact]
  41. public async Task Should_Negate_True_String()
  42. {
  43. var data = new { Foo = "True" };
  44. var target = ExpressionObserverBuilder.Build(data, "!Foo");
  45. var result = await target.Take(1);
  46. Assert.False((bool)result);
  47. GC.KeepAlive(data);
  48. }
  49. [Fact]
  50. public async Task Should_Return_BindingNotification_For_String_Not_Convertible_To_Boolean()
  51. {
  52. var data = new { Foo = "foo" };
  53. var target = ExpressionObserverBuilder.Build(data, "!Foo");
  54. var result = await target.Take(1);
  55. Assert.Equal(
  56. new BindingNotification(
  57. new InvalidCastException($"Unable to convert 'foo' to bool."),
  58. BindingErrorType.Error),
  59. result);
  60. GC.KeepAlive(data);
  61. }
  62. [Fact]
  63. public async Task Should_Return_BindingNotification_For_Value_Not_Convertible_To_Boolean()
  64. {
  65. var data = new { Foo = new object() };
  66. var target = ExpressionObserverBuilder.Build(data, "!Foo");
  67. var result = await target.Take(1);
  68. Assert.Equal(
  69. new BindingNotification(
  70. new InvalidCastException($"Unable to convert 'System.Object' to bool."),
  71. BindingErrorType.Error),
  72. result);
  73. GC.KeepAlive(data);
  74. }
  75. [Fact]
  76. public async Task Should_Negate_BindingNotification_Value()
  77. {
  78. var data = new { Foo = true };
  79. var target = ExpressionObserverBuilder.Build(data, "!Foo", enableDataValidation: true);
  80. var result = await target.Take(1);
  81. Assert.Equal(new BindingNotification(false), result);
  82. GC.KeepAlive(data);
  83. }
  84. [Fact]
  85. public async Task Should_Pass_Through_BindingNotification_Error()
  86. {
  87. var data = new { };
  88. var target = ExpressionObserverBuilder.Build(data, "!Foo", enableDataValidation: true);
  89. var result = await target.Take(1);
  90. Assert.Equal(
  91. new BindingNotification(
  92. new MissingMemberException("Could not find a matching property accessor for 'Foo' on '{ }'"),
  93. BindingErrorType.Error),
  94. result);
  95. GC.KeepAlive(data);
  96. }
  97. [Fact]
  98. public async Task Should_Negate_BindingNotification_Error_FallbackValue()
  99. {
  100. var data = new Test { DataValidationError = "Test error" };
  101. var target = ExpressionObserverBuilder.Build(data, "!Foo", enableDataValidation: true);
  102. var result = await target.Take(1);
  103. Assert.Equal(
  104. new BindingNotification(
  105. new DataValidationException("Test error"),
  106. BindingErrorType.DataValidationError,
  107. true),
  108. result);
  109. GC.KeepAlive(data);
  110. }
  111. [Fact]
  112. public async Task Should_Add_Error_To_BindingNotification_For_FallbackValue_Not_Convertible_To_Boolean()
  113. {
  114. var data = new Test { Bar = new object(), DataValidationError = "Test error" };
  115. var target = ExpressionObserverBuilder.Build(data, "!Bar", enableDataValidation: true);
  116. var result = await target.Take(1);
  117. Assert.Equal(
  118. new BindingNotification(
  119. new AggregateException(
  120. new DataValidationException("Test error"),
  121. new InvalidCastException($"Unable to convert 'System.Object' to bool.")),
  122. BindingErrorType.Error),
  123. result);
  124. GC.KeepAlive(data);
  125. }
  126. [Fact]
  127. public void SetValue_Should_Return_False_For_Invalid_Value()
  128. {
  129. var data = new { Foo = "foo" };
  130. var target = ExpressionObserverBuilder.Build(data, "!Foo");
  131. target.Subscribe(_ => { });
  132. Assert.False(target.SetValue("bar"));
  133. GC.KeepAlive(data);
  134. }
  135. private class Test : INotifyDataErrorInfo
  136. {
  137. private string _dataValidationError;
  138. public bool Foo { get; set; }
  139. public object Bar { get; set; }
  140. public string DataValidationError
  141. {
  142. get => _dataValidationError;
  143. set
  144. {
  145. if (value == _dataValidationError)
  146. return;
  147. _dataValidationError = value;
  148. ErrorsChanged?
  149. .Invoke(this, new DataErrorsChangedEventArgs(nameof(DataValidationError)));
  150. }
  151. }
  152. public bool HasErrors => !string.IsNullOrWhiteSpace(DataValidationError);
  153. public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
  154. public IEnumerable GetErrors(string propertyName)
  155. {
  156. return DataValidationError is object ? new[] { DataValidationError } : null;
  157. }
  158. }
  159. }
  160. }