Skip to content

Commit 4614177

Browse files
couple of bug fixes
#60
1 parent f00e9ae commit 4614177

12 files changed

+207
-59
lines changed

src/RustAnalyzer.TestAdapter.UnitTests/Cargo/ToolChainServiceExtensionsTests.cs

Lines changed: 97 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@ namespace KS.RustAnalyzer.TestAdapter.UnitTests.Cargo;
66
using System.IO;
77
using System.Linq;
88
using System.Threading.Tasks;
9+
using ApprovalTests;
10+
using ApprovalTests.Namers;
11+
using ApprovalTests.Reporters;
912
using FluentAssertions;
1013
using KS.RustAnalyzer.TestAdapter.Cargo;
1114
using KS.RustAnalyzer.TestAdapter.Common;
1215
using KS.RustAnalyzer.Tests.Common;
16+
using Newtonsoft.Json;
1317
using Xunit;
1418

1519
public sealed class ToolchainServiceExtensionsTests
@@ -41,15 +45,100 @@ public async Task TestGetBinAndLibPathsAsync()
4145
(binPath + Constants.CargoExe).FileExists().Should().BeTrue();
4246
}
4347

44-
[Fact]
45-
public async Task TestGetInstalledToolchainsBasicAsync()
48+
/// <summary>
49+
/// In cases of test failure:
50+
/// a. use "rustup show --verbose" to update the inline data first.
51+
/// b. 2 cases: one with same active and default toolchain, and another with separate active &amp; default toolchains.
52+
/// </summary>
53+
[Theory]
54+
[UseReporter(typeof(RaVsDiffReporter))]
55+
[InlineData(
56+
#pragma warning disable SA1118 // Parameter should not span multiple lines
57+
"separate_active_and_default",
58+
@"Default host: x86_64-pc-windows-msvc
59+
rustup home: C:\Users\parth\scoop\persist\rustup\.rustup
60+
61+
installed toolchains
62+
--------------------
63+
stable-x86_64-pc-windows-msvc (active)
64+
rustc 1.86.0 (05f9846f8 2025-03-31)
65+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\stable-x86_64-pc-windows-msvc
66+
67+
nightly-x86_64-pc-windows-msvc (default)
68+
rustc 1.89.0-nightly (8405332bd 2025-05-12)
69+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\nightly-x86_64-pc-windows-msvc
70+
71+
nightly-2024-03-27-x86_64-pc-windows-msvc
72+
rustc 1.79.0-nightly (47ecded35 2024-03-26)
73+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\nightly-2024-03-27-x86_64-pc-windows-msvc
74+
75+
1.75.0-x86_64-pc-windows-msvc
76+
rustc 1.75.0 (82e1608df 2023-12-21)
77+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\1.75.0-x86_64-pc-windows-msvc
78+
79+
1.76.0-x86_64-pc-windows-msvc
80+
rustc 1.76.0 (07dca489a 2024-02-04)
81+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\1.76.0-x86_64-pc-windows-msvc
82+
83+
active toolchain
84+
----------------
85+
name: stable-x86_64-pc-windows-msvc
86+
active because: directory override for 'D:\'
87+
compiler: rustc 1.86.0 (05f9846f8 2025-03-31)
88+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\stable-x86_64-pc-windows-msvc
89+
installed targets:
90+
aarch64-unknown-none
91+
wasm32-unknown-unknown
92+
x86_64-pc-windows-msvc")]
93+
#pragma warning restore SA1118 // Parameter should not span multiple lines
94+
[InlineData(
95+
#pragma warning disable SA1118 // Parameter should not span multiple lines
96+
"same_active_and_default",
97+
@"Default host: x86_64-pc-windows-msvc
98+
rustup home: C:\Users\parth\scoop\persist\rustup\.rustup
99+
100+
installed toolchains
101+
--------------------
102+
stable-x86_64-pc-windows-msvc
103+
rustc 1.86.0 (05f9846f8 2025-03-31)
104+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\stable-x86_64-pc-windows-msvc
105+
106+
nightly-x86_64-pc-windows-msvc (active, default)
107+
rustc 1.89.0-nightly (8405332bd 2025-05-12)
108+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\nightly-x86_64-pc-windows-msvc
109+
110+
nightly-2024-03-27-x86_64-pc-windows-msvc
111+
rustc 1.79.0-nightly (47ecded35 2024-03-26)
112+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\nightly-2024-03-27-x86_64-pc-windows-msvc
113+
114+
1.75.0-x86_64-pc-windows-msvc
115+
rustc 1.75.0 (82e1608df 2023-12-21)
116+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\1.75.0-x86_64-pc-windows-msvc
117+
118+
1.76.0-x86_64-pc-windows-msvc
119+
rustc 1.76.0 (07dca489a 2024-02-04)
120+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\1.76.0-x86_64-pc-windows-msvc
121+
122+
active toolchain
123+
----------------
124+
name: nightly-x86_64-pc-windows-msvc
125+
active because: directory override for 'D:\src'
126+
compiler: rustc 1.89.0-nightly (8405332bd 2025-05-12)
127+
path: C:\Users\parth\scoop\persist\rustup\.rustup\toolchains\nightly-x86_64-pc-windows-msvc
128+
installed targets:
129+
aarch64-unknown-none
130+
wasm32-unknown-unknown
131+
x86_64-pc-windows-msvc")]
132+
#pragma warning restore SA1118 // Parameter should not span multiple lines
133+
public async Task TestGetInstalledToolchainsBasicAsync(string testName, string output)
46134
{
47-
var installToolchains = await ToolchainServiceExtensions.GetInstalledToolchainsAsync(TestHelpers.ThisTestRoot, default);
135+
NamerFactory.AdditionalInformation = testName;
136+
var installToolchains = await ToolchainServiceExtensions.GetInstalledToolchainsAsync(
137+
new ToolchainServiceExtensions.RustupShowOutput.Simulated(output.Split('\r', '\n')),
138+
TestHelpers.ThisTestRoot,
139+
default);
48140

49-
installToolchains.Should().NotBeEmpty();
50-
installToolchains.Select(x => x.Name).Should().Contain(x => !x.IsNullOrEmptyOrWhiteSpace());
51-
installToolchains.Select(x => x.Version).Should().Contain(x => !x.IsNullOrEmptyOrWhiteSpace());
52-
installToolchains.Where(x => x.IsDefault).Should().HaveCount(1);
141+
Approvals.VerifyAll(installToolchains.OrderBy(x => x.Name).Select(o => o.SerializeObject(Formatting.Indented)), label: string.Empty);
53142
}
54143

55144
[Fact]
@@ -58,7 +147,7 @@ public async Task TestGetTargetsAsync()
58147
var targets = await ToolchainServiceExtensions.GetTargets(default);
59148

60149
targets.Should().NotContain(ToolchainServiceExtensions.AlwaysAvailableTarget);
61-
targets.Should().OnlyContain(t => !t.Contains(" ("));
150+
targets.Should().OnlyContain(t => !t.Contains("("));
62151
targets.Take(ToolchainServiceExtensions.CommonTargets.Length)
63152
.Should()
64153
.ContainInOrder(ToolchainServiceExtensions.CommonTargets.OrderBy(x => x));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[0] = {
2+
"Name": "1.75.0-x86_64-pc-windows-msvc",
3+
"Version": "1.75.0 (2023-12-21)",
4+
"IsActive": false
5+
}
6+
[1] = {
7+
"Name": "1.76.0-x86_64-pc-windows-msvc",
8+
"Version": "1.76.0 (2024-02-04)",
9+
"IsActive": false
10+
}
11+
[2] = {
12+
"Name": "nightly-2024-03-27-x86_64-pc-windows-msvc",
13+
"Version": "1.79.0-nightly (2024-03-26)",
14+
"IsActive": false
15+
}
16+
[3] = {
17+
"Name": "nightly-x86_64-pc-windows-msvc",
18+
"Version": "1.89.0-nightly (2025-05-12)",
19+
"IsActive": true
20+
}
21+
[4] = {
22+
"Name": "stable-x86_64-pc-windows-msvc",
23+
"Version": "1.86.0 (2025-03-31)",
24+
"IsActive": false
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[0] = {
2+
"Name": "1.75.0-x86_64-pc-windows-msvc",
3+
"Version": "1.75.0 (2023-12-21)",
4+
"IsActive": false
5+
}
6+
[1] = {
7+
"Name": "1.76.0-x86_64-pc-windows-msvc",
8+
"Version": "1.76.0 (2024-02-04)",
9+
"IsActive": false
10+
}
11+
[2] = {
12+
"Name": "nightly-2024-03-27-x86_64-pc-windows-msvc",
13+
"Version": "1.79.0-nightly (2024-03-26)",
14+
"IsActive": false
15+
}
16+
[3] = {
17+
"Name": "nightly-x86_64-pc-windows-msvc",
18+
"Version": "1.89.0-nightly (2025-05-12)",
19+
"IsActive": false
20+
}
21+
[4] = {
22+
"Name": "stable-x86_64-pc-windows-msvc",
23+
"Version": "1.86.0 (2025-03-31)",
24+
"IsActive": true
25+
}

src/RustAnalyzer.TestAdapter.UnitTests/Common/ProcessExtensionTests.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ public sealed class ProcessExtensionTests
1212
{
1313
private const int TimeoutSeconds = 15;
1414

15-
[Fact(Skip = "Unblocking release, will switch to pwsh")]
15+
[Fact]
1616
public void CanFindAliveParentProcessId()
1717
{
1818
var p1 = Process.Start(("cmd", $"/k timeout {TimeoutSeconds} /NOBREAK").PSI());
1919

2020
var ppids = "timEOut".GetProcessesByName().Select(p => p.GetParentProcessId());
21-
p1.HasExited.Should().BeFalse();
2221
ppids.Should().Contain(p1.Id);
22+
p1.HasExited.Should().BeFalse();
2323

2424
p1.Kill();
2525
}
@@ -42,12 +42,10 @@ public async Task CanFindDeadParentProcessIdAsync()
4242
[Fact]
4343
public void TestProcessOwnerUser()
4444
{
45-
var p1 = Process.Start(("cmd", $"/k timeout.exe {TimeoutSeconds} /NOBREAK").PSI());
45+
var p1 = Process.Start(("cmd", $"/c timeout.exe {TimeoutSeconds} /NOBREAK").PSI());
4646

4747
p1.GetProcessOwnerUser()
4848
.Should().Be(Process.GetCurrentProcess().GetProcessOwnerUser());
49-
50-
p1.Kill();
5149
}
5250

5351
[Fact]

src/RustAnalyzer.TestAdapter.UnitTests/RustAnalyzer.TestAdapter.UnitTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
44
<PropertyGroup>

src/RustAnalyzer.TestAdapter/Cargo/ToolChainServiceExtensions.cs

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public static class ToolchainServiceExtensions
3030
};
3131

3232
private static readonly Regex NameCracker =
33-
new(@"^((?<name>.*)(?<default> \(default\))?)$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
33+
new(@"^((?<name>.*)(?<aOrD> \((active|active, default|default)\))?)$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
3434

3535
private static readonly Regex VersionCracker =
3636
new(@"^rustc (?<version>\d+.\d+.\d+(-.*)?) (\(.* (?<date>\d{4}-\d{2}-\d{2})\))$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
@@ -61,9 +61,48 @@ public static PathEx GetRustupSettingsPath() =>
6161
return (root + "bin", root + $@"lib\rustlib\{AlwaysAvailableTarget}\lib");
6262
}
6363

64-
public static async Task<Toolchain[]> GetInstalledToolchainsAsync(PathEx workingDirectory, CancellationToken ct)
64+
public abstract class RustupShowOutput
6565
{
66-
var output = await GetCommandOutput("rustup", "show --verbose", workingDirectory, ct);
66+
private RustupShowOutput()
67+
{
68+
}
69+
70+
public sealed class Simulated : RustupShowOutput
71+
{
72+
public string[] Value { get; }
73+
74+
public Simulated(string[] value) => Value = value;
75+
}
76+
77+
public sealed class Real : RustupShowOutput
78+
{
79+
public Real()
80+
{
81+
}
82+
}
83+
}
84+
85+
public static async Task<Toolchain[]> GetInstalledToolchainsAsync(RustupShowOutput rustupShowOutput, PathEx workingDirectory, CancellationToken ct)
86+
{
87+
string[] output = null;
88+
switch (rustupShowOutput)
89+
{
90+
case RustupShowOutput.Simulated simulated:
91+
{
92+
output = simulated.Value;
93+
break;
94+
}
95+
96+
case RustupShowOutput.Real _:
97+
{
98+
output = await GetCommandOutput("rustup", "show --verbose", workingDirectory, ct);
99+
break;
100+
}
101+
102+
default:
103+
throw new NotSupportedException($"Unsupported rustup show output type: {rustupShowOutput.GetType()}");
104+
}
105+
67106
var tcRaw = output
68107
.Select(x => x.Trim())
69108
.Where(x => !x.IsNullOrEmptyOrWhiteSpace())
@@ -72,52 +111,22 @@ public static async Task<Toolchain[]> GetInstalledToolchainsAsync(PathEx working
72111
.TakeWhile(x => !x.Equals("active toolchain"))
73112
.ToList();
74113

75-
var tcs = Enumerable.Range(0, tcRaw.Count / 2)
76-
.Select(i => (tcRaw[i * 2], tcRaw[(i * 2) + 1]))
114+
var tcs1 = Enumerable.Range(0, tcRaw.Count / 3)
115+
.Select(i => (tcRaw[i * 3], tcRaw[(i * 3) + 1]));
116+
var tcs = tcs1
77117
.Select(x => (NameCracker.Match(x.Item1), VersionCracker.Match(x.Item2)))
78118
.Where(x => x.Item1.Success && x.Item2.Success)
79119
.Select(x =>
80120
new Toolchain
81121
{
82122
Name = x.Item1.Groups["name"].Value,
83123
Version = $"{x.Item2.Groups["version"].Value} ({x.Item2.Groups["date"].Value})",
84-
IsDefault = false
124+
IsActive = x.Item1.Groups["aOrD"].Value?.Contains("active") ?? false,
85125
})
86126
.OrderBy(tc => tc.Name)
87127
.ThenBy(tc => tc.Version)
88128
.ToArray();
89129

90-
var activeRaw = output
91-
.Select(x => x.Trim())
92-
.Where(x => !x.IsNullOrEmptyOrWhiteSpace())
93-
.SkipWhile(x => !x.Equals("active toolchain"))
94-
.Skip(2)
95-
.FirstOrDefault()
96-
.Split(' ')[0];
97-
if (activeRaw != null)
98-
{
99-
var i = Array.FindIndex(tcs, tc => tc.Name == activeRaw);
100-
101-
// 1.Background: There are cases where projects are pinned to specific Rust versions, and it's also possible that users have installed multiple Rust versions.
102-
103-
// 2.Result: This leads to matching failures during exact name matching.
104-
105-
// Example(e.g.):
106-
// Actual Name: `1.85.1 - x86_64 - pc - windows - msvc(active)`
107-
// activeRaw: `1.85.1 - x86_64 - pc - windows - msvc`
108-
109-
// This results in the error: "Sequence contains no elements"
110-
if (i == -1)
111-
{
112-
i = Array.FindIndex(tcs, t => t.Name.StartsWith(activeRaw));
113-
}
114-
115-
if (i != -1)
116-
{
117-
tcs[i].IsDefault = true;
118-
}
119-
}
120-
121130
return tcs;
122131
}
123132

@@ -137,7 +146,7 @@ public static async Task<string[]> GetTargets(CancellationToken ct)
137146

138147
public static async Task<string> GetDefaultToolchainAsync(PathEx workingDirectory, CancellationToken ct)
139148
{
140-
return (await GetInstalledToolchainsAsync(workingDirectory, ct)).Where(x => x.IsDefault).First().Name;
149+
return (await GetInstalledToolchainsAsync(new RustupShowOutput.Real(), workingDirectory, ct)).Where(x => x.IsActive).First().Name;
141150
}
142151

143152
public static async Task<TestContainer> ReadTestContainerAsync(this PathEx @this, CancellationToken ct)
@@ -281,5 +290,5 @@ public struct Toolchain
281290

282291
public string Version { get; set; }
283292

284-
public bool IsDefault { get; set; }
293+
public bool IsActive { get; set; }
285294
}

src/RustAnalyzer.TestAdapter/Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static class Constants
3131
public const string TestsContainerExtension = ".rusttests";
3232
public const string TestContainersSearchPattern = $"*{TestsContainerExtension}";
3333

34-
public const string RlsLatestInPackageVersion = "2025-02-10";
34+
public const string RlsLatestInPackageVersion = "2025-06-09";
3535
public static readonly Version MinimumRequiredVsVersion = new(17, 12);
3636

3737
public static readonly PathEx TestsContainerExtension2 = (PathEx)TestsContainerExtension;

src/RustAnalyzer.TestAdapter/RustAnalyzer.TestAdapter.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<PackageReference Include="System.ComponentModel.Composition" Version="9.0.0-preview.7.24405.7" />
1313
<PackageReference Include="Microsoft.TestPlatform.ObjectModel" Version="17.11.0" />
1414
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
15+
<PackageReference Include="System.Collections.Immutable" Version="7.0.0" />
1516
</ItemGroup>
1617

1718
<Import Project="..\KS.Common.targets" />

src/RustAnalyzer/RustAnalyzer.csproj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<PropertyGroup>
44
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
@@ -107,11 +107,11 @@
107107
</ItemGroup>
108108
<ItemGroup>
109109
<Content Include="..\external\rust-analyzer.exe">
110-
<Link>2025-02-10\rust-analyzer.exe</Link>
110+
<Link>2025-06-09\rust-analyzer.exe</Link>
111111
<IncludeInVSIX>true</IncludeInVSIX>
112112
</Content>
113113
<Content Include="..\external\rust_analyzer.pdb">
114-
<Link>2025-02-10\rust_analyzer.pdb</Link>
114+
<Link>2025-06-09\rust_analyzer.pdb</Link>
115115
<IncludeInVSIX>true</IncludeInVSIX>
116116
</Content>
117117
<Content Include="languages.pkgdef">
@@ -156,6 +156,7 @@
156156
<Reference Include="System.Windows.Forms" />
157157
</ItemGroup>
158158
<ItemGroup>
159+
<PackageReference Include="System.Collections.Immutable" Version="7.0.0" />
159160
<Reference Include="Microsoft.VisualBasic" />
160161
<PackageReference Include="System.ComponentModel.Composition" Version="9.0.0-preview.7.24405.7" />
161162
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.11.20" />

0 commit comments

Comments
 (0)