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(); }
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(); }
private void FileSystemWatcher_ProjectConfigurationFileEvent(string physicalFilePath, RazorFileChangeKind kind) { var args = new ProjectConfigurationFileChangeEventArgs(physicalFilePath, kind); foreach (var listener in _listeners) { listener.ProjectConfigurationFileChanged(args); } }
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(); }
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(); }
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(); }
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(); }
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(); }
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(); }
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>()); } }
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>()); } }