/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/EditorFeatures/Test/RenameTracking/RenameTrackingTestState.cs
222 строки
9 KB
Cyrus Najmabadi
Use implicit object creation expressions
13 сен 2025, 01:48
13 сен 2025, 01:48
4c6a36a
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Utilities; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; using Microsoft.VisualStudio.Text.Operations; using Microsoft.VisualStudio.Text.Tagging; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.UnitTests.RenameTracking; internal sealed class RenameTrackingTestState : IDisposable { private readonly ITagger<RenameTrackingTag> _tagger; public readonly EditorTestWorkspace Workspace; private readonly IWpfTextView _view; private readonly ITextUndoHistoryRegistry _historyRegistry; private string _notificationMessage = null; public EditorTestHostDocument HostDocument { get; } public IEditorOperations EditorOperations { get; } public MockRefactorNotifyService RefactorNotifyService { get; } private readonly RenameTrackingCodeRefactoringProvider _codeRefactoringProvider; private readonly RenameTrackingCancellationCommandHandler _commandHandler = new(); public static RenameTrackingTestState Create( string markup, string languageName, bool onBeforeGlobalSymbolRenamedReturnValue = true, bool onAfterGlobalSymbolRenamedReturnValue = true) { var workspace = CreateTestWorkspace(markup, languageName); return new RenameTrackingTestState(workspace, languageName, onBeforeGlobalSymbolRenamedReturnValue, onAfterGlobalSymbolRenamedReturnValue); } public static RenameTrackingTestState CreateFromWorkspaceXml( string workspaceXml, string languageName, bool onBeforeGlobalSymbolRenamedReturnValue = true, bool onAfterGlobalSymbolRenamedReturnValue = true) { var workspace = CreateTestWorkspace(workspaceXml); return new RenameTrackingTestState(workspace, languageName, onBeforeGlobalSymbolRenamedReturnValue, onAfterGlobalSymbolRenamedReturnValue); } public RenameTrackingTestState( EditorTestWorkspace workspace, string languageName, bool onBeforeGlobalSymbolRenamedReturnValue = true, bool onAfterGlobalSymbolRenamedReturnValue = true) { this.Workspace = workspace; HostDocument = Workspace.Documents.First(); _view = HostDocument.GetTextView(); _view.Caret.MoveTo(new SnapshotPoint(_view.TextSnapshot, HostDocument.CursorPosition.Value)); EditorOperations = Workspace.GetService<IEditorOperationsFactoryService>().GetEditorOperations(_view); _historyRegistry = Workspace.ExportProvider.GetExport<ITextUndoHistoryRegistry>().Value; RefactorNotifyService = new MockRefactorNotifyService { OnBeforeSymbolRenamedReturnValue = onBeforeGlobalSymbolRenamedReturnValue, OnAfterSymbolRenamedReturnValue = onAfterGlobalSymbolRenamedReturnValue }; // Mock the action taken by the workspace INotificationService var notificationService = (INotificationServiceCallback)Workspace.Services.GetRequiredService<INotificationService>(); var callback = new Action<string, string, NotificationSeverity>((message, title, severity) => _notificationMessage = message); notificationService.NotificationCallback = callback; var tracker = new RenameTrackingTaggerProvider( Workspace.GetService<IThreadingContext>(), Workspace.GetService<IInlineRenameService>(), Workspace.GetService<IGlobalOptionService>(), Workspace.GetService<IAsynchronousOperationListenerProvider>()); _tagger = tracker.CreateTagger<RenameTrackingTag>(HostDocument.GetTextBuffer()); if (languageName is LanguageNames.CSharp or LanguageNames.VisualBasic) { _codeRefactoringProvider = new RenameTrackingCodeRefactoringProvider( _historyRegistry, [RefactorNotifyService]); } else { throw new ArgumentException("Invalid language name: " + languageName, nameof(languageName)); } } private static EditorTestWorkspace CreateTestWorkspace(string code, string languageName) { return CreateTestWorkspace(string.Format(""" <Workspace> <Project Language="{0}" CommonReferences="true"> <Document>{1}</Document> </Project> </Workspace> """, languageName, code)); } private static EditorTestWorkspace CreateTestWorkspace(string xml) { return EditorTestWorkspace.Create(xml, composition: EditorTestCompositions.EditorFeatures); } public void SendEscape() => _commandHandler.ExecuteCommand(new EscapeKeyCommandArgs(_view, _view.TextBuffer), TestCommandExecutionContext.Create()); public void MoveCaret(int delta) { var position = _view.Caret.Position.BufferPosition.Position; _view.Caret.MoveTo(new SnapshotPoint(_view.TextSnapshot, position + delta)); } public void Undo(int count = 1) { var history = _historyRegistry.GetHistory(_view.TextBuffer); history.Undo(count); } public void Redo(int count = 1) { var history = _historyRegistry.GetHistory(_view.TextBuffer); history.Redo(count); } public async Task AssertNoTag() { await WaitForAsyncOperationsAsync(); var tags = _tagger.GetTags(_view.TextBuffer.CurrentSnapshot.GetSnapshotSpanCollection()); Assert.Equal(0, tags.Count()); } /// <param name="textSpan">If <see langword="null"/> the current caret position will be used.</param> public async Task<CodeAction> TryGetCodeActionAsync(TextSpan? textSpan = null) { var span = textSpan ?? new TextSpan(_view.Caret.Position.BufferPosition, 0); var document = this.Workspace.CurrentSolution.GetDocument(HostDocument.Id); var actions = new List<CodeAction>(); var context = new CodeRefactoringContext( document, span, actions.Add, CancellationToken.None); await _codeRefactoringProvider.ComputeRefactoringsAsync(context); return actions.SingleOrDefault(); } public async Task AssertTag(string expectedFromName, string expectedToName, bool invokeAction = false) { await WaitForAsyncOperationsAsync(); var tags = _tagger.GetTags(_view.TextBuffer.CurrentSnapshot.GetSnapshotSpanCollection()); // There should only ever be one tag Assert.Equal(1, tags.Count()); var tag = tags.Single(); // There should only be one code action for the tag var codeAction = await TryGetCodeActionAsync(tag.Span.Span.ToTextSpan()); Assert.NotNull(codeAction); Assert.Equal(string.Format(WorkspacesResources.Rename_0_to_1, expectedFromName, expectedToName), codeAction.Title); if (invokeAction) { var operations = (await codeAction.GetOperationsAsync(CancellationToken.None)).ToArray(); Assert.Equal(1, operations.Length); await operations[0].TryApplyAsync(this.Workspace, this.Workspace.CurrentSolution, CodeAnalysisProgress.None, CancellationToken.None); } } public void AssertNoNotificationMessage() => Assert.Null(_notificationMessage); public void AssertNotificationMessage() => Assert.NotNull(_notificationMessage); private async Task WaitForAsyncOperationsAsync() { var provider = Workspace.ExportProvider.GetExportedValue<AsynchronousOperationListenerProvider>(); await provider.WaitAllDispatcherOperationAndTasksAsync( Workspace, FeatureAttribute.RenameTracking, FeatureAttribute.SolutionCrawlerLegacy, FeatureAttribute.Workspace, FeatureAttribute.EventHookup); } public void Dispose() => Workspace.Dispose(); }