1
0

BindingExpressionTests.GetValue.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. using System;
  2. using Avalonia.Data;
  3. using Avalonia.Data.Converters;
  4. using Avalonia.Data.Core;
  5. using Avalonia.UnitTests;
  6. using Xunit;
  7. #nullable enable
  8. namespace Avalonia.Base.UnitTests.Data.Core;
  9. public abstract partial class BindingExpressionTests
  10. {
  11. [Fact]
  12. public void Should_Get_Source_Value()
  13. {
  14. var data = "foo";
  15. var target = CreateTargetWithSource(data, o => o);
  16. Assert.Equal("foo", target.String);
  17. GC.KeepAlive(data);
  18. }
  19. [Fact]
  20. public void Should_Convert_String_To_Double()
  21. {
  22. var data = new ViewModel { StringValue = $"{5.6}" };
  23. var target = CreateTargetWithSource(
  24. data,
  25. o => o.StringValue,
  26. targetProperty: TargetClass.DoubleProperty);
  27. Assert.Equal(5.6, target.Double);
  28. GC.KeepAlive(data);
  29. }
  30. [Fact]
  31. public void Should_Convert_Double_To_String()
  32. {
  33. var data = new ViewModel { DoubleValue = 5.6 };
  34. var target = CreateTargetWithSource(
  35. data,
  36. o => o.DoubleValue,
  37. targetProperty: TargetClass.StringProperty);
  38. Assert.Equal($"{5.6}", target.String);
  39. GC.KeepAlive(data);
  40. }
  41. [Fact]
  42. public void Should_Use_FallbackValue_For_NonConvertible_Target_Value()
  43. {
  44. var data = new ViewModel { StringValue = "foo" };
  45. var target = CreateTargetWithSource(
  46. data,
  47. o => o.StringValue,
  48. fallbackValue: 42,
  49. targetProperty: TargetClass.IntProperty);
  50. Assert.Equal(42, target.Int);
  51. GC.KeepAlive(data);
  52. }
  53. [Fact]
  54. public void Should_Pass_ConverterParameter_To_Converter()
  55. {
  56. var data = new ViewModel { DoubleValue = 5.6 };
  57. var converter = new PrefixConverter();
  58. var target = CreateTargetWithSource(
  59. data,
  60. o => o.DoubleValue,
  61. converter: converter,
  62. converterParameter: "foo",
  63. targetProperty: TargetClass.StringProperty);
  64. Assert.Equal("foo5.6", target.String);
  65. }
  66. [Fact]
  67. public void TargetNullValue_Should_Be_Used_When_Source_String_Is_Null()
  68. {
  69. var data = new ViewModel { StringValue = "foo" };
  70. var target = CreateTargetWithSource(
  71. data,
  72. o => o.StringValue,
  73. targetNullValue: "bar");
  74. Assert.Equal("foo", target.String);
  75. data.StringValue = null;
  76. Assert.Equal("bar", target.String);
  77. GC.KeepAlive(data);
  78. }
  79. [Fact]
  80. public void TargetNullValue_Should_Be_Used_When_Source_Is_Data_Context_And_Null()
  81. {
  82. var target = CreateTarget<string?, string?>(
  83. o => o,
  84. targetNullValue: "bar");
  85. Assert.Equal("bar", target.String);
  86. }
  87. [Fact]
  88. public void Can_Use_UpdateTarget_To_Update_From_Non_INPC_Data()
  89. {
  90. var data = new PodViewModel { StringValue = "foo" };
  91. var (target, expression) = CreateTargetAndExpression<PodViewModel, string?>(
  92. o => o.StringValue,
  93. source: data);
  94. Assert.Equal("foo", target.String);
  95. data.StringValue = "bar";
  96. Assert.Equal("foo", target.String);
  97. expression.UpdateTarget();
  98. Assert.Equal("bar", target.String);
  99. }
  100. [Fact]
  101. public void Should_Use_Converter_For_RelativeSource_Self_Binding_With_No_Path()
  102. {
  103. var converter = new PrefixConverter();
  104. var target = CreateTarget<TargetClass, TargetClass>(
  105. o => o,
  106. converter: converter,
  107. converterParameter: "foo",
  108. relativeSource: new RelativeSource(RelativeSourceMode.Self),
  109. targetProperty: TargetClass.StringProperty);
  110. Assert.Equal("fooTargetClass", target.String);
  111. }
  112. [Fact]
  113. public void Should_Not_Pass_UnsetValue_To_Converter_Until_First_Value_Produced()
  114. {
  115. var data = new ViewModel { StringValue = "Bar" };
  116. var converter = new PrefixConverter();
  117. var target = CreateTarget<ViewModel, string?>(
  118. o => o.StringValue,
  119. converter: converter,
  120. converterParameter: "foo");
  121. Assert.Null(target.String);
  122. target.DataContext = data;
  123. Assert.Equal("fooBar", target.String);
  124. }
  125. [Fact]
  126. public void Should_Use_Converter_For_Null_DataContext_Without_Path()
  127. {
  128. var converter = new PrefixConverter();
  129. var target = CreateTarget<string?, string?>(
  130. o => o,
  131. converter: converter,
  132. converterParameter: "foo");
  133. Assert.Equal("foo", target.String);
  134. }
  135. [Fact]
  136. public void LeafNode_Should_Be_Null_When_Nodes_List_Is_Empty()
  137. {
  138. using (UnitTestApplication.Start(TestServices.StyledWindow))
  139. {
  140. // Reproduces issue #20441
  141. // Create a binding expression with no nodes (e.g., {Binding Source='Elements', Converter={...}})
  142. var bindingExpression = new BindingExpression(
  143. source: "Elements",
  144. nodes: null, // This results in an empty nodes list
  145. fallbackValue: AvaloniaProperty.UnsetValue,
  146. converter: new PrefixConverter("Prefix"),
  147. mode: BindingMode.OneWay,
  148. targetProperty: TargetClass.StringProperty,
  149. targetTypeConverter: TargetTypeConverter.GetReflectionConverter());
  150. // These should not throw
  151. var leafNode = bindingExpression.LeafNode;
  152. var description = bindingExpression.Description;
  153. // LeafNode should be null when there are no nodes
  154. Assert.Null(leafNode);
  155. }
  156. }
  157. }