public void TryDeserialize_MemoizesResults()
        {
            // Arrange
            var jsonFileDeserializer = new Mock <JsonFileDeserializer>(MockBehavior.Strict);
            var projectRazorJson     = new ProjectRazorJson(
                "/path/to/obj/project.razor.json",
                "c:/path/to/project.csproj",
                configuration: null,
                rootNamespace: null,
                projectWorkspaceState: null,
                documents: Array.Empty <DocumentSnapshotHandle>());

            jsonFileDeserializer.Setup(deserializer => deserializer.Deserialize <ProjectRazorJson>(It.IsAny <string>()))
            .Returns(projectRazorJson);
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/obj/project.razor.json", RazorFileChangeKind.Added, jsonFileDeserializer.Object);

            // Act
            var result1 = args.TryDeserialize(out var projectRazorJson1);
            var result2 = args.TryDeserialize(out var projectRazorJson2);

            // Assert
            Assert.True(result1);
            Assert.True(result2);
            Assert.Same(projectRazorJson, projectRazorJson1);
            Assert.Same(projectRazorJson, projectRazorJson2);
        }
        public void ProjectConfigurationFileChanged_Added_AddAndUpdatesProject()
        {
            // Arrange
            var handle = new FullProjectSnapshotHandle(
                "path/to/project.csproj",
                RazorConfiguration.Default,
                rootNamespace: "TestRootNamespace",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp5),
                Array.Empty <DocumentSnapshotHandle>());
            var projectService = new Mock <RazorProjectService>(MockBehavior.Strict);

            projectService.Setup(service => service.AddProject(handle.FilePath)).Verifiable();
            projectService.Setup(service => service.UpdateProject(
                                     handle.FilePath,
                                     handle.Configuration,
                                     handle.RootNamespace,
                                     handle.ProjectWorkspaceState,
                                     handle.Documents)).Verifiable();
            var synchronizer         = GetSynchronizer(projectService.Object);
            var jsonFileDeserializer = CreateJsonFileDeserializer(handle);
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Added, jsonFileDeserializer);

            // Act
            synchronizer.ProjectConfigurationFileChanged(args);
            WaitForEnqueueAsync(synchronizer).Wait();

            // Assert
            projectService.VerifyAll();
        }
Ejemplo n.º 3
0
        public async Task ProjectConfigurationFileChanged_Added_AddAndUpdatesProject()
        {
            // Arrange
            var projectRazorJson = new ProjectRazorJson(
                "/path/to/obj/project.razor.json",
                "path/to/project.csproj",
                RazorConfiguration.Default,
                rootNamespace: "TestRootNamespace",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp5),
                Array.Empty <DocumentSnapshotHandle>());
            var projectService = new Mock <RazorProjectService>(MockBehavior.Strict);

            projectService.Setup(service => service.AddProject(projectRazorJson.FilePath)).Verifiable();
            projectService.Setup(service => service.UpdateProject(
                                     projectRazorJson.FilePath,
                                     projectRazorJson.Configuration,
                                     projectRazorJson.RootNamespace,
                                     projectRazorJson.ProjectWorkspaceState,
                                     projectRazorJson.Documents)).Verifiable();
            var synchronizer         = GetSynchronizer(projectService.Object);
            var jsonFileDeserializer = CreateJsonFileDeserializer(projectRazorJson);
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/obj/project.razor.json", RazorFileChangeKind.Added, jsonFileDeserializer);

            // Act
            var enqueueTask = await Dispatcher.RunOnDispatcherThreadAsync(async() =>
            {
                synchronizer.ProjectConfigurationFileChanged(args);
                await WaitForEnqueue_DispatcherThreadAsync(synchronizer);
            }, CancellationToken.None);

            await enqueueTask;

            // Assert
            projectService.VerifyAll();
        }
Ejemplo n.º 4
0
        private void FileSystemWatcher_ProjectConfigurationFileEvent(string physicalFilePath, RazorFileChangeKind kind)
        {
            var args = new ProjectConfigurationFileChangeEventArgs(physicalFilePath, kind);

            foreach (var listener in _listeners)
            {
                listener.ProjectConfigurationFileChanged(args);
            }
        }
Ejemplo n.º 5
0
        public void ProjectConfigurationFileChanged_Changed_UpdatesProject()
        {
            // Arrange
            var initialHandle = new FullProjectSnapshotHandle(
                "path/to/project.csproj",
                RazorConfiguration.Default,
                rootNamespace: "TestRootNamespace",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp5),
                Array.Empty <DocumentSnapshotHandle>());
            var projectService = new Mock <RazorProjectService>(MockBehavior.Strict);

            projectService.Setup(service => service.AddProject(initialHandle.FilePath)).Verifiable();
            projectService.Setup(service => service.UpdateProject(
                                     initialHandle.FilePath,
                                     initialHandle.Configuration,
                                     initialHandle.RootNamespace,
                                     initialHandle.ProjectWorkspaceState,
                                     initialHandle.Documents)).Verifiable();
            var changedHandle = new FullProjectSnapshotHandle(
                "path/to/project.csproj",
                RazorConfiguration.Create(
                    RazorLanguageVersion.Experimental,
                    "TestConfiguration",
                    Array.Empty <RazorExtension>()),
                rootNamespace: "TestRootNamespace2",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp6),
                Array.Empty <DocumentSnapshotHandle>());

            projectService.Setup(service => service.UpdateProject(
                                     changedHandle.FilePath,
                                     changedHandle.Configuration,
                                     changedHandle.RootNamespace,
                                     changedHandle.ProjectWorkspaceState,
                                     changedHandle.Documents)).Verifiable();
            var synchronizer    = GetSynchronizer(projectService.Object);
            var addDeserializer = CreateJsonFileDeserializer(initialHandle);
            var addArgs         = new ProjectConfigurationFileChangeEventArgs("path/to/project.razor.json", RazorFileChangeKind.Added, addDeserializer);

            synchronizer.ProjectConfigurationFileChanged(addArgs);

            WaitForEnqueue(synchronizer).Wait();

            var changedDeserializer = CreateJsonFileDeserializer(changedHandle);
            var changedArgs         = new ProjectConfigurationFileChangeEventArgs("path/to/project.razor.json", RazorFileChangeKind.Changed, changedDeserializer);

            // Act
            synchronizer.ProjectConfigurationFileChanged(changedArgs);
            WaitForEnqueue(synchronizer).Wait();

            // Assert
            projectService.VerifyAll();
        }
        public void ProjectConfigurationFileChanged_Added_CantDeserialize_Noops()
        {
            // Arrange
            var projectService       = new Mock <RazorProjectService>(MockBehavior.Strict);
            var synchronizer         = new ProjectConfigurationStateSynchronizer(Dispatcher, projectService.Object, FilePathNormalizer);
            var jsonFileDeserializer = Mock.Of <JsonFileDeserializer>();
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Added, jsonFileDeserializer);

            // Act
            synchronizer.ProjectConfigurationFileChanged(args);

            // Assert
            projectService.VerifyAll();
        }
        public void ProjectConfigurationFileChanged_Added_CantDeserialize_Noops()
        {
            // Arrange
            var projectService       = new Mock <RazorProjectService>(MockBehavior.Strict);
            var synchronizer         = GetSynchronizer(projectService.Object);
            var jsonFileDeserializer = Mock.Of <JsonFileDeserializer>(d => d.Deserialize <FullProjectSnapshotHandle>(It.IsAny <string>()) == null, MockBehavior.Strict);
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Added, jsonFileDeserializer);

            // Act
            synchronizer.ProjectConfigurationFileChanged(args);

            // Assert
            projectService.VerifyAll();
        }
        public void ProjectConfigurationFileChanged_Removed_UnknownDocumentNoops()
        {
            // Arrange
            var projectService       = new Mock <RazorProjectService>(MockBehavior.Strict);
            var synchronizer         = GetSynchronizer(projectService.Object);
            var jsonFileDeserializer = Mock.Of <JsonFileDeserializer>(MockBehavior.Strict);
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Removed, jsonFileDeserializer);

            // Act
            synchronizer.ProjectConfigurationFileChanged(args);

            // Assert
            projectService.VerifyAll();
        }
        public void ProjectConfigurationFileChanged_Changed_CantDeserialize_ResetsProject()
        {
            // Arrange
            var initialHandle = new FullProjectSnapshotHandle(
                "path/to/project.csproj",
                RazorConfiguration.Default,
                rootNamespace: "TestRootNamespace",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp5),
                Array.Empty <DocumentSnapshotHandle>());
            var projectService = new Mock <RazorProjectService>(MockBehavior.Strict);

            projectService.Setup(service => service.AddProject(initialHandle.FilePath)).Verifiable();
            projectService.Setup(service => service.UpdateProject(
                                     initialHandle.FilePath,
                                     initialHandle.Configuration,
                                     initialHandle.RootNamespace,
                                     initialHandle.ProjectWorkspaceState,
                                     initialHandle.Documents)).Verifiable();
            var changedHandle = new FullProjectSnapshotHandle(
                "path/to/project.csproj",
                RazorConfiguration.Create(
                    RazorLanguageVersion.Experimental,
                    "TestConfiguration",
                    Array.Empty <RazorExtension>()),
                rootNamespace: "TestRootNamespace2",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp6),
                Array.Empty <DocumentSnapshotHandle>());

            // This is the request that happens when the server is reset
            projectService.Setup(service => service.UpdateProject(
                                     initialHandle.FilePath,
                                     null,
                                     null,
                                     ProjectWorkspaceState.Default,
                                     Array.Empty <DocumentSnapshotHandle>())).Verifiable();
            var synchronizer    = new ProjectConfigurationStateSynchronizer(Dispatcher, projectService.Object, FilePathNormalizer);
            var addDeserializer = CreateJsonFileDeserializer(initialHandle);
            var addArgs         = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Added, addDeserializer);

            synchronizer.ProjectConfigurationFileChanged(addArgs);
            var changedDeserializer = Mock.Of <JsonFileDeserializer>();
            var changedArgs         = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Changed, changedDeserializer);

            // Act
            synchronizer.ProjectConfigurationFileChanged(changedArgs);

            // Assert
            projectService.VerifyAll();
        }
Ejemplo n.º 10
0
        public async Task ProjectConfigurationFileChanged_Removed_UnknownDocumentNoops()
        {
            // Arrange
            var projectService       = new Mock <RazorProjectService>(MockBehavior.Strict);
            var synchronizer         = GetSynchronizer(projectService.Object);
            var jsonFileDeserializer = Mock.Of <JsonFileDeserializer>(MockBehavior.Strict);
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Removed, jsonFileDeserializer);

            // Act
            await Dispatcher.RunOnDispatcherThreadAsync(
                () => synchronizer.ProjectConfigurationFileChanged(args), CancellationToken.None);

            // Assert
            projectService.VerifyAll();
        }
        public void ProjectConfigurationFileChanged_Changed_UntrackedProject_Noops()
        {
            // Arrange
            var projectService      = new Mock <RazorProjectService>(MockBehavior.Strict);
            var synchronizer        = GetSynchronizer(projectService.Object);
            var changedDeserializer = Mock.Of <JsonFileDeserializer>(d => d.Deserialize <FullProjectSnapshotHandle>(It.IsAny <string>()) == null, MockBehavior.Strict);
            var changedArgs         = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Changed, changedDeserializer);

            // Act
            synchronizer.ProjectConfigurationFileChanged(changedArgs);
            WaitForEnqueueAsync(synchronizer, hasTask: false).Wait();

            // Assert
            projectService.VerifyAll();
        }
Ejemplo n.º 12
0
        public async Task ProjectConfigurationFileChanged_Added_CantDeserialize_Noops()
        {
            // Arrange
            var projectService       = new Mock <RazorProjectService>(MockBehavior.Strict);
            var synchronizer         = GetSynchronizer(projectService.Object);
            var jsonFileDeserializer = Mock.Of <JsonFileDeserializer>(d => d.Deserialize <ProjectRazorJson>(It.IsAny <string>()) == null, MockBehavior.Strict);
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Added, jsonFileDeserializer);

            // Act
            await Dispatcher.RunOnDispatcherThreadAsync(
                () => synchronizer.ProjectConfigurationFileChanged(args), CancellationToken.None);

            // Assert
            projectService.VerifyAll();
        }
Ejemplo n.º 13
0
        public async Task ProjectConfigurationFileChanged_RemoveThenAdd_OnlyAdds()
        {
            // Arrange
            var projectRazorJson = new ProjectRazorJson(
                "/path/to/obj/project.razor.json",
                "path/to/project.csproj",
                RazorConfiguration.Default,
                rootNamespace: "TestRootNamespace",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp5),
                Array.Empty <DocumentSnapshotHandle>());

            var filePath       = "path/to/project.csproj";
            var projectService = new Mock <RazorProjectService>(MockBehavior.Strict);

            projectService.Setup(service => service.AddProject(projectRazorJson.FilePath)).Verifiable();
            projectService.Setup(p => p.UpdateProject(
                                     filePath,
                                     It.IsAny <RazorConfiguration>(),
                                     It.IsAny <string>(),
                                     It.IsAny <ProjectWorkspaceState>(),
                                     It.IsAny <IReadOnlyList <DocumentSnapshotHandle> >()));

            var synchronizer        = GetSynchronizer(projectService.Object);
            var changedDeserializer = CreateJsonFileDeserializer(projectRazorJson);
            var removedArgs         = new ProjectConfigurationFileChangeEventArgs(projectRazorJson.SerializedFilePath, RazorFileChangeKind.Removed, changedDeserializer);
            var addedArgs           = new ProjectConfigurationFileChangeEventArgs(projectRazorJson.SerializedFilePath, RazorFileChangeKind.Added, changedDeserializer);
            var changedArgs         = new ProjectConfigurationFileChangeEventArgs(projectRazorJson.SerializedFilePath, RazorFileChangeKind.Changed, changedDeserializer);

            // Act
            var enqueueTask = await Dispatcher.RunOnDispatcherThreadAsync(async() =>
            {
                synchronizer.ProjectConfigurationFileChanged(addedArgs);
                synchronizer.ProjectConfigurationFileChanged(changedArgs);
                await WaitForEnqueue_DispatcherThreadAsync(synchronizer);
            }, CancellationToken.None);

            await enqueueTask;

            // Assert
            projectService.Verify(p => p.UpdateProject(
                                      filePath,
                                      It.IsAny <RazorConfiguration>(),
                                      It.IsAny <string>(),
                                      It.IsAny <ProjectWorkspaceState>(),
                                      It.IsAny <IReadOnlyList <DocumentSnapshotHandle> >()), Times.Once);

            projectService.VerifyAll();
        }
Ejemplo n.º 14
0
        public void TryDeserialize_RemovedKind_ReturnsFalse()
        {
            // Arrange
            var jsonFileDeserializer = new Mock <JsonFileDeserializer>(MockBehavior.Strict);

            jsonFileDeserializer.Setup(deserializer => deserializer.Deserialize <FullProjectSnapshotHandle>(It.IsAny <string>()))
            .Returns(new FullProjectSnapshotHandle("c:/path/to/project.csproj", configuration: null, rootNamespace: null, projectWorkspaceState: null, documents: Array.Empty <DocumentSnapshotHandle>()));
            var args = new ProjectConfigurationFileChangeEventArgs("c:/some/path", RazorFileChangeKind.Removed, jsonFileDeserializer.Object);

            // Act
            var result = args.TryDeserialize(out var handle);

            // Assert
            Assert.False(result);
            Assert.Null(handle);
        }
        public void ProjectConfigurationFileChanged_RemoveThenAdd_OnlyAdds()
        {
            // Arrange
            var handle = new FullProjectSnapshotHandle(
                "path/to/project.csproj",
                RazorConfiguration.Default,
                rootNamespace: "TestRootNamespace",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp5),
                Array.Empty <DocumentSnapshotHandle>());

            var filePath       = "path/to/project.csproj";
            var projectService = new Mock <RazorProjectService>(MockBehavior.Strict);

            projectService.Setup(service => service.AddProject(handle.FilePath)).Verifiable();
            projectService.Setup(p => p.UpdateProject(
                                     filePath,
                                     It.IsAny <RazorConfiguration>(),
                                     It.IsAny <string>(),
                                     It.IsAny <ProjectWorkspaceState>(),
                                     It.IsAny <IReadOnlyList <DocumentSnapshotHandle> >()));

            var synchronizer        = GetSynchronizer(projectService.Object);
            var changedDeserializer = CreateJsonFileDeserializer(handle);
            var removedArgs         = new ProjectConfigurationFileChangeEventArgs(filePath, RazorFileChangeKind.Removed, changedDeserializer);
            var addedArgs           = new ProjectConfigurationFileChangeEventArgs(filePath, RazorFileChangeKind.Added, changedDeserializer);
            var changedArgs         = new ProjectConfigurationFileChangeEventArgs(filePath, RazorFileChangeKind.Changed, changedDeserializer);

            // Act
            synchronizer.ProjectConfigurationFileChanged(addedArgs);
            synchronizer.ProjectConfigurationFileChanged(changedArgs);
            WaitForEnqueueAsync(synchronizer).Wait();

            // Assert
            projectService.Verify(p => p.UpdateProject(
                                      filePath,
                                      It.IsAny <RazorConfiguration>(),
                                      It.IsAny <string>(),
                                      It.IsAny <ProjectWorkspaceState>(),
                                      It.IsAny <IReadOnlyList <DocumentSnapshotHandle> >()), Times.Once);

            projectService.VerifyAll();
        }
Ejemplo n.º 16
0
        public async Task ProjectConfigurationFileChanged_Changed_UntrackedProject_Noops()
        {
            // Arrange
            var projectService      = new Mock <RazorProjectService>(MockBehavior.Strict);
            var synchronizer        = GetSynchronizer(projectService.Object);
            var changedDeserializer = Mock.Of <JsonFileDeserializer>(d => d.Deserialize <ProjectRazorJson>(It.IsAny <string>()) == null, MockBehavior.Strict);
            var changedArgs         = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Changed, changedDeserializer);

            // Act
            var enqueueTask = await Dispatcher.RunOnDispatcherThreadAsync(async() =>
            {
                synchronizer.ProjectConfigurationFileChanged(changedArgs);
                await WaitForEnqueue_DispatcherThreadAsync(synchronizer, hasTask: false);
            }, CancellationToken.None);

            await enqueueTask;

            // Assert
            projectService.VerifyAll();
        }
        public void TryDeserialize_NullFileDeserialization_MemoizesResults_ReturnsFalse()
        {
            // Arrange
            var jsonFileDeserializer = new Mock <JsonFileDeserializer>(MockBehavior.Strict);
            var callCount            = 0;

            jsonFileDeserializer.Setup(deserializer => deserializer.Deserialize <ProjectRazorJson>(It.IsAny <string>()))
            .Callback(() => callCount++)
            .Returns <ProjectRazorJson>(null);
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/obj/project.razor.json", RazorFileChangeKind.Changed, jsonFileDeserializer.Object);

            // Act
            var result1 = args.TryDeserialize(out var handle1);
            var result2 = args.TryDeserialize(out var handle2);

            // Assert
            Assert.False(result1);
            Assert.False(result2);
            Assert.Null(handle1);
            Assert.Null(handle2);
            Assert.Equal(1, callCount);
        }
        public void TryDeserialize_DifferingSerializationPaths_ReturnsFalse()
        {
            // Arrange
            var jsonFileDeserializer = new Mock <JsonFileDeserializer>(MockBehavior.Strict);
            var projectRazorJson     = new ProjectRazorJson(
                "/path/to/ORIGINAL/obj/project.razor.json",
                "c:/path/to/project.csproj",
                configuration: null,
                rootNamespace: null,
                projectWorkspaceState: null,
                documents: Array.Empty <DocumentSnapshotHandle>());

            jsonFileDeserializer.Setup(deserializer => deserializer.Deserialize <ProjectRazorJson>(It.IsAny <string>()))
            .Returns(projectRazorJson);
            var args = new ProjectConfigurationFileChangeEventArgs("/path/to/DIFFERENT/obj/project.razor.json", RazorFileChangeKind.Added, jsonFileDeserializer.Object);

            // Act
            var result = args.TryDeserialize(out var deserializedProjectRazorJson);

            // Assert
            Assert.False(result);
            Assert.Null(deserializedProjectRazorJson);
        }
        public void ProjectConfigurationFileChanged_Removed_NonNormalizedPaths()
        {
            // Arrange
            var handle = new FullProjectSnapshotHandle(
                "path/to/project.csproj",
                RazorConfiguration.Default,
                rootNamespace: "TestRootNamespace",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp5),
                Array.Empty <DocumentSnapshotHandle>());
            var projectService = new Mock <RazorProjectService>(MockBehavior.Strict);

            projectService.Setup(service => service.AddProject(handle.FilePath)).Verifiable();
            projectService.Setup(service => service.UpdateProject(
                                     handle.FilePath,
                                     handle.Configuration,
                                     handle.RootNamespace,
                                     handle.ProjectWorkspaceState,
                                     handle.Documents)).Verifiable();
            projectService.Setup(service => service.UpdateProject(
                                     handle.FilePath,
                                     null,
                                     null,
                                     ProjectWorkspaceState.Default,
                                     Array.Empty <DocumentSnapshotHandle>())).Verifiable();
            var synchronizer         = new ProjectConfigurationStateSynchronizer(Dispatcher, projectService.Object, FilePathNormalizer);
            var jsonFileDeserializer = CreateJsonFileDeserializer(handle);
            var addArgs = new ProjectConfigurationFileChangeEventArgs("/path/to\\project.razor.json", RazorFileChangeKind.Added, jsonFileDeserializer);

            synchronizer.ProjectConfigurationFileChanged(addArgs);
            var removeArgs = new ProjectConfigurationFileChangeEventArgs("/path/to/project.razor.json", RazorFileChangeKind.Removed, Mock.Of <JsonFileDeserializer>());

            // Act
            synchronizer.ProjectConfigurationFileChanged(removeArgs);

            // Assert
            projectService.VerifyAll();
        }
Ejemplo n.º 20
0
        public void ProjectConfigurationFileChanged(ProjectConfigurationFileChangeEventArgs args)
        {
            if (args is null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            _projectSnapshotManagerDispatcher.AssertDispatcherThread();

            switch (args.Kind)
            {
            case RazorFileChangeKind.Changed:
            {
                var configurationFilePath = _filePathNormalizer.Normalize(args.ConfigurationFilePath);
                if (!args.TryDeserialize(out var projectRazorJson))
                {
                    if (!_configurationToProjectMap.TryGetValue(configurationFilePath, out var associatedProjectFilePath))
                    {
                        // Could not resolve an associated project file, noop.
                        _logger.LogWarning("Failed to deserialize configuration file after change for an unknown project. Configuration file path: '{0}'", configurationFilePath);
                        return;
                    }
                    else
                    {
                        _logger.LogWarning("Failed to deserialize configuration file after change for project '{0}': '{1}'", associatedProjectFilePath, configurationFilePath);
                    }

                    // We found the last associated project file for the configuration file. Reset the project since we can't
                    // accurately determine its configurations.

                    EnqueueUpdateProject(associatedProjectFilePath, projectRazorJson: null);
                    return;
                }

                var projectFilePath = _filePathNormalizer.Normalize(projectRazorJson.FilePath);
                _logger.LogInformation("Project configuration file changed for project '{0}': '{1}'", projectFilePath, configurationFilePath);

                EnqueueUpdateProject(projectFilePath, projectRazorJson);
                break;
            }

            case RazorFileChangeKind.Added:
            {
                var configurationFilePath = _filePathNormalizer.Normalize(args.ConfigurationFilePath);
                if (!args.TryDeserialize(out var projectRazorJson))
                {
                    // Given that this is the first time we're seeing this configuration file if we can't deserialize it
                    // then we have to noop.
                    _logger.LogWarning("Failed to deserialize configuration file on configuration added event. Configuration file path: '{0}'", configurationFilePath);
                    return;
                }

                var projectFilePath = _filePathNormalizer.Normalize(projectRazorJson.FilePath);
                _configurationToProjectMap[configurationFilePath] = projectFilePath;
                _projectService.AddProject(projectFilePath);

                _logger.LogInformation("Project configuration file added for project '{0}': '{1}'", projectFilePath, configurationFilePath);
                EnqueueUpdateProject(projectFilePath, projectRazorJson);
                break;
            }

            case RazorFileChangeKind.Removed:
            {
                var configurationFilePath = _filePathNormalizer.Normalize(args.ConfigurationFilePath);
                if (!_configurationToProjectMap.TryGetValue(configurationFilePath, out var projectFilePath))
                {
                    // Failed to deserialize the initial project configuration file on add so we can't remove the configuration file because it doesn't exist in the list.
                    _logger.LogWarning("Failed to resolve associated project on configuration removed event. Configuration file path: '{0}'", configurationFilePath);
                    return;
                }

                _configurationToProjectMap.Remove(configurationFilePath);

                _logger.LogInformation("Project configuration file removed for project '{0}': '{1}'", projectFilePath, configurationFilePath);

                EnqueueUpdateProject(projectFilePath, projectRazorJson: null);
                break;
            }
            }

            void UpdateProject(string projectFilePath, ProjectRazorJson?projectRazorJson)
            {
                if (projectFilePath is null)
                {
                    throw new ArgumentNullException(nameof(projectFilePath));
                }

                if (projectRazorJson is null)
                {
                    ResetProject(projectFilePath);
                    return;
                }

                var projectWorkspaceState = projectRazorJson.ProjectWorkspaceState ?? ProjectWorkspaceState.Default;
                var documents             = projectRazorJson.Documents ?? Array.Empty <DocumentSnapshotHandle>();

                _projectService.UpdateProject(
                    projectRazorJson.FilePath,
                    projectRazorJson.Configuration,
                    projectRazorJson.RootNamespace,
                    projectWorkspaceState,
                    documents);
            }

            async Task UpdateAfterDelayAsync(string projectFilePath)
            {
                await Task.Delay(EnqueueDelay).ConfigureAwait(true);

                var delayedProjectInfo = ProjectInfoMap[projectFilePath];

                UpdateProject(projectFilePath, delayedProjectInfo.ProjectRazorJson);
            }

            void EnqueueUpdateProject(string projectFilePath, ProjectRazorJson?projectRazorJson)
            {
                projectFilePath = _filePathNormalizer.Normalize(projectFilePath);
                if (!ProjectInfoMap.ContainsKey(projectFilePath))
                {
                    ProjectInfoMap[projectFilePath] = new DelayedProjectInfo();
                }

                var delayedProjectInfo = ProjectInfoMap[projectFilePath];

                delayedProjectInfo.ProjectRazorJson = projectRazorJson;

                if (delayedProjectInfo.ProjectUpdateTask is null || delayedProjectInfo.ProjectUpdateTask.IsCompleted)
                {
                    delayedProjectInfo.ProjectUpdateTask = UpdateAfterDelayAsync(projectFilePath);
                }
            }

            void ResetProject(string projectFilePath)
            {
                _projectService.UpdateProject(
                    projectFilePath,
                    configuration: null,
                    rootNamespace: null,
                    ProjectWorkspaceState.Default,
                    Array.Empty <DocumentSnapshotHandle>());
            }
        }
Ejemplo n.º 21
0
        public async Task ProjectConfigurationFileChanged_Changed_CantDeserialize_ResetsProject()
        {
            // Arrange
            var initialProjectRazorJson = new ProjectRazorJson(
                "/path/to/obj/project.razor.json",
                "path/to/project.csproj",
                RazorConfiguration.Default,
                rootNamespace: "TestRootNamespace",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp5),
                Array.Empty <DocumentSnapshotHandle>());
            var projectService = new Mock <RazorProjectService>(MockBehavior.Strict);

            projectService.Setup(service => service.AddProject(initialProjectRazorJson.FilePath)).Verifiable();
            projectService.Setup(service => service.UpdateProject(
                                     initialProjectRazorJson.FilePath,
                                     initialProjectRazorJson.Configuration,
                                     initialProjectRazorJson.RootNamespace,
                                     initialProjectRazorJson.ProjectWorkspaceState,
                                     initialProjectRazorJson.Documents)).Verifiable();
            var changedProjectRazorJson = new ProjectRazorJson(
                "/path/to/obj/project.razor.json",
                "path/to/project.csproj",
                RazorConfiguration.Create(
                    RazorLanguageVersion.Experimental,
                    "TestConfiguration",
                    Array.Empty <RazorExtension>()),
                rootNamespace: "TestRootNamespace2",
                new ProjectWorkspaceState(Array.Empty <TagHelperDescriptor>(), LanguageVersion.CSharp6),
                Array.Empty <DocumentSnapshotHandle>());

            // This is the request that happens when the server is reset
            projectService.Setup(service => service.UpdateProject(
                                     initialProjectRazorJson.FilePath,
                                     null,
                                     null,
                                     ProjectWorkspaceState.Default,
                                     Array.Empty <DocumentSnapshotHandle>())).Verifiable();
            var synchronizer    = GetSynchronizer(projectService.Object);
            var addDeserializer = CreateJsonFileDeserializer(initialProjectRazorJson);
            var addArgs         = new ProjectConfigurationFileChangeEventArgs("/path/to/obj/project.razor.json", RazorFileChangeKind.Added, addDeserializer);
            var enqueueTask     = await Dispatcher.RunOnDispatcherThreadAsync(async() =>
            {
                synchronizer.ProjectConfigurationFileChanged(addArgs);
                await WaitForEnqueue_DispatcherThreadAsync(synchronizer);
            }, CancellationToken.None);

            await enqueueTask;

            var changedDeserializer = Mock.Of <JsonFileDeserializer>(d => d.Deserialize <ProjectRazorJson>(It.IsAny <string>()) == null, MockBehavior.Strict);
            var changedArgs         = new ProjectConfigurationFileChangeEventArgs("/path/to/obj/project.razor.json", RazorFileChangeKind.Changed, changedDeserializer);

            // Act
            enqueueTask = await Dispatcher.RunOnDispatcherThreadAsync(async() =>
            {
                synchronizer.ProjectConfigurationFileChanged(changedArgs);
                await WaitForEnqueue_DispatcherThreadAsync(synchronizer);
            }, CancellationToken.None);

            await enqueueTask;

            // Assert
            projectService.VerifyAll();
        }
        public void ProjectConfigurationFileChanged(ProjectConfigurationFileChangeEventArgs args)
        {
            if (args is null)
            {
                throw new ArgumentNullException(nameof(args));
            }

            _foregroundDispatcher.AssertForegroundThread();

            switch (args.Kind)
            {
            case RazorFileChangeKind.Changed:
            {
                if (!args.TryDeserialize(out var handle))
                {
                    var configurationFilePath = _filePathNormalizer.Normalize(args.ConfigurationFilePath);
                    if (!_configurationToProjectMap.TryGetValue(configurationFilePath, out var projectFilePath))
                    {
                        // Could not resolve an associated project file, noop.
                        return;
                    }

                    // We found the last associated project file for the configuration file. Reset the project since we can't
                    // accurately determine its configurations.
                    ResetProject(projectFilePath);
                    return;
                }

                UpdateProject(handle);
                break;
            }

            case RazorFileChangeKind.Added:
            {
                if (!args.TryDeserialize(out var handle))
                {
                    // Given that this is the first time we're seeing this configuration file if we can't deserialize it
                    // then we have to noop.
                    return;
                }

                var projectFilePath       = _filePathNormalizer.Normalize(handle.FilePath);
                var configurationFilePath = _filePathNormalizer.Normalize(args.ConfigurationFilePath);
                _configurationToProjectMap[configurationFilePath] = projectFilePath;
                _projectService.AddProject(projectFilePath);
                UpdateProject(handle);
                break;
            }

            case RazorFileChangeKind.Removed:
            {
                var configurationFilePath = _filePathNormalizer.Normalize(args.ConfigurationFilePath);
                if (!_configurationToProjectMap.TryGetValue(configurationFilePath, out var projectFilePath))
                {
                    // Failed to deserialize the initial handle on add so we can't remove the configuration file because it doesn't exist in the list.
                    return;
                }

                _configurationToProjectMap.Remove(configurationFilePath);

                ResetProject(projectFilePath);
                break;
            }
            }

            void UpdateProject(FullProjectSnapshotHandle handle)
            {
                if (handle is null)
                {
                    throw new ArgumentNullException(nameof(handle));
                }

                var projectWorkspaceState = handle.ProjectWorkspaceState ?? ProjectWorkspaceState.Default;
                var documents             = handle.Documents ?? Array.Empty <DocumentSnapshotHandle>();

                _projectService.UpdateProject(
                    handle.FilePath,
                    handle.Configuration,
                    handle.RootNamespace,
                    projectWorkspaceState,
                    documents);
            }

            void ResetProject(string projectFilePath)
            {
                _projectService.UpdateProject(
                    projectFilePath,
                    configuration: null,
                    rootNamespace: null,
                    ProjectWorkspaceState.Default,
                    Array.Empty <DocumentSnapshotHandle>());
            }
        }