Skip to content

Commit 35ef70e

Browse files
authored
Merge pull request #5064 from IvenBach/Issue2964_TestExplorerDisableTestViaContextMenu
Add menu item to Test Explorer context menu allowing Ignore/Unignore of unit test
2 parents 66e505a + 9b5eedf commit 35ef70e

File tree

8 files changed

+111
-17
lines changed

8 files changed

+111
-17
lines changed

Rubberduck.Core/UI/UnitTesting/TestExplorerControl.xaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,13 @@
5454
<BitmapImage x:Key="OutcomeInconclusive" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/exclamation.png" />
5555
<BitmapImage x:Key="OutcomeSucceeded" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/tick-circle.png" />
5656

57+
<BitmapImage x:Key="IgnoreTestImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/flask-empty.png" />
58+
<BitmapImage x:Key="UnignoreTestImage" UriSource="pack://application:,,,/Rubberduck.Resources;component/Icons/Fugue/flask-undo.png" />
59+
5760
<local:TestOutcomeImageSourceConverter x:Key="OutcomeIconConverter" />
5861
<converters:MillisecondToTimeMagnitudeConverter x:Key="FormattedTime" />
5962
<converters:InvertBoolValueConverter x:Key="InvertBoolValue" />
63+
<BooleanToVisibilityConverter x:Key="BoolToVisibility" />
6064

6165
<Style x:Key="ToolbarImageOpacity" TargetType="Image" >
6266
<Setter Property="Height" Value="16" />
@@ -433,6 +437,20 @@
433437
<Image Source="{StaticResource RunAllTestsImage}" />
434438
</MenuItem.Icon>
435439
</MenuItem>
440+
<MenuItem Command="{Binding IgnoreTestCommand}"
441+
Header="{Resx ResxName=Rubberduck.Resources.UnitTesting.TestExplorer, Key=TestExplorer_TestToggle_Ignore}"
442+
Visibility="{Binding DisplayIgnoreTestLabel, Converter={StaticResource BoolToVisibility}}">
443+
<MenuItem.Icon>
444+
<Image Source="{StaticResource IgnoreTestImage}" />
445+
</MenuItem.Icon>
446+
</MenuItem>
447+
<MenuItem Command="{Binding UnignoreTestCommand}"
448+
Header="{Resx ResxName=Rubberduck.Resources.UnitTesting.TestExplorer, Key=TestExplorer_TestToggle_Unignore}"
449+
Visibility="{Binding DisplayUnignoreTestLabel, Converter={StaticResource BoolToVisibility}}">
450+
<MenuItem.Icon>
451+
<Image Source="{StaticResource UnignoreTestImage}" />
452+
</MenuItem.Icon>
453+
</MenuItem>
436454
</ContextMenu>
437455
</DataGrid.ContextMenu>
438456
<i:Interaction.Behaviors>

Rubberduck.Core/UI/UnitTesting/TestExplorerViewModel.cs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
using System.ComponentModel;
55
using System.Globalization;
66
using System.Linq;
7+
using System.Windows.Annotations;
78
using System.Windows.Data;
89
using NLog;
910
using Rubberduck.Common;
1011
using Rubberduck.Interaction.Navigation;
12+
using Rubberduck.Parsing;
13+
using Rubberduck.Parsing.Rewriter;
14+
using Rubberduck.Parsing.VBA;
15+
using Rubberduck.Resources;
1116
using Rubberduck.Settings;
1217
using Rubberduck.SettingsProvider;
1318
using Rubberduck.UI.Command;
@@ -49,7 +54,9 @@ public TestExplorerViewModel(ISelectionService selectionService,
4954
IClipboardWriter clipboard,
5055
// ReSharper disable once UnusedParameter.Local - left in place because it will likely be needed for app wide font settings, etc.
5156
IConfigurationService<Configuration> configService,
52-
ISettingsFormFactory settingsFormFactory)
57+
ISettingsFormFactory settingsFormFactory,
58+
IRewritingManager rewritingManager,
59+
IAnnotationUpdater annotationUpdater)
5360
{
5461
_clipboard = clipboard;
5562
_settingsFormFactory = settingsFormFactory;
@@ -64,6 +71,11 @@ public TestExplorerViewModel(ISelectionService selectionService,
6471
OpenTestSettingsCommand = new DelegateCommand(LogManager.GetCurrentClassLogger(), OpenSettings);
6572
CollapseAllCommand = new DelegateCommand(LogManager.GetCurrentClassLogger(), ExecuteCollapseAll);
6673
ExpandAllCommand = new DelegateCommand(LogManager.GetCurrentClassLogger(), ExecuteExpandAll);
74+
IgnoreTestCommand = new DelegateCommand(LogManager.GetCurrentClassLogger(), ExecuteIgnoreTestCommand);
75+
UnignoreTestCommand = new DelegateCommand(LogManager.GetCurrentClassLogger(), ExecuteUnignoreTestCommand);
76+
77+
RewritingManager = rewritingManager;
78+
AnnotationUpdater = annotationUpdater;
6779

6880
Model = model;
6981
Model.TestCompleted += HandleTestCompletion;
@@ -99,6 +111,7 @@ public TestMethodViewModel MouseOverTest
99111
}
100112
_mouseOverTest = value;
101113
OnPropertyChanged();
114+
RefreshContextMenu();
102115
}
103116
}
104117

@@ -114,9 +127,16 @@ public CollectionViewGroup MouseOverGroup
114127
}
115128
_mouseOverGroup = value;
116129
OnPropertyChanged();
130+
RefreshContextMenu();
117131
}
118132
}
119133

134+
private void RefreshContextMenu()
135+
{
136+
OnPropertyChanged(nameof(DisplayUnignoreTestLabel));
137+
OnPropertyChanged(nameof(DisplayIgnoreTestLabel));
138+
}
139+
120140
private static readonly Dictionary<TestExplorerGrouping, PropertyGroupDescription> GroupDescriptions = new Dictionary<TestExplorerGrouping, PropertyGroupDescription>
121141
{
122142
{ TestExplorerGrouping.Outcome, new PropertyGroupDescription("Result.Outcome", new TestResultToOutcomeTextConverter()) },
@@ -214,6 +234,13 @@ private void HandleTestCompletion(object sender, TestCompletedEventArgs e)
214234
Tests.Refresh();
215235
}
216236

237+
public IRewritingManager RewritingManager { get; }
238+
public IAnnotationUpdater AnnotationUpdater { get; }
239+
240+
private TestMethod _mousedOverTestMethod => ((TestMethodViewModel)SelectedItem).Method;
241+
public bool DisplayUnignoreTestLabel => SelectedItem != null && _mousedOverTestMethod.IsIgnored;
242+
public bool DisplayIgnoreTestLabel => SelectedItem != null && !_mousedOverTestMethod.IsIgnored;
243+
217244
#region Commands
218245

219246
public ReparseCommand RefreshCommand { get; set; }
@@ -245,6 +272,9 @@ private void HandleTestCompletion(object sender, TestCompletedEventArgs e)
245272
public CommandBase CollapseAllCommand { get; }
246273
public CommandBase ExpandAllCommand { get; }
247274

275+
public CommandBase IgnoreTestCommand { get; }
276+
public CommandBase UnignoreTestCommand { get; }
277+
248278
#endregion
249279

250280
#region Delegates
@@ -340,6 +370,29 @@ private void ExecuteResetResultsCommand(object parameter)
340370
Tests.Refresh();
341371
}
342372

373+
private void ExecuteIgnoreTestCommand(object parameter)
374+
{
375+
var rewriteSession = RewritingManager.CheckOutCodePaneSession();
376+
377+
AnnotationUpdater.AddAnnotation(rewriteSession, _mousedOverTestMethod.Declaration, Parsing.Annotations.AnnotationType.IgnoreTest);
378+
379+
rewriteSession.TryRewrite();
380+
}
381+
382+
private void ExecuteUnignoreTestCommand(object parameter)
383+
{
384+
var rewriteSession = RewritingManager.CheckOutCodePaneSession();
385+
var ignoreTestAnnotations = _mousedOverTestMethod.Declaration.Annotations
386+
.Where(iannotations => iannotations.AnnotationType == Parsing.Annotations.AnnotationType.IgnoreTest);
387+
388+
foreach (var ignoreTestAnnotation in ignoreTestAnnotations)
389+
{
390+
AnnotationUpdater.RemoveAnnotation(rewriteSession, ignoreTestAnnotation);
391+
}
392+
393+
rewriteSession.TryRewrite();
394+
}
395+
343396
private void ExecuteCopyResultsCommand(object parameter)
344397
{
345398
const string XML_SPREADSHEET_DATA_FORMAT = "XML Spreadsheet";

Rubberduck.Parsing/QualifiedContext.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,19 @@ public override bool Equals(object obj)
3939

4040
public static bool operator ==(QualifiedContext context1, QualifiedContext context2)
4141
{
42-
if ((object)context1 == null)
42+
if (context1 is null)
4343
{
44-
return (object)context2 == null;
44+
return context2 is null;
4545
}
4646

4747
return context1.Equals(context2);
4848
}
4949

5050
public static bool operator !=(QualifiedContext context1, QualifiedContext context2)
5151
{
52-
if ((object)context1 == null)
52+
if (context1 is null)
5353
{
54-
return (object)context2 != null;
54+
return !(context2 is null);
5555
}
5656

5757
return !context1.Equals(context2);

Rubberduck.Parsing/Rewriter/RewriterInfo/RewriterInfo.cs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,21 @@ namespace Rubberduck.Parsing.Rewriter.RewriterInfo
55
{
66
public struct RewriterInfo : IEquatable<RewriterInfo>
77
{
8-
private readonly string _replacement;
9-
private readonly int _startTokenIndex;
10-
private readonly int _stopTokenIndex;
11-
128
public RewriterInfo(int startTokenIndex, int stopTokenIndex)
139
: this(string.Empty, startTokenIndex, stopTokenIndex) { }
1410

1511
public RewriterInfo(string replacement, int startTokenIndex, int stopTokenIndex)
1612
{
17-
_replacement = replacement;
18-
_startTokenIndex = startTokenIndex;
19-
_stopTokenIndex = stopTokenIndex;
13+
Replacement = replacement;
14+
StartTokenIndex = startTokenIndex;
15+
StopTokenIndex = stopTokenIndex;
2016
}
2117

22-
public string Replacement { get { return _replacement; } }
23-
public int StartTokenIndex { get { return _startTokenIndex; } }
24-
public int StopTokenIndex { get { return _stopTokenIndex; } }
18+
public string Replacement { get; }
19+
public int StartTokenIndex { get; }
20+
public int StopTokenIndex { get; }
2521

26-
public static RewriterInfo None { get { return default(RewriterInfo); } }
22+
public static RewriterInfo None => default;
2723

2824
public bool Equals(RewriterInfo other)
2925
{

Rubberduck.Resources/UnitTesting/TestExplorer.Designer.cs

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Rubberduck.Resources/UnitTesting/TestExplorer.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,4 +345,10 @@
345345
<data name="TestExplorer_AllResults" xml:space="preserve">
346346
<value>All</value>
347347
</data>
348+
<data name="TestExplorer_TestToggle_Ignore" xml:space="preserve">
349+
<value>Ignore test</value>
350+
</data>
351+
<data name="TestExplorer_TestToggle_Unignore" xml:space="preserve">
352+
<value>Unignore test</value>
353+
</data>
348354
</root>

Rubberduck.UnitTesting/UnitTesting/TestMethod.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public NavigateCodeEventArgs GetNavigationArgs()
3737
return new NavigateCodeEventArgs(new QualifiedSelection(Declaration.QualifiedName.QualifiedModuleName, Declaration.Context.GetSelection()));
3838
}
3939

40+
public bool IsIgnored => Declaration.Annotations.Any(annotation => annotation.AnnotationType == AnnotationType.IgnoreTest);
41+
42+
4043
public bool Equals(TestMethod other) => other != null && Declaration.QualifiedName.Equals(other.Declaration.QualifiedName) && TestCode.Equals(other.TestCode);
4144

4245
public override bool Equals(object obj) => obj is TestMethod method && Equals(method);

RubberduckTests/UnitTesting/MockedTestExplorer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public MockedTestExplorer(MockedTestExplorerModel model)
1414
Vbe = model.Engine.Vbe.Object;
1515
State = model.Engine.ParserState;
1616
Model = model.Model;
17-
ViewModel = new TestExplorerViewModel(null, Model, ClipboardWriter.Object, null, null);
17+
ViewModel = new TestExplorerViewModel(null, Model, ClipboardWriter.Object, null, null, null, null);
1818
}
1919

2020
public RubberduckParserState State { get; set; }

0 commit comments

Comments
 (0)