using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xunit;
using Xunit.Abstractions;
namespace Terminal.Gui.ViewsTests;
public class TreeViewTests {
readonly ITestOutputHelper _output;
public TreeViewTests (ITestOutputHelper output) => _output = output;
///
/// Tests that and are consistent
///
[Fact]
public void IsExpanded_TrueAfterExpand ()
{
var tree = CreateTree (out var f, out _, out _);
Assert.False (tree.IsExpanded (f));
tree.Expand (f);
Assert.True (tree.IsExpanded (f));
tree.Collapse (f);
Assert.False (tree.IsExpanded (f));
}
[Fact]
public void EmptyTreeView_ContentSizes ()
{
var emptyTree = new TreeView ();
Assert.Equal (0, emptyTree.ContentHeight);
Assert.Equal (0, emptyTree.GetContentWidth (true));
Assert.Equal (0, emptyTree.GetContentWidth (false));
}
[Fact]
public void EmptyTreeViewGeneric_ContentSizes ()
{
var emptyTree = new TreeView ();
Assert.Equal (0, emptyTree.ContentHeight);
Assert.Equal (0, emptyTree.GetContentWidth (true));
Assert.Equal (0, emptyTree.GetContentWidth (false));
}
///
/// Tests that results in a correct content height
///
[Fact]
public void ContentHeight_BiggerAfterExpand ()
{
var tree = CreateTree (out var f, out _, out _);
Assert.Equal (1, tree.ContentHeight);
tree.Expand (f);
Assert.Equal (3, tree.ContentHeight);
tree.Collapse (f);
Assert.Equal (1, tree.ContentHeight);
}
[Fact]
public void ContentWidth_BiggerAfterExpand ()
{
var tree = CreateTree (out var f, out var car1, out _);
tree.BeginInit ();
tree.EndInit ();
tree.Bounds = new Rect (0, 0, 10, 10);
InitFakeDriver ();
//-+Factory
Assert.Equal (9, tree.GetContentWidth (true));
car1.Name = "123456789";
tree.Expand (f);
//..├-123456789
Assert.Equal (13, tree.GetContentWidth (true));
tree.Collapse (f);
//-+Factory
Assert.Equal (9, tree.GetContentWidth (true));
Application.Shutdown ();
}
[Fact]
public void ContentWidth_VisibleVsAll ()
{
var tree = CreateTree (out var f, out var car1, out var car2);
tree.BeginInit ();
tree.EndInit ();
// control only allows 1 row to be viewed at once
tree.Bounds = new Rect (0, 0, 20, 1);
InitFakeDriver ();
//-+Factory
Assert.Equal (9, tree.GetContentWidth (true));
Assert.Equal (9, tree.GetContentWidth (false));
car1.Name = "123456789";
car2.Name = "12345678";
tree.Expand (f);
// Although expanded the bigger (longer) child node is not in the rendered area of the control
Assert.Equal (9, tree.GetContentWidth (true));
Assert.Equal (13, tree.GetContentWidth (false)); // If you ask for the global max width it includes the longer child
// Now that we have scrolled down 1 row we should see the big child
tree.ScrollOffsetVertical = 1;
Assert.Equal (13, tree.GetContentWidth (true));
Assert.Equal (13, tree.GetContentWidth (false));
// Scroll down so only car2 is visible
tree.ScrollOffsetVertical = 2;
Assert.Equal (12, tree.GetContentWidth (true));
Assert.Equal (13, tree.GetContentWidth (false));
// Scroll way down (off bottom of control even)
tree.ScrollOffsetVertical = 5;
Assert.Equal (0, tree.GetContentWidth (true));
Assert.Equal (13, tree.GetContentWidth (false));
Application.Shutdown ();
}
///
/// Tests that and behaves correctly when
/// an object cannot be expanded (because it has no children)
///
[Fact]
public void IsExpanded_FalseIfCannotExpand ()
{
var tree = CreateTree (out var f, out var c, out _);
// expose the car by expanding the factory
tree.Expand (f);
// car is not expanded
Assert.False (tree.IsExpanded (c));
//try to expand the car (should have no effect because cars have no children)
tree.Expand (c);
Assert.False (tree.IsExpanded (c));
// should also be ignored
tree.Collapse (c);
Assert.False (tree.IsExpanded (c));
Application.Shutdown ();
}
///
/// Tests illegal ranges for
///
[Fact]
public void ScrollOffset_CannotBeNegative ()
{
var tree = CreateTree ();
Assert.Equal (0, tree.ScrollOffsetVertical);
tree.ScrollOffsetVertical = -100;
Assert.Equal (0, tree.ScrollOffsetVertical);
tree.ScrollOffsetVertical = 10;
Assert.Equal (10, tree.ScrollOffsetVertical);
}
///
/// Tests for objects that are as yet undiscovered by the tree
///
[Fact]
public void GetScrollOffsetOf_MinusOneForUnRevealed ()
{
var tree = CreateTree (out var f, out var c1, out var c2);
// to start with the tree is collapsed and only knows about the root object
Assert.Equal (0, tree.GetScrollOffsetOf (f));
Assert.Equal (-1, tree.GetScrollOffsetOf (c1));
Assert.Equal (-1, tree.GetScrollOffsetOf (c2));
// reveal it by expanding the root object
tree.Expand (f);
// tree now knows about children
Assert.Equal (0, tree.GetScrollOffsetOf (f));
Assert.Equal (1, tree.GetScrollOffsetOf (c1));
Assert.Equal (2, tree.GetScrollOffsetOf (c2));
// after collapsing the root node again
tree.Collapse (f);
// tree no longer knows about the locations of these objects
Assert.Equal (0, tree.GetScrollOffsetOf (f));
Assert.Equal (-1, tree.GetScrollOffsetOf (c1));
Assert.Equal (-1, tree.GetScrollOffsetOf (c2));
}
///
/// Simulates behind the scenes changes to an object (which children it has) and how to sync that into the tree using
///
///
[Fact]
public void RefreshObject_ChildRemoved ()
{
var tree = CreateTree (out var f, out var c1, out var c2);
//reveal it by expanding the root object
tree.Expand (f);
Assert.Equal (0, tree.GetScrollOffsetOf (f));
Assert.Equal (1, tree.GetScrollOffsetOf (c1));
Assert.Equal (2, tree.GetScrollOffsetOf (c2));
// Factory now no longer makes Car c1 (only c2)
f.Cars = new [] { c2 };
// Tree does not know this yet
Assert.Equal (0, tree.GetScrollOffsetOf (f));
Assert.Equal (1, tree.GetScrollOffsetOf (c1));
Assert.Equal (2, tree.GetScrollOffsetOf (c2));
// If the user has selected the node c1
tree.SelectedObject = c1;
// When we refresh the tree
tree.RefreshObject (f);
// Now tree knows that factory has only one child node c2
Assert.Equal (0, tree.GetScrollOffsetOf (f));
Assert.Equal (-1, tree.GetScrollOffsetOf (c1));
Assert.Equal (1, tree.GetScrollOffsetOf (c2));
// The old selection was c1 which is now gone so selection should default to the parent of that branch (the factory)
Assert.Equal (f, tree.SelectedObject);
}
///
/// Tests that returns the parent object for
/// Cars (Factories). Note that the method only works once the parent branch (Factory)
/// is expanded to expose the child (Car)
///
[Fact]
public void GetParent_ReturnsParentOnlyWhenExpanded ()
{
var tree = CreateTree (out var f, out var c1, out var c2);
Assert.Null (tree.GetParent (f));
Assert.Null (tree.GetParent (c1));
Assert.Null (tree.GetParent (c2));
// now when we expand the factory we discover the cars
tree.Expand (f);
Assert.Null (tree.GetParent (f));
Assert.Equal (f, tree.GetParent (c1));
Assert.Equal (f, tree.GetParent (c2));
tree.Collapse (f);
Assert.Null (tree.GetParent (f));
Assert.Null (tree.GetParent (c1));
Assert.Null (tree.GetParent (c2));
}
///
/// Tests how the tree adapts to changes in the ChildrenGetter delegate during runtime
/// when some branches are expanded and the new delegate returns children for a node that
/// previously didn't have any children
///
[Fact]
public void RefreshObject_AfterChangingChildrenGetterDuringRuntime ()
{
var tree = CreateTree (out var f, out var c1, out var c2);
var wheel = "Shiny Wheel";
// Expand the Factory
tree.Expand (f);
// c1 cannot have children
Assert.Equal (f, tree.GetParent (c1));
// expanding it does nothing
tree.Expand (c1);
Assert.False (tree.IsExpanded (c1));
// change the children getter so that now cars can have wheels
tree.TreeBuilder = new DelegateTreeBuilder