Skip to content

Commit 06136b4

Browse files
committed
Add mocks for configuration for testing, still need to fix some parameter tests
1 parent 2da8267 commit 06136b4

File tree

5 files changed

+54
-58
lines changed

5 files changed

+54
-58
lines changed

src/PowerShellEditorServices/Server/PsesLanguageServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public async Task StartAsync()
8686
.AddLanguageProtocolLogging()
8787
.SetMinimumLevel(_minimumLogLevel))
8888
// TODO: Consider replacing all WithHandler with AddSingleton
89-
.WithConfigurationSection("powershell")
89+
.WithConfigurationSection("powershell.rename")
9090
.WithHandler<PsesWorkspaceSymbolsHandler>()
9191
.WithHandler<PsesTextDocumentHandler>()
9292
.WithHandler<GetVersionHandler>()

src/PowerShellEditorServices/Services/PowerShell/Refactoring/IterativeVariableVisitor.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ internal class IterativeVariableRename
2424
internal bool isParam;
2525
internal bool AliasSet;
2626
internal FunctionDefinitionAst TargetFunction;
27-
internal RenameServiceOptions options;
27+
internal bool CreateAlias;
2828

29-
public IterativeVariableRename(string NewName, int StartLineNumber, int StartColumnNumber, Ast ScriptAst, RenameServiceOptions options)
29+
public IterativeVariableRename(string NewName, int StartLineNumber, int StartColumnNumber, Ast ScriptAst, bool CreateAlias)
3030
{
3131
this.NewName = NewName;
3232
this.StartLineNumber = StartLineNumber;
3333
this.StartColumnNumber = StartColumnNumber;
3434
this.ScriptAst = ScriptAst;
35-
this.options = options;
35+
this.CreateAlias = CreateAlias;
3636

3737
VariableExpressionAst Node = (VariableExpressionAst)GetVariableTopAssignment(StartLineNumber, StartColumnNumber, ScriptAst);
3838
if (Node != null)
@@ -404,7 +404,7 @@ private void ProcessVariableExpressionAst(VariableExpressionAst variableExpressi
404404
};
405405
// If the variables parent is a parameterAst Add a modification
406406
if (variableExpressionAst.Parent is ParameterAst paramAst && !AliasSet &&
407-
options.createVariableAlias)
407+
CreateAlias)
408408
{
409409
TextEdit aliasChange = NewParameterAliasChange(variableExpressionAst, paramAst);
410410
Modifications.Add(aliasChange);

src/PowerShellEditorServices/Services/TextDocument/RenameService.cs

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919

2020
namespace Microsoft.PowerShell.EditorServices.Services;
2121

22+
/// <summary>
23+
/// Used with Configuration Bind to sync the settings to what is set on the client.
24+
/// </summary>
2225
public class RenameServiceOptions
2326
{
24-
internal bool createFunctionAlias { get; set; }
25-
internal bool createVariableAlias { get; set; }
26-
internal bool acceptDisclaimer { get; set; }
27+
public bool createFunctionAlias { get; set; }
28+
public bool createVariableAlias { get; set; }
29+
public bool acceptDisclaimer { get; set; }
2730
}
2831

2932
public interface IRenameService
@@ -46,44 +49,44 @@ internal class RenameService(
4649
WorkspaceService workspaceService,
4750
ILanguageServerFacade lsp,
4851
ILanguageServerConfiguration config,
52+
bool disclaimerDeclinedForSession = false,
53+
bool disclaimerAcceptedForSession = false,
4954
string configSection = "powershell.rename"
5055
) : IRenameService
5156
{
52-
private bool disclaimerDeclined;
53-
private bool disclaimerAccepted;
54-
55-
private readonly RenameServiceOptions settings = new();
5657

57-
internal void RefreshSettings() => config.GetSection(configSection).Bind(settings);
58+
private async Task<RenameServiceOptions> GetScopedSettings(DocumentUri uri, CancellationToken cancellationToken = default)
59+
{
60+
IScopedConfiguration scopedConfig = await config.GetScopedConfiguration(uri, cancellationToken).ConfigureAwait(false);
61+
return scopedConfig.GetSection(configSection).Get<RenameServiceOptions>() ?? new RenameServiceOptions();
62+
}
5863

5964
public async Task<RangeOrPlaceholderRange?> PrepareRenameSymbol(PrepareRenameParams request, CancellationToken cancellationToken)
6065
{
61-
62-
if (!await AcceptRenameDisclaimer(cancellationToken).ConfigureAwait(false)) { return null; }
63-
ScriptFile scriptFile = workspaceService.GetFile(request.TextDocument.Uri);
64-
65-
// TODO: Is this too aggressive? We can still rename inside a var/function even if dotsourcing is in use in a file, we just need to be clear it's not supported to expect rename actions to propogate.
66-
if (Utilities.AssertContainsDotSourced(scriptFile.ScriptAst))
66+
RenameParams renameRequest = new()
6767
{
68-
throw new HandlerErrorException("Dot Source detected, this is currently not supported");
69-
}
70-
71-
// TODO: FindRenamableSymbol may create false positives for renaming, so we probably should go ahead and execute a full rename and return true if edits are found.
72-
73-
ScriptPositionAdapter position = request.Position;
74-
Ast? target = FindRenamableSymbol(scriptFile, position);
68+
NewName = "PREPARERENAMETEST", //A placeholder just to gather edits
69+
Position = request.Position,
70+
TextDocument = request.TextDocument
71+
};
72+
// TODO: Should we cache these resuls and just fetch them on the actual rename, and move the bulk to an implementation method?
73+
WorkspaceEdit? renameResponse = await RenameSymbol(renameRequest, cancellationToken).ConfigureAwait(false);
7574

7675
// Since LSP 3.16 we can simply basically return a DefaultBehavior true or null to signal to the client that the position is valid for rename and it should use its default selection criteria (which is probably the language semantic highlighting or grammar). For the current scope of the rename provider, this should be fine, but we have the option to supply the specific range in the future for special cases.
77-
RangeOrPlaceholderRange? renamable = target is null ? null : new RangeOrPlaceholderRange
78-
(
79-
new RenameDefaultBehavior() { DefaultBehavior = true }
80-
);
81-
return renamable;
76+
return (renameResponse?.Changes?[request.TextDocument.Uri].ToArray().Length > 0)
77+
? new RangeOrPlaceholderRange
78+
(
79+
new RenameDefaultBehavior() { DefaultBehavior = true }
80+
)
81+
: null;
8282
}
8383

8484
public async Task<WorkspaceEdit?> RenameSymbol(RenameParams request, CancellationToken cancellationToken)
8585
{
86-
if (!await AcceptRenameDisclaimer(cancellationToken).ConfigureAwait(false)) { return null; }
86+
// We want scoped settings because a workspace setting might be relevant here.
87+
RenameServiceOptions options = await GetScopedSettings(request.TextDocument.Uri, cancellationToken).ConfigureAwait(false);
88+
89+
if (!await AcceptRenameDisclaimer(options.acceptDisclaimer, cancellationToken).ConfigureAwait(false)) { return null; }
8790

8891
ScriptFile scriptFile = workspaceService.GetFile(request.TextDocument.Uri);
8992
ScriptPositionAdapter position = request.Position;
@@ -95,7 +98,7 @@ internal class RenameService(
9598
TextEdit[] changes = tokenToRename switch
9699
{
97100
FunctionDefinitionAst or CommandAst => RenameFunction(tokenToRename, scriptFile.ScriptAst, request),
98-
VariableExpressionAst => RenameVariable(tokenToRename, scriptFile.ScriptAst, request),
101+
VariableExpressionAst => RenameVariable(tokenToRename, scriptFile.ScriptAst, request, options.createVariableAlias),
99102
// FIXME: Only throw if capability is not prepareprovider
100103
_ => throw new InvalidOperationException("This should not happen as PrepareRename should have already checked for viability. File an issue if you see this.")
101104
};
@@ -122,17 +125,16 @@ internal static TextEdit[] RenameFunction(Ast target, Ast scriptAst, RenameParam
122125
return visitor.VisitAndGetEdits(scriptAst);
123126
}
124127

125-
internal TextEdit[] RenameVariable(Ast symbol, Ast scriptAst, RenameParams requestParams)
128+
internal static TextEdit[] RenameVariable(Ast symbol, Ast scriptAst, RenameParams requestParams, bool createAlias)
126129
{
127130
if (symbol is VariableExpressionAst or ParameterAst or CommandParameterAst or StringConstantExpressionAst)
128131
{
129-
130132
IterativeVariableRename visitor = new(
131133
requestParams.NewName,
132134
symbol.Extent.StartLineNumber,
133135
symbol.Extent.StartColumnNumber,
134136
scriptAst,
135-
settings
137+
createAlias
136138
);
137139
visitor.Visit(scriptAst);
138140
return visitor.Modifications.ToArray();
@@ -200,15 +202,10 @@ internal static ScriptExtentAdapter GetFunctionNameExtent(FunctionDefinitionAst
200202
/// Prompts the user to accept the rename disclaimer.
201203
/// </summary>
202204
/// <returns>true if accepted, false if rejected</returns>
203-
private async Task<bool> AcceptRenameDisclaimer(CancellationToken cancellationToken)
205+
private async Task<bool> AcceptRenameDisclaimer(bool acceptDisclaimerOption, CancellationToken cancellationToken)
204206
{
205-
// Fetch the latest settings from the client, in case they have changed.
206-
config.GetSection(configSection).Bind(settings);
207-
208-
// User has declined for the session so we don't want this popping up a bunch.
209-
if (disclaimerDeclined) { return false; }
210-
211-
if (settings.acceptDisclaimer || disclaimerAccepted) { return true; }
207+
if (disclaimerDeclinedForSession) { return false; }
208+
if (acceptDisclaimerOption || disclaimerAcceptedForSession) { return true; }
212209

213210
// TODO: Localization
214211
const string renameDisclaimer = "PowerShell rename functionality is only supported in a limited set of circumstances. Please review the notice and understand the limitations and risks.";
@@ -242,8 +239,8 @@ private async Task<bool> AcceptRenameDisclaimer(CancellationToken cancellationTo
242239
Type = MessageType.Info
243240
};
244241
lsp.SendNotification(msgParams);
245-
disclaimerDeclined = true;
246-
return !disclaimerDeclined;
242+
disclaimerDeclinedForSession = true;
243+
return !disclaimerDeclinedForSession;
247244
}
248245
if (result.Title == acceptAnswer)
249246
{
@@ -255,8 +252,8 @@ private async Task<bool> AcceptRenameDisclaimer(CancellationToken cancellationTo
255252
};
256253
lsp.SendNotification(msgParams);
257254

258-
disclaimerAccepted = true;
259-
return disclaimerAccepted;
255+
disclaimerAcceptedForSession = true;
256+
return disclaimerAcceptedForSession;
260257
}
261258
// if (result.Title == acceptWorkspaceAnswer)
262259
// {
@@ -514,7 +511,6 @@ public ScriptPositionAdapter(Position position) : this(position.Line + 1, positi
514511
scriptPosition.position.LineNumber - 1, scriptPosition.position.ColumnNumber - 1
515512
);
516513

517-
518514
public static implicit operator ScriptPositionAdapter(ScriptPosition position) => new(position);
519515
public static implicit operator ScriptPosition(ScriptPositionAdapter position) => position;
520516

test/PowerShellEditorServices.Test/Refactoring/PrepareRenameHandlerTests.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using MediatR;
1010
using Microsoft.Extensions.Configuration;
1111
using Microsoft.Extensions.Logging.Abstractions;
12-
using Microsoft.Extensions.Primitives;
1312
using Microsoft.PowerShell.EditorServices.Handlers;
1413
using Microsoft.PowerShell.EditorServices.Services;
1514
using Microsoft.PowerShell.EditorServices.Test.Shared;
@@ -44,7 +43,8 @@ public PrepareRenameHandlerTests()
4443
(
4544
workspace,
4645
new fakeLspSendMessageRequestFacade("I Accept"),
47-
new fakeConfigurationService()
46+
new EmptyConfiguration(),
47+
disclaimerAcceptedForSession: true //Suppresses prompts
4848
)
4949
);
5050
}
@@ -134,18 +134,17 @@ public async Task<TResponse> SendRequest<TResponse>(IRequest<TResponse> request,
134134
public bool TryGetRequest(long id, out string method, out TaskCompletionSource<JToken> pendingTask) => throw new NotImplementedException();
135135
}
136136

137-
public class fakeConfigurationService : ILanguageServerConfiguration
137+
138+
139+
public class EmptyConfiguration : ConfigurationRoot, ILanguageServerConfiguration, IScopedConfiguration
138140
{
139-
public string this[string key] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
141+
public EmptyConfiguration() : base([]) { }
140142

141143
public bool IsSupported => throw new NotImplementedException();
142144

143145
public ILanguageServerConfiguration AddConfigurationItems(IEnumerable<ConfigurationItem> configurationItems) => throw new NotImplementedException();
144-
public IEnumerable<IConfigurationSection> GetChildren() => throw new NotImplementedException();
145146
public Task<IConfiguration> GetConfiguration(params ConfigurationItem[] items) => throw new NotImplementedException();
146-
public IChangeToken GetReloadToken() => throw new NotImplementedException();
147-
public Task<IScopedConfiguration> GetScopedConfiguration(DocumentUri scopeUri, CancellationToken cancellationToken) => throw new NotImplementedException();
148-
public IConfigurationSection GetSection(string key) => throw new NotImplementedException();
147+
public Task<IScopedConfiguration> GetScopedConfiguration(DocumentUri scopeUri, CancellationToken cancellationToken) => Task.FromResult((IScopedConfiguration)this);
149148
public ILanguageServerConfiguration RemoveConfigurationItems(IEnumerable<ConfigurationItem> configurationItems) => throw new NotImplementedException();
150149
public bool TryGetScopedConfiguration(DocumentUri scopeUri, out IScopedConfiguration configuration) => throw new NotImplementedException();
151150
}

test/PowerShellEditorServices.Test/Refactoring/RenameHandlerTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public RenameHandlerTests()
3636
(
3737
workspace,
3838
new fakeLspSendMessageRequestFacade("I Accept"),
39-
new fakeConfigurationService()
39+
new EmptyConfiguration(),
40+
disclaimerAcceptedForSession: true //Disables UI prompts
4041
)
4142
);
4243
}

0 commit comments

Comments
 (0)