| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- // Copyright (c) The Avalonia Project. All rights reserved.
- // Licensed under the MIT license. See licence.md file in the project root for full license information.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Avalonia.Controls;
- using Avalonia.Controls.Templates;
- using Avalonia.Diagnostics;
- using Avalonia.Layout;
- using Avalonia.Platform;
- using Avalonia.Rendering;
- using Avalonia.UnitTests;
- using Avalonia.VisualTree;
- using JetBrains.dotMemoryUnit;
- using Moq;
- using Xunit;
- using Xunit.Abstractions;
- namespace Avalonia.LeakTests
- {
- [DotMemoryUnit(FailIfRunWithoutSupport = false)]
- public class ControlTests
- {
- public ControlTests(ITestOutputHelper atr)
- {
- DotMemoryUnitTestOutput.SetOutputMethod(atr.WriteLine);
- }
- [Fact]
- public void Canvas_Is_Freed()
- {
- using (Start())
- {
- Func<Window> run = () =>
- {
- var window = new Window
- {
- Content = new Canvas()
- };
- window.Show();
- // Do a layout and make sure that Canvas gets added to visual tree.
- window.LayoutManager.ExecuteInitialLayoutPass(window);
- Assert.IsType<Canvas>(window.Presenter.Child);
- // Clear the content and ensure the Canvas is removed.
- window.Content = null;
- window.LayoutManager.ExecuteLayoutPass();
- Assert.Null(window.Presenter.Child);
- return window;
- };
- var result = run();
- dotMemory.Check(memory =>
- Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
- }
- }
- [Fact]
- public void Named_Canvas_Is_Freed()
- {
- using (Start())
- {
- Func<Window> run = () =>
- {
- var window = new Window
- {
- Content = new Canvas
- {
- Name = "foo"
- }
- };
- window.Show();
- // Do a layout and make sure that Canvas gets added to visual tree.
- window.LayoutManager.ExecuteInitialLayoutPass(window);
- Assert.IsType<Canvas>(window.Find<Canvas>("foo"));
- Assert.IsType<Canvas>(window.Presenter.Child);
- // Clear the content and ensure the Canvas is removed.
- window.Content = null;
- window.LayoutManager.ExecuteLayoutPass();
- Assert.Null(window.Presenter.Child);
- return window;
- };
- var result = run();
- dotMemory.Check(memory =>
- Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
- }
- }
- [Fact]
- public void ScrollViewer_With_Content_Is_Freed()
- {
- using (Start())
- {
- Func<Window> run = () =>
- {
- var window = new Window
- {
- Content = new ScrollViewer
- {
- Content = new Canvas()
- }
- };
- window.Show();
- // Do a layout and make sure that ScrollViewer gets added to visual tree and its
- // template applied.
- window.LayoutManager.ExecuteInitialLayoutPass(window);
- Assert.IsType<ScrollViewer>(window.Presenter.Child);
- Assert.IsType<Canvas>(((ScrollViewer)window.Presenter.Child).Presenter.Child);
- // Clear the content and ensure the ScrollViewer is removed.
- window.Content = null;
- window.LayoutManager.ExecuteLayoutPass();
- Assert.Null(window.Presenter.Child);
- return window;
- };
- var result = run();
- dotMemory.Check(memory =>
- Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TextBox>()).ObjectsCount));
- dotMemory.Check(memory =>
- Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Canvas>()).ObjectsCount));
- }
- }
- [Fact]
- public void TextBox_Is_Freed()
- {
- using (Start())
- {
- Func<Window> run = () =>
- {
- var window = new Window
- {
- Content = new TextBox()
- };
- window.Show();
- // Do a layout and make sure that TextBox gets added to visual tree and its
- // template applied.
- window.LayoutManager.ExecuteInitialLayoutPass(window);
- Assert.IsType<TextBox>(window.Presenter.Child);
- Assert.NotEqual(0, window.Presenter.Child.GetVisualChildren().Count());
- // Clear the content and ensure the TextBox is removed.
- window.Content = null;
- window.LayoutManager.ExecuteLayoutPass();
- Assert.Null(window.Presenter.Child);
- return window;
- };
- var result = run();
- dotMemory.Check(memory =>
- Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TextBox>()).ObjectsCount));
- }
- }
- [Fact]
- public void TextBox_With_Xaml_Binding_Is_Freed()
- {
- using (Start())
- {
- Func<Window> run = () =>
- {
- var window = new Window
- {
- DataContext = new Node { Name = "foo" },
- Content = new TextBox()
- };
- var binding = new Avalonia.Markup.Xaml.Data.Binding
- {
- Path = "Name"
- };
- var textBox = (TextBox)window.Content;
- textBox.Bind(TextBox.TextProperty, binding);
- window.Show();
- // Do a layout and make sure that TextBox gets added to visual tree and its
- // Text property set.
- window.LayoutManager.ExecuteInitialLayoutPass(window);
- Assert.IsType<TextBox>(window.Presenter.Child);
- Assert.Equal("foo", ((TextBox)window.Presenter.Child).Text);
- // Clear the content and DataContext and ensure the TextBox is removed.
- window.Content = null;
- window.DataContext = null;
- window.LayoutManager.ExecuteLayoutPass();
- Assert.Null(window.Presenter.Child);
- return window;
- };
- var result = run();
- dotMemory.Check(memory =>
- Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TextBox>()).ObjectsCount));
- dotMemory.Check(memory =>
- Assert.Equal(0, memory.GetObjects(where => where.Type.Is<Node>()).ObjectsCount));
- }
- }
- [Fact]
- public void TextBox_Class_Listeners_Are_Freed()
- {
- using (Start())
- {
- TextBox textBox;
- var window = new Window
- {
- Content = textBox = new TextBox()
- };
- window.Show();
- // Do a layout and make sure that TextBox gets added to visual tree and its
- // template applied.
- window.LayoutManager.ExecuteInitialLayoutPass(window);
- Assert.Same(textBox, window.Presenter.Child);
- // Get the border from the TextBox template.
- var border = textBox.GetTemplateChildren().FirstOrDefault(x => x.Name == "border");
- // The TextBox should have subscriptions to its Classes collection from the
- // default theme.
- Assert.NotEmpty(((INotifyCollectionChangedDebug)textBox.Classes).GetCollectionChangedSubscribers());
- // Clear the content and ensure the TextBox is removed.
- window.Content = null;
- window.LayoutManager.ExecuteLayoutPass();
- Assert.Null(window.Presenter.Child);
- // Check that the TextBox has no subscriptions to its Classes collection.
- Assert.Null(((INotifyCollectionChangedDebug)textBox.Classes).GetCollectionChangedSubscribers());
- }
- }
- [Fact]
- public void TreeView_Is_Freed()
- {
- using (Start())
- {
- Func<Window> run = () =>
- {
- var nodes = new[]
- {
- new Node
- {
- Children = new[] { new Node() },
- }
- };
- TreeView target;
- var window = new Window
- {
- Content = target = new TreeView
- {
- DataTemplates = new DataTemplates
- {
- new FuncTreeDataTemplate<Node>(
- x => new TextBlock { Text = x.Name },
- x => x.Children)
- },
- Items = nodes
- }
- };
- window.Show();
- // Do a layout and make sure that TreeViewItems get realized.
- window.LayoutManager.ExecuteInitialLayoutPass(window);
- Assert.Equal(1, target.ItemContainerGenerator.Containers.Count());
- // Clear the content and ensure the TreeView is removed.
- window.Content = null;
- window.LayoutManager.ExecuteLayoutPass();
- Assert.Null(window.Presenter.Child);
- return window;
- };
- var result = run();
- dotMemory.Check(memory =>
- Assert.Equal(0, memory.GetObjects(where => where.Type.Is<TreeView>()).ObjectsCount));
- }
- }
- [Fact]
- public void RendererIsDisposed()
- {
- using (Start())
- {
- var renderer = new Mock<IRenderer>();
- renderer.Setup(x => x.Dispose());
- var impl = new Mock<IWindowImpl>();
- impl.SetupGet(x => x.Scaling).Returns(1);
- impl.SetupProperty(x => x.Closed);
- impl.Setup(x => x.Dispose()).Callback(() => impl.Object.Closed());
- AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatform>()
- .ToConstant(new MockWindowingPlatform(() => impl.Object));
- AvaloniaLocator.CurrentMutable.Bind<IRendererFactory>()
- .ToConstant(new MockRendererFactory(renderer.Object));
- var window = new Window()
- {
- Content = new Button()
- };
- window.Show();
- window.Close();
- renderer.Verify(r => r.Dispose());
- }
- }
- private IDisposable Start()
- {
- var services = TestServices.StyledWindow.With(renderer: (root, loop) => new NullRenderer());
- return UnitTestApplication.Start(services);
- }
- private class Node
- {
- public string Name { get; set; }
- public IEnumerable<Node> Children { get; set; }
- }
- private class NullRenderer : IRenderer
- {
- public bool DrawFps { get; set; }
- public bool DrawDirtyRects { get; set; }
- public void AddDirty(IVisual visual)
- {
- }
- public void Dispose()
- {
- }
- public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter) => null;
- public void Paint(Rect rect)
- {
- }
- public void Resized(Size size)
- {
- }
- }
- }
- }
|