// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Roslyn.Test.Utilities; using Xunit; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Editor.Host; using System.Collections.Generic; using System; using System.Collections.Immutable; using System.Linq; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Interactive.Commands { public class ResetInteractiveTests { private string WorkspaceXmlStr => @" ResetInteractiveVisualBasicSubproject "; [WpfFact] [Trait(Traits.Feature, Traits.Features.Interactive)] public async void TestResetREPLWithProjectContext() { using (var workspace = await TestWorkspace.CreateAsync(WorkspaceXmlStr)) { var project = workspace.CurrentSolution.Projects.FirstOrDefault(p => p.AssemblyName == "ResetInteractiveTestsAssembly"); var document = project.Documents.FirstOrDefault(d => d.FilePath == "ResetInteractiveTestsDocument"); var replReferenceCommands = GetProjectReferences(workspace, project).Select(r => CreateReplReferenceCommand(r)); Assert.True(replReferenceCommands.Any(rc => rc.EndsWith(@"ResetInteractiveTestsAssembly.dll"""))); Assert.True(replReferenceCommands.Any(rc => rc.EndsWith(@"ResetInteractiveVisualBasicSubproject.dll"""))); var expectedSubmissions = new List(); expectedSubmissions.AddRange(replReferenceCommands.Select(r => r + "\r\n")); expectedSubmissions.Add(string.Join("\r\n", @"using ""ns1"";", @"using ""ns2"";") + "\r\n"); AssertResetInteractive(workspace, project, buildSucceeds: true, expectedSubmissions: expectedSubmissions); // Test that no submissions are executed if the build fails. AssertResetInteractive(workspace, project, buildSucceeds: false, expectedSubmissions: new List()); } } private async void AssertResetInteractive( TestWorkspace workspace, Project project, bool buildSucceeds, List expectedSubmissions) { InteractiveWindowTestHost testHost = new InteractiveWindowTestHost(); List executedSubmissionCalls = new List(); EventHandler ExecuteSubmission = (_, code) => { executedSubmissionCalls.Add(code); }; testHost.Evaluator.OnExecute += ExecuteSubmission; IWaitIndicator waitIndicator = workspace.GetService(); TestResetInteractive resetInteractive = new TestResetInteractive( waitIndicator, CreateReplReferenceCommand, CreateImport, buildSucceeds: buildSucceeds) { References = ImmutableArray.CreateRange(GetProjectReferences(workspace, project)), ReferenceSearchPaths = ImmutableArray.Create("rsp1", "rsp2"), SourceSearchPaths = ImmutableArray.Create("ssp1", "ssp2"), NamespacesToImport = ImmutableArray.Create("ns1", "ns2"), ProjectDirectory = "pj", }; await resetInteractive.Execute(testHost.Window, "Interactive C#"); // Validate that the project was rebuilt. Assert.Equal(1, resetInteractive.BuildProjectCount); Assert.Equal(0, resetInteractive.CancelBuildProjectCount); AssertEx.Equal(expectedSubmissions, executedSubmissionCalls); testHost.Evaluator.OnExecute -= ExecuteSubmission; } /// /// Simulates getting all project references. /// /// Workspace with the solution. /// A project that should be built. /// A list of paths that should be referenced. private IEnumerable GetProjectReferences(TestWorkspace workspace, Project project) { var metadataReferences = project.MetadataReferences.Select(r => r.Display); var projectReferences = project.ProjectReferences.SelectMany(p => GetProjectReferences( workspace, workspace.CurrentSolution.GetProject(p.ProjectId))); var outputReference = new string[] { project.OutputFilePath }; return metadataReferences.Union(projectReferences).Concat(outputReference); } private string CreateReplReferenceCommand(string referenceName) { return $@"#r ""{referenceName}"""; } private string CreateImport(string importName) { return $@"using ""{importName}"";"; } } }