Skip to content

Commit d3804ab

Browse files
authored
Close vulnerability info bar when the solution closes (#5726)
1 parent 7ad6fcc commit d3804ab

3 files changed

Lines changed: 170 additions & 6 deletions

File tree

src/NuGet.Clients/NuGet.SolutionRestoreManager/VulnerablePackagesInfoBar.cs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Microsoft.VisualStudio.Imaging;
1414
using Microsoft.VisualStudio.Shell;
1515
using Microsoft.VisualStudio.Shell.Interop;
16+
using NuGet.PackageManagement;
1617
using NuGet.VisualStudio;
1718
using NuGet.VisualStudio.Telemetry;
1819

@@ -23,14 +24,36 @@ namespace NuGet.SolutionRestoreManager
2324
public class VulnerablePackagesInfoBar : IVulnerabilitiesNotificationService, IVsInfoBarUIEvents
2425
{
2526
private IAsyncServiceProvider _asyncServiceProvider = AsyncServiceProvider.GlobalProvider;
26-
private IVsInfoBarUIElement? _infoBarUIElement;
27-
private bool _infoBarVisible = false; // InfoBar is currently being displayed in the Solution Explorer
28-
private bool _wasInfoBarClosed = false; // InfoBar was closed by the user, using the 'x'(close) in the InfoBar
29-
private bool _wasInfoBarHidden = false; // InfoBar was hid, this is caused because there are no more vulnerabilities to address
27+
internal IVsInfoBarUIElement? _infoBarUIElement;
28+
internal bool _infoBarVisible = false; // InfoBar is currently being displayed in the Solution Explorer
29+
internal bool _wasInfoBarClosed = false; // InfoBar was closed by the user, using the 'x'(close) in the InfoBar
30+
internal bool _wasInfoBarHidden = false; // InfoBar was hid, this is caused because there are no more vulnerabilities to address
3031
private uint? _eventCookie; // To hold the connection cookie
3132

32-
[Import]
33-
private Lazy<IPackageManagerLaunchService>? PackageManagerLaunchService { get; set; }
33+
private Lazy<IPackageManagerLaunchService>? PackageManagerLaunchService { get; }
34+
private ISolutionManager? SolutionManager { get; }
35+
36+
[ImportingConstructor]
37+
public VulnerablePackagesInfoBar(ISolutionManager solutionManager, Lazy<IPackageManagerLaunchService> packageManagerLaunchService)
38+
{
39+
SolutionManager = solutionManager;
40+
PackageManagerLaunchService = packageManagerLaunchService;
41+
SolutionManager.SolutionClosed += OnSolutionClosed;
42+
}
43+
44+
private void OnSolutionClosed(object sender, EventArgs e)
45+
{
46+
ThreadHelper.ThrowIfNotOnUIThread();
47+
48+
if (_infoBarVisible)
49+
{
50+
_infoBarUIElement?.Close();
51+
}
52+
// Reset all the state to defaults, since the solution is closed.
53+
_wasInfoBarHidden = false;
54+
_wasInfoBarClosed = false;
55+
_infoBarVisible = false;
56+
}
3457

3558
public async Task ReportVulnerabilitiesAsync(bool hasVulnerabilitiesInSolution, CancellationToken cancellationToken)
3659
{
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Reflection;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using FluentAssertions;
9+
using Microsoft.VisualStudio.Shell;
10+
using Microsoft.VisualStudio.Threading;
11+
using NuGet.VisualStudio;
12+
using Test.Utility;
13+
using Xunit;
14+
using Microsoft.VisualStudio.Sdk.TestFramework;
15+
using Microsoft.VisualStudio.Shell.Interop;
16+
using Moq;
17+
18+
namespace NuGet.SolutionRestoreManager.Test
19+
{
20+
[Collection(MockedVS.Collection)]
21+
public class VulnerablePackagesInfoBarTests
22+
{
23+
public VulnerablePackagesInfoBarTests(GlobalServiceProvider sp)
24+
{
25+
sp.Reset();
26+
}
27+
28+
[Fact]
29+
public void Constructor_SubscribesToCloseEvents()
30+
{
31+
// Arrange
32+
TestSolutionManager solutionManager = new TestSolutionManager(string.Empty);
33+
34+
// Act
35+
VulnerablePackagesInfoBar infoBar = new VulnerablePackagesInfoBar(solutionManager, new Lazy<IPackageManagerLaunchService>());
36+
37+
EventHandler e = typeof(TestSolutionManager)
38+
.GetField(nameof(TestSolutionManager.SolutionClosed), BindingFlags.Instance | BindingFlags.NonPublic)
39+
.GetValue(solutionManager) as EventHandler;
40+
e.Should().NotBeNull();
41+
42+
Delegate[] subscribers = e.GetInvocationList();
43+
44+
// Assert
45+
subscribers.Should().HaveCount(1);
46+
subscribers[0].Target.Should().BeSameAs(infoBar);
47+
}
48+
49+
[Fact]
50+
public async Task ReportVulnerabilitiesAsync_WhenNoVulnerabilitiesExist_InfoBarIsNotLaunched()
51+
{
52+
// Arrange
53+
TestSolutionManager solutionManager = new TestSolutionManager(string.Empty);
54+
VulnerablePackagesInfoBar infoBar = new VulnerablePackagesInfoBar(solutionManager, new Lazy<IPackageManagerLaunchService>());
55+
56+
// Act
57+
await infoBar.ReportVulnerabilitiesAsync(hasVulnerabilitiesInSolution: false, CancellationToken.None);
58+
59+
// Assert
60+
infoBar._infoBarVisible.Should().BeFalse();
61+
infoBar._wasInfoBarHidden.Should().BeFalse();
62+
infoBar._wasInfoBarClosed.Should().BeFalse();
63+
}
64+
65+
[Fact]
66+
public async Task OnSolutionClosed_ResetsInfoBarStatusProperties()
67+
{
68+
// Arrange
69+
TestSolutionManager solutionManager = new TestSolutionManager(string.Empty);
70+
VulnerablePackagesInfoBar infoBar = new VulnerablePackagesInfoBar(solutionManager, new Lazy<IPackageManagerLaunchService>());
71+
72+
infoBar._infoBarVisible = true;
73+
infoBar._wasInfoBarHidden = true;
74+
infoBar._wasInfoBarClosed = true;
75+
// Act
76+
await NuGetUIThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
77+
solutionManager.OnSolutionClosed();
78+
79+
// Assert
80+
infoBar._infoBarVisible.Should().BeFalse();
81+
infoBar._wasInfoBarHidden.Should().BeFalse();
82+
infoBar._wasInfoBarClosed.Should().BeFalse();
83+
}
84+
85+
[Fact]
86+
public async Task OnSolutionClosed_WithInfoBarVisible_ClosesInfoBar()
87+
{
88+
// Arrange
89+
TestSolutionManager solutionManager = new TestSolutionManager(string.Empty);
90+
VulnerablePackagesInfoBar infoBar = new VulnerablePackagesInfoBar(solutionManager, new Lazy<IPackageManagerLaunchService>());
91+
92+
infoBar._infoBarVisible = true;
93+
infoBar._wasInfoBarHidden = true;
94+
infoBar._wasInfoBarClosed = true;
95+
96+
Mock<IVsInfoBarUIElement> infoBarUIElement = new Mock<IVsInfoBarUIElement>();
97+
98+
99+
infoBar._infoBarUIElement = infoBarUIElement.Object;
100+
// Act
101+
await NuGetUIThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
102+
solutionManager.OnSolutionClosed();
103+
104+
// Assert
105+
infoBar._infoBarVisible.Should().BeFalse();
106+
infoBar._wasInfoBarHidden.Should().BeFalse();
107+
infoBar._wasInfoBarClosed.Should().BeFalse();
108+
infoBarUIElement.Verify(ui => ui.Close(), Times.Once());
109+
}
110+
111+
[Fact]
112+
public async Task OnSolutionClosed_WithInfoBarNotVisible_DoesNotAttemptToCloseInfoBar()
113+
{
114+
// Arrange
115+
TestSolutionManager solutionManager = new TestSolutionManager(string.Empty);
116+
VulnerablePackagesInfoBar infoBar = new VulnerablePackagesInfoBar(solutionManager, new Lazy<IPackageManagerLaunchService>());
117+
118+
infoBar._infoBarVisible = false;
119+
infoBar._wasInfoBarHidden = true;
120+
infoBar._wasInfoBarClosed = false;
121+
122+
Mock<IVsInfoBarUIElement> infoBarUIElement = new Mock<IVsInfoBarUIElement>();
123+
124+
infoBar._infoBarUIElement = infoBarUIElement.Object;
125+
// Act
126+
await NuGetUIThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
127+
solutionManager.OnSolutionClosed();
128+
129+
// Assert
130+
infoBar._infoBarVisible.Should().BeFalse();
131+
infoBar._wasInfoBarHidden.Should().BeFalse();
132+
infoBar._wasInfoBarClosed.Should().BeFalse();
133+
infoBarUIElement.Verify(ui => ui.Close(), Times.Never());
134+
}
135+
}
136+
}

test/TestUtilities/Test.Utility/PackageManagement/TestSolutionManager.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ public void OnActionsExecuted(IEnumerable<ResolvedAction> actions)
232232
}
233233
}
234234

235+
public void OnSolutionClosed()
236+
{
237+
SolutionClosed?.Invoke(this, EventArgs.Empty);
238+
}
239+
235240
public void Dispose()
236241
{
237242
var testDirectory = TestDirectory;

0 commit comments

Comments
 (0)