#nullable enable using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Globalization; using System.Linq; using System.Reactive.Subjects; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Xml; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Data.Converters; using Avalonia.Data.Core; using Avalonia.Input; using Avalonia.Markup.Data; using Avalonia.Markup.Xaml.MarkupExtensions; using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings; using Avalonia.Markup.Xaml.Templates; using Avalonia.Media; using Avalonia.Media.Immutable; using Avalonia.Metadata; using Avalonia.UnitTests; using Xunit; namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions { public class CompiledBindingExtensionTests { static CompiledBindingExtensionTests() { RuntimeHelpers.RunClassConstructor(typeof(RelativeSource).TypeHandle); } [Fact] public void ResolvesClrPropertyBasedOnDataContextType() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext { StringProperty = "foobar" }; window.DataContext = dataContext; Assert.Equal(dataContext.StringProperty, textBlock.Text); } } [Fact] public void ResolvesClrPropertyBasedOnDataContextType_InterfaceInheritance() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext { StringProperty = "foobar" }; window.DataContext = dataContext; Assert.Equal(dataContext.StringProperty, textBlock.Text); } } [Fact] public void ResolvesPathPassedByProperty() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext { StringProperty = "foobar" }; window.DataContext = dataContext; Assert.Equal(dataContext.StringProperty, textBlock.Text); } } [Fact] public void ResolvesPathPassedByPropertyWithInnerItemTemplate() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("itemsControl"); var dataContext = new TestDataContext { ListProperty = { "Hello" } }; window.DataContext = dataContext; Assert.Equal(dataContext.ListProperty, textBlock.ItemsSource); } } [Fact] public void ResolvesStaticClrPropertyBased() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); textBlock.DataContext = new TestDataContext(); Assert.Equal(TestDataContext.StaticProperty, textBlock.Text); } } [Fact] public void ResolvesDataTypeFromBindingProperty() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext { StringProperty = "foobar" }; window.DataContext = dataContext; Assert.Equal(dataContext.StringProperty, textBlock.Text); } } [Fact] public void ResolvesDataTypeFromBindingProperty_TypeExtension() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext { StringProperty = "foobar" }; window.DataContext = dataContext; Assert.Equal(dataContext.StringProperty, textBlock.Text); } } [Fact] public void ResolvesStreamTaskBindingCorrectly() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext { TaskProperty = Task.FromResult("foobar") }; window.DataContext = dataContext; Assert.Equal(dataContext.TaskProperty.Result, textBlock.Text); } } [Fact] public void ResolvesStreamObservableBindingCorrectly() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); DelayedBinding.ApplyBindings(textBlock); var subject = new Subject(); var dataContext = new TestDataContext { ObservableProperty = subject }; window.DataContext = dataContext; subject.OnNext("foobar"); Assert.Equal("foobar", textBlock.Text); } } [Fact] public void ResolvesIndexerBindingCorrectly() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext { ListProperty = { "A", "B", "C", "D", "E" } }; window.DataContext = dataContext; Assert.Equal(dataContext.ListProperty[3], textBlock.Text); } } [Fact] public void ResolvesArrayIndexerBindingCorrectly() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext { ArrayProperty = new[] { "A", "B", "C", "D", "E" } }; window.DataContext = dataContext; Assert.Equal(dataContext.ArrayProperty[3], textBlock.Text); } } [Fact] public void ResolvesObservableIndexerBindingCorrectly() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext { ObservableCollectionProperty = { "A", "B", "C", "D", "E" } }; window.DataContext = dataContext; Assert.Equal(dataContext.ObservableCollectionProperty[3], textBlock.Text); dataContext.ObservableCollectionProperty[3] = "New Value"; Assert.Equal(dataContext.ObservableCollectionProperty[3], textBlock.Text); } } [Fact] public void InfersCompiledBindingDataContextFromDataContextBinding() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); window.ApplyTemplate(); window.Presenter!.ApplyTemplate(); var dataContext = new TestDataContext { StringProperty = "A" }; window.DataContext = dataContext; Assert.Equal(dataContext.StringProperty, textBlock.Text); } } [Fact] public void ResolvesNonIntegerIndexerBindingCorrectly() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext(); dataContext.NonIntegerIndexerProperty["Test"] = "Initial Value"; window.DataContext = dataContext; Assert.Equal(dataContext.NonIntegerIndexerProperty["Test"], textBlock.Text); dataContext.NonIntegerIndexerProperty["Test"] = "New Value"; Assert.Equal(dataContext.NonIntegerIndexerProperty["Test"], textBlock.Text); } } [Fact] public void ResolvesNonIntegerIndexerBindingFromParentInterfaceCorrectly() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("textBlock"); var dataContext = new TestDataContext(); dataContext.NonIntegerIndexerInterfaceProperty["Test"] = "Initial Value"; window.DataContext = dataContext; Assert.Equal(dataContext.NonIntegerIndexerInterfaceProperty["Test"], textBlock.Text); dataContext.NonIntegerIndexerInterfaceProperty["Test"] = "New Value"; Assert.Equal(dataContext.NonIntegerIndexerInterfaceProperty["Test"], textBlock.Text); } } [Fact] public void InfersDataTemplateTypeFromDataTypeProperty() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var target = window.GetControl("target"); var dataContext = new TestDataContext(); dataContext.StringProperty = "Initial Value"; window.DataContext = dataContext; window.ApplyTemplate(); target.ApplyTemplate(); target.Presenter!.UpdateChild(); Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text); } } [Fact] public void ThrowsOnUninferrableLooseDataTemplateNoDataTypeWithCompiledBindingPath() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; Assert.ThrowsAny(() => AvaloniaRuntimeXamlLoader.Load(xaml)); } } [Fact] public void ThrowsOnUninferrableDataTypeFromNonCompiledDataContextBindingWithCompiledBindingPath() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; Assert.ThrowsAny(() => AvaloniaRuntimeXamlLoader.Load(xaml)); } } [Fact] public void ReportsMultipleErrorsOnDataContextAndBindingPathErrors() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var ex = Assert.Throws(() => AvaloniaRuntimeXamlLoader.Load(xaml)); Assert.Collection( ex.InnerExceptions, inner => Assert.IsAssignableFrom(inner), inner => Assert.IsAssignableFrom(inner), inner => Assert.IsAssignableFrom(inner)); } } [Fact] public void InfersDataTemplateTypeFromParentCollectionItemsType() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var target = window.GetControl("target"); var dataContext = new TestDataContext(); dataContext.ListProperty.Add("Test"); window.DataContext = dataContext; window.ApplyTemplate(); target.ApplyTemplate(); target.Presenter!.ApplyTemplate(); Assert.Equal(dataContext.ListProperty[0], (string?)((ContentPresenter)target.Presenter.Panel!.Children[0]).Content); } } [Fact] public void InfersDataTemplateTypeFromParentDataGridItemsType() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var window = (Window)AvaloniaRuntimeXamlLoader.Load(@" "); var target = window.GetControl("target"); var column = target.Columns.Single(); var dataContext = new TestDataContext(); dataContext.ListProperty.Add("Test"); window.DataContext = dataContext; window.ApplyTemplate(); target.ApplyTemplate(); // Assert DataGridLikeColumn.Binding data type. var compiledPath = ((CompiledBindingExtension)column.Binding!).Path; var node = Assert.IsType(Assert.Single(compiledPath.Elements)); Assert.Equal(typeof(int), node.Property.PropertyType); // Assert DataGridLikeColumn.Template data type by evaluating the template. var firstItem = dataContext.ListProperty[0]; var textBlockFromTemplate = (TextBlock)column.Template!.Build(firstItem)!; textBlockFromTemplate.DataContext = firstItem; Assert.Equal(firstItem.Length.ToString(), textBlockFromTemplate.Text); } } [Fact] public void ExplicitDataTypeStillWorksOnDataGridLikeControls() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var window = (Window)AvaloniaRuntimeXamlLoader.Load(@" "); var target = window.GetControl("target"); var column = target.Columns.Single(); var dataContext = new TestDataContext(); dataContext.ListProperty.Add("Test"); target.Items = dataContext.ListProperty; window.ApplyTemplate(); target.ApplyTemplate(); // Assert DataGridLikeColumn.Binding data type. var compiledPath = ((CompiledBindingExtension)column.Binding!).Path; var node = Assert.IsType(Assert.Single(compiledPath.Elements)); Assert.Equal(typeof(int), node.Property.PropertyType); // Assert DataGridLikeColumn.Template data type by evaluating the template. var firstItem = dataContext.ListProperty[0]; var textBlockFromTemplate = (TextBlock)column.Template!.Build(firstItem)!; textBlockFromTemplate.DataContext = firstItem; Assert.Equal(firstItem.Length.ToString(), textBlockFromTemplate.Text); } } [Fact] public void ThrowsOnUninferrableDataTemplateInItemsControlWithoutItemsBinding() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; Assert.ThrowsAny(() => AvaloniaRuntimeXamlLoader.Load(xaml)); } } [Fact] public void IgnoresDataTemplateTypeFromDataTypePropertyIfXDataTypeDefined() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var target = window.GetControl("target"); var dataContext = new TestDataContext(); dataContext.StringProperty = "Initial Value"; window.DataContext = dataContext; window.ApplyTemplate(); target.ApplyTemplate(); target.Presenter!.UpdateChild(); Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text); } } [Fact] public void InfersCustomDataTemplateBasedOnAttribute() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var target = window.GetControl("target"); var dataContext = new TestDataContext(); dataContext.StringProperty = "Initial Value"; window.DataContext = dataContext; window.ApplyTemplate(); target.ApplyTemplate(); target.Presenter!.UpdateChild(); Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text); } } [Fact] public void InfersCustomDataTemplateBasedOnAttributeFromBaseClass() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var target = window.GetControl("target"); var dataContext = new TestDataContext(); dataContext.StringProperty = "Initial Value"; window.DataContext = dataContext; window.ApplyTemplate(); target.ApplyTemplate(); target.Presenter!.UpdateChild(); Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text); } } [Fact] public void ResolvesElementNameBinding() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("text2"); var dataContext = new TestDataContext { StringProperty = "foobar" }; window.DataContext = dataContext; Assert.Equal(dataContext.StringProperty, textBlock.Text); } } [Fact] public void ResolvesElementNameBindingFromLongForm() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("text2"); var dataContext = new TestDataContext { StringProperty = "foobar" }; window.DataContext = dataContext; Assert.Equal(dataContext.StringProperty, textBlock.Text); } } [Fact] public void ResolvesElementNameBindingFromLongFormWithoutPath() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var textBlock = window.GetControl("text2"); Assert.Equal("Avalonia.Controls.TextBlock", textBlock.Text); } } [Fact] public void ResolvesRelativeSourceBindingLongForm() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var target = window.GetControl("text"); window.ApplyTemplate(); window.Presenter!.ApplyTemplate(); target.ApplyTemplate(); Assert.Equal("test", target.Text); } } [Fact] public void ResolvesRelativeSourceBindingEvenLongerForm() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var target = window.GetControl("text"); window.ApplyTemplate(); window.Presenter!.ApplyTemplate(); target.ApplyTemplate(); //Assert.Equal("test", target.Text); } } [Fact] public void ResolvesRelativeSourceBindingFromTemplate() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var contentControl = AvaloniaRuntimeXamlLoader.Parse(xaml); contentControl.DataContext = new TestDataContext(); // should be ignored contentControl.Measure(new Size(10, 10)); var result = contentControl.GetTemplateChildren().OfType().First(); Assert.Equal(false, result.Focusable); } } [Fact] public void ResolvesRelativeSourceBindingFromStyleSelector() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var textBox = AvaloniaRuntimeXamlLoader.Parse(xaml); textBox.DataContext = new TestDataContext(); // should be ignored textBox.Measure(new Size(10, 10)); var result = textBox.GetTemplateChildren().OfType().First(); Assert.Equal(textBox.InnerLeftContent, result.Content); } } [Fact] public void Binds_To_TemplatedParent_From_Non_Control() { using (UnitTestApplication.Start(TestServices.StyledWindow)) { var xaml = @" "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var button = window.FindControl