예제 #1
0
        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));
                }
            }
        }
예제 #2
0
        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;
            }
예제 #4
0
        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));
                }
            }
        }
예제 #5
0
        public DefaultProjectSnapshot WithComputedUpdate(ProjectSnapshotUpdateContext update)
        {
            if (update == null)
            {
                throw new ArgumentNullException(nameof(update));
            }

            return(new DefaultProjectSnapshot(update, this));
        }
예제 #6
0
        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));
        }
예제 #7
0
        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);
        }
예제 #9
0
        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;
        }
예제 #10
0
        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();
            }
        }
예제 #11
0
        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);
        }
예제 #13
0
        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);
        }
예제 #14
0
        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;
        }
예제 #15
0
        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);
        }
예제 #18
0
 protected override void NotifyBackgroundWorker(ProjectSnapshotUpdateContext context)
 {
 }
 public abstract void ProjectUpdated(ProjectSnapshotUpdateContext update);
예제 #20
0
 public override Task ProcessUpdateAsync(ProjectSnapshotUpdateContext update, CancellationToken cancellationToken = default(CancellationToken))
 {
     return(Task.CompletedTask);
 }
예제 #21
0
        // virtual so it can be overridden in tests
        protected virtual void NotifyBackgroundWorker(ProjectSnapshotUpdateContext context)
        {
            _foregroundDispatcher.AssertForegroundThread();

            _workerQueue.Enqueue(context);
        }
예제 #22
0
 public abstract Task ProcessUpdateAsync(ProjectSnapshotUpdateContext update, CancellationToken cancellationToken = default(CancellationToken));