Skip to content

Commit

Permalink
Sort tree nodes by name or duration
Browse files Browse the repository at this point in the history
  • Loading branch information
rowo360 committed Feb 8, 2025
1 parent c2f2ba4 commit 9c0b971
Show file tree
Hide file tree
Showing 9 changed files with 556 additions and 7 deletions.
6 changes: 4 additions & 2 deletions src/TestCentric/testcentric.gui/Presenters/DisplayStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ namespace TestCentric.Gui.Presenters
using Model;
using Model.Settings;
using Views;
using Elements;
using System.IO;
using System.Linq;

/// <summary>
Expand Down Expand Up @@ -96,6 +94,10 @@ public virtual void OnTestRunStarting()

public virtual void OnTestRunFinished()
{
if (_view.SortCommand.SelectedItem == TreeViewNodeComparer.Duration)
{
_view.InvokeIfRequired(() => _view.Sort());
}
if (_settings.Gui.TestTree.ShowTestDuration)
_view.InvokeIfRequired(() => UpdateTreeNodeNames());
}
Expand Down
146 changes: 146 additions & 0 deletions src/TestCentric/testcentric.gui/Presenters/TreeViewNodeComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// ***********************************************************************
// Copyright (c) Charlie Poole and TestCentric contributors.
// Licensed under the MIT License. See LICENSE file in root directory.
// ***********************************************************************

using System.Collections;
using System.Windows.Forms;
using TestCentric.Gui.Model;

namespace TestCentric.Gui.Presenters
{
/// <summary>
/// This class is responsible for the sorting functionality of tree nodes
/// by providing different IComparer implementations.
/// </summary>
public class TreeViewNodeComparer
{
public const string Name = "Name";
public const string Duration = "Duration";
public const string Ascending = "Ascending";
public const string Descending = "Descending";


/// <summary>
/// Get a IComparer implementation used to sort the tree nodes
/// The sortModes are used by the context menu items in their Tag property
/// </summary>
public static IComparer GetComparer(ITestModel model, string sortMode, string sortDirection, bool showNamespaces)
{
bool ascending = sortDirection == Ascending;

if (sortMode == Name && !showNamespaces)
return new NameComparer(ascending);
if (sortMode == Duration)
return new DurationComparer(model, ascending);

return new FullnameComparer(ascending);
}

/// <summary>
/// The FullnameComparer uses the FullName of the TestNodes (Namespace + class + method name)
/// It's indented to provide the same order as provided by NUnit
/// </summary>
private class FullnameComparer : IComparer
{
private bool _ascending;

internal FullnameComparer(bool ascending)
{
_ascending = ascending;
}

public int Compare(object x, object y)
{
TreeNode node1 = x as TreeNode;
TreeNode node2 = y as TreeNode;

TestNode testNode1 = node1.Tag as TestNode;
TestNode testNode2 = node2.Tag as TestNode;

if (!_ascending)
Swap(ref testNode1, ref testNode2);

if (testNode1 == null || testNode2 == null)
return 1;

return testNode1.FullName.CompareTo(testNode2.FullName);
}
}

/// <summary>
/// The NameComparer uses the Name of the TestNodes (either Namespace or class or method name)
/// If Namespaces are shown in the tree, it will provide the same results as the FullnameComparer
/// However if Namespaces are hidden, the NameComparer will sort the class names properly.
/// </summary>
private class NameComparer : IComparer
{
private bool _ascending;

internal NameComparer(bool ascending)
{
_ascending = ascending;
}

public int Compare(object x, object y)
{
TreeNode node1 = x as TreeNode;
TreeNode node2 = y as TreeNode;

if (!_ascending)
Swap(ref node1, ref node2);

if (node1 != null && node2 != null)
return node1.Text.CompareTo(node2.Text);

return 1;
}
}

/// <summary>
/// The DurationComparer uses the Duration of the TestResults
/// It no test results are available yet, it uses the Name.
/// </summary>
private class DurationComparer : IComparer
{
private ITestModel _model;
private bool _ascending;

internal DurationComparer(ITestModel model, bool ascending)
{
_model = model;
_ascending = ascending;
}

public int Compare(object x, object y)
{
TreeNode node1 = x as TreeNode;
TreeNode node2 = y as TreeNode;

if (!_ascending)
Swap(ref node1, ref node2);

TestNode testNode1 = node1?.Tag as TestNode;
TestNode testNode2 = node2?.Tag as TestNode;

if (testNode1 == null || testNode2 == null)
return 1;

ResultNode resultNode1 = _model.GetResultForTest(testNode1.Id);
ResultNode resultNode2 = _model.GetResultForTest(testNode2.Id);

if (resultNode1 != null && resultNode2 != null)
return resultNode1.Duration.CompareTo(resultNode2.Duration);

return node1.Text.CompareTo(node2.Text); ;
}
}

internal static void Swap<T>(ref T x, ref T y)
{
T tmp = x;
x = y;
y = tmp;
}
}
}
22 changes: 18 additions & 4 deletions src/TestCentric/testcentric.gui/Presenters/TreeViewPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@
// ***********************************************************************

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using TestCentric.Common;

namespace TestCentric.Gui.Presenters
{
using Model;
using Views;
using Dialogs;
using System.Xml;
using System.Drawing;
using System.IO;
using TestCentric.Gui.Controls;
using System.Collections;

/// <summary>
/// TreeViewPresenter is the presenter for the TestTreeView
Expand Down Expand Up @@ -136,6 +133,7 @@ private void WireUpEvents()
case "TestCentric.Gui.TestTree.TestList.GroupBy":
case "TestCentric.Gui.TestTree.FixtureList.GroupBy":
case "TestCentric.Gui.TestTree.ShowNamespace":
SortTreeView();
Strategy?.Reload();
break;
case "TestCentric.Gui.TestTree.ShowCheckBoxes":
Expand Down Expand Up @@ -172,6 +170,10 @@ private void WireUpEvents()
Strategy?.UpdateTreeNodeNames();
};

_view.SortCommand.SelectionChanged += () => SortTreeView();

_view.SortDirectionCommand.SelectionChanged += () => SortTreeView();

_view.RunContextCommand.Execute += () =>
{
if (_view.ContextNode != null)
Expand Down Expand Up @@ -300,6 +302,18 @@ private void WireUpEvents()
//};
}

private void SortTreeView()
{
var sortMode = _view.SortCommand.SelectedItem;

// Activate 'ShowTestDuration' in case sort by duration is selected
if (sortMode == TreeViewNodeComparer.Duration)
_view.ShowTestDuration.Checked = true;

IComparer comparer = TreeViewNodeComparer.GetComparer(_model, sortMode, _view.SortDirectionCommand.SelectedItem, _treeSettings.ShowNamespace);
_view.Sort(comparer);
}

private void UpdateTreeSettingsFromVisualState(VisualState visualState)
{
_treeSettings.DisplayFormat = visualState.DisplayStrategy;
Expand Down
7 changes: 7 additions & 0 deletions src/TestCentric/testcentric.gui/Views/ITestTreeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

namespace TestCentric.Gui.Views
{
using System.Collections;
using System.Collections.Generic;
using Elements;

Expand All @@ -29,6 +30,9 @@ public interface ITestTreeView : IView
IToolStripMenu ActiveConfiguration { get; }
IChecked ShowCheckBoxes { get; }
IChecked ShowTestDuration { get; }
ISelection SortCommand { get; }
ISelection SortDirectionCommand { get; }

ICommand ExpandAllCommand { get; }
ICommand CollapseAllCommand { get; }
ICommand CollapseToFixturesCommand { get; }
Expand Down Expand Up @@ -66,6 +70,9 @@ public interface ITestTreeView : IView
void Add(TreeNode treeNode);
void ExpandAll();
void CollapseAll();

void Sort();
void Sort(IComparer comparer);
void SetImageIndex(TreeNode treeNode, int imageIndex);

/// <summary>
Expand Down
73 changes: 73 additions & 0 deletions src/TestCentric/testcentric.gui/Views/TestTreeView.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9c0b971

Please sign in to comment.