Prevent Razor Core from running in non-core scenarios.

- Also added tests.

#1776
This commit is contained in:
N. Taylor Mullen 2017-11-16 13:16:36 -08:00
parent fa2d79296a
commit 4f7aab7720
3 changed files with 81 additions and 5 deletions

View File

@ -16,6 +16,8 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
[Export(typeof(TextBufferProjectService))]
internal class DefaultTextBufferProjectService : TextBufferProjectService
{
private const string DotNetCoreCapability = "(CSharp|VB)&CPS";
private readonly RunningDocumentTable _documentTable;
private readonly ITextDocumentFactoryService _documentFactory;
@ -79,7 +81,20 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
throw new ArgumentNullException(nameof(hierarchy));
}
return hierarchy.IsCapabilityMatch("DotNetCoreWeb");
try
{
return hierarchy.IsCapabilityMatch(DotNetCoreCapability);
}
catch (NotSupportedException)
{
// IsCapabilityMatch throws a NotSupportedException if it can't create a BooleanSymbolExpressionEvaluator COM object
}
catch (ObjectDisposedException)
{
// IsCapabilityMatch throws an ObjectDisposedException if the underlying hierarchy has been disposed.
}
return false;
}
}
}

View File

@ -8,6 +8,8 @@ using System.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Editor.Razor;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Utilities;
@ -20,14 +22,21 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
internal class RazorTextViewConnectionListener : IWpfTextViewConnectionListener
{
private readonly ForegroundDispatcher _foregroundDispatcher;
private readonly TextBufferProjectService _projectService;
private readonly RazorEditorFactoryService _editorFactoryService;
private readonly Workspace _workspace;
[ImportingConstructor]
public RazorTextViewConnectionListener(
TextBufferProjectService projectService,
RazorEditorFactoryService editorFactoryService,
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
{
if (projectService == null)
{
throw new ArgumentNullException(nameof(projectService));
}
if (editorFactoryService == null)
{
throw new ArgumentNullException(nameof(editorFactoryService));
@ -38,6 +47,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
throw new ArgumentNullException(nameof(workspace));
}
_projectService = projectService;
_editorFactoryService = editorFactoryService;
_workspace = workspace;
@ -47,6 +57,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
// This is only for testing. We want to avoid using the actual Roslyn GetService methods in unit tests.
internal RazorTextViewConnectionListener(
ForegroundDispatcher foregroundDispatcher,
TextBufferProjectService projectService,
RazorEditorFactoryService editorFactoryService,
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
{
@ -55,6 +66,11 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
if (projectService == null)
{
throw new ArgumentNullException(nameof(projectService));
}
if (editorFactoryService == null)
{
throw new ArgumentNullException(nameof(editorFactoryService));
@ -66,6 +82,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
}
_foregroundDispatcher = foregroundDispatcher;
_projectService = projectService;
_editorFactoryService = editorFactoryService;
_workspace = workspace;
}
@ -94,6 +111,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
continue;
}
var hierarchy = _projectService.GetHierarchy(textBuffer);
if (!_projectService.IsSupportedProject(hierarchy))
{
return;
}
if (!_editorFactoryService.TryGetDocumentTracker(textBuffer, out var documentTracker) ||
!(documentTracker is DefaultVisualStudioDocumentTracker tracker))
{

View File

@ -34,12 +34,32 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
private IContentType NonRazorContentType { get; } = Mock.Of<IContentType>(c => c.IsOfType(It.IsAny<string>()) == false);
private TextBufferProjectService SupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(s => s.IsSupportedProject(It.IsAny<IVsHierarchy>()) == true);
private TextBufferProjectService UnsupportedProjectService { get; } = Mock.Of<TextBufferProjectService>(s => s.IsSupportedProject(It.IsAny<IVsHierarchy>()) == false);
[ForegroundFact]
public void SubjectBuffersConnected_ForNonRazorCoreProject_DoesNothing()
{
// Arrange
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
var factory = new RazorTextViewConnectionListener(Dispatcher, UnsupportedProjectService, editorFactoryService.Object, Workspace);
var textView = Mock.Of<IWpfTextView>();
var buffers = new Collection<ITextBuffer>()
{
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
};
// Act & Assert
factory.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
}
[ForegroundFact]
public void SubjectBuffersConnected_ForNonRazorTextBuffer_DoesNothing()
{
// Arrange
var editorFactoryService = new Mock<RazorEditorFactoryService>(MockBehavior.Strict);
var factory = new RazorTextViewConnectionListener(Dispatcher, editorFactoryService.Object, Workspace);
var factory = new RazorTextViewConnectionListener(Dispatcher, SupportedProjectService, editorFactoryService.Object, Workspace);
var textView = Mock.Of<IWpfTextView>();
var buffers = new Collection<ITextBuffer>()
{
@ -61,7 +81,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
};
VisualStudioDocumentTracker documentTracker = new DefaultVisualStudioDocumentTracker("AFile", ProjectManager, ProjectService, EditorSettingsManager, Workspace, buffers[0]);
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(factoryService => factoryService.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, editorFactoryService, Workspace);
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, SupportedProjectService, editorFactoryService, Workspace);
// Act
textViewListener.SubjectBuffersConnected(textView, ConnectionReason.BufferGraphChange, buffers);
@ -93,7 +113,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
tracker.AddTextView(textView1);
tracker.AddTextView(textView2);
buffers[1].Properties.AddProperty(typeof(VisualStudioDocumentTracker), tracker);
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, Mock.Of<RazorEditorFactoryService>(), Workspace);
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, SupportedProjectService, Mock.Of<RazorEditorFactoryService>(), Workspace);
// Act
textViewListener.SubjectBuffersDisconnected(textView2, ConnectionReason.BufferGraphChange, buffers);
@ -106,11 +126,29 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor.Editor
Assert.Collection(tracker.TextViews, v => Assert.Same(v, textView1));
}
[ForegroundFact]
public void SubjectBuffersDisconnected_FoNonRazorCoreProject_DoesNothing()
{
// Arrange
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, UnsupportedProjectService, Mock.Of<RazorEditorFactoryService>(), Workspace);
var textView = Mock.Of<IWpfTextView>();
var buffers = new Collection<ITextBuffer>()
{
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
};
// Act
textViewListener.SubjectBuffersDisconnected(textView, ConnectionReason.BufferGraphChange, buffers);
// Assert
Assert.False(buffers[0].Properties.ContainsProperty(typeof(VisualStudioDocumentTracker)));
}
[ForegroundFact]
public void SubjectBuffersDisconnected_ForAnyTextBufferWithoutTracker_DoesNothing()
{
// Arrange
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, Mock.Of<RazorEditorFactoryService>(), Workspace);
var textViewListener = new RazorTextViewConnectionListener(Dispatcher, SupportedProjectService, Mock.Of<RazorEditorFactoryService>(), Workspace);
var textView = Mock.Of<IWpfTextView>();