public override void ProjectUpdated(ProjectSnapshotUpdateContext update) { if (update == null) { throw new ArgumentNullException(nameof(update)); } _foregroundDispatcher.AssertForegroundThread(); if (_projects.TryGetValue(update.WorkspaceProject.FilePath, out var original)) { if (!original.IsInitialized) { // If the project has been uninitialized, just ignore the update. return; } // This is an update to the project's computed values, so everything should be overwritten var snapshot = original.WithComputedUpdate(update); _projects[update.WorkspaceProject.FilePath] = snapshot; if (snapshot.IsDirty) { // It's possible that the snapshot can still be dirty if we got a project update while computing state in // the background. We need to trigger the background work to asynchronously compute the effect of the updates. NotifyBackgroundWorker(snapshot.CreateUpdateContext()); } if (!object.Equals(snapshot.ComputedVersion, original.ComputedVersion)) { NotifyListeners(new ProjectChangeEventArgs(snapshot, ProjectChangeKind.TagHelpersChanged)); } } }
public void ProjectChanged_BackgroundUpdate_StillDirty_WithSignificantChanges_NotifiesListeners_AndStartsBackgroundWorker() { // Arrange var project = Workspace.CurrentSolution.AddProject("Test", "Test", LanguageNames.CSharp); ProjectManager.ProjectAdded(project); ProjectManager.Reset(); var configuration = Mock.Of <ProjectExtensibilityConfiguration>(); // Compute an update for "Test" var update = new ProjectSnapshotUpdateContext(project) { Configuration = configuration }; project = project.WithAssemblyName("Test1"); // Simulate a project change ProjectManager.ProjectChanged(project); ProjectManager.Reset(); // Act ProjectManager.ProjectUpdated(update); // Assert var snapshot = ProjectManager.GetSnapshot(project.Id); Assert.True(snapshot.IsDirty); Assert.Same(configuration, snapshot.Configuration); Assert.True(ProjectManager.ListenersNotified); Assert.True(ProjectManager.WorkerStarted); }
protected override void NotifyBackgroundWorker(ProjectSnapshotUpdateContext context) { Assert.NotNull(context.HostProject); Assert.NotNull(context.WorkspaceProject); WorkerStarted = true; }
public override void ProjectUpdated(ProjectSnapshotUpdateContext update) { if (update == null) { throw new ArgumentNullException(nameof(update)); } if (_projects.TryGetValue(update.UnderlyingProject.Id, out var original)) { // This is an update to the project's computed values, so everything should be overwritten var snapshot = original.WithProjectChange(update); _projects[update.UnderlyingProject.Id] = snapshot; if (snapshot.IsDirty) { // It's possible that the snapshot can still be dirty if we got a project update while computing state in // the background. We need to trigger the background work to asynchronously compute the effect of the updates. NotifyBackgroundWorker(snapshot.UnderlyingProject); } // Now we need to know if the changes that we applied are significant. If that's the case then // we need to notify listeners. if (snapshot.HasChangesComparedTo(original)) { NotifyListeners(new ProjectChangeEventArgs(snapshot, ProjectChangeKind.Changed)); } } }
public DefaultProjectSnapshot WithComputedUpdate(ProjectSnapshotUpdateContext update) { if (update == null) { throw new ArgumentNullException(nameof(update)); } return(new DefaultProjectSnapshot(update, this)); }
public override Task ProcessUpdateAsync(ProjectSnapshotUpdateContext update, CancellationToken cancellationToken = default(CancellationToken)) { if (update == null) { throw new ArgumentNullException(nameof(update)); } // Don't block the main thread if (_foregroundDispatcher.IsForegroundThread) { return(Task.Factory.StartNew(ProjectUpdatesCoreAsync, update, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.BackgroundScheduler)); } return(ProjectUpdatesCoreAsync(update)); }
public void HaveTagHelpersChanged_NoUpdatesToTagHelpers_ReturnsFalse() { // Arrange var underlyingProject = GetProject("Test1"); var original = new DefaultProjectSnapshot(underlyingProject); var anotherProject = GetProject("Test1"); var update = new ProjectSnapshotUpdateContext(anotherProject); var snapshot = original.WithProjectChange(update); // Act var result = snapshot.HaveTagHelpersChanged(original); // Assert Assert.False(result); }
public void HaveTagHelpersChanged_NoUpdatesToTagHelpers_ReturnsFalse() { // Arrange var hostProject = new HostProject("Test1.csproj", RazorConfiguration.Default); var workspaceProject = GetWorkspaceProject("Test1"); var original = new DefaultProjectSnapshot(hostProject, workspaceProject); var anotherProject = GetWorkspaceProject("Test1"); var update = new ProjectSnapshotUpdateContext("Test1.csproj", hostProject, anotherProject, VersionStamp.Default); var snapshot = original.WithComputedUpdate(update); // Act var result = snapshot.HaveTagHelpersChanged(original); // Assert Assert.False(result); }
private DefaultProjectSnapshot(ProjectSnapshotUpdateContext update, DefaultProjectSnapshot other) { if (update == null) { throw new ArgumentNullException(nameof(update)); } if (other == null) { throw new ArgumentNullException(nameof(other)); } UnderlyingProject = other.UnderlyingProject; ComputedVersion = update.UnderlyingProject.Version; Configuration = update.Configuration; }
public void Enqueue(ProjectSnapshotUpdateContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } _foregroundDispatcher.AssertForegroundThread(); lock (_projects) { // We only want to store the last 'seen' version of any given project. That way when we pick one to process // it's always the best version to use. _projects[context.FilePath] = context; StartWorker(); } }
private DefaultProjectSnapshot(ProjectSnapshotUpdateContext update, DefaultProjectSnapshot other) { if (update == null) { throw new ArgumentNullException(nameof(update)); } if (other == null) { throw new ArgumentNullException(nameof(other)); } UnderlyingProject = other.UnderlyingProject; ComputedVersion = update.UnderlyingProject.Version; Configuration = update.Configuration; TagHelpers = update.TagHelpers ?? Array.Empty <TagHelperDescriptor>(); }
public void WithProjectChange_WithProject_CreatesSnapshot_UpdatesValues() { // Arrange var hostProject = new HostProject("Test.cshtml", FallbackRazorConfiguration.MVC_2_0); var workspaceProject = GetWorkspaceProject("Test1"); var original = new DefaultProjectSnapshot(hostProject, workspaceProject); var anotherProject = GetWorkspaceProject("Test1"); var update = new ProjectSnapshotUpdateContext(original.FilePath, hostProject, anotherProject, original.Version) { TagHelpers = Array.Empty <TagHelperDescriptor>(), }; // Act var snapshot = original.WithComputedUpdate(update); // Assert Assert.Same(original.WorkspaceProject, snapshot.WorkspaceProject); Assert.Same(update.TagHelpers, snapshot.TagHelpers); }
public void WithProjectChange_WithProject_CreatesSnapshot_UpdatesValues() { // Arrange var underlyingProject = GetProject("Test1"); var original = new DefaultProjectSnapshot(underlyingProject); var anotherProject = GetProject("Test1"); var update = new ProjectSnapshotUpdateContext(anotherProject) { Configuration = Mock.Of <ProjectExtensibilityConfiguration>(), TagHelpers = Array.Empty <TagHelperDescriptor>(), }; // Act var snapshot = original.WithProjectChange(update); // Assert Assert.Same(original.UnderlyingProject, snapshot.UnderlyingProject); Assert.Equal(update.UnderlyingProject.Version, snapshot.ComputedVersion); Assert.Same(update.Configuration, snapshot.Configuration); Assert.Same(update.TagHelpers, snapshot.TagHelpers); }
private DefaultProjectSnapshot(ProjectSnapshotUpdateContext update, DefaultProjectSnapshot other) { if (update == null) { throw new ArgumentNullException(nameof(update)); } if (other == null) { throw new ArgumentNullException(nameof(other)); } ComputedVersion = update.Version; FilePath = other.FilePath; HostProject = other.HostProject; TagHelpers = update.TagHelpers ?? Array.Empty <TagHelperDescriptor>(); WorkspaceProject = other.WorkspaceProject; // This doesn't represent a new version of the underlying data. Keep the same version. Version = other.Version; }
public void HaveTagHelpersChanged_TagHelpersUpdated_ReturnsTrue() { // Arrange var underlyingProject = GetProject("Test1"); var original = new DefaultProjectSnapshot(underlyingProject); var anotherProject = GetProject("Test1"); var update = new ProjectSnapshotUpdateContext(anotherProject) { TagHelpers = new[] { TagHelperDescriptorBuilder.Create("One", "TestAssembly").Build(), TagHelperDescriptorBuilder.Create("Two", "TestAssembly").Build(), }, }; var snapshot = original.WithProjectChange(update); // Act var result = snapshot.HaveTagHelpersChanged(original); // Assert Assert.True(result); }
public async Task ProcessUpdateAsync_DoesntBlockForegroundThread() { // Arrange var worker = new DefaultProjectSnapshotWorker(Dispatcher, ConfigurationFactory); var context = new ProjectSnapshotUpdateContext(Project); var configuration = Mock.Of <ProjectExtensibilityConfiguration>(); // Act 1 -- We want to verify that this doesn't block the main thread var task = worker.ProcessUpdateAsync(context); // Assert 1 // // We haven't let the background task proceed yet, so this is still null. Assert.Null(context.Configuration); // Act 2 - Ok let's go CompletionSource.SetResult(configuration); await task; // Assert 2 Assert.Same(configuration, context.Configuration); }
public void HaveTagHelpersChanged_TagHelpersUpdated_ReturnsTrue() { // Arrange var hostProject = new HostProject("Test1.csproj", RazorConfiguration.Default); var workspaceProject = GetWorkspaceProject("Test1"); var original = new DefaultProjectSnapshot(hostProject, workspaceProject); var anotherProject = GetWorkspaceProject("Test1"); var update = new ProjectSnapshotUpdateContext("Test1.csproj", hostProject, anotherProject, VersionStamp.Default) { TagHelpers = new[] { TagHelperDescriptorBuilder.Create("One", "TestAssembly").Build(), TagHelperDescriptorBuilder.Create("Two", "TestAssembly").Build(), }, }; var snapshot = original.WithComputedUpdate(update); // Act var result = snapshot.HaveTagHelpersChanged(original); // Assert Assert.True(result); }
protected override void NotifyBackgroundWorker(ProjectSnapshotUpdateContext context) { }
public abstract void ProjectUpdated(ProjectSnapshotUpdateContext update);
public override Task ProcessUpdateAsync(ProjectSnapshotUpdateContext update, CancellationToken cancellationToken = default(CancellationToken)) { return(Task.CompletedTask); }
// virtual so it can be overridden in tests protected virtual void NotifyBackgroundWorker(ProjectSnapshotUpdateContext context) { _foregroundDispatcher.AssertForegroundThread(); _workerQueue.Enqueue(context); }
public abstract Task ProcessUpdateAsync(ProjectSnapshotUpdateContext update, CancellationToken cancellationToken = default(CancellationToken));