Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/dotnet-core-uninstall/Shared/BundleInfo/Bundle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ public override string ToString()
{
return $"{Version.ToString()} ({Arch.ToString().ToLower()})";
}

public virtual string ToDebugString()
{
return $"{Version.ToString()} ({Arch.ToString().ToLower()})";
}
}

internal class Bundle<TBundleVersion> : Bundle, IComparable, IComparable<Bundle>, IEquatable<Bundle<TBundleVersion>>
Expand Down Expand Up @@ -104,5 +109,9 @@ public override int GetHashCode()
{
return HashCode.Combine(base.GetHashCode());
}

public override string ToDebugString() {
return $"{nameof(TBundleVersion)} {Version.ToString()} ({Arch.ToString().ToLower()}) - {UninstallCommand ?? "n/a"}";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.DotNet.Tools.Uninstall.Shared.VSVersioning
internal static class VisualStudioSafeVersionsExtractor
{
// The tool should not be used to uninstall any more recent versions of the sdk
public static readonly SemanticVersion UpperLimit = new SemanticVersion(7, 0, 0);
public static readonly SemanticVersion UpperLimit = new SemanticVersion(8, 0, 0);

// Must keep one of each of these divisions to ensure Visual Studio works.
// Pairs are [inclusive, exclusive)
Expand All @@ -25,7 +25,8 @@ internal static class VisualStudioSafeVersionsExtractor
{ (new SemanticVersion(2, 1, 600), new SemanticVersion(2, 1, 900)), string.Format(LocalizableStrings.WindowsRequirementExplainationString, " 2019") },
{ (new SemanticVersion(2, 2, 100), new SemanticVersion(2, 2, 200)), string.Format(LocalizableStrings.WindowsRequirementExplainationString, " 2017") },
{ (new SemanticVersion(2, 2, 200), new SemanticVersion(2, 2, 500)), string.Format(LocalizableStrings.WindowsRequirementExplainationString, " 2019") },
{ (new SemanticVersion(2, 2, 500), UpperLimit), string.Format(LocalizableStrings.WindowsRequirementExplainationString, "") }
{ (new SemanticVersion(3, 0, 100), new SemanticVersion(5, 0, 600)), string.Format(LocalizableStrings.WindowsRequirementExplainationString, " 2019") },
{ (new SemanticVersion(6, 0, 100), UpperLimit), string.Format(LocalizableStrings.WindowsRequirementExplainationString, "") }
};

private static (IDictionary<IEnumerable<Bundle>, string>, IEnumerable<Bundle>) ApplyWindowsVersionDivisions(IEnumerable<Bundle> bundleList)
Expand Down
1 change: 1 addition & 0 deletions src/dotnet-core-uninstall/dotnet-core-uninstall.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<RuntimeIdentifiers>win-x86;osx-x64</RuntimeIdentifiers>
<SignAssembly>true</SignAssembly>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RollForward>LatestMajor</RollForward>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.CommandLine.Parsing;
using System.Linq;
using FluentAssertions;
using FluentAssertions.Execution;
using Microsoft.DotNet.Tools.Uninstall.Shared.BundleInfo;
using Microsoft.DotNet.Tools.Uninstall.Shared.BundleInfo.Versioning;
using Microsoft.DotNet.Tools.Uninstall.Shared.Commands;
Expand All @@ -19,7 +20,7 @@ namespace Microsoft.DotNet.Tools.Uninstall.Tests.Shared.Commands
{
public class CommandBundleFilterTests
{
private static readonly string[] versions = { "1.0.0", "1.0.1", "1.1.0", "2.1.0", "2.1.500", "2.1.600", "2.2.100", "2.2.200", "5.0.0", "7.0.1", "10.10.10" };
private static readonly string[] versions = { "1.0.0", "1.0.1", "1.1.0", "2.1.0", "2.1.500", "2.1.600", "2.2.100", "2.2.200", "5.0.0", "7.0.1", "8.0.1", "10.10.10" };
private Dictionary<string, BundleArch> versionsWithArch = new Dictionary<string, BundleArch>
{
{ "3.0.0", BundleArch.X64 },
Expand All @@ -42,7 +43,7 @@ public class CommandBundleFilterTests
[InlineData("remove --sdk 1.0.1", new string[] { "1.0.1" })]
[InlineData("remove --sdk 1.0.0", new string[] { "1.0.0" })]
[InlineData("remove --sdk 1.0.1 2.1.0 1.0.1", new string[] { "2.1.0", "1.0.1", "1.0.1" })]
[InlineData("remove --sdk 1.0.0 1.0.1 1.1.0 2.1.0 2.1.500 2.1.600 2.2.100 2.2.200",
[InlineData("remove --sdk 1.0.0 1.0.1 1.1.0 2.1.0 2.1.500 2.1.600 2.2.100 2.2.200",
new string[] { "1.0.0", "1.0.1", "1.1.0", "2.1.0", "2.1.500", "2.1.600", "2.2.100", "2.2.200" })]
internal void TestRequiredUninstallableWhenExplicitlyAddedWindows(string command, string[] expectedUninstallable)
{
Expand Down Expand Up @@ -103,8 +104,14 @@ internal void TestRequiredUninstallableWithOptionsMac(string command, string[] e

internal void TestRequiredUninstallableWhenExplicitlyAdded(IEnumerable<Bundle> bundles, string command, string[] expectedUninstallableSdk, string[] expectedUninstallableRuntime)
{
using var scope = new AssertionScope();
scope.AddReportable("bundles", () => String.Join(Environment.NewLine, bundles.Select(b => b.ToDebugString())));
scope.AddReportable("command", () => command);
scope.AddReportable("expectedUninstallableSdk", () => String.Join(Environment.NewLine, expectedUninstallableSdk));
scope.AddReportable("expectedUninstallableRuntime", () => String.Join(Environment.NewLine, expectedUninstallableRuntime));
var parseResult = CommandLineConfigs.UninstallRootCommand.Parse(command);
var uninstallableBundles = CommandBundleFilter.GetFilteredBundles(bundles, parseResult);
scope.AddReportable("uninstallableBundles", () => String.Join(Environment.NewLine, uninstallableBundles.Select(b => b.ToDebugString())));

var uninstallableSdks = uninstallableBundles.Where(b => b.Version is SdkVersion).Select(b => b.DisplayName);
var requiredSdks = bundles.Except(uninstallableBundles).Where(b => b.Version is SdkVersion).Select(b => b.DisplayName);
Expand All @@ -122,7 +129,7 @@ internal void TestRequiredUninstallableWhenExplicitlyAdded(IEnumerable<Bundle> b
}

[Theory]
[InlineData("remove {0} 7.0.1")]
[InlineData("remove {0} 8.0.1")]
[InlineData("remove {0} 10.10.10")]
[InlineData("remove {0} --all --force")]
[InlineData("remove {0} 1.0.0 1.0.1 1.1.0 2.1.0 2.1.500 2.1.600 2.2.100 2.2.200 5.0.0 7.0.1 10.10.10")]
Expand Down Expand Up @@ -158,13 +165,13 @@ internal void CheckUpperLimitAlwaysRequired(string command, IEnumerable<Bundle>
{
var parseResult = CommandLineConfigs.UninstallRootCommand.Parse(command);
Action filteringAction = () => CommandBundleFilter.GetFilteredBundles(bundles, parseResult);
filteringAction.Should().Throw<UninstallationNotAllowedException>();
filteringAction.Should().Throw<UninstallationNotAllowedException>("Expected command '{0}' to fail when the following bundles were installed: {1}", command, String.Join(", ", bundles.Select(b => b.DisplayName).ToList()));
}

[Fact]
public void TestHelpOutputContainsExplainationParagraph()
{
foreach (var command in new string[] { "dry-run -h", "whatif -h", "remove -h" })
foreach (var command in new string[] { "dry-run -h", "whatif -h", "remove -h" })
{
var console = new TestConsole();
_ = CommandLineConfigs.UninstallCommandParser.InvokeAsync(command, console).Result;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using FluentAssertions.Execution;
using Microsoft.DotNet.Tools.Uninstall.Shared.BundleInfo;
using Microsoft.DotNet.Tools.Uninstall.Shared.BundleInfo.Versioning;
using Microsoft.DotNet.Tools.Uninstall.Shared.VSVersioning;
Expand All @@ -25,8 +27,8 @@ public class VSVersionTests
[InlineData(new string[] { "2.2.100", "2.2.200" }, new bool[] { false, false })]
[InlineData(new string[] { "2.2.100", "2.2.200", "2.2.300" }, new bool[] { false, true, false })]
[InlineData(new string[] { "3.0.0", "3.0.1", "5.0.0" }, new bool[] { true, true, false })]
[InlineData(new string[] { "5.0.0", "5.0.1", "6.0.1" }, new bool[] { true, true, false })]
[InlineData(new string[] { "6.0.0", "6.0.1", "7.0.0" }, new bool[] { true, false, false })]
[InlineData(new string[] { "5.0.0", "5.0.1", "6.0.1" }, new bool[] { true, false, true })]
[InlineData(new string[] { "6.0.0", "6.0.1", "7.0.0" }, new bool[] { true, true, false })]
[InlineData(new string[] { "9.0.0", "9.0.1", "10.100.100" }, new bool[] { false, false, false })]
internal void TestGetUninstallableWindows(string[] versions, bool[] allowed)
{
Expand All @@ -48,7 +50,7 @@ internal void TestGetUninstallableWindows(string[] versions, bool[] allowed)
[InlineData(new string[] { "1.0.0" }, new bool[] { false }, new string[] { "1.0.0" }, new bool[] { false })]
[InlineData(new string[] { "1.0.0", "1.0.1" }, new bool[] { true, false }, new string[] { "1.0.0", "1.0.1" }, new bool[] { true, false })]
[InlineData(new string[] { "2.1.0", "1.0.1" }, new bool[] { false, true }, new string[] { "1.0.0", "1.1.0" }, new bool[] { false, false })]
[InlineData(new string[] { "3.0.0", "7.0.0" }, new bool[] { false, false }, new string[] { "1.0.0", "1.1.0", "1.0.1", "1.0.2", "1.1.3" }, new bool[] { true, true, true, false, false })]
[InlineData(new string[] { "3.0.0", "7.0.0" }, new bool[] { true, false }, new string[] { "1.0.0", "1.1.0", "1.0.1", "1.0.2", "1.1.3" }, new bool[] { true, true, true, false, false })]
[InlineData(new string[] { "3.0.0", "5.0.0" }, new bool[] { true, false }, new string[] { "1.0.0", "1.1.0", "1.0.1", "5.0.0" }, new bool[] { true, false, false, false })]
[InlineData(new string[] { "5.0.0", "5.0.1", "10.100.100" }, new bool[] { true, false, false }, new string[] { "5.0.0", "10.0.0" }, new bool[] { false, false })]
[InlineData(new string[] { "5.0.0", "6.0.0", "6.0.1" }, new bool[] { true, true, false }, new string[] { "5.0.0" }, new bool[] { false })]
Expand Down Expand Up @@ -77,7 +79,7 @@ internal void TestGetUninstallableMac(string[] sdkVersions, bool[] sdkAllowed, s
[InlineData(new string[] { "2.1.500", "2.1.400", "2.1.600" }, new bool[] { false, true, false })]
[InlineData(new string[] { "2.2.100", "2.2.200", "2.2.300" }, new bool[] { false, true, false })]
[InlineData(new string[] { "5.0.0", "5.0.1", "10.0.1" }, new bool[] { true, false, false })]
[InlineData(new string[] { "5.0.0", "6.0.0", "6.0.1" }, new bool[] { true, true, false })]
[InlineData(new string[] { "5.0.0", "6.0.0", "6.0.1" }, new bool[] { false, true, true })]
[InlineData(new string[] { "9.0.0", "9.0.1", "10.100.100" }, new bool[] { false, false, false })]
internal void TestGetUninstallableNonSdkVersionsWindows(string[] versions, bool[] allowed)
{
Expand Down Expand Up @@ -113,7 +115,7 @@ internal void TestGetUninstallableNonSdkVersionsMac(string[] sdkVersions, bool[]
internal void TestGetUninstallableNonSdkVersions(IEnumerable<Bundle> bundles, bool[] sdkAllowed, bool[] runtimeAllowed)
{
bundles = bundles.Concat(new List<Bundle>
{
{
new Bundle<AspNetRuntimeVersion>(new AspNetRuntimeVersion("1.0.0"), new BundleArch(), string.Empty, "AspNetVersion"),
new Bundle<AspNetRuntimeVersion>(new AspNetRuntimeVersion("10.0.0"), new BundleArch(), string.Empty, "AspNetVersion"),
new Bundle<HostingBundleVersion>(new HostingBundleVersion("1.0.0"), new BundleArch(), string.Empty, "HostingBundleVersion"),
Expand All @@ -129,52 +131,55 @@ internal void TestGetUninstallableNonSdkVersions(IEnumerable<Bundle> bundles, bo
CheckAllowed(bundles, uninstallable, sdkAllowed, runtimeAllowed);
}

private void CheckAllowed(IEnumerable<Bundle> bundles, IEnumerable<Bundle> uninstallable, bool[] sdkAllowed, bool[] runtimeAllowed)
private void CheckAllowed(IEnumerable<Bundle> allBundles, IEnumerable<Bundle> uninstallableBundles, bool[] sdkAllowed, bool[] runtimeAllowed)
{
var sdkBundles = bundles.Where(bundle => bundle.Version is SdkVersion).ToArray();
var runtimeBundles = bundles.Where(bundle => bundle.Version is RuntimeVersion).ToArray();
var otherBundles = bundles.Except(sdkBundles).Except(runtimeBundles);
using var scope = new AssertionScope();
scope.AddReportable("allBundles", () => String.Join(Environment.NewLine, allBundles.Select(b => b.ToDebugString())));
scope.AddReportable("uninstallableBundles", () => String.Join(Environment.NewLine, uninstallableBundles.Select(b => b.ToDebugString())));
var sdkBundles = allBundles.Where(bundle => bundle.Version is SdkVersion).ToArray();
var runtimeBundles = allBundles.Where(bundle => bundle.Version is RuntimeVersion).ToArray();
var otherBundles = allBundles.Except(sdkBundles).Except(runtimeBundles);
for (int i = 0; i < sdkBundles.Count(); i++)
{
if (sdkAllowed[i])
{
uninstallable.Should().Contain(sdkBundles[i]);
uninstallableBundles.Should().Contain(sdkBundles[i]);
}
else
{
uninstallable.Should().NotContain(sdkBundles[i]);
uninstallableBundles.Should().NotContain(sdkBundles[i]);
}
}

for (int i = 0; i < runtimeBundles.Count(); i++)
{
if (runtimeAllowed[i])
{
uninstallable.Should().Contain(runtimeBundles[i]);
uninstallableBundles.Should().Contain(runtimeBundles[i]);
}
else
{
uninstallable.Should().NotContain(runtimeBundles[i]);
uninstallableBundles.Should().NotContain(runtimeBundles[i]);
}
}
// Check others are uninstallable unless their version is above the upper limit
foreach (Bundle bundle in otherBundles)
{
if (bundle.Version.SemVer > VisualStudioSafeVersionsExtractor.UpperLimit)
{
uninstallable.Should().NotContain(bundle);
uninstallableBundles.Should().NotContain(bundle);
}
else
{
uninstallable.Should().Contain(bundle);
uninstallableBundles.Should().Contain(bundle);
}
}
}

[WindowsOnlyTheory]
[InlineData(new string[] { }, new string[] { })]
[InlineData(new string[] { "1.0.1", "1.0.0" }, new string[] { "", "None" })]
[InlineData(new string[] { "2.3.0", "2.1.800", "2.1.300" }, new string[] { "", " 2019", " 2017" })]
[InlineData(new string[] { "2.3.0", "2.1.800", "2.1.300" }, new string[] { "None", " 2019", " 2017" })]
[InlineData(new string[] { "2.1.500", "2.1.400", "2.1.600" }, new string[] { " 2017", "None", " 2019" })]
[InlineData(new string[] { "2.1.500", "10.0.1", "10.0.0" }, new string[] { " 2017", "UpperLimit", "UpperLimit" })]
internal void TestGetListCommandUninstallableStringsWindows(string[] versions, string[] expectedStrings)
Expand Down Expand Up @@ -262,7 +267,7 @@ private string[] ExpandExpectationShortHand(string[] input)
{ "Runtime", LocalizableStrings.MacRuntimeRequirementExplainationString}
};
var output = new string[input.Length];

for (int i = 0; i < input.Length; i++)
{
output[i] = shortHandToFullExpectedString[input[i]];
Expand Down