From e67c73ff2f566f13ff926db9385dc6702a6fed3b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 18 Sep 2014 01:45:40 +0200 Subject: [PATCH] Added some Visual tests. --- Perspex.Controls/TreeViewItem.cs | 2 +- .../Perspex.SceneGraph.UnitTests.csproj | 102 +++++++++++++++ .../Properties/AssemblyInfo.cs | 36 ++++++ Perspex.SceneGraph.UnitTests/TestRoot.cs | 20 +++ Perspex.SceneGraph.UnitTests/TestVisual.cs | 77 ++++++++++++ Perspex.SceneGraph.UnitTests/VisualTests.cs | 119 ++++++++++++++++++ Perspex.SceneGraph.UnitTests/packages.config | 4 + Perspex.SceneGraph/Visual.cs | 66 +++++++++- Perspex.sln | 6 + packages/repositories.config | 1 + 10 files changed, 426 insertions(+), 7 deletions(-) create mode 100644 Perspex.SceneGraph.UnitTests/Perspex.SceneGraph.UnitTests.csproj create mode 100644 Perspex.SceneGraph.UnitTests/Properties/AssemblyInfo.cs create mode 100644 Perspex.SceneGraph.UnitTests/TestRoot.cs create mode 100644 Perspex.SceneGraph.UnitTests/TestVisual.cs create mode 100644 Perspex.SceneGraph.UnitTests/VisualTests.cs create mode 100644 Perspex.SceneGraph.UnitTests/packages.config diff --git a/Perspex.Controls/TreeViewItem.cs b/Perspex.Controls/TreeViewItem.cs index b3b3826c31..fb103e8d62 100644 --- a/Perspex.Controls/TreeViewItem.cs +++ b/Perspex.Controls/TreeViewItem.cs @@ -48,7 +48,7 @@ namespace Perspex.Controls } } - protected override void OnVisualParentChanged(IVisual oldParent) + protected override void OnVisualParentChanged(Visual oldParent) { this.parent = this.GetVisualAncestors().OfType().FirstOrDefault(); } diff --git a/Perspex.SceneGraph.UnitTests/Perspex.SceneGraph.UnitTests.csproj b/Perspex.SceneGraph.UnitTests/Perspex.SceneGraph.UnitTests.csproj new file mode 100644 index 0000000000..9f4ee04ecf --- /dev/null +++ b/Perspex.SceneGraph.UnitTests/Perspex.SceneGraph.UnitTests.csproj @@ -0,0 +1,102 @@ + + + + Debug + AnyCPU + {76716382-3159-460E-BDA6-C5715CF606D7} + Library + Properties + Perspex.SceneGraph.UnitTests + Perspex.SceneGraph.UnitTests + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\packages\Splat.1.3.3\lib\Net45\Splat.dll + + + + + + + + + + + + + + + + + + + + + + + + {b09b78d8-9b26-48b0-9149-d64a2f120f3f} + Perspex.Base + + + {eb582467-6abb-43a1-b052-e981ba910e3a} + Perspex.SceneGraph + + + + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/Perspex.SceneGraph.UnitTests/Properties/AssemblyInfo.cs b/Perspex.SceneGraph.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..372d2b3c81 --- /dev/null +++ b/Perspex.SceneGraph.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Perspex.SceneGraph.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Perspex.SceneGraph.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9b18d549-61cc-46b3-a3f2-80a0b68b747f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Perspex.SceneGraph.UnitTests/TestRoot.cs b/Perspex.SceneGraph.UnitTests/TestRoot.cs new file mode 100644 index 0000000000..03fbf4d7b6 --- /dev/null +++ b/Perspex.SceneGraph.UnitTests/TestRoot.cs @@ -0,0 +1,20 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- +namespace Perspex.SceneGraph.UnitTests +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Perspex.Rendering; + + public class TestRoot : TestVisual, IRenderRoot + { + public IRenderManager RenderManager + { + get { throw new NotImplementedException(); } + } + } +} diff --git a/Perspex.SceneGraph.UnitTests/TestVisual.cs b/Perspex.SceneGraph.UnitTests/TestVisual.cs new file mode 100644 index 0000000000..889f486ebe --- /dev/null +++ b/Perspex.SceneGraph.UnitTests/TestVisual.cs @@ -0,0 +1,77 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- +namespace Perspex.SceneGraph.UnitTests +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Perspex.Rendering; + + public class ParamEventArgs : EventArgs + { + public ParamEventArgs(T param) + { + this.Param = param; + } + + public T Param { get; set; } + } + + public class TestVisual : Visual + { + public Visual[] InitialChildren { get; set; } + + public event EventHandler> VisualParentChangedCalled; + + public event EventHandler> AttachedToVisualTreeCalled; + + public event EventHandler> DetachedFromVisualTreeCalled; + + public void AddChild(Visual v) + { + this.AddVisualChild(v); + } + + public void RemoveChild(Visual v) + { + this.RemoveVisualChild(v); + } + + public void ClearChildren() + { + this.ClearVisualChildren(); + } + + protected override IEnumerable CreateVisualChildren() + { + return this.InitialChildren ?? Enumerable.Empty(); + } + + protected override void OnVisualParentChanged(Visual oldParent) + { + if (this.VisualParentChangedCalled != null) + { + this.VisualParentChangedCalled(this, new ParamEventArgs(oldParent)); + } + } + + protected override void OnAttachedToVisualTree(IRenderRoot root) + { + if (this.AttachedToVisualTreeCalled != null) + { + this.AttachedToVisualTreeCalled(this, new ParamEventArgs(root)); + } + } + + protected override void OnDetachedFromVisualTree(IRenderRoot oldRoot) + { + if (this.DetachedFromVisualTreeCalled != null) + { + this.DetachedFromVisualTreeCalled(this, new ParamEventArgs(oldRoot)); + } + } + } +} diff --git a/Perspex.SceneGraph.UnitTests/VisualTests.cs b/Perspex.SceneGraph.UnitTests/VisualTests.cs new file mode 100644 index 0000000000..c687f9b7dc --- /dev/null +++ b/Perspex.SceneGraph.UnitTests/VisualTests.cs @@ -0,0 +1,119 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- +using Microsoft.VisualStudio.TestTools.UnitTesting; +namespace Perspex.SceneGraph.UnitTests +{ + using System.Linq; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class VisualTests + { + [TestMethod] + public void Initial_Children_Should_Be_Created() + { + var target = new TestVisual + { + InitialChildren = new[] { new Visual(), new Visual() } + }; + + var result = target.GetVisualChildren().ToList(); + + CollectionAssert.AreEqual(target.InitialChildren.ToList(), result); + } + + [TestMethod] + public void Initial_Children_Should_Have_VisualParent_Set() + { + var target = new TestVisual + { + InitialChildren = new[] { new Visual(), new Visual() } + }; + + var result = target.GetVisualChildren().Select(x => x.GetVisualParent()).ToList(); + + CollectionAssert.AreEqual(new[] { target, target }, result); + } + + [TestMethod] + public void Added_Child_Should_Have_VisualParent_Set() + { + var target = new TestVisual(); + var child = new Visual(); + + target.AddChild(child); + + Assert.AreEqual(target, child.GetVisualParent()); + } + + [TestMethod] + public void Removed_Child_Should_Have_VisualParent_Cleared() + { + var target = new TestVisual(); + var child = new Visual(); + + target.AddChild(child); + target.RemoveChild(child); + + Assert.IsNull(child.GetVisualParent()); + } + + [TestMethod] + public void Clearing_Children_Should_Clear_VisualParent() + { + var target = new TestVisual + { + InitialChildren = new[] { new Visual(), new Visual() } + }; + + target.ClearChildren(); + + var result = target.InitialChildren.Select(x => x.GetVisualParent()).ToList(); + + CollectionAssert.AreEqual(new Visual[] { null, null }, result); + } + + [TestMethod] + public void ParentChanged_Attached_Methods_Should_Be_Called_In_Right_Order() + { + var target = new TestRoot(); + var child = new TestVisual(); + int changed = 0; + int attched = 0; + int i = 1; + + target.InitialChildren = new[] { child }; + child.VisualParentChangedCalled += (s, e) => changed = i++; + child.AttachedToVisualTreeCalled += (s, e) => attched = i++; + + target.GetVisualChildren().First(); + + Assert.AreEqual(1, changed); + Assert.AreEqual(2, attched); + } + + [TestMethod] + public void ParentChanged_Detached_Methods_Should_Be_Called_In_Right_Order() + { + var target = new TestRoot(); + var child = new TestVisual(); + int changed = 0; + int detached = 0; + int i = 1; + + target.InitialChildren = new[] { child }; + target.GetVisualChildren().First(); + + child.VisualParentChangedCalled += (s, e) => changed = i++; + child.DetachedFromVisualTreeCalled += (s, e) => detached = i++; + + target.ClearChildren(); + + Assert.AreEqual(1, changed); + Assert.AreEqual(2, detached); + } + } +} diff --git a/Perspex.SceneGraph.UnitTests/packages.config b/Perspex.SceneGraph.UnitTests/packages.config new file mode 100644 index 0000000000..5b20dfceb1 --- /dev/null +++ b/Perspex.SceneGraph.UnitTests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Perspex.SceneGraph/Visual.cs b/Perspex.SceneGraph/Visual.cs index ebd4c39c11..105c8db50a 100644 --- a/Perspex.SceneGraph/Visual.cs +++ b/Perspex.SceneGraph/Visual.cs @@ -14,7 +14,7 @@ namespace Perspex using Perspex.Rendering; using Splat; - public abstract class Visual : PerspexObject, IVisual + public class Visual : PerspexObject, IVisual { public static readonly PerspexProperty IsVisibleProperty = PerspexProperty.Register("IsVisible", true); @@ -32,7 +32,7 @@ namespace Perspex private PerspexList visualChildren; - private IVisual visualParent; + private Visual visualParent; static Visual() { @@ -79,7 +79,10 @@ namespace Perspex IVisual IVisual.VisualParent { - get { return this.visualParent; } + get + { + return this.visualParent; + } } public void InvalidateVisual() @@ -119,7 +122,13 @@ namespace Perspex protected void ClearVisualChildren() { this.EnsureVisualChildrenCreated(); - this.visualChildren.Clear(); + + // TODO: Just call visualChildren.Clear() when we have a PerspexList that notifies of + // the removed items. + while (this.visualChildren.Count > 0) + { + this.visualChildren.RemoveAt(this.visualChildren.Count - 1); + } } protected void RemoveVisualChild(Visual visual) @@ -146,7 +155,7 @@ namespace Perspex { } - protected virtual void OnVisualParentChanged(IVisual oldParent) + protected virtual void OnVisualParentChanged(Visual oldParent) { } @@ -164,13 +173,58 @@ namespace Perspex { if (this.visualChildren == null) { - this.visualChildren = new PerspexList(this.CreateVisualChildren()); + this.visualChildren = new PerspexList(); this.visualChildren.CollectionChanged += VisualChildrenChanged; + this.visualChildren.AddRange(this.CreateVisualChildren()); + } + } + + private void SetVisualParent(Visual value) + { + if (this.visualParent != value) + { + var old = this.visualParent; + var oldRoot = this.GetVisualAncestors().OfType().FirstOrDefault(); + var newRoot = default(IRenderRoot); + + if (value != null) + { + newRoot = value.GetSelfAndVisualAncestors().OfType().FirstOrDefault(); + } + + this.visualParent = value; + this.OnVisualParentChanged(old); + + if (oldRoot != null) + { + this.NotifyDetachedFromVisualTree(oldRoot); + } + + if (newRoot != null) + { + this.NotifyAttachedToVisualTree(newRoot); + } } } private void VisualChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) { + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + foreach (Visual v in e.NewItems) + { + v.SetVisualParent(this); + } + break; + + case NotifyCollectionChangedAction.Remove: + foreach (Visual v in e.OldItems) + { + v.SetVisualParent(null); + } + break; + } } private void NotifyAttachedToVisualTree(IRenderRoot root) diff --git a/Perspex.sln b/Perspex.sln index 1b079a89e7..c079b421c8 100644 --- a/Perspex.sln +++ b/Perspex.sln @@ -37,6 +37,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Controls.UnitTests" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Themes.Default", "Perspex.Themes.Default\Perspex.Themes.Default.csproj", "{3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.SceneGraph.UnitTests", "Perspex.SceneGraph.UnitTests\Perspex.SceneGraph.UnitTests.csproj", "{76716382-3159-460E-BDA6-C5715CF606D7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -107,6 +109,10 @@ Global {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.Build.0 = Debug|Any CPU {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.Build.0 = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76716382-3159-460E-BDA6-C5715CF606D7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/packages/repositories.config b/packages/repositories.config index d62b3a7e2d..f96ee0e3c3 100644 --- a/packages/repositories.config +++ b/packages/repositories.config @@ -8,6 +8,7 @@ +