Skip to content

Commit

Permalink
Merge pull request #7714 from ocallesp/fix1420437
Browse files Browse the repository at this point in the history
[Dev17.0] Fix1420437
  • Loading branch information
ocallesp authored Oct 22, 2021
2 parents 25148a7 + c7836b7 commit c9fae6c
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information.

using System.Threading.Tasks;
using Microsoft.VisualStudio.ProjectSystem.Properties;

namespace Microsoft.VisualStudio.ProjectSystem.VS.Debug
{
internal class OutputTypeChecker
{
private readonly ProjectProperties _properties;

public OutputTypeChecker(ProjectProperties properties)
{
_properties = properties;
}

public Task<bool> IsLibraryAsync() => IsOutputTypeAsync(ConfigurationGeneral.OutputTypeValues.Library);

public Task<bool> IsConsoleAsync() => IsOutputTypeAsync(ConfigurationGeneral.OutputTypeValues.Exe);

public async Task<bool> IsOutputTypeAsync(string outputType)
{
IEnumValue? actualOutputType = await GetEvaluatedOutputTypeAsync();

return actualOutputType is not null && StringComparers.PropertyLiteralValues.Equals(actualOutputType.Name, outputType);
}

public virtual async Task<IEnumValue?> GetEvaluatedOutputTypeAsync()
{
// Used by default Windows debugger to figure out whether to add an extra
// pause to end of window when CTRL+F5'ing a console application
ConfigurationGeneral configuration = await _properties.GetConfigurationGeneralPropertiesAsync();

var actualOutputType = (IEnumValue?)await configuration.OutputType.GetValueAsync();

return actualOutputType;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ internal class ProjectLaunchTargetsProvider :
private readonly IFileSystem _fileSystem;
private readonly IEnvironmentHelper _environment;
private readonly IActiveDebugFrameworkServices _activeDebugFramework;
private readonly ProjectProperties _properties;
private readonly IProjectThreadingService _threadingService;
private readonly IVsUIService<IVsDebugger10> _debugger;
private readonly IRemoteDebuggerAuthenticationService _remoteDebuggerAuthenticationService;
private readonly Lazy<IProjectHotReloadSessionManager> _hotReloadSessionManager;
private readonly Lazy<IDebuggerSettings> _debuggerSettings;
private readonly OutputTypeChecker _outputTypeChecker;

[ImportingConstructor]
public ProjectLaunchTargetsProvider(
Expand All @@ -70,12 +70,13 @@ public ProjectLaunchTargetsProvider(
_fileSystem = fileSystem;
_environment = environment;
_activeDebugFramework = activeDebugFramework;
_properties = properties;
_threadingService = threadingService;
_debugger = debugger;
_remoteDebuggerAuthenticationService = remoteDebuggerAuthenticationService;
_hotReloadSessionManager = hotReloadSessionManager;
_debuggerSettings = debuggerSettings;

_outputTypeChecker = new OutputTypeChecker(properties);
}

private Task<ConfiguredProject?> GetConfiguredProjectForDebugAsync() =>
Expand Down Expand Up @@ -115,23 +116,6 @@ public async Task OnAfterLaunchAsync(DebugLaunchOptions launchOptions, ILaunchPr
await _hotReloadSessionManager.Value.ActivateSessionAsync((int)processInfos[0].dwProcessId, runningUnderDebugger);
}

private Task<bool> IsClassLibraryAsync() => IsOutputTypeAsync(ConfigurationGeneral.OutputTypeValues.Library);

private Task<bool> IsConsoleAppAsync() => IsOutputTypeAsync(ConfigurationGeneral.OutputTypeValues.Exe);

private async Task<bool> IsOutputTypeAsync(string outputType)
{
// Used by default Windows debugger to figure out whether to add an extra
// pause to end of window when CTRL+F5'ing a console application
ConfigurationGeneral configuration = await _properties.GetConfigurationGeneralPropertiesAsync();

var actualOutputType = (IEnumValue?)await configuration.OutputType.GetValueAsync();

Assumes.NotNull(actualOutputType);

return StringComparers.PropertyLiteralValues.Equals(actualOutputType.Name, outputType);
}

public async Task<bool> CanBeStartupProjectAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile)
{
if (IsRunProjectCommand(profile))
Expand Down Expand Up @@ -388,7 +372,7 @@ private async Task<bool> IsIntegratedConsoleEnabledAsync()
}

bool useCmdShell = false;
if (await IsConsoleAppAsync())
if (await _outputTypeChecker.IsConsoleAsync())
{
if (await IsIntegratedConsoleEnabledAsync())
{
Expand Down Expand Up @@ -530,7 +514,7 @@ private static bool UseCmdShellForConsoleLaunch(ILaunchProfile profile, DebugLau
if (Strings.IsNullOrEmpty(runCommand))
{
// If we're launching for debug purposes, prevent someone F5'ing a class library
if (validateSettings && await IsClassLibraryAsync())
if (validateSettings && await _outputTypeChecker.IsLibraryAsync())
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE.md file in the project root for more information.

using System.Threading.Tasks;
using Microsoft.Build.Framework.XamlTypes;
using Microsoft.VisualStudio.ProjectSystem.Properties;
using Xunit;

namespace Microsoft.VisualStudio.ProjectSystem.VS.Debug
{
public class OutputTypeCheckerTest
{
private readonly string _ProjectFile = @"c:\test\project\project.csproj";

[Fact]
public async Task OutputTypeChecker_False_IsLibraryAsyncWhenEvaluationFails()
{
OutputTypeChecker outputTypeChecker = CreateFailedOutputTypeChecker();

Assert.False(await outputTypeChecker.IsLibraryAsync());
}

[Fact]
public async Task OutputTypeChecker_True_IsLibraryAsync()
{
OutputTypeChecker outputTypeChecker = CreateOutputTypeChecker(ConfigurationGeneral.OutputTypeValues.Library);

Assert.True(await outputTypeChecker.IsLibraryAsync());
}

[Fact]
public async Task OutputTypeChecker_False_IsLibraryAsync()
{
OutputTypeChecker outputTypeChecker = CreateOutputTypeChecker(ConfigurationGeneral.OutputTypeValues.Exe);

Assert.False(await outputTypeChecker.IsLibraryAsync());
}

[Fact]
public async Task OutputTypeChecker_True_IsConsoleAsync()
{
OutputTypeChecker outputTypeChecker = CreateOutputTypeChecker(ConfigurationGeneral.OutputTypeValues.Exe);

Assert.True(await outputTypeChecker.IsConsoleAsync());
}

[Fact]
public async Task OutputTypeChecker_False_IsConsoleAsync()
{
OutputTypeChecker outputTypeChecker = CreateOutputTypeChecker(ConfigurationGeneral.OutputTypeValues.Library);

Assert.False(await outputTypeChecker.IsConsoleAsync());
}

private OutputTypeChecker CreateFailedOutputTypeChecker()
{
var projectProperties = ProjectPropertiesFactory.CreateEmpty();

return new OutputTypeChecker2(projectProperties);
}

private OutputTypeChecker CreateOutputTypeChecker(string outputType)
{
var project = UnconfiguredProjectFactory.Create(fullPath: _ProjectFile);

var outputTypeEnum = new PageEnumValue(new EnumValue { Name = outputType });
var data = new PropertyPageData(ConfigurationGeneral.SchemaName, ConfigurationGeneral.OutputTypeProperty, outputTypeEnum);
var projectProperties = ProjectPropertiesFactory.Create(project, data);

return new OutputTypeChecker(projectProperties);
}

internal class OutputTypeChecker2 : OutputTypeChecker
{
public OutputTypeChecker2(ProjectProperties properties) : base(properties)
{
}

public override Task<IEnumValue?> GetEvaluatedOutputTypeAsync()
{
// Evaluation fails
return Task.FromResult<IEnumValue?>(null);
}
}
}
}

0 comments on commit c9fae6c

Please sign in to comment.