Update DefaultRazorEditorFactoryService to be per-workspace.
- Updated the a `VisualStudioWorkspaceAccessor` API in windows to enable the factory to retrieve a workspace given a text buffer. - Added a way to add test services to `AdhocWorkspace` so we can test against services being retrieved from a `Workspace`. This will be much more common once we rely on services coming from `TextBuffer`s in our other tooling pieces. - Added tests for the default workspace provider. #1989
This commit is contained in:
parent
5e454a36fa
commit
6d2460ae7f
|
|
@ -14,10 +14,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
internal class DefaultRazorEditorFactoryService : RazorEditorFactoryService
|
||||
{
|
||||
private static readonly object RazorTextBufferInitializationKey = new object();
|
||||
|
||||
private readonly VisualStudioDocumentTrackerFactory _documentTrackerFactory;
|
||||
private readonly VisualStudioRazorParserFactory _parserFactory;
|
||||
private readonly BraceSmartIndenterFactory _braceSmartIndenterFactory;
|
||||
private readonly VisualStudioWorkspaceAccessor _workspaceAccessor;
|
||||
|
||||
[ImportingConstructor]
|
||||
public DefaultRazorEditorFactoryService(VisualStudioWorkspaceAccessor workspaceAccessor)
|
||||
|
|
@ -27,36 +24,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
throw new ArgumentNullException(nameof(workspaceAccessor));
|
||||
}
|
||||
|
||||
var razorLanguageServices = workspaceAccessor.Workspace.Services.GetLanguageServices(RazorLanguage.Name);
|
||||
_documentTrackerFactory = razorLanguageServices.GetRequiredService<VisualStudioDocumentTrackerFactory>();
|
||||
_parserFactory = razorLanguageServices.GetRequiredService<VisualStudioRazorParserFactory>();
|
||||
_braceSmartIndenterFactory = razorLanguageServices.GetRequiredService<BraceSmartIndenterFactory>();
|
||||
}
|
||||
|
||||
// Internal for testing
|
||||
internal DefaultRazorEditorFactoryService(
|
||||
VisualStudioDocumentTrackerFactory documentTrackerFactory,
|
||||
VisualStudioRazorParserFactory parserFactory,
|
||||
BraceSmartIndenterFactory braceSmartIndenterFactory)
|
||||
{
|
||||
if (documentTrackerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentTrackerFactory));
|
||||
}
|
||||
|
||||
if (parserFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(parserFactory));
|
||||
}
|
||||
|
||||
if (braceSmartIndenterFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(braceSmartIndenterFactory));
|
||||
}
|
||||
|
||||
_documentTrackerFactory = documentTrackerFactory;
|
||||
_parserFactory = parserFactory;
|
||||
_braceSmartIndenterFactory = braceSmartIndenterFactory;
|
||||
_workspaceAccessor = workspaceAccessor;
|
||||
}
|
||||
|
||||
public override bool TryGetDocumentTracker(ITextBuffer textBuffer, out VisualStudioDocumentTracker documentTracker)
|
||||
|
|
@ -72,7 +40,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
return false;
|
||||
}
|
||||
|
||||
EnsureTextBufferInitialized(textBuffer);
|
||||
var textBufferInitialized = TryInitializeTextBuffer(textBuffer);
|
||||
if (!textBufferInitialized)
|
||||
{
|
||||
documentTracker = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!textBuffer.Properties.TryGetProperty(typeof(VisualStudioDocumentTracker), out documentTracker))
|
||||
{
|
||||
|
|
@ -96,7 +69,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
return false;
|
||||
}
|
||||
|
||||
EnsureTextBufferInitialized(textBuffer);
|
||||
var textBufferInitialized = TryInitializeTextBuffer(textBuffer);
|
||||
if (!textBufferInitialized)
|
||||
{
|
||||
parser = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!textBuffer.Properties.TryGetProperty(typeof(VisualStudioRazorParser), out parser))
|
||||
{
|
||||
|
|
@ -120,7 +98,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
return false;
|
||||
}
|
||||
|
||||
EnsureTextBufferInitialized(textBuffer);
|
||||
var textBufferInitialized = TryInitializeTextBuffer(textBuffer);
|
||||
if (!textBufferInitialized)
|
||||
{
|
||||
braceSmartIndenter = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!textBuffer.Properties.TryGetProperty(typeof(BraceSmartIndenter), out braceSmartIndenter))
|
||||
{
|
||||
|
|
@ -132,24 +115,37 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
}
|
||||
|
||||
// Internal for testing
|
||||
internal void EnsureTextBufferInitialized(ITextBuffer textBuffer)
|
||||
internal bool TryInitializeTextBuffer(ITextBuffer textBuffer)
|
||||
{
|
||||
if (textBuffer.Properties.ContainsProperty(RazorTextBufferInitializationKey))
|
||||
{
|
||||
// Buffer already initialized.
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
var tracker = _documentTrackerFactory.Create(textBuffer);
|
||||
if (!_workspaceAccessor.TryGetWorkspace(textBuffer, out var workspace))
|
||||
{
|
||||
// Could not locate workspace for given text buffer.
|
||||
return false;
|
||||
}
|
||||
|
||||
var razorLanguageServices = workspace.Services.GetLanguageServices(RazorLanguage.Name);
|
||||
var documentTrackerFactory = razorLanguageServices.GetRequiredService<VisualStudioDocumentTrackerFactory>();
|
||||
var parserFactory = razorLanguageServices.GetRequiredService<VisualStudioRazorParserFactory>();
|
||||
var braceSmartIndenterFactory = razorLanguageServices.GetRequiredService<BraceSmartIndenterFactory>();
|
||||
|
||||
var tracker = documentTrackerFactory.Create(textBuffer);
|
||||
textBuffer.Properties[typeof(VisualStudioDocumentTracker)] = tracker;
|
||||
|
||||
var parser = _parserFactory.Create(tracker);
|
||||
var parser = parserFactory.Create(tracker);
|
||||
textBuffer.Properties[typeof(VisualStudioRazorParser)] = parser;
|
||||
|
||||
var braceSmartIndenter = _braceSmartIndenterFactory.Create(tracker);
|
||||
var braceSmartIndenter = braceSmartIndenterFactory.Create(tracker);
|
||||
textBuffer.Properties[typeof(BraceSmartIndenter)] = braceSmartIndenter;
|
||||
|
||||
textBuffer.Properties.AddProperty(RazorTextBufferInitializationKey, RazorTextBufferInitializationKey);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
|
||||
namespace Microsoft.VisualStudio.Editor.Razor
|
||||
{
|
||||
internal abstract class VisualStudioWorkspaceAccessor
|
||||
{
|
||||
public abstract Workspace Workspace { get; }
|
||||
|
||||
public abstract bool TryGetWorkspace(ITextBuffer textBuffer, out Workspace workspace);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using Microsoft.VisualStudio.Editor.Razor;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Projection;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||
{
|
||||
|
|
@ -11,12 +16,105 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
|||
[Export(typeof(VisualStudioWorkspaceAccessor))]
|
||||
internal class DefaultVisualStudioWorkspaceAccessor : VisualStudioWorkspaceAccessor
|
||||
{
|
||||
private readonly IBufferGraphFactoryService _bufferGraphService;
|
||||
private readonly TextBufferProjectService _projectService;
|
||||
private readonly Workspace _defaultWorkspace;
|
||||
|
||||
[ImportingConstructor]
|
||||
public DefaultVisualStudioWorkspaceAccessor([Import(typeof(VisualStudioWorkspace))] Workspace workspace)
|
||||
public DefaultVisualStudioWorkspaceAccessor(
|
||||
IBufferGraphFactoryService bufferGraphService,
|
||||
TextBufferProjectService projectService,
|
||||
[Import(typeof(VisualStudioWorkspace))] Workspace defaultWorkspace)
|
||||
{
|
||||
Workspace = workspace;
|
||||
if (bufferGraphService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(bufferGraphService));
|
||||
}
|
||||
|
||||
if (projectService == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(projectService));
|
||||
}
|
||||
|
||||
if (defaultWorkspace == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(defaultWorkspace));
|
||||
}
|
||||
|
||||
_bufferGraphService = bufferGraphService;
|
||||
_projectService = projectService;
|
||||
_defaultWorkspace = defaultWorkspace;
|
||||
}
|
||||
|
||||
public override Workspace Workspace { get; }
|
||||
public override Workspace Workspace => _defaultWorkspace;
|
||||
|
||||
public override bool TryGetWorkspace(ITextBuffer textBuffer, out Workspace workspace)
|
||||
{
|
||||
if (textBuffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(textBuffer));
|
||||
}
|
||||
|
||||
// We do a best effort approach in this method to get the workspace that belongs to the TextBuffer.
|
||||
// The approaches we take to find the workspace are:
|
||||
//
|
||||
// 1. Look for a C# projection buffer associated with the Razor buffer. If we can find one we let
|
||||
// Roslyn take control of finding the Workspace (projectionBuffer.GetWorkspace()). If not,
|
||||
// fall back to determining if we can use the default workspace.
|
||||
// 2. Look to see if this ITextBuffer is associated with a host project. If we find that our Razor
|
||||
// buffer has a host project, we make the assumption that we should use the default VisualStudioWorkspace.
|
||||
|
||||
if (TryGetWorkspaceFromProjectionBuffer(textBuffer, out workspace))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryGetWorkspaceFromHostProject(textBuffer, out workspace))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
workspace = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Internal virtual for testing
|
||||
internal virtual bool TryGetWorkspaceFromProjectionBuffer(ITextBuffer textBuffer, out Workspace workspace)
|
||||
{
|
||||
var graph = _bufferGraphService.CreateBufferGraph(textBuffer);
|
||||
var projectedCSharpBuffer = graph.GetTextBuffers(buffer => buffer.ContentType.IsOfType("CSharp")).FirstOrDefault();
|
||||
|
||||
if (projectedCSharpBuffer == null)
|
||||
{
|
||||
workspace = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
workspace = projectedCSharpBuffer.GetWorkspace();
|
||||
if (workspace == null)
|
||||
{
|
||||
// Couldn't resolve a workspace for the projected csharp buffer.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Internal virtual for testing
|
||||
internal virtual bool TryGetWorkspaceFromHostProject(ITextBuffer textBuffer, out Workspace workspace)
|
||||
{
|
||||
var project = _projectService.GetHostProject(textBuffer);
|
||||
|
||||
if (project == null)
|
||||
{
|
||||
// Could not locate a project for the given text buffer.
|
||||
workspace = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We have a host project, assume default workspace.
|
||||
workspace = _defaultWorkspace;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System.ComponentModel.Composition;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.VisualStudio.Editor.Razor;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using MonoDevelop.Ide.TypeSystem;
|
||||
|
||||
namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor
|
||||
|
|
@ -18,5 +19,10 @@ namespace Microsoft.VisualStudio.Mac.LanguageServices.Razor
|
|||
}
|
||||
|
||||
public override Workspace Workspace { get; }
|
||||
|
||||
public override bool TryGetWorkspace(ITextBuffer textBuffer, out Workspace workspace)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Razor.Test.Common\Microsoft.AspNetCore.Razor.Test.Common.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.CodeAnalysis.Razor\Microsoft.CodeAnalysis.Razor.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
|
||||
namespace Microsoft.CodeAnalysis.Host
|
||||
{
|
||||
internal class TestRazorLanguageServices : HostLanguageServices
|
||||
{
|
||||
private readonly HostWorkspaceServices _workspaceServices;
|
||||
private readonly IEnumerable<ILanguageService> _languageServices;
|
||||
|
||||
public TestRazorLanguageServices(HostWorkspaceServices workspaceServices, IEnumerable<ILanguageService> languageServices)
|
||||
{
|
||||
if (workspaceServices == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(workspaceServices));
|
||||
}
|
||||
|
||||
if (languageServices == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(languageServices));
|
||||
}
|
||||
|
||||
_workspaceServices = workspaceServices;
|
||||
_languageServices = languageServices;
|
||||
}
|
||||
|
||||
public override HostWorkspaceServices WorkspaceServices => _workspaceServices;
|
||||
|
||||
public override string Language => RazorLanguage.Name;
|
||||
|
||||
public override TLanguageService GetService<TLanguageService>()
|
||||
{
|
||||
var service = _languageServices.OfType<TLanguageService>().FirstOrDefault();
|
||||
|
||||
if (service == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Test Razor language services not configured properly, missing language service '{typeof(TLanguageService).FullName}'.");
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.CodeAnalysis.Host
|
||||
{
|
||||
public class TestServices : HostServices
|
||||
{
|
||||
private readonly IEnumerable<IWorkspaceService> _workspaceServices;
|
||||
private readonly IEnumerable<ILanguageService> _razorLanguageServices;
|
||||
|
||||
private TestServices(IEnumerable<IWorkspaceService> workspaceServices, IEnumerable<ILanguageService> razorLanguageServices)
|
||||
{
|
||||
if (workspaceServices == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(workspaceServices));
|
||||
}
|
||||
|
||||
if (razorLanguageServices == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(razorLanguageServices));
|
||||
}
|
||||
|
||||
_workspaceServices = workspaceServices;
|
||||
_razorLanguageServices = razorLanguageServices;
|
||||
}
|
||||
|
||||
protected override HostWorkspaceServices CreateWorkspaceServices(Workspace workspace)
|
||||
{
|
||||
if (workspace == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(workspace));
|
||||
}
|
||||
|
||||
return new TestWorkspaceServices(this, _workspaceServices, _razorLanguageServices, workspace);
|
||||
}
|
||||
|
||||
public static HostServices Create(IEnumerable<ILanguageService> razorLanguageServices)
|
||||
=> Create(Enumerable.Empty<IWorkspaceService>(), razorLanguageServices);
|
||||
|
||||
public static HostServices Create(IEnumerable<IWorkspaceService> workspaceServices, IEnumerable<ILanguageService> razorLanguageServices)
|
||||
=> new TestServices(workspaceServices, razorLanguageServices);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.CodeAnalysis.Host;
|
||||
|
||||
namespace Microsoft.CodeAnalysis
|
||||
{
|
||||
|
|
@ -9,11 +10,13 @@ namespace Microsoft.CodeAnalysis
|
|||
{
|
||||
private static readonly object WorkspaceLock = new object();
|
||||
|
||||
public static Workspace Create(Action<AdhocWorkspace> configure = null)
|
||||
public static Workspace Create(Action<AdhocWorkspace> configure = null) => Create(services: null, configure: configure);
|
||||
|
||||
public static Workspace Create(HostServices services, Action<AdhocWorkspace> configure = null)
|
||||
{
|
||||
lock (WorkspaceLock)
|
||||
{
|
||||
var workspace = new AdhocWorkspace();
|
||||
var workspace = services == null ? new AdhocWorkspace() : new AdhocWorkspace(services);
|
||||
configure?.Invoke(workspace);
|
||||
|
||||
return workspace;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
|
||||
namespace Microsoft.CodeAnalysis.Host
|
||||
{
|
||||
internal class TestWorkspaceServices : HostWorkspaceServices
|
||||
{
|
||||
private static readonly Workspace DefaultWorkspace = TestWorkspace.Create();
|
||||
|
||||
private readonly HostServices _hostServices;
|
||||
private readonly IEnumerable<IWorkspaceService> _workspaceServices;
|
||||
private readonly TestRazorLanguageServices _razorLanguageServices;
|
||||
private readonly Workspace _workspace;
|
||||
|
||||
public TestWorkspaceServices(
|
||||
HostServices hostServices,
|
||||
IEnumerable<IWorkspaceService> workspaceServices,
|
||||
IEnumerable<ILanguageService> razorLanguageServices,
|
||||
Workspace workspace)
|
||||
{
|
||||
if (hostServices == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(hostServices));
|
||||
}
|
||||
|
||||
if (workspaceServices == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(workspaceServices));
|
||||
}
|
||||
|
||||
if (razorLanguageServices == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(razorLanguageServices));
|
||||
}
|
||||
|
||||
if (workspace == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(workspace));
|
||||
}
|
||||
|
||||
_hostServices = hostServices;
|
||||
_workspaceServices = workspaceServices;
|
||||
_razorLanguageServices = new TestRazorLanguageServices(this, razorLanguageServices);
|
||||
_workspace = workspace;
|
||||
}
|
||||
|
||||
public override HostServices HostServices => _hostServices;
|
||||
|
||||
public override Workspace Workspace => _workspace;
|
||||
|
||||
public override TWorkspaceService GetService<TWorkspaceService>()
|
||||
{
|
||||
var service = _workspaceServices.OfType<TWorkspaceService>().FirstOrDefault();
|
||||
|
||||
if (service == null)
|
||||
{
|
||||
// Fallback to default host services to resolve roslyn specific features.
|
||||
service = DefaultWorkspace.Services.GetService<TWorkspaceService>();
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
public override HostLanguageServices GetLanguageServices(string languageName)
|
||||
{
|
||||
if (languageName != RazorLanguage.Name)
|
||||
{
|
||||
throw new InvalidOperationException($"Test services do not support language service '{languageName}'. The only language services supported are '{RazorLanguage.Name}'.");
|
||||
}
|
||||
|
||||
return _razorLanguageServices;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> SupportedLanguages => new[] { RazorLanguage.Name };
|
||||
|
||||
public override bool IsSupported(string languageName) => languageName == RazorLanguage.Name;
|
||||
|
||||
public override IEnumerable<TLanguageService> FindLanguageServices<TLanguageService>(MetadataFilter filter) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Host;
|
||||
using Microsoft.CodeAnalysis.Razor;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Utilities;
|
||||
|
|
@ -47,7 +49,25 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureTextBufferInitialized_StoresTracker()
|
||||
public void TryInitializeTextBuffer_WorkspaceAccessorCanNotAccessWorkspace_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
Workspace workspace = null;
|
||||
var workspaceAccessor = new Mock<VisualStudioWorkspaceAccessor>();
|
||||
workspaceAccessor.Setup(provider => provider.TryGetWorkspace(It.IsAny<ITextBuffer>(), out workspace))
|
||||
.Returns(false);
|
||||
var factoryService = new DefaultRazorEditorFactoryService(workspaceAccessor.Object);
|
||||
var textBuffer = Mock.Of<ITextBuffer>(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection());
|
||||
|
||||
// Act
|
||||
var result = factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryInitializeTextBuffer_StoresTracker_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var expectedDocumentTracker = Mock.Of<VisualStudioDocumentTracker>();
|
||||
|
|
@ -55,29 +75,31 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
var textBuffer = Mock.Of<ITextBuffer>(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection());
|
||||
|
||||
// Act
|
||||
factoryService.EnsureTextBufferInitialized(textBuffer);
|
||||
var result = factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.True(textBuffer.Properties.TryGetProperty(typeof(VisualStudioDocumentTracker), out VisualStudioDocumentTracker documentTracker));
|
||||
Assert.Same(expectedDocumentTracker, documentTracker);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureTextBufferInitialized_OnlyStoresTrackerOnTextBufferOnce()
|
||||
public void TryInitializeTextBuffer_OnlyStoresTrackerOnTextBufferOnce_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var factoryService = CreateFactoryService();
|
||||
var textBuffer = Mock.Of<ITextBuffer>(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection());
|
||||
factoryService.EnsureTextBufferInitialized(textBuffer);
|
||||
factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
var expectedDocumentTracker = textBuffer.Properties[typeof(VisualStudioDocumentTracker)];
|
||||
|
||||
// Create a second factory service so it generates a different tracker
|
||||
factoryService = CreateFactoryService();
|
||||
|
||||
// Act
|
||||
factoryService.EnsureTextBufferInitialized(textBuffer);
|
||||
var result = factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.True(textBuffer.Properties.TryGetProperty(typeof(VisualStudioDocumentTracker), out VisualStudioDocumentTracker documentTracker));
|
||||
Assert.Same(expectedDocumentTracker, documentTracker);
|
||||
}
|
||||
|
|
@ -114,7 +136,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureTextBufferInitialized_StoresParser()
|
||||
public void TryInitializeTextBuffer_StoresParser_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var expectedParser = Mock.Of<VisualStudioRazorParser>();
|
||||
|
|
@ -122,29 +144,31 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
var textBuffer = Mock.Of<ITextBuffer>(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection());
|
||||
|
||||
// Act
|
||||
factoryService.EnsureTextBufferInitialized(textBuffer);
|
||||
var result = factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.True(textBuffer.Properties.TryGetProperty(typeof(VisualStudioRazorParser), out VisualStudioRazorParser parser));
|
||||
Assert.Same(expectedParser, parser);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureTextBufferInitialized_OnlyStoresParserOnTextBufferOnce()
|
||||
public void TryInitializeTextBuffer_OnlyStoresParserOnTextBufferOnce_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var factoryService = CreateFactoryService();
|
||||
var textBuffer = Mock.Of<ITextBuffer>(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection());
|
||||
factoryService.EnsureTextBufferInitialized(textBuffer);
|
||||
factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
var expectedParser = textBuffer.Properties[typeof(VisualStudioRazorParser)];
|
||||
|
||||
// Create a second factory service so it generates a different parser
|
||||
factoryService = CreateFactoryService();
|
||||
|
||||
// Act
|
||||
factoryService.EnsureTextBufferInitialized(textBuffer);
|
||||
var result = factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.True(textBuffer.Properties.TryGetProperty(typeof(VisualStudioRazorParser), out VisualStudioRazorParser parser));
|
||||
Assert.Same(expectedParser, parser);
|
||||
}
|
||||
|
|
@ -181,7 +205,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureTextBufferInitialized_StoresSmartIndenter()
|
||||
public void TryInitializeTextBuffer_StoresSmartIndenter_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var expectedSmartIndenter = Mock.Of<BraceSmartIndenter>();
|
||||
|
|
@ -189,29 +213,31 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
var textBuffer = Mock.Of<ITextBuffer>(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection());
|
||||
|
||||
// Act
|
||||
factoryService.EnsureTextBufferInitialized(textBuffer);
|
||||
var result = factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.True(textBuffer.Properties.TryGetProperty(typeof(BraceSmartIndenter), out BraceSmartIndenter smartIndenter));
|
||||
Assert.Same(expectedSmartIndenter, smartIndenter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnsureTextBufferInitialized_OnlyStoresSmartIndenterOnTextBufferOnce()
|
||||
public void TryInitializeTextBuffer_OnlyStoresSmartIndenterOnTextBufferOnce_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var factoryService = CreateFactoryService();
|
||||
var textBuffer = Mock.Of<ITextBuffer>(b => b.ContentType == RazorCoreContentType && b.Properties == new PropertyCollection());
|
||||
factoryService.EnsureTextBufferInitialized(textBuffer);
|
||||
factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
var expectedSmartIndenter = textBuffer.Properties[typeof(BraceSmartIndenter)];
|
||||
|
||||
// Create a second factory service so it generates a different smart indenter
|
||||
factoryService = CreateFactoryService();
|
||||
|
||||
// Act
|
||||
factoryService.EnsureTextBufferInitialized(textBuffer);
|
||||
var result = factoryService.TryInitializeTextBuffer(textBuffer);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.True(textBuffer.Properties.TryGetProperty(typeof(BraceSmartIndenter), out BraceSmartIndenter smartIndenter));
|
||||
Assert.Same(expectedSmartIndenter, smartIndenter);
|
||||
}
|
||||
|
|
@ -228,7 +254,20 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
|||
var documentTrackerFactory = Mock.Of<VisualStudioDocumentTrackerFactory>(f => f.Create(It.IsAny<ITextBuffer>()) == documentTracker);
|
||||
var parserFactory = Mock.Of<VisualStudioRazorParserFactory>(f => f.Create(It.IsAny<VisualStudioDocumentTracker>()) == parser);
|
||||
var smartIndenterFactory = Mock.Of<BraceSmartIndenterFactory>(f => f.Create(It.IsAny<VisualStudioDocumentTracker>()) == smartIndenter);
|
||||
var factoryService = new DefaultRazorEditorFactoryService(documentTrackerFactory, parserFactory, smartIndenterFactory);
|
||||
|
||||
var services = TestServices.Create(new ILanguageService[]
|
||||
{
|
||||
documentTrackerFactory,
|
||||
parserFactory,
|
||||
smartIndenterFactory
|
||||
});
|
||||
|
||||
var workspace = TestWorkspace.Create(services);
|
||||
var workspaceAccessor = new Mock<VisualStudioWorkspaceAccessor>();
|
||||
workspaceAccessor.Setup(p => p.TryGetWorkspace(It.IsAny<ITextBuffer>(), out workspace))
|
||||
.Returns(true);
|
||||
|
||||
var factoryService = new DefaultRazorEditorFactoryService(workspaceAccessor.Object);
|
||||
|
||||
return factoryService;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.VisualStudio.Editor.Razor;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Projection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||
{
|
||||
public class DefaultVisualStudioWorkspaceAccessorTest
|
||||
{
|
||||
[Fact]
|
||||
public void TryGetWorkspace_CanGetWorkspaceFromProjectionBuffersOnly()
|
||||
{
|
||||
// Arrange
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
var workspaceAccessor = new TestWorkspaceAccessor(true, false);
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspace(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspace_CanGetWorkspaceFromBuffersInHierarchyOnly()
|
||||
{
|
||||
// Arrange
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
var workspaceAccessor = new TestWorkspaceAccessor(false, true);
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspace(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspace_CanGetWorkspaceFromBuffersInHierarchyOrProjectionBuffers()
|
||||
{
|
||||
// Arrange
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
var workspaceAccessor = new TestWorkspaceAccessor(true, true);
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspace(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspaceFromProjectionBuffer_NoProjectionBuffer_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var bufferGraph = new Mock<IBufferGraph>();
|
||||
bufferGraph.Setup(graph => graph.GetTextBuffers(It.IsAny<Predicate<ITextBuffer>>()))
|
||||
.Returns<Predicate<ITextBuffer>>(predicate => new Collection<ITextBuffer>());
|
||||
var bufferGraphService = new Mock<IBufferGraphFactoryService>();
|
||||
bufferGraphService.Setup(service => service.CreateBufferGraph(It.IsAny<ITextBuffer>()))
|
||||
.Returns(bufferGraph.Object);
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(bufferGraphService.Object, Mock.Of<TextBufferProjectService>(), TestWorkspace.Create());
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspaceFromProjectionBuffer(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspaceFromHostProject_NoHostProject_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<IBufferGraphFactoryService>(), Mock.Of<TextBufferProjectService>(), TestWorkspace.Create());
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspaceFromHostProject(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryGetWorkspaceFromHostProject_HasHostProject_ReturnsTrueWithDefaultWorkspace()
|
||||
{
|
||||
// Arrange
|
||||
var textBuffer = Mock.Of<ITextBuffer>();
|
||||
var projectService = Mock.Of<TextBufferProjectService>(service => service.GetHostProject(textBuffer) == new object());
|
||||
var defaultWorkspace = TestWorkspace.Create();
|
||||
var workspaceAccessor = new DefaultVisualStudioWorkspaceAccessor(Mock.Of<IBufferGraphFactoryService>(), projectService, defaultWorkspace);
|
||||
|
||||
// Act
|
||||
var result = workspaceAccessor.TryGetWorkspaceFromHostProject(textBuffer, out var workspace);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Same(defaultWorkspace, workspace);
|
||||
}
|
||||
|
||||
private class TestWorkspaceAccessor : DefaultVisualStudioWorkspaceAccessor
|
||||
{
|
||||
private readonly bool _canGetWorkspaceFromProjectionBuffer;
|
||||
private readonly bool _canGetWorkspaceFromHostProject;
|
||||
|
||||
internal TestWorkspaceAccessor(bool canGetWorkspaceFromProjectionBuffer, bool canGetWorkspaceFromHostProject) :
|
||||
base(
|
||||
Mock.Of<IBufferGraphFactoryService>(),
|
||||
Mock.Of<TextBufferProjectService>(),
|
||||
TestWorkspace.Create())
|
||||
{
|
||||
_canGetWorkspaceFromProjectionBuffer = canGetWorkspaceFromProjectionBuffer;
|
||||
_canGetWorkspaceFromHostProject = canGetWorkspaceFromHostProject;
|
||||
}
|
||||
|
||||
internal override bool TryGetWorkspaceFromProjectionBuffer(ITextBuffer textBuffer, out Workspace workspace)
|
||||
{
|
||||
if (_canGetWorkspaceFromProjectionBuffer)
|
||||
{
|
||||
workspace = TestWorkspace.Create();
|
||||
return true;
|
||||
}
|
||||
|
||||
workspace = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal override bool TryGetWorkspaceFromHostProject(ITextBuffer textBuffer, out Workspace workspace)
|
||||
{
|
||||
if (_canGetWorkspaceFromHostProject)
|
||||
{
|
||||
workspace = TestWorkspace.Create();
|
||||
return true;
|
||||
}
|
||||
|
||||
workspace = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue