Assert foreground thread before dispatching events

This commit is contained in:
Ajay Bhargav Baaskaran 2017-12-12 12:17:51 -08:00
parent b73c50be41
commit 7654f73c54
8 changed files with 55 additions and 29 deletions

View File

@ -9,11 +9,18 @@ namespace Microsoft.CodeAnalysis.Razor.Editor
{
public override event EventHandler<EditorSettingsChangedEventArgs> Changed;
private readonly ForegroundDispatcher _foregroundDispatcher;
private readonly object SettingsAccessorLock = new object();
private EditorSettings _settings;
public DefaultEditorSettingsManagerInternal()
public DefaultEditorSettingsManagerInternal(ForegroundDispatcher dispatcher)
{
if (dispatcher == null)
{
throw new ArgumentNullException(nameof(dispatcher));
}
_foregroundDispatcher = dispatcher;
_settings = EditorSettings.Default;
}
@ -47,6 +54,8 @@ namespace Microsoft.CodeAnalysis.Razor.Editor
private void OnChanged()
{
_foregroundDispatcher.AssertForegroundThread();
var args = new EditorSettingsChangedEventArgs(Current);
Changed?.Invoke(this, args);
}

View File

@ -19,7 +19,9 @@ namespace Microsoft.CodeAnalysis.Razor.Editor
throw new ArgumentNullException(nameof(languageServices));
}
return new DefaultEditorSettingsManagerInternal();
var foregroundDispatcher = languageServices.WorkspaceServices.GetRequiredService<ForegroundDispatcher>();
return new DefaultEditorSettingsManagerInternal(foregroundDispatcher);
}
}
}

View File

@ -210,12 +210,16 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
// virtual so it can be overridden in tests
protected virtual void NotifyBackgroundWorker(Project project)
{
_foregroundDispatcher.AssertForegroundThread();
_workerQueue.Enqueue(project);
}
// virtual so it can be overridden in tests
protected virtual void NotifyListeners(ProjectChangeEventArgs e)
{
_foregroundDispatcher.AssertForegroundThread();
var handler = Changed;
if (handler != null)
{

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.VisualStudio.Text;
@ -14,6 +15,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
{
internal class DefaultVisualStudioDocumentTracker : VisualStudioDocumentTracker
{
private readonly ForegroundDispatcher _foregroundDispatcher;
private readonly string _filePath;
private readonly string _projectPath;
private readonly ProjectSnapshotManager _projectManager;
@ -28,6 +30,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public override event EventHandler<ContextChangeEventArgs> ContextChanged;
public DefaultVisualStudioDocumentTracker(
ForegroundDispatcher dispatcher,
string filePath,
string projectPath,
ProjectSnapshotManager projectManager,
@ -36,6 +39,11 @@ namespace Microsoft.VisualStudio.Editor.Razor
ITextBuffer textBuffer,
ImportDocumentManager importDocumentManager)
{
if (dispatcher == null)
{
throw new ArgumentNullException(nameof(dispatcher));
}
if (string.IsNullOrEmpty(filePath))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(filePath));
@ -71,6 +79,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
throw new ArgumentNullException(nameof(importDocumentManager));
}
_foregroundDispatcher = dispatcher;
_filePath = filePath;
_projectPath = projectPath;
_projectManager = projectManager;
@ -172,6 +181,8 @@ namespace Microsoft.VisualStudio.Editor.Razor
private void OnContextChanged(ProjectSnapshot project, ContextChangeKind kind)
{
_foregroundDispatcher.AssertForegroundThread();
_project = project;
var handler = ContextChanged;

View File

@ -97,7 +97,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
var projectPath = _projectService.GetProjectPath(project);
var tracker = new DefaultVisualStudioDocumentTracker(filePath, projectPath, _projectManager, _editorSettingsManager, _workspace, textBuffer, _importDocumentManager);
var tracker = new DefaultVisualStudioDocumentTracker(_foregroundDispatcher, filePath, projectPath, _projectManager, _editorSettingsManager, _workspace, textBuffer, _importDocumentManager);
return tracker;
}

View File

@ -27,7 +27,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
private ProjectSnapshotManager ProjectManager => Mock.Of<ProjectSnapshotManager>(p => p.Projects == new List<ProjectSnapshot>());
private EditorSettingsManagerInternal EditorSettingsManager => new DefaultEditorSettingsManagerInternal();
private EditorSettingsManagerInternal EditorSettingsManager => new DefaultEditorSettingsManagerInternal(Dispatcher);
private ImportDocumentManager ImportDocumentManager => Mock.Of<ImportDocumentManager>();
@ -81,7 +81,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
{
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
};
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker;
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker;
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(factoryService => factoryService.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
var documentManager = new DefaultRazorDocumentManager(Dispatcher, editorFactoryService, SupportedProjectService);
@ -102,7 +102,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
};
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker;
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager) as VisualStudioDocumentTracker;
var editorFactoryService = Mock.Of<RazorEditorFactoryService>(f => f.TryGetDocumentTracker(It.IsAny<ITextBuffer>(), out documentTracker) == true);
var documentManager = new DefaultRazorDocumentManager(Dispatcher, editorFactoryService, SupportedProjectService);
@ -165,12 +165,12 @@ namespace Microsoft.VisualStudio.Editor.Razor
};
// Preload the buffer's properties with a tracker, so it's like we've already tracked this one.
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager);
documentTracker.AddTextView(textView1);
documentTracker.AddTextView(textView2);
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[1], ImportDocumentManager);
documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[1], ImportDocumentManager);
documentTracker.AddTextView(textView1);
documentTracker.AddTextView(textView2);
buffers[1].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
@ -200,7 +200,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
Mock.Of<ITextBuffer>(b => b.ContentType == RazorContentType && b.Properties == new PropertyCollection()),
Mock.Of<ITextBuffer>(b => b.ContentType == NonRazorContentType && b.Properties == new PropertyCollection()),
};
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, buffers[0], ImportDocumentManager);
buffers[0].Properties.AddProperty(typeof(VisualStudioDocumentTracker), documentTracker);
var editorFactoryService = Mock.Of<RazorEditorFactoryService>();
var documentManager = new DefaultRazorDocumentManager(Dispatcher, editorFactoryService, SupportedProjectService);

View File

@ -15,7 +15,7 @@ using Xunit;
namespace Microsoft.VisualStudio.Editor.Razor
{
public class DefaultVisualStudioDocumentTrackerTest
public class DefaultVisualStudioDocumentTrackerTest : ForegroundDispatcherTestBase
{
private IContentType RazorContentType { get; } = Mock.Of<IContentType>(c => c.IsOfType(RazorLanguage.ContentType) == true);
@ -27,7 +27,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
private ProjectSnapshotManager ProjectManager => Mock.Of<ProjectSnapshotManager>(p => p.Projects == new List<ProjectSnapshot>());
private EditorSettingsManagerInternal EditorSettingsManager => new DefaultEditorSettingsManagerInternal();
private EditorSettingsManagerInternal EditorSettingsManager => new DefaultEditorSettingsManagerInternal(Dispatcher);
private Workspace Workspace => new AdhocWorkspace();
@ -37,7 +37,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void EditorSettingsManager_Changed_TriggersContextChanged()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var called = false;
documentTracker.ContextChanged += (sender, args) =>
{
@ -57,7 +57,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void ProjectManager_Changed_ProjectChanged_TriggersContextChanged()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var project = new AdhocWorkspace().AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Path/TestProject.csproj"));
var projectSnapshot = new DefaultProjectSnapshot(project);
@ -81,7 +81,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void ProjectManager_Changed_TagHelpersChanged_TriggersContextChanged()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var project = new AdhocWorkspace().AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Path/TestProject.csproj"));
var projectSnapshot = new DefaultProjectSnapshot(project);
@ -105,7 +105,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void ProjectManager_Changed_IgnoresUnknownProject()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var project = new AdhocWorkspace().AddProject(ProjectInfo.Create(ProjectId.CreateNewId(), new VersionStamp(), "Test1", "TestAssembly", LanguageNames.CSharp, filePath: "C:/Some/Other/Path/TestProject.csproj"));
var projectSnapshot = new DefaultProjectSnapshot(project);
@ -128,7 +128,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void Import_Changed_ImportAssociatedWithDocument_TriggersContextChanged()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var called = false;
documentTracker.ContextChanged += (sender, args) =>
@ -150,7 +150,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void Import_Changed_UnrelatedImport_DoesNothing()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
documentTracker.ContextChanged += (sender, args) =>
{
@ -167,7 +167,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void Subscribe_SetsSupportedProjectAndTriggersContextChanged()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var called = false;
documentTracker.ContextChanged += (sender, args) =>
{
@ -187,7 +187,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void Unsubscribe_ResetsSupportedProjectAndTriggersContextChanged()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
// Subscribe once to set supported project
documentTracker.Subscribe();
@ -211,7 +211,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void AddTextView_AddsToTextViewCollection()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var textView = Mock.Of<ITextView>();
// Act
@ -225,7 +225,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void AddTextView_DoesNotAddDuplicateTextViews()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var textView = Mock.Of<ITextView>();
// Act
@ -240,7 +240,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void AddTextView_AddsMultipleTextViewsToCollection()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var textView1 = Mock.Of<ITextView>();
var textView2 = Mock.Of<ITextView>();
@ -259,7 +259,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void RemoveTextView_RemovesTextViewFromCollection_SingleItem()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var textView = Mock.Of<ITextView>();
documentTracker.AddTextView(textView);
@ -274,7 +274,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void RemoveTextView_RemovesTextViewFromCollection_MultipleItems()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var textView1 = Mock.Of<ITextView>();
var textView2 = Mock.Of<ITextView>();
var textView3 = Mock.Of<ITextView>();
@ -296,7 +296,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
public void RemoveTextView_NoopsWhenRemovingTextViewNotInCollection()
{
// Arrange
var documentTracker = new DefaultVisualStudioDocumentTracker(FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var documentTracker = new DefaultVisualStudioDocumentTracker(Dispatcher, FilePath, ProjectPath, ProjectManager, EditorSettingsManager, Workspace, TextBuffer, ImportDocumentManager);
var textView1 = Mock.Of<ITextView>();
documentTracker.AddTextView(textView1);
var textView2 = Mock.Of<ITextView>();

View File

@ -5,13 +5,13 @@ using Xunit;
namespace Microsoft.CodeAnalysis.Razor.Editor
{
public class DefaultEditorSettingsManagerInternalTest
public class DefaultEditorSettingsManagerInternalTest : ForegroundDispatcherTestBase
{
[Fact]
public void InitialSettingsAreDefault()
{
// Act
var manager = new DefaultEditorSettingsManagerInternal();
var manager = new DefaultEditorSettingsManagerInternal(Dispatcher);
// Assert
Assert.Equal(EditorSettings.Default, manager.Current);
@ -21,7 +21,7 @@ namespace Microsoft.CodeAnalysis.Razor.Editor
public void Update_TriggersChangedIfEditorSettingsAreDifferent()
{
// Arrange
var manager = new DefaultEditorSettingsManagerInternal();
var manager = new DefaultEditorSettingsManagerInternal(Dispatcher);
var called = false;
manager.Changed += (caller, args) =>
{
@ -41,7 +41,7 @@ namespace Microsoft.CodeAnalysis.Razor.Editor
public void Update_DoesNotTriggerChangedIfEditorSettingsAreSame()
{
// Arrange
var manager = new DefaultEditorSettingsManagerInternal();
var manager = new DefaultEditorSettingsManagerInternal(Dispatcher);
var called = false;
manager.Changed += (caller, args) =>
{