Skip to content

Commit

Permalink
Merge pull request #1153 from TestCentric/AlternativeNUnitTreeDisplays
Browse files Browse the repository at this point in the history
NUnit tree: add option to show/hide namespace nodes; add folding of namespace nodes
  • Loading branch information
CharliePoole authored Oct 23, 2024
2 parents 183bfb4 + ae1922c commit 1e18cd2
Show file tree
Hide file tree
Showing 16 changed files with 400 additions and 9 deletions.
15 changes: 10 additions & 5 deletions src/TestCentric/testcentric.gui/Presenters/DisplayStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ protected TreeNode MakeTreeNode(TestGroup group, bool recursive)

public TreeNode MakeTreeNode(TestNode testNode, bool recursive)
{
string treeNodeName = GetTestNodeDisplayName(testNode);
string treeNodeName = GetTreeNodeDisplayName(testNode);
TreeNode treeNode = new TreeNode(treeNodeName);
treeNode.Tag = testNode;

Expand Down Expand Up @@ -176,14 +176,19 @@ public string GroupDisplayName(TestGroup group)
return string.Format("{0} ({1})", group.Name, group.Count());
}

private string GetTestNodeDisplayName(TestNode testNode)
protected virtual string GetTreeNodeName(TestNode testNode)
{
string treeNodeName = testNode.Name;
return testNode.Name;
}

private string GetTreeNodeDisplayName(TestNode testNode)
{
string treeNodeName = GetTreeNodeName(testNode);

// Check if test result is available for this node
ResultNode result = _model.GetResultForTest(testNode.Id);
if (_settings.Gui.TestTree.ShowTestDuration && result != null)
treeNodeName = testNode.Name + $" [{result.Duration:0.000}s]";
treeNodeName += $" [{result.Duration:0.000}s]";

return treeNodeName;
}
Expand Down Expand Up @@ -212,7 +217,7 @@ private void UpdateTreeNodeName(TreeNode treeNode)
if (testNode == null)
return;

string treeNodeName = GetTestNodeDisplayName(testNode);
string treeNodeName = GetTreeNodeDisplayName(testNode);
_view.InvokeIfRequired(() => treeNode.Text = treeNodeName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

namespace TestCentric.Gui.Presenters
{
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Model;
using Views;

Expand All @@ -18,6 +19,8 @@ namespace TestCentric.Gui.Presenters
/// </summary>
public class NUnitTreeDisplayStrategy : DisplayStrategy
{
private IDictionary<TestNode, string> _foldedNodeNames = new Dictionary<TestNode, string>();

public NUnitTreeDisplayStrategy(ITestTreeView view, ITestModel model)
: base(view, model) { }

Expand All @@ -32,17 +35,98 @@ public override string Description
public override void OnTestLoaded(TestNode testNode, VisualState visualState)
{
ClearTree();
_foldedNodeNames.Clear();

foreach (var topLevelNode in testNode.Children)
_view.Add(MakeTreeNode(topLevelNode, true));
_view.Add(CreateNUnitTreeNode(null, topLevelNode));

if (visualState != null)
visualState.ApplyTo(_view.TreeView);
else
SetDefaultInitialExpansion();
}

protected override VisualState CreateVisualState() => new VisualState("NUNIT_TREE").LoadFrom(_view.TreeView);
protected override VisualState CreateVisualState() => new VisualState("NUNIT_TREE", _settings.Gui.TestTree.ShowNamespace).LoadFrom(_view.TreeView);

protected override string GetTreeNodeName(TestNode testNode)
{
// For folded namespace nodes use the combined name of all folded nodes ("Library.Test.Folder")
if (_foldedNodeNames.TryGetValue(testNode, out var name))
return name;

return base.GetTreeNodeName(testNode);
}

private TreeNode CreateNUnitTreeNode(TreeNode parentNode, TestNode testNode)
{
TreeNode treeNode = null;

if (ShowTreeNodeType(testNode))
{
if (IsNamespaceNode(testNode))
{
// Get list of all namespace nodes which can be folded
// And get name of folded namespaces and store in dictionary for later usage
IList<TestNode> foldedNodes = FoldNamespaceNodes(testNode);
_foldedNodeNames[foldedNodes.First()] = GetFoldedNamespaceName(foldedNodes);

treeNode = MakeTreeNode(foldedNodes.First(), false); // Create TreeNode representing the first node
testNode = foldedNodes.Last(); // But proceed building up tree with last node
}
else
treeNode = MakeTreeNode(testNode, false);

parentNode?.Nodes.Add(treeNode);
parentNode = treeNode;
}

foreach (TestNode child in testNode.Children)
{
CreateNUnitTreeNode(parentNode, child);
}

return treeNode;
}

/// <summary>
/// Check if a tree node type should be shown or omitted
/// Currently we support only omitting the namespace nodes
/// </summary>
private bool ShowTreeNodeType(TestNode testNode)
{
if (IsNamespaceNode(testNode))
return _settings.Gui.TestTree.ShowNamespace;

return true;
}

private string GetFoldedNamespaceName(IList<TestNode> foldedNamespaces)
{
var namespaceNames = foldedNamespaces.Select(x => x.Name);
return String.Join(".", namespaceNames);
}

private IList<TestNode> FoldNamespaceNodes(TestNode testNode)
{
if (!IsNamespaceNode(testNode))
{
return new List<TestNode>();
}

// If a namespace node only contains one child item which is also a namespace node, we can fold them.
List<TestNode> namespaceNodes = new List<TestNode>() { testNode };
if (testNode.Children.Count == 1 && IsNamespaceNode(testNode.Children[0]))
{
namespaceNodes.AddRange(FoldNamespaceNodes(testNode.Children[0]));
}

return namespaceNodes;
}

private bool IsNamespaceNode(TestNode testNode)
{
return testNode.IsSuite && (testNode.Type == "TestSuite" || testNode.Type == "SetUpFixture");
}

private void SetDefaultInitialExpansion()
{
Expand Down
11 changes: 11 additions & 0 deletions src/TestCentric/testcentric.gui/Presenters/TestCentricPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ void OnRunFinished(ResultNode result)
case "TestCentric.Gui.TestTree.FixtureList.GroupBy":
_view.GroupBy.SelectedItem = _settings.Gui.TestTree.FixtureList.GroupBy;
break;
case "TestCentric.Gui.TestTree.ShowNamespace":
_view.ShowNamespace.SelectedIndex = _settings.Gui.TestTree.ShowNamespace ? 0 : 1;
break;
}
};

Expand Down Expand Up @@ -489,6 +492,11 @@ void OnRunFinished(ResultNode result)
_settings.Gui.TestTree.DisplayFormat = _view.DisplayFormat.SelectedItem;
};

_view.ShowNamespace.SelectionChanged += () =>
{
_settings.Gui.TestTree.ShowNamespace = _view.ShowNamespace.SelectedIndex == 0;
};

_view.GroupBy.SelectionChanged += () =>
{
switch(_view.DisplayFormat.SelectedItem)
Expand Down Expand Up @@ -945,6 +953,9 @@ private void UpdateTreeDisplayMenuItem()
_view.GroupBy.SelectedItem = _settings.Gui.TestTree.FixtureList.GroupBy;
break;
}

_view.ShowNamespace.SelectedIndex = _settings.Gui.TestTree.ShowNamespace ? 0 : 1;
_view.ShowNamespace.Enabled = displayFormat == "NUNIT_TREE";
}

private void RunAllTests()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ private void WireUpEvents()
}
case "TestCentric.Gui.TestTree.TestList.GroupBy":
case "TestCentric.Gui.TestTree.FixtureList.GroupBy":
case "TestCentric.Gui.TestTree.ShowNamespace":
Strategy?.Reload();
break;
case "TestCentric.Gui.TestTree.ShowCheckBoxes":
Expand Down Expand Up @@ -283,6 +284,8 @@ private void UpdateTreeSettingsFromVisualState(VisualState visualState)
{
_treeSettings.FixtureList.GroupBy = visualState.GroupBy;
}

_treeSettings.ShowNamespace = visualState.ShowNamespace;
}

private void EnsureNonRunnableFilesAreVisible(TestNode testNode)
Expand Down
1 change: 1 addition & 0 deletions src/TestCentric/testcentric.gui/Views/IMainView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public interface IMainView
IViewElement DisplayFormatButton { get; }
ISelection DisplayFormat { get; }
ISelection GroupBy { get; }
ISelection ShowNamespace { get; }
ICommand RunParametersButton { get; }

IChecked RunSummaryButton { get; }
Expand Down
25 changes: 25 additions & 0 deletions src/TestCentric/testcentric.gui/Views/TestCentricMainView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ public class TestCentricMainView : TestCentricFormBase, IMainView
private ToolStripMenuItem nunitTreeMenuItem;
private ToolStripMenuItem fixtureListMenuItem;
private ToolStripMenuItem testListMenuItem;
private ToolStripMenuItem nunitTreeShowNamespaceMenuItem;
private ToolStripMenuItem nunitTreeHideNamespaceMenuItem;
private ToolStripSeparator toolStripSeparator13;
private ToolStripMenuItem byAssemblyMenuItem;
private ToolStripMenuItem byFixtureMenuItem;
Expand Down Expand Up @@ -175,6 +177,7 @@ public TestCentricMainView() : base("TestCentric")
GroupBy = new CheckedToolStripMenuGroup(
"testGrouping",
byAssemblyMenuItem, byFixtureMenuItem, byCategoryMenuItem, byOutcomeMenuItem, byDurationMenuItem);
ShowNamespace = new CheckedToolStripMenuGroup("showNamespace", nunitTreeShowNamespaceMenuItem, nunitTreeHideNamespaceMenuItem);
RunParametersButton = new ToolStripButtonElement(runParametersButton);
RunSummaryButton = new CheckBoxElement(runSummaryButton);

Expand Down Expand Up @@ -217,6 +220,8 @@ private void InitializeComponent()
this.nunitTreeMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.fixtureListMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.testListMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.nunitTreeShowNamespaceMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.nunitTreeHideNamespaceMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator();
this.byAssemblyMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.byFixtureMenuItem = new System.Windows.Forms.ToolStripMenuItem();
Expand Down Expand Up @@ -405,13 +410,32 @@ private void InitializeComponent()
this.displayFormatButton.Size = new System.Drawing.Size(29, 21);
this.displayFormatButton.Text = "Display";
this.displayFormatButton.ToolTipText = "Tree Display Format";

//
// nunitTreeShowNamespaceMenuItem
//
this.nunitTreeShowNamespaceMenuItem.Name = "NUNIT_TREE_SHOW_NAMESPACE";
this.nunitTreeShowNamespaceMenuItem.Size = new System.Drawing.Size(198, 22);
this.nunitTreeShowNamespaceMenuItem.Tag = "NUNIT_TREE_SHOW_NAMESPACE";
this.nunitTreeShowNamespaceMenuItem.Text = "Show Namespace";

//
// nunitTreeHideNamespaceMenuItem
//
this.nunitTreeHideNamespaceMenuItem.Name = "NUNIT_TREE_HIDE_NAMESPACE";
this.nunitTreeHideNamespaceMenuItem.Size = new System.Drawing.Size(198, 22);
this.nunitTreeHideNamespaceMenuItem.Tag = "NUNIT_TREE_HIDE_NAMESPACE";
this.nunitTreeHideNamespaceMenuItem.Text = "Hide Namespace";

//
// nunitTreeMenuItem
//
this.nunitTreeMenuItem.Name = "nunitTreeMenuItem";
this.nunitTreeMenuItem.Size = new System.Drawing.Size(198, 22);
this.nunitTreeMenuItem.Tag = "NUNIT_TREE";
this.nunitTreeMenuItem.Text = "NUnit Tree";
nunitTreeMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { nunitTreeShowNamespaceMenuItem, nunitTreeHideNamespaceMenuItem });

//
// fixtureListMenuItem
//
Expand Down Expand Up @@ -1124,6 +1148,7 @@ public int SplitterPosition
public IViewElement DisplayFormatButton { get; private set; }
public ISelection DisplayFormat { get; private set; }
public ISelection GroupBy { get; private set; }
public ISelection ShowNamespace { get; private set; }
public ICommand RunParametersButton { get; private set; }

public IChecked RunSummaryButton { get; private set; }
Expand Down
13 changes: 12 additions & 1 deletion src/TestCentric/testcentric.gui/VisualState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ public VisualState(string strategyID)
DisplayStrategy = strategyID;
}

public VisualState(string strategyID, bool showNamespace)
{
DisplayStrategy = strategyID;
ShowNamespace = showNamespace;
}

public VisualState(string strategyID, string groupID)
{
if (strategyID == "NUNIT_TREE")
Expand All @@ -53,6 +59,8 @@ public VisualState(string strategyID, string groupID)
//[XmlAttribute, DefaultValue(false)]
public bool ShowCheckBoxes;

public bool ShowNamespace;

// TODO: Categories not yet supported
//public List<string> SelectedCategories;
//public bool ExcludeCategories;
Expand Down Expand Up @@ -250,6 +258,7 @@ public void ReadXml(XmlReader reader)
// GroupBy is null for NUnitTree strategy, otherwise required
if (GroupBy == null && strategy != "NUNIT_TREE") GroupBy = "ASSEMBLY";
ShowCheckBoxes = reader.GetAttribute("ShowCheckBoxes") == "True";
ShowNamespace = reader.GetAttribute("ShowNamespace") == "True";

while (reader.Read())
{
Expand Down Expand Up @@ -364,7 +373,9 @@ public void WriteXml(XmlWriter writer)
writer.WriteAttributeString("GroupBy", GroupBy);
if (ShowCheckBoxes)
writer.WriteAttributeString("ShowCheckBoxes", "True");

if (ShowNamespace)
writer.WriteAttributeString("ShowNamespace", "True");

WriteVisualTreeNodes(Nodes);

void WriteVisualTreeNodes(List<VisualTreeNode> nodes)
Expand Down
14 changes: 14 additions & 0 deletions src/TestCentric/tests/Presenters/Main/CommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -349,5 +349,19 @@ public void SelectedTestsChanged_TestSelected_CommandIsEnabled()
// Assert
Assert.That(_view.RunSelectedButton.Enabled, Is.True);
}

[TestCase(0, true)]
[TestCase(1, false)]
public void ShowNamespaceChanged_ChangesModelSetting(int selectedMenuItem, bool expectedShowNamespace)
{
// Arrange
_view.ShowNamespace.SelectedIndex.Returns(selectedMenuItem);

// Act
_view.ShowNamespace.SelectionChanged += Raise.Event<CommandHandler>();

// Assert
Assert.That(_model.Settings.Gui.TestTree.ShowNamespace, Is.EqualTo(expectedShowNamespace));
}
}
}
11 changes: 11 additions & 0 deletions src/TestCentric/tests/Presenters/Main/WhenSettingsChanged.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,16 @@ public void TestListGroupBy_SettingChanged_MenuItemIsUpdated(string groupBy)
// 2. Assert
_view.GroupBy.SelectedItem = groupBy;
}

[TestCase(true, 0)]
[TestCase(false, 1)]
public void ShowNamespace_SettingChanged_MenuItemIsUpdated(bool showNamespace, int expectedMenuIndex)
{
// 1. Act
_settings.Gui.TestTree.ShowNamespace = showNamespace;

// 2. Assert
_view.ShowNamespace.SelectedIndex = expectedMenuIndex;
}
}
}
Loading

0 comments on commit 1e18cd2

Please sign in to comment.