Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BaseOutputPath to common targets #5238

Merged
merged 7 commits into from
Dec 7, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions src/Tasks.UnitTests/OutputPathTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.IO;

using Microsoft.Build.Evaluation;
using Microsoft.Build.Shared;
using Microsoft.Build.UnitTests;

using Shouldly;

using Xunit;
using Xunit.Abstractions;

namespace Microsoft.Build.Tasks.UnitTests
{
public sealed class OutputPathTests : IDisposable
{
private readonly ITestOutputHelper _output;
private readonly string _projectRelativePath = Path.Combine("src", "test", "test.csproj");

public OutputPathTests(ITestOutputHelper output)
{
_output = output;
ObjectModelHelpers.DeleteTempProjectDirectory();
}

public void Dispose()
{
ObjectModelHelpers.DeleteTempProjectDirectory();
}

/// <summary>
/// Test when both BaseOutputPath and OutputPath are not specified.
/// </summary>
[Fact]
public void BothBaseOutputPathAndOutputPathWereNotSpecified()
{
// Arrange
var baseOutputPath = "bin";

var projectFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(_projectRelativePath,
$@"<Project DefaultTargets=`Build` xmlns=`msbuildnamespace` ToolsVersion=`msbuilddefaulttoolsversion`>

<Import Project=`$(MSBuildToolsPath)\Microsoft.Common.props`/>

<PropertyGroup>
<Platform>AnyCPU</Platform>
<Configuration>Debug</Configuration>
</PropertyGroup>

<Import Project=`$(MSBuildToolsPath)\Microsoft.Common.targets`/>
<Target Name=`Build`/>

</Project>");

// Act
Project project = ObjectModelHelpers.LoadProjectFileInTempProjectDirectory(projectFilePath, touchProject: false);

project.Build(new MockLogger(_output)).ShouldBeFalse();

// Assert
project.GetPropertyValue("BaseOutputPath").ShouldBe(baseOutputPath.WithTrailingSlash());
project.GetPropertyValue("BaseOutputPathWasSpecified").ShouldBe(string.Empty);
project.GetPropertyValue("_OutputPathWasMissing").ShouldBe("true");
}

/// <summary>
/// Test when BaseOutputPath is specified without the OutputPath.
/// </summary>
[Fact]
public void BaseOutputPathWasSpecifiedAndIsOverridable()
{
// Arrange
var baseOutputPath = Path.Combine("build", "bin");

var projectFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(_projectRelativePath,
$@"<Project DefaultTargets=`Build` xmlns=`msbuildnamespace` ToolsVersion=`msbuilddefaulttoolsversion`>

<Import Project=`$(MSBuildToolsPath)\Microsoft.Common.props`/>

<PropertyGroup>
<Platform>AnyCPU</Platform>
<Configuration>Debug</Configuration>
<BaseOutputPath>{baseOutputPath}</BaseOutputPath>
</PropertyGroup>

<Import Project=`$(MSBuildToolsPath)\Microsoft.Common.targets`/>
<Target Name=`Build`/>

</Project>");

// Act
Project project = ObjectModelHelpers.LoadProjectFileInTempProjectDirectory(projectFilePath, touchProject: false);

project.Build(new MockLogger(_output)).ShouldBeTrue();

// Assert
project.GetPropertyValue("BaseOutputPath").ShouldBe(baseOutputPath.WithTrailingSlash());
project.GetPropertyValue("BaseOutputPathWasSpecified").ShouldBe("true");
project.GetPropertyValue("_OutputPathWasMissing").ShouldBe("true");
}

/// <summary>
/// Test when both BaseOutputPath and OutputPath are specified.
/// </summary>
[Fact]
public void BothBaseOutputPathAndOutputPathWereSpecified()
{
// Arrange
var baseOutputPath = Path.Combine("build", "bin");
var outputPath = Path.Combine("bin", "Debug");
var outputPathAlt = Path.Combine("bin", "Release");

var projectFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(_projectRelativePath,
$@"<Project DefaultTargets=`Build` xmlns=`msbuildnamespace` ToolsVersion=`msbuilddefaulttoolsversion`>

<Import Project=`$(MSBuildToolsPath)\Microsoft.Common.props`/>

<PropertyGroup>
<Platform>AnyCPU</Platform>
<Configuration>Debug</Configuration>
</PropertyGroup>

<PropertyGroup>
<BaseOutputPath>{baseOutputPath}</BaseOutputPath>
<OutputPath Condition=`'$(Platform)|$(Configuration)' == 'AnyCPU|Debug'`>{outputPath}</OutputPath>
<OutputPath Condition=`'$(Platform)|$(Configuration)' == 'AnyCPU|Release'`>{outputPathAlt}</OutputPath>
</PropertyGroup>

<Import Project=`$(MSBuildToolsPath)\Microsoft.Common.targets`/>
<Target Name=`Build`/>

</Project>");

// Act
Project project = ObjectModelHelpers.LoadProjectFileInTempProjectDirectory(projectFilePath, touchProject: false);

project.Build(new MockLogger(_output)).ShouldBeTrue();

// Assert
project.GetPropertyValue("BaseOutputPath").ShouldBe(baseOutputPath.WithTrailingSlash());
project.GetPropertyValue("OutputPath").ShouldBe(outputPath.WithTrailingSlash());
project.GetPropertyValue("BaseOutputPathWasSpecified").ShouldBe("true");
project.GetPropertyValue("_OutputPathWasMissing").ShouldBe(string.Empty);
}

/// <summary>
/// Test for [MSBuild]::NormalizePath and [MSBuild]::NormalizeDirectory returning current directory instead of current Project directory.
/// </summary>
[ConditionalFact(typeof(NativeMethodsShared), nameof(NativeMethodsShared.IsWindows), Skip = "Skipping this test for now until we have a consensus about this issue.")]
public void MSBuildNormalizePathShouldReturnProjectDirectory()
{
// Arrange
var configuration = "Debug";
var baseOutputPath = "bin";

var projectFilePath = ObjectModelHelpers.CreateFileInTempProjectDirectory(_projectRelativePath,
$@"<Project DefaultTargets=`Build` xmlns=`msbuildnamespace` ToolsVersion=`msbuilddefaulttoolsversion`>

<Import Project=`$(MSBuildToolsPath)\Microsoft.Common.props`/>

<PropertyGroup Condition=`'$(OutputPath)' == ''`>
<OutputPath>$([MSBuild]::NormalizeDirectory('{baseOutputPath}', '{configuration}'))</OutputPath>
</PropertyGroup>

<Import Project=`$(MSBuildToolsPath)\Microsoft.Common.targets`/>
<Target Name=`Build`/>

</Project>");

// Act
Project project = ObjectModelHelpers.LoadProjectFileInTempProjectDirectory(projectFilePath, touchProject: false);

project.Build(new MockLogger(_output)).ShouldBeTrue();

// Assert
project.GetPropertyValue("Configuration").ShouldBe(configuration);
project.GetPropertyValue("BaseOutputPath").ShouldBe(baseOutputPath.WithTrailingSlash());

var expectedOutputPath = FileUtilities.CombinePaths(project.DirectoryPath, baseOutputPath, configuration).WithTrailingSlash();
project.GetPropertyValue("OutputPath").ShouldBe(expectedOutputPath);
}
}
}
2 changes: 1 addition & 1 deletion src/Tasks/Microsoft.Common.CrossTargeting.targets
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
<PropertyGroup Condition="'$(ImportDirectoryBuildTargets)' == 'true' and '$(DirectoryBuildTargetsPath)' == ''">
<_DirectoryBuildTargetsFile Condition="'$(_DirectoryBuildTargetsFile)' == ''">Directory.Build.targets</_DirectoryBuildTargetsFile>
<_DirectoryBuildTargetsBasePath Condition="'$(_DirectoryBuildTargetsBasePath)' == ''">$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), '$(_DirectoryBuildTargetsFile)'))</_DirectoryBuildTargetsBasePath>
<DirectoryBuildTargetsPath Condition="'$(_DirectoryBuildTargetsBasePath)' != '' and '$(_DirectoryBuildTargetsFile)' != ''">$([System.IO.Path]::Combine('$(_DirectoryBuildTargetsBasePath)', '$(_DirectoryBuildTargetsFile)'))</DirectoryBuildTargetsPath>
<DirectoryBuildTargetsPath Condition="'$(_DirectoryBuildTargetsBasePath)' != '' and '$(_DirectoryBuildTargetsFile)' != ''">$([MSBuild]::NormalizePath('$(_DirectoryBuildTargetsBasePath)', '$(_DirectoryBuildTargetsFile)'))</DirectoryBuildTargetsPath>
</PropertyGroup>

<Import Project="$(DirectoryBuildTargetsPath)" Condition="'$(ImportDirectoryBuildTargets)' == 'true' and exists('$(DirectoryBuildTargetsPath)')"/>
Expand Down
Loading