-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor TestCentricTestFilter class: introduce separate TestFilter c…
…lasses, each one dedicated to one single filter condition
- Loading branch information
Showing
10 changed files
with
374 additions
and
192 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// *********************************************************************** | ||
// Copyright (c) Charlie Poole and TestCentric contributors. | ||
// Licensed under the MIT License. See LICENSE file in root directory. | ||
// *********************************************************************** | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Xml; | ||
|
||
namespace TestCentric.Gui.Model.Filter | ||
{ | ||
/// <summary> | ||
/// Filters the TestNodes by test categories. Use item 'No category' to filter for tests without any test category. | ||
/// </summary> | ||
public class CategoryFilter : ITestFilter | ||
{ | ||
public const string NoCategory = "No category"; | ||
|
||
private List<string> _condition = new List<string>(); | ||
|
||
internal CategoryFilter(ITestModel model) | ||
{ | ||
TestModel = model; | ||
} | ||
|
||
private ITestModel TestModel { get; } | ||
|
||
public string FilterId => "CategoryFilter"; | ||
|
||
public IEnumerable<string> Condition | ||
{ | ||
get { return _condition; } | ||
set { _condition = value.ToList(); } | ||
} | ||
|
||
public IEnumerable<string> AllCategories { get; private set; } | ||
|
||
public bool IsMatching(TestNode testNode) | ||
{ | ||
if (_condition.Any() == false) | ||
return false; | ||
|
||
string xpathExpression = "ancestor-or-self::*/properties/property[@name='Category']"; | ||
|
||
// 1. Get list of available categories at TestNode | ||
IList<string> categories = new List<string>(); | ||
foreach (XmlNode node in testNode.Xml.SelectNodes(xpathExpression)) | ||
{ | ||
var groupName = node.Attributes["value"].Value; | ||
if (!string.IsNullOrEmpty(groupName)) | ||
categories.Add(groupName); | ||
} | ||
|
||
if (categories.Any() == false) | ||
categories.Add(NoCategory); | ||
|
||
// 2. Check if any filter category matches the available categories | ||
return _condition.Intersect(categories).Any(); | ||
} | ||
|
||
public void Reset() | ||
{ | ||
_condition = GetAllCategories(); | ||
} | ||
|
||
public void Init() | ||
{ | ||
AllCategories = GetAllCategories(); | ||
_condition = AllCategories.ToList(); | ||
} | ||
|
||
private List<string> GetAllCategories() | ||
{ | ||
var items = TestModel.AvailableCategories; | ||
var allCategories = items.Concat(new[] { NoCategory }); | ||
return allCategories.ToList(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// *********************************************************************** | ||
// Copyright (c) Charlie Poole and TestCentric contributors. | ||
// Licensed under the MIT License. See LICENSE file in root directory. | ||
// *********************************************************************** | ||
|
||
using System.Collections.Generic; | ||
|
||
namespace TestCentric.Gui.Model.Filter | ||
{ | ||
/// <summary> | ||
/// Interface for all test filters | ||
/// </summary> | ||
internal interface ITestFilter | ||
{ | ||
/// <summary> | ||
/// Unqiue identifier of the filter | ||
/// </summary> | ||
string FilterId { get; } | ||
|
||
/// <summary> | ||
/// The filter condition | ||
/// </summary> | ||
IEnumerable<string> Condition { get; set; } | ||
|
||
/// <summary> | ||
/// Reset the filter condition to its default state | ||
/// </summary> | ||
void Reset(); | ||
|
||
/// <summary> | ||
/// Init filter after a project is loaded | ||
/// </summary> | ||
void Init(); | ||
|
||
/// <summary> | ||
/// Checks if the testNode matches the filter condition | ||
/// </summary> | ||
bool IsMatching(TestNode testNode); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// *********************************************************************** | ||
// Copyright (c) Charlie Poole and TestCentric contributors. | ||
// Licensed under the MIT License. See LICENSE file in root directory. | ||
// *********************************************************************** | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace TestCentric.Gui.Model.Filter | ||
{ | ||
/// <summary> | ||
/// Filters the TestNodes by outcome (for example: 'Passed', 'Failed' or 'Not run') | ||
/// </summary> | ||
public class OutcomeFilter : ITestFilter | ||
{ | ||
public const string AllOutcome = "All"; | ||
public const string NotRunOutcome = "Not Run"; | ||
|
||
private List<string> _condition = new List<string>() { AllOutcome }; | ||
|
||
internal OutcomeFilter(ITestModel model) | ||
{ | ||
TestModel = model; | ||
} | ||
|
||
public string FilterId => "OutcomeFilter"; | ||
|
||
private ITestModel TestModel { get; } | ||
|
||
public IEnumerable<string> Condition | ||
{ | ||
get { return _condition; } | ||
set { _condition = value.ToList(); } | ||
} | ||
|
||
public bool IsMatching(TestNode testNode) | ||
{ | ||
// All kind of outcomes should be displayed (no outcome filtering) | ||
if (_condition.Contains(AllOutcome)) | ||
return true; | ||
|
||
string outcome = NotRunOutcome; | ||
|
||
var result = TestModel.GetResultForTest(testNode.Id); | ||
if (result != null) | ||
{ | ||
switch (result.Outcome.Status) | ||
{ | ||
case TestStatus.Failed: | ||
case TestStatus.Passed: | ||
case TestStatus.Inconclusive: | ||
outcome = result.Outcome.Status.ToString(); | ||
break; | ||
case TestStatus.Skipped: | ||
outcome = result.Outcome.Label == "Ignored" ? "Ignored" : "Skipped"; | ||
break; | ||
} | ||
} | ||
|
||
return _condition.Contains(outcome); | ||
} | ||
|
||
public void Reset() | ||
{ | ||
_condition = new List<string>() { AllOutcome }; | ||
} | ||
|
||
public void Init() | ||
{ | ||
_condition = new List<string>() { AllOutcome }; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// *********************************************************************** | ||
// Copyright (c) Charlie Poole and TestCentric contributors. | ||
// Licensed under the MIT License. See LICENSE file in root directory. | ||
// *********************************************************************** | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace TestCentric.Gui.Model.Filter | ||
{ | ||
public class TestCentricTestFilter : ITestCentricTestFilter | ||
{ | ||
private List<ITestFilter> _filters = new List<ITestFilter>(); | ||
|
||
public TestCentricTestFilter(ITestModel model, Action filterChangedEvent) | ||
{ | ||
TestModel = model; | ||
FireFilterChangedEvent = filterChangedEvent; | ||
|
||
_filters.Add(new OutcomeFilter(model)); | ||
_filters.Add(new TextFilter()); | ||
_filters.Add(new CategoryFilter(model)); | ||
} | ||
|
||
private ITestModel TestModel { get; } | ||
|
||
private Action FireFilterChangedEvent; | ||
|
||
public IEnumerable<string> OutcomeFilter | ||
{ | ||
get => GetFilterCondition("OutcomeFilter"); | ||
set => SetFilterCondition("OutcomeFilter", value); | ||
} | ||
|
||
public IEnumerable<string> CategoryFilter | ||
{ | ||
get => GetFilterCondition("CategoryFilter"); | ||
|
||
set => SetFilterCondition("CategoryFilter", value); | ||
} | ||
|
||
public string TextFilter | ||
{ | ||
get => GetFilterCondition("TextFilter").First(); | ||
set => SetFilterCondition("TextFilter", new string[] { value }); | ||
} | ||
|
||
public IEnumerable<string> AllCategories | ||
{ | ||
get | ||
{ | ||
var categoryFilter = _filters.FirstOrDefault(f => f.FilterId == "CategoryFilter") as CategoryFilter; | ||
return categoryFilter?.AllCategories ?? Enumerable.Empty<string>(); | ||
} | ||
} | ||
|
||
public void ClearAllFilters() | ||
{ | ||
foreach (ITestFilter filter in _filters) | ||
{ | ||
filter.Reset(); | ||
} | ||
|
||
FilterNodes(TestModel.LoadedTests); | ||
FireFilterChangedEvent(); | ||
} | ||
|
||
public void Init() | ||
{ | ||
foreach (ITestFilter filter in _filters) | ||
{ | ||
filter.Init(); | ||
} | ||
} | ||
|
||
private bool FilterNodes(TestNode testNode) | ||
{ | ||
// 1. Check if any child is visible => parent must be visible too | ||
bool childIsVisible = false; | ||
foreach (TestNode child in testNode.Children) | ||
if (FilterNodes(child)) | ||
childIsVisible = true; | ||
|
||
// 2. Check if node itself is visible | ||
bool isVisible = _filters.All(f => f.IsMatching(testNode)); | ||
testNode.IsVisible = isVisible || childIsVisible; | ||
return testNode.IsVisible; | ||
} | ||
|
||
private IEnumerable<string> GetFilterCondition(string filterId) | ||
{ | ||
var testFilter = _filters.FirstOrDefault(f => f.FilterId == filterId); | ||
return testFilter.Condition ?? Enumerable.Empty<string>(); | ||
} | ||
|
||
private void SetFilterCondition(string filterId, IEnumerable<string> filter) | ||
{ | ||
// 1. Get concrete filter by ID | ||
var testFilter = _filters.FirstOrDefault(f => f.FilterId == filterId); | ||
if (testFilter == null) | ||
return; | ||
|
||
// 2. Set condition, apply new filter to all nodes and fire event | ||
testFilter.Condition = filter; | ||
FilterNodes(TestModel.LoadedTests); | ||
FireFilterChangedEvent(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// *********************************************************************** | ||
// Copyright (c) Charlie Poole and TestCentric contributors. | ||
// Licensed under the MIT License. See LICENSE file in root directory. | ||
// *********************************************************************** | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace TestCentric.Gui.Model.Filter | ||
{ | ||
/// <summary> | ||
/// Filters the TestNodes by matching a text (for example: Namespace, Class name or test method name - filter is case insensitive) | ||
/// </summary> | ||
internal class TextFilter : ITestFilter | ||
{ | ||
private string _condition = string.Empty; | ||
|
||
public string FilterId => "TextFilter"; | ||
|
||
public IEnumerable<string> Condition | ||
{ | ||
get { return new List<string>() { _condition }; } | ||
set { _condition = value.FirstOrDefault(); } | ||
} | ||
|
||
public bool IsMatching(TestNode testNode) | ||
{ | ||
if (string.IsNullOrEmpty(_condition)) | ||
{ | ||
return true; | ||
} | ||
|
||
return testNode.FullName.IndexOf(_condition, StringComparison.InvariantCultureIgnoreCase) > -1; | ||
} | ||
|
||
public void Reset() | ||
{ | ||
_condition = string.Empty; | ||
} | ||
|
||
public void Init() | ||
{ | ||
_condition = string.Empty; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.