Exemple #1
0
        public async Task WorkspaceChanged_ProjectChangeEvents_UpdatesProjectState_AfterDelay(WorkspaceChangeKind kind)
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator)
            {
                EnqueueDelay = 1,
                BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false),
            };

            var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace);

            projectManager.ProjectAdded(HostProjectOne);

            var solution = SolutionWithTwoProjects.WithProjectAssemblyName(ProjectNumberOne.Id, "Changed");
            var e        = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);

            // Assert
            //
            // The change hasn't come through yet.
            Assert.Empty(workspaceStateGenerator.UpdateQueue);

            detector.BlockDelayedUpdateWorkEnqueue.Set();

            await detector._deferredUpdates.Single().Value;

            var update = Assert.Single(workspaceStateGenerator.UpdateQueue);

            Assert.Equal(update.workspaceProject.Id, ProjectNumberOne.Id);
            Assert.Equal(update.projectSnapshot.FilePath, HostProjectOne.FilePath);
        }
Exemple #2
0
        public async Task SolutionClosing_StopsActiveWork()
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue);

            WorkQueueTestAccessor.BlockBackgroundWorkStart     = new ManualResetEventSlim(initialState: false);
            WorkQueueTestAccessor.NotifyBackgroundWorkStarting = new ManualResetEventSlim(initialState: false);

            Workspace.TryApplyChanges(SolutionWithTwoProjects);
            var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace);
            await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None).ConfigureAwait(false);

            workspaceStateGenerator.ClearQueue();
            WorkQueueTestAccessor.NotifyBackgroundWorkStarting.Wait();

            // Act
            await Dispatcher.RunOnDispatcherThreadAsync(() =>
            {
                projectManager.SolutionClosed();

                // Trigger a project removed event while solution is closing to clear state.
                projectManager.ProjectRemoved(HostProjectOne);
            }, CancellationToken.None).ConfigureAwait(false);

            // Assert
            //
            // The change hasn't come through yet.
            Assert.Empty(workspaceStateGenerator.UpdateQueue);

            WorkQueueTestAccessor.BlockBackgroundWorkStart.Set();
            WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait();

            Assert.Empty(workspaceStateGenerator.UpdateQueue);
        }
        public RazorDocumentInfoProviderTest()
        {
            var serviceProviderFactory          = new DefaultRazorDocumentServiceProviderFactory();
            var lspEditorEnabledFeatureDetector = Mock.Of <LSPEditorFeatureDetector>(detector => detector.IsLSPEditorFeatureEnabled() == true, MockBehavior.Strict);

            InnerDynamicDocumentInfoProvider = new DefaultRazorDynamicFileInfoProvider(serviceProviderFactory, lspEditorEnabledFeatureDetector);
            ProjectSnapshotManager           = new TestProjectSnapshotManager(Workspace);

            var hostProject = new HostProject("C:/path/to/project.csproj", RazorConfiguration.Default, "RootNamespace");

            ProjectSnapshotManager.ProjectAdded(hostProject);

            var hostDocument   = new HostDocument("C:/path/to/document.cshtml", "/C:/path/to/document.cshtml");
            var sourceText     = SourceText.From("Hello World");
            var textAndVersion = TextAndVersion.Create(sourceText, VersionStamp.Default, hostDocument.FilePath);

            ProjectSnapshotManager.DocumentAdded(hostProject, hostDocument, TextLoader.From(textAndVersion));

            ProjectSnapshot  = ProjectSnapshotManager.Projects[0];
            DocumentSnapshot = ProjectSnapshot.GetDocument(hostDocument.FilePath);
            var factory = new Mock <VisualStudioMacDocumentInfoFactory>(MockBehavior.Strict);

            factory.Setup(f => f.CreateEmpty(It.IsAny <string>(), It.IsAny <ProjectId>()))
            .Returns <string, ProjectId>((razorFilePath, projectId) =>
            {
                var documentId   = DocumentId.CreateNewId(projectId);
                var documentInfo = DocumentInfo.Create(documentId, "testDoc", filePath: razorFilePath);
                return(documentInfo);
            });
            Factory = factory.Object;
        }
        public async Task ProcessDocument_SwallowsUnauthorizedAccessExceptions()
        {
            // Arrange
            var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace);

            projectManager.ProjectAdded(HostProject1);

            var textLoader = new Mock <TextLoader>();

            textLoader.Setup(loader => loader.LoadTextAndVersionAsync(It.IsAny <Workspace>(), It.IsAny <DocumentId>(), It.IsAny <CancellationToken>()))
            .Throws <UnauthorizedAccessException>();
            projectManager.DocumentAdded(HostProject1, Documents[0], textLoader.Object);

            var project = projectManager.GetLoadedProject(HostProject1.FilePath);

            var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider, DivergenceChecker)
            {
                Delay = TimeSpan.FromMilliseconds(1),
                NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false),
                NotifyErrorBeingReported      = new ManualResetEventSlim(initialState: false),
            };

            queue.Initialize(projectManager);

            // Act & Assert
            queue.Enqueue(project, project.GetDocument(Documents[0].FilePath));

            await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));

            Assert.False(queue.NotifyErrorBeingReported.IsSet);
        }
        public DefaultRazorDocumentInfoProviderTest()
        {
            ProjectSnapshotManager = new TestProjectSnapshotManager(Workspace);

            var hostProject = new HostProject("C:/path/to/project.csproj", RazorConfiguration.Default, "RootNamespace");

            ProjectSnapshotManager.ProjectAdded(hostProject);

            var hostDocument   = new HostDocument("C:/path/to/document.cshtml", "/C:/path/to/document.cshtml");
            var sourceText     = SourceText.From("Hello World");
            var textAndVersion = TextAndVersion.Create(sourceText, VersionStamp.Default, hostDocument.FilePath);

            ProjectSnapshotManager.DocumentAdded(hostProject, hostDocument, TextLoader.From(textAndVersion));

            ProjectSnapshot  = ProjectSnapshotManager.Projects[0];
            DocumentSnapshot = ProjectSnapshot.GetDocument(hostDocument.FilePath);
            var factory = new Mock <VisualStudioMacDocumentInfoFactory>();

            factory.Setup(f => f.CreateEmpty(It.IsAny <string>(), It.IsAny <ProjectId>()))
            .Returns <string, ProjectId>((razorFilePath, projectId) =>
            {
                var documentId   = DocumentId.CreateNewId(projectId);
                var documentInfo = DocumentInfo.Create(documentId, "testDoc", filePath: razorFilePath);
                return(documentInfo);
            });
            Factory = factory.Object;
        }
Exemple #6
0
        public async Task WorkspaceChanged_DocumentChanged_Razor_UpdatesProjectState_AfterDelay()
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue);

            WorkQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);

            Workspace.TryApplyChanges(SolutionWithTwoProjects);
            var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace);
            await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None).ConfigureAwait(false);

            workspaceStateGenerator.ClearQueue();

            var solution = SolutionWithTwoProjects.WithDocumentText(RazorDocumentId, SourceText.From("Hello World"));
            var e        = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id, RazorDocumentId);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);

            // Assert
            //
            // The change hasn't come through yet.
            Assert.Empty(workspaceStateGenerator.UpdateQueue);

            WorkQueueTestAccessor.BlockBackgroundWorkStart.Set();
            WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait();

            var update = Assert.Single(workspaceStateGenerator.UpdateQueue);

            Assert.Equal(update.WorkspaceProject.Id, ProjectNumberOne.Id);
            Assert.Equal(update.ProjectSnapshot.FilePath, HostProjectOne.FilePath);
        }
Exemple #7
0
        public async Task WorkspaceChanged_DocumentChanged_Razor_UpdatesProjectState_AfterDelay()
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator)
            {
                EnqueueDelay = 50,
            };

            Workspace.TryApplyChanges(SolutionWithTwoProjects);
            var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace);

            projectManager.ProjectAdded(HostProjectOne);
            workspaceStateGenerator.ClearQueue();

            var solution = SolutionWithTwoProjects.WithDocumentText(RazorDocumentId, SourceText.From("Hello World"));
            var e        = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id, RazorDocumentId);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);

            // Assert
            //
            // The change hasn't come through yet.
            Assert.Empty(workspaceStateGenerator.UpdateQueue);

            await detector._deferredUpdates.Single().Value;

            var update = Assert.Single(workspaceStateGenerator.UpdateQueue);

            Assert.Equal(update.workspaceProject.Id, ProjectNumberOne.Id);
            Assert.Equal(update.projectSnapshot.FilePath, HostProjectOne.FilePath);
        }
Exemple #8
0
        public async Task WorkspaceChanged_ProjectEvents_EnqueuesUpdatesForDependentProjects(WorkspaceChangeKind kind)
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue)
            {
                NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false),
            };

            WorkQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);

            var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace);

            await Dispatcher.RunOnDispatcherThreadAsync(() =>
            {
                projectManager.ProjectAdded(HostProjectOne);
                projectManager.ProjectAdded(HostProjectTwo);
                projectManager.ProjectAdded(HostProjectThree);
            }, CancellationToken.None).ConfigureAwait(false);

            // Initialize with a project. This will get removed.
            var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.SolutionAdded, oldSolution: EmptySolution, newSolution: SolutionWithOneProject);

            detector.Workspace_WorkspaceChanged(Workspace, e);
            detector.NotifyWorkspaceChangedEventComplete.Wait();
            detector.NotifyWorkspaceChangedEventComplete.Reset();

            e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithOneProject, newSolution: SolutionWithDependentProject);

            var solution = SolutionWithDependentProject.WithProjectAssemblyName(ProjectNumberThree.Id, "Changed");

            e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithDependentProject, newSolution: solution, projectId: ProjectNumberThree.Id);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);
            detector.NotifyWorkspaceChangedEventComplete.Wait();

            // Assert
            Assert.Equal(3, WorkQueueTestAccessor.Work.Count);
            Assert.Contains(WorkQueueTestAccessor.Work, u => u.Key == ProjectNumberOne.FilePath);
            Assert.Contains(WorkQueueTestAccessor.Work, u => u.Key == ProjectNumberTwo.FilePath);
            Assert.Contains(WorkQueueTestAccessor.Work, u => u.Key == ProjectNumberThree.FilePath);

            WorkQueueTestAccessor.BlockBackgroundWorkStart.Set();
            WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait();
            Assert.Empty(WorkQueueTestAccessor.Work);
        }
Exemple #9
0
        public async Task WorkspaceChanged_SolutionEvents_EnqueuesStateClear_EnqueuesSolutionProjectUpdates(WorkspaceChangeKind kind)
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue)
            {
                NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false),
            };

            var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace);

            await Dispatcher.RunOnDispatcherThreadAsync(() =>
            {
                projectManager.ProjectAdded(HostProjectOne);
                projectManager.ProjectAdded(HostProjectTwo);
                projectManager.ProjectAdded(HostProjectThree);
            }, CancellationToken.None).ConfigureAwait(false);

            // Initialize with a project. This will get removed.
            var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.SolutionAdded, oldSolution: EmptySolution, newSolution: SolutionWithOneProject);

            detector.Workspace_WorkspaceChanged(Workspace, e);
            detector.NotifyWorkspaceChangedEventComplete.Wait();
            detector.NotifyWorkspaceChangedEventComplete.Reset();
            WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait();
            WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Reset();

            e = new WorkspaceChangeEventArgs(kind, oldSolution: SolutionWithOneProject, newSolution: SolutionWithTwoProjects);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);
            detector.NotifyWorkspaceChangedEventComplete.Wait();
            WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait();

            // Assert
            Assert.Collection(
                workspaceStateGenerator.UpdateQueue,
                p => Assert.Equal(ProjectNumberThree.Id, p.WorkspaceProject.Id),
                p => Assert.Null(p.WorkspaceProject),
                p => Assert.Equal(ProjectNumberOne.Id, p.WorkspaceProject.Id),
                p => Assert.Equal(ProjectNumberTwo.Id, p.WorkspaceProject.Id));
        }
        public async Task DocumentRemoved_ReparsesRelatedFiles()
        {
            // Arrange
            var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace)
            {
                AllowNotifyListeners = true,
            };

            projectManager.ProjectAdded(HostProject1);
            projectManager.DocumentAdded(HostProject1, TestProjectData.SomeProjectComponentFile1, null);
            projectManager.DocumentAdded(HostProject1, TestProjectData.SomeProjectImportFile, null);

            var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider)
            {
                Delay = TimeSpan.FromMilliseconds(1),
                BlockBackgroundWorkStart         = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundWorkStarting     = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundCapturedWorkload = new ManualResetEventSlim(initialState: false),
                BlockBackgroundWorkCompleting    = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundWorkCompleted    = new ManualResetEventSlim(initialState: false),
            };

            queue.Initialize(projectManager);

            // Act & Assert
            projectManager.DocumentRemoved(HostProject1, TestProjectData.SomeProjectImportFile);

            Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue");
            Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue");

            var kvp         = Assert.Single(queue.Work);
            var expectedKey = new DocumentKey(HostProject1.FilePath, TestProjectData.SomeProjectComponentFile1.FilePath);

            Assert.Equal(expectedKey, kvp.Key);

            // Allow the background work to start.
            queue.BlockBackgroundWorkStart.Set();

            await Task.Run(() => queue.NotifyBackgroundWorkStarting.Wait(TimeSpan.FromSeconds(1)));

            Assert.True(queue.IsScheduledOrRunning, "Worker should be processing now");

            await Task.Run(() => queue.NotifyBackgroundCapturedWorkload.Wait(TimeSpan.FromSeconds(1)));

            Assert.False(queue.HasPendingNotifications, "Worker should have taken all notifications");

            // Allow work to complete
            queue.BlockBackgroundWorkCompleting.Set();

            await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));

            Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications");
            Assert.False(queue.IsScheduledOrRunning, "Queue should not have restarted");
        }
Exemple #11
0
        public async Task WorkspaceChanged_DocumentChanged_PartialComponent_UpdatesProjectState_AfterDelay()
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator)
            {
                EnqueueDelay = 1,
                BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false),
            };

            Workspace.TryApplyChanges(SolutionWithTwoProjects);
            var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace);

            projectManager.ProjectAdded(HostProjectOne);
            workspaceStateGenerator.ClearQueue();

            var sourceText = SourceText.From(
                $@"
public partial class TestComponent : {ComponentsApi.IComponent.MetadataName} {{}}
namespace Microsoft.AspNetCore.Components
{{
    public interface IComponent {{}}
}}
");
            var syntaxTreeRoot = CSharpSyntaxTree.ParseText(sourceText).GetRoot();
            var solution       = SolutionWithTwoProjects
                                 .WithDocumentText(PartialComponentClassDocumentId, sourceText)
                                 .WithDocumentSyntaxRoot(PartialComponentClassDocumentId, syntaxTreeRoot, PreservationMode.PreserveIdentity);
            var document = solution.GetDocument(PartialComponentClassDocumentId);

            // The change detector only operates when a semantic model / syntax tree is available.
            await document.GetSyntaxRootAsync();

            await document.GetSemanticModelAsync();

            var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: solution, newSolution: solution, projectId: ProjectNumberOne.Id, PartialComponentClassDocumentId);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);

            // Assert
            //
            // The change hasn't come through yet.
            Assert.Empty(workspaceStateGenerator.UpdateQueue);

            detector.BlockDelayedUpdateWorkEnqueue.Set();

            await detector._deferredUpdates.Single().Value;

            var update = Assert.Single(workspaceStateGenerator.UpdateQueue);

            Assert.Equal(update.workspaceProject.Id, ProjectNumberOne.Id);
            Assert.Equal(update.projectSnapshot.FilePath, HostProjectOne.FilePath);
        }
Exemple #12
0
        public async Task WorkspaceChanged_DocumentChanged_PartialComponent_UpdatesProjectState_AfterDelay()
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue);

            WorkQueueTestAccessor.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);

            Workspace.TryApplyChanges(SolutionWithTwoProjects);
            var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace);
            await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectOne), CancellationToken.None).ConfigureAwait(false);

            workspaceStateGenerator.ClearQueue();

            var sourceText = SourceText.From(
                $@"
public partial class TestComponent : {ComponentsApi.IComponent.MetadataName} {{}}
namespace Microsoft.AspNetCore.Components
{{
    public interface IComponent {{}}
}}
");
            var syntaxTreeRoot = await CSharpSyntaxTree.ParseText(sourceText).GetRootAsync();

            var solution = SolutionWithTwoProjects
                           .WithDocumentText(PartialComponentClassDocumentId, sourceText)
                           .WithDocumentSyntaxRoot(PartialComponentClassDocumentId, syntaxTreeRoot, PreservationMode.PreserveIdentity);
            var document = solution.GetDocument(PartialComponentClassDocumentId);

            // The change detector only operates when a semantic model / syntax tree is available.
            await document.GetSyntaxRootAsync();

            await document.GetSemanticModelAsync();

            var e = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: solution, newSolution: solution, projectId: ProjectNumberOne.Id, PartialComponentClassDocumentId);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);

            // Assert
            //
            // The change hasn't come through yet.
            Assert.Empty(workspaceStateGenerator.UpdateQueue);

            WorkQueueTestAccessor.BlockBackgroundWorkStart.Set();

            WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait();

            var update = Assert.Single(workspaceStateGenerator.UpdateQueue);

            Assert.Equal(update.WorkspaceProject.Id, ProjectNumberOne.Id);
            Assert.Equal(update.ProjectSnapshot.FilePath, HostProjectOne.FilePath);
        }
Exemple #13
0
        public void WorkspaceChanged_ProjectRemovedEvent_QueuesProjectStateRemoval()
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector       = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator);
            var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace);

            projectManager.ProjectAdded(HostProjectOne);
            projectManager.ProjectAdded(HostProjectTwo);

            var solution = SolutionWithTwoProjects.RemoveProject(ProjectNumberOne.Id);
            var e        = new WorkspaceChangeEventArgs(WorkspaceChangeKind.ProjectRemoved, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);

            // Assert
            Assert.Collection(
                workspaceStateGenerator.UpdateQueue,
                p => Assert.Null(p.workspaceProject));
        }
Exemple #14
0
        public void WorkspaceChanged_SolutionEvents_EnqueuesUpdatesForProjectsInSolution(WorkspaceChangeKind kind)
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector       = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator);
            var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace);

            projectManager.ProjectAdded(HostProjectOne);
            projectManager.ProjectAdded(HostProjectTwo);

            var e = new WorkspaceChangeEventArgs(kind, oldSolution: EmptySolution, newSolution: SolutionWithTwoProjects);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);

            // Assert
            Assert.Collection(
                workspaceStateGenerator.UpdateQueue,
                p => Assert.Equal(ProjectNumberOne.Id, p.workspaceProject.Id),
                p => Assert.Equal(ProjectNumberTwo.Id, p.workspaceProject.Id));
        }
        public async Task Queue_ProcessesNotifications_AndGoesBackToSleep()
        {
            // Arrange
            var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace);

            projectManager.ProjectAdded(HostProject1);
            projectManager.ProjectAdded(HostProject2);
            projectManager.DocumentAdded(HostProject1, Documents[0], null);
            projectManager.DocumentAdded(HostProject1, Documents[1], null);

            var project = projectManager.GetLoadedProject(HostProject1.FilePath);

            var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider)
            {
                Delay = TimeSpan.FromMilliseconds(1),
                BlockBackgroundWorkStart      = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundWorkStarting  = new ManualResetEventSlim(initialState: false),
                BlockBackgroundWorkCompleting = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false),
            };

            queue.Initialize(projectManager);

            // Act & Assert
            queue.Enqueue(project, project.GetDocument(Documents[0].FilePath));

            Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue");
            Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue");

            // Allow the background work to proceed.
            queue.BlockBackgroundWorkStart.Set();
            queue.BlockBackgroundWorkCompleting.Set();

            await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));

            Assert.False(queue.IsScheduledOrRunning, "Queue should not have restarted");
            Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications");
        }
        public async Task ProcessDocument_LongDocumentParse_DoesNotUpdateAfterSuppress()
        {
            // Arrange
            var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace);

            projectManager.ProjectAdded(HostProject1);

            // We utilize a task completion source here so we can "fake" a document parse taking a significant amount of time
            var tcs        = new TaskCompletionSource <TextAndVersion>();
            var textLoader = new Mock <TextLoader>(MockBehavior.Strict);

            textLoader.Setup(loader => loader.LoadTextAndVersionAsync(It.IsAny <Workspace>(), It.IsAny <DocumentId>(), It.IsAny <CancellationToken>()))
            .Returns(tcs.Task);
            var hostDocument = Documents[0];

            var project = projectManager.GetLoadedProject(HostProject1.FilePath);
            var queue   = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider)
            {
                Delay = TimeSpan.FromMilliseconds(1),
                NotifyBackgroundWorkCompleted    = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundCapturedWorkload = new ManualResetEventSlim(initialState: false),
            };

            queue.Initialize(projectManager);

            // We trigger enqueued notifications via adding/opening to the project manager
            projectManager.AllowNotifyListeners = true;

            // Act & Assert
            projectManager.DocumentAdded(HostProject1, hostDocument, textLoader.Object);

            queue.NotifyBackgroundCapturedWorkload.Wait();

            projectManager.DocumentOpened(HostProject1.FilePath, hostDocument.FilePath, SourceText.From(string.Empty));

            // Verify document was suppressed because it was opened
            Assert.Null(DynamicFileInfoProvider.DynamicDocuments[hostDocument.FilePath]);

            // Unblock document processing
            tcs.SetResult(TextAndVersion.Create(SourceText.From(string.Empty), VersionStamp.Default));

            await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));

            // Validate that even though document parsing took a significant amount of time that the dynamic document wasn't "unsuppressed"
            Assert.Null(DynamicFileInfoProvider.DynamicDocuments[hostDocument.FilePath]);
        }
Exemple #17
0
        public void WorkspaceChanged_ProjectAddedEvent_AddsProject()
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector       = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator);
            var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace);

            projectManager.ProjectAdded(HostProjectThree);

            var solution = SolutionWithOneProject;
            var e        = new WorkspaceChangeEventArgs(WorkspaceChangeKind.ProjectAdded, oldSolution: EmptySolution, newSolution: solution, projectId: ProjectNumberThree.Id);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);

            // Assert
            Assert.Collection(
                workspaceStateGenerator.UpdateQueue,
                p => Assert.Equal(ProjectNumberThree.Id, p.workspaceProject.Id));
        }
Exemple #18
0
        public async Task WorkspaceChanged_DocumentChanged_BackgroundVirtualCS_UpdatesProjectState_AfterDelay()
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator)
            {
                EnqueueDelay = 1,
                BlockDelayedUpdateWorkEnqueue = new ManualResetEventSlim(initialState: false),
            };

            Workspace.TryApplyChanges(SolutionWithTwoProjects);
            var projectManager = new TestProjectSnapshotManager(new[] { detector }, Workspace);

            projectManager.ProjectAdded(HostProjectOne);
            workspaceStateGenerator.ClearQueue();

            var solution = SolutionWithTwoProjects.WithDocumentText(BackgroundVirtualCSharpDocumentId, SourceText.From("public class Foo{}"));
            var e        = new WorkspaceChangeEventArgs(WorkspaceChangeKind.DocumentChanged, oldSolution: SolutionWithTwoProjects, newSolution: solution, projectId: ProjectNumberOne.Id, BackgroundVirtualCSharpDocumentId);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);

            // Assert
            //
            // The change hasn't come through yet.
            Assert.Empty(workspaceStateGenerator.UpdateQueue);

            detector.BlockDelayedUpdateWorkEnqueue.Set();

            await detector._deferredUpdates.Single().Value;

            var update = Assert.Single(workspaceStateGenerator.UpdateQueue);

            Assert.Equal(update.workspaceProject.Id, ProjectNumberOne.Id);
            Assert.Equal(update.projectSnapshot.FilePath, HostProjectOne.FilePath);
        }
Exemple #19
0
        public async Task WorkspaceChanged_ProjectAddedEvent_AddsProject()
        {
            // Arrange
            var workspaceStateGenerator = new TestProjectWorkspaceStateGenerator();
            var detector = new WorkspaceProjectStateChangeDetector(workspaceStateGenerator, Dispatcher, WorkQueue)
            {
                NotifyWorkspaceChangedEventComplete = new ManualResetEventSlim(initialState: false),
            };
            var projectManager = new TestProjectSnapshotManager(Dispatcher, new[] { detector }, Workspace);
            await Dispatcher.RunOnDispatcherThreadAsync(() => projectManager.ProjectAdded(HostProjectThree), CancellationToken.None).ConfigureAwait(false);

            var solution = SolutionWithOneProject;
            var e        = new WorkspaceChangeEventArgs(WorkspaceChangeKind.ProjectAdded, oldSolution: EmptySolution, newSolution: solution, projectId: ProjectNumberThree.Id);

            // Act
            detector.Workspace_WorkspaceChanged(Workspace, e);
            detector.NotifyWorkspaceChangedEventComplete.Wait();
            WorkQueueTestAccessor.NotifyBackgroundWorkCompleted.Wait();

            // Assert
            Assert.Collection(
                workspaceStateGenerator.UpdateQueue,
                p => Assert.Equal(ProjectNumberThree.Id, p.WorkspaceProject.Id));
        }
        public async Task Queue_ProcessesNotifications_AndRestarts()
        {
            // Arrange
            var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace);

            projectManager.ProjectAdded(HostProject1);
            projectManager.ProjectAdded(HostProject2);
            projectManager.DocumentAdded(HostProject1, Documents[0], null);
            projectManager.DocumentAdded(HostProject1, Documents[1], null);

            var project = projectManager.GetLoadedProject(HostProject1.FilePath);

            var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider, DivergenceChecker)
            {
                Delay = TimeSpan.FromMilliseconds(1),
                BlockBackgroundWorkStart         = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundWorkStarting     = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundCapturedWorkload = new ManualResetEventSlim(initialState: false),
                BlockBackgroundWorkCompleting    = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundWorkCompleted    = new ManualResetEventSlim(initialState: false),
            };

            queue.Initialize(projectManager);

            // Act & Assert
            queue.Enqueue(project, project.GetDocument(Documents[0].FilePath));

            Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue");
            Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue");

            // Allow the background work to start.
            queue.BlockBackgroundWorkStart.Set();

            await Task.Run(() => queue.NotifyBackgroundWorkStarting.Wait(TimeSpan.FromSeconds(1)));

            Assert.True(queue.IsScheduledOrRunning, "Worker should be processing now");

            await Task.Run(() => queue.NotifyBackgroundCapturedWorkload.Wait(TimeSpan.FromSeconds(1)));

            Assert.False(queue.HasPendingNotifications, "Worker should have taken all notifications");

            queue.Enqueue(project, project.GetDocument(Documents[1].FilePath));
            Assert.True(queue.HasPendingNotifications); // Now we should see the worker restart when it finishes.

            // Allow work to complete, which should restart the timer.
            queue.BlockBackgroundWorkCompleting.Set();

            await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));

            queue.NotifyBackgroundWorkCompleted.Reset();

            // It should start running again right away.
            Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue");
            Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue");

            // Allow the background work to proceed.
            queue.BlockBackgroundWorkStart.Set();

            queue.BlockBackgroundWorkCompleting.Set();
            await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));

            Assert.False(queue.IsScheduledOrRunning, "Queue should not have restarted");
            Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications");
        }
        public async Task DocumentChanged_ReparsesRelatedFiles()
        {
            // Arrange
            var projectManager = new TestProjectSnapshotManager(Dispatcher, Workspace)
            {
                AllowNotifyListeners = true,
            };
            var documents = new[]
            {
                TestProjectData.SomeProjectComponentFile1,
                TestProjectData.SomeProjectImportFile
            };

            projectManager.ProjectAdded(HostProject1);
            for (var i = 0; i < documents.Length; i++)
            {
                projectManager.DocumentAdded(HostProject1, documents[i], null);
            }

            var queue = new BackgroundDocumentGenerator(Dispatcher, DynamicFileInfoProvider)
            {
                Delay = TimeSpan.FromMilliseconds(1),
                BlockBackgroundWorkStart         = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundWorkStarting     = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundCapturedWorkload = new ManualResetEventSlim(initialState: false),
                BlockBackgroundWorkCompleting    = new ManualResetEventSlim(initialState: false),
                NotifyBackgroundWorkCompleted    = new ManualResetEventSlim(initialState: false),
            };

            var changedSourceText = SourceText.From("@inject DateTime Time");

            queue.Initialize(projectManager);

            // Act & Assert
            projectManager.DocumentChanged(HostProject1.FilePath, TestProjectData.SomeProjectImportFile.FilePath, changedSourceText);

            Assert.True(queue.IsScheduledOrRunning, "Queue should be scheduled during Enqueue");
            Assert.True(queue.HasPendingNotifications, "Queue should have a notification created during Enqueue");

            for (var i = 0; i < documents.Length; i++)
            {
                var key = new DocumentKey(HostProject1.FilePath, documents[i].FilePath);
                Assert.True(queue.Work.ContainsKey(key));
            }

            // Allow the background work to start.
            queue.BlockBackgroundWorkStart.Set();

            await Task.Run(() => queue.NotifyBackgroundWorkStarting.Wait(TimeSpan.FromSeconds(1)));

            Assert.True(queue.IsScheduledOrRunning, "Worker should be processing now");

            await Task.Run(() => queue.NotifyBackgroundCapturedWorkload.Wait(TimeSpan.FromSeconds(1)));

            Assert.False(queue.HasPendingNotifications, "Worker should have taken all notifications");

            // Allow work to complete
            queue.BlockBackgroundWorkCompleting.Set();

            await Task.Run(() => queue.NotifyBackgroundWorkCompleted.Wait(TimeSpan.FromSeconds(3)));

            Assert.False(queue.HasPendingNotifications, "Queue should have processed all notifications");
            Assert.False(queue.IsScheduledOrRunning, "Queue should not have restarted");
        }