A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

194 lines
5.5 KiB

using System;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Data.Core;
using Avalonia.UnitTests;
using Xunit;
#nullable enable
namespace Avalonia.Base.UnitTests.Data.Core;
public abstract partial class BindingExpressionTests
{
[Fact]
public void Should_Get_Source_Value()
{
var data = "foo";
var target = CreateTargetWithSource(data, o => o);
Assert.Equal("foo", target.String);
GC.KeepAlive(data);
}
[Fact]
public void Should_Convert_String_To_Double()
{
var data = new ViewModel { StringValue = $"{5.6}" };
var target = CreateTargetWithSource(
data,
o => o.StringValue,
targetProperty: TargetClass.DoubleProperty);
Assert.Equal(5.6, target.Double);
GC.KeepAlive(data);
}
[Fact]
public void Should_Convert_Double_To_String()
{
var data = new ViewModel { DoubleValue = 5.6 };
var target = CreateTargetWithSource(
data,
o => o.DoubleValue,
targetProperty: TargetClass.StringProperty);
Assert.Equal($"{5.6}", target.String);
GC.KeepAlive(data);
}
[Fact]
public void Should_Use_FallbackValue_For_NonConvertible_Target_Value()
{
var data = new ViewModel { StringValue = "foo" };
var target = CreateTargetWithSource(
data,
o => o.StringValue,
fallbackValue: 42,
targetProperty: TargetClass.IntProperty);
Assert.Equal(42, target.Int);
GC.KeepAlive(data);
}
[Fact]
public void Should_Pass_ConverterParameter_To_Converter()
{
var data = new ViewModel { DoubleValue = 5.6 };
var converter = new PrefixConverter();
var target = CreateTargetWithSource(
data,
o => o.DoubleValue,
converter: converter,
converterParameter: "foo",
targetProperty: TargetClass.StringProperty);
Assert.Equal("foo5.6", target.String);
}
[Fact]
public void TargetNullValue_Should_Be_Used_When_Source_String_Is_Null()
{
var data = new ViewModel { StringValue = "foo" };
var target = CreateTargetWithSource(
data,
o => o.StringValue,
targetNullValue: "bar");
Assert.Equal("foo", target.String);
data.StringValue = null;
Assert.Equal("bar", target.String);
GC.KeepAlive(data);
}
[Fact]
public void TargetNullValue_Should_Be_Used_When_Source_Is_Data_Context_And_Null()
{
var target = CreateTarget<string?, string?>(
o => o,
targetNullValue: "bar");
Assert.Equal("bar", target.String);
}
[Fact]
public void Can_Use_UpdateTarget_To_Update_From_Non_INPC_Data()
{
var data = new PodViewModel { StringValue = "foo" };
var (target, expression) = CreateTargetAndExpression<PodViewModel, string?>(
o => o.StringValue,
source: data);
Assert.Equal("foo", target.String);
data.StringValue = "bar";
Assert.Equal("foo", target.String);
expression.UpdateTarget();
Assert.Equal("bar", target.String);
}
[Fact]
public void Should_Use_Converter_For_RelativeSource_Self_Binding_With_No_Path()
{
var converter = new PrefixConverter();
var target = CreateTarget<TargetClass, TargetClass>(
o => o,
converter: converter,
converterParameter: "foo",
relativeSource: new RelativeSource(RelativeSourceMode.Self),
targetProperty: TargetClass.StringProperty);
Assert.Equal("fooTargetClass", target.String);
}
[Fact]
public void Should_Not_Pass_UnsetValue_To_Converter_Until_First_Value_Produced()
{
var data = new ViewModel { StringValue = "Bar" };
var converter = new PrefixConverter();
var target = CreateTarget<ViewModel, string?>(
o => o.StringValue,
converter: converter,
converterParameter: "foo");
Assert.Null(target.String);
target.DataContext = data;
Assert.Equal("fooBar", target.String);
}
[Fact]
public void Should_Use_Converter_For_Null_DataContext_Without_Path()
{
var converter = new PrefixConverter();
var target = CreateTarget<string?, string?>(
o => o,
converter: converter,
converterParameter: "foo");
Assert.Equal("foo", target.String);
}
[Fact]
public void LeafNode_Should_Be_Null_When_Nodes_List_Is_Empty()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
// Reproduces issue #20441
// Create a binding expression with no nodes (e.g., {Binding Source='Elements', Converter={...}})
var bindingExpression = new BindingExpression(
source: "Elements",
nodes: null, // This results in an empty nodes list
fallbackValue: AvaloniaProperty.UnsetValue,
converter: new PrefixConverter("Prefix"),
mode: BindingMode.OneWay,
targetProperty: TargetClass.StringProperty,
targetTypeConverter: TargetTypeConverter.GetReflectionConverter());
// These should not throw
var leafNode = bindingExpression.LeafNode;
var description = bindingExpression.Description;
// LeafNode should be null when there are no nodes
Assert.Null(leafNode);
}
}
}