|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System.Runtime.CompilerServices;
using Microsoft.DotNet.Cli.Utils;
namespace Microsoft.DotNet.Cli.Publish.Tests
{
public class GivenDotnetPublishPublishesProjects : SdkTest
{
private static string _defaultConfiguration = "Release";
public GivenDotnetPublishPublishesProjects(ITestOutputHelper log) : base(log)
{
}
[Fact]
public void ItPublishesARunnablePortableApp()
{
var testAppName = "MSBuildTestApp";
var testInstance = _testAssetsManager.CopyTestAsset(testAppName)
.WithSource();
var testProjectDirectory = testInstance.Path;
new RestoreCommand(testInstance)
.Execute()
.Should().Pass();
new DotnetPublishCommand(Log)
.WithWorkingDirectory(testProjectDirectory)
.Execute("--framework", ToolsetInfo.CurrentTargetFramework)
.Should().Pass();
var configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? _defaultConfiguration;
var outputDll = Path.Combine(OutputPathCalculator.FromProject(testProjectDirectory).GetPublishDirectory(configuration: configuration), $"{testAppName}.dll");
new DotnetCommand(Log)
.Execute(outputDll)
.Should().Pass()
.And.HaveStdOutContaining("Hello World");
}
[Fact]
public void ItImplicitlyRestoresAProjectWhenPublishing()
{
var testAppName = "MSBuildTestApp";
var testInstance = _testAssetsManager.CopyTestAsset(testAppName)
.WithSource();
var testProjectDirectory = testInstance.Path;
new DotnetPublishCommand(Log)
.WithWorkingDirectory(testProjectDirectory)
.Execute("--framework", ToolsetInfo.CurrentTargetFramework)
.Should().Pass();
}
[Fact]
public void ItCanPublishAMultiTFMProjectWithImplicitRestore()
{
var testInstance = _testAssetsManager.CopyTestAsset(
"NETFrameworkReferenceNETStandard20",
testAssetSubdirectory: TestAssetSubdirectories.DesktopTestProjects)
.WithSource();
string projectDirectory = Path.Combine(testInstance.Path, "MultiTFMTestApp");
new DotnetPublishCommand(Log)
.WithWorkingDirectory(projectDirectory)
.Execute("--framework", ToolsetInfo.CurrentTargetFramework)
.Should().Pass();
}
[Fact]
public void ItDoesNotImplicitlyRestoreAProjectWhenPublishingWithTheNoRestoreOption()
{
var testAppName = "MSBuildTestApp";
var testInstance = _testAssetsManager.CopyTestAsset(testAppName)
.WithSource();
var testProjectDirectory = testInstance.Path;
new DotnetPublishCommand(Log)
.WithWorkingDirectory(testProjectDirectory)
.Execute("--framework", "netcoreapp3.0", "--no-restore")
.Should().Fail()
.And.HaveStdOutContaining("project.assets.json");
}
[Theory]
[InlineData("publish", "-property", "Configuration=Debug")]
[InlineData("publish", "-p", "Configuration=Debug")]
[InlineData("publish", "--property", "Configuration=Debug")]
public void ItParsesSpacedPropertiesInPublishReleaseEvaluationPhase(string command, string propertyKey, string propertyVal)
{
var testInstance = _testAssetsManager.CopyTestAsset("TestAppSimple")
.WithSource()
.Restore(Log);
var rootDir = testInstance.Path;
new DotnetCommand(Log)
.WithWorkingDirectory(rootDir)
.Execute(command, propertyKey, propertyVal)
.Should().Pass().And.NotHaveStdErr();
}
[Theory]
[InlineData(null)]
[InlineData("--sc")]
[InlineData("--self-contained")]
[InlineData("--sc=true")]
[InlineData("--self-contained=true")]
public void ItPublishesSelfContainedWithRid(string args)
{
var testAppName = "MSBuildTestApp";
var rid = EnvironmentInfo.GetCompatibleRid();
var outputDirectory = PublishApp(testAppName, rid, args);
var outputProgram = Path.Combine(outputDirectory.FullName, $"{testAppName}{Constants.ExeSuffix}");
new RunExeCommand(Log, outputProgram)
.Execute()
.Should().Pass()
.And.HaveStdOutContaining("Hello World");
}
[Fact]
public void ItPublishesSelfContainedWithPublishSelfContainedTrue()
{
var testAppName = "MSBuildTestApp";
var rid = EnvironmentInfo.GetCompatibleRid();
var outputDirectory = PublishApp(testAppName, rid, "-p:PublishSelfContained=true");
var outputProgram = Path.Combine(outputDirectory.FullName, $"{testAppName}{Constants.ExeSuffix}");
outputDirectory.Should().HaveFiles(new[] {
"System.dll", // File that should only exist if self contained
});
new RunExeCommand(Log, outputProgram)
.Execute()
.Should().Pass()
.And.HaveStdOutContaining("Hello World");
}
[Theory]
[InlineData(true, false, false)] // PublishSC sets SC to true even if SC is false in the project file
[InlineData(false, false, false)] // PublishSC sets SC to false even if SC is true in the project file
[InlineData(true, true, false)] // PublishSC does not take effect if SC is global
public void PublishSelfContainedPropertyDoesOrDoesntOverrideSelfContained(bool publishSelfContained, bool selfContainedIsGlobal, bool publishSelfContainedIsGlobal)
{
bool selfContained = !publishSelfContained;
bool resultShouldBeSelfContained = publishSelfContained && !selfContainedIsGlobal;
string targetFramework = ToolsetInfo.CurrentTargetFramework;
var testProject = new TestProject("MainProject")
{
TargetFrameworks = targetFramework,
IsExe = true
};
testProject.RecordProperties("SelfContained");
if (!publishSelfContainedIsGlobal)
testProject.AdditionalProperties["PublishSelfContained"] = publishSelfContained.ToString();
if (!selfContainedIsGlobal)
testProject.AdditionalProperties["SelfContained"] = selfContained.ToString();
var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: $"PSC-OVERRIDES-{publishSelfContained}-{selfContainedIsGlobal}-{publishSelfContainedIsGlobal}");
var publishCommand = new DotnetCommand(Log);
List<string> args = new()
{
"publish",
selfContainedIsGlobal ? $"/p:SelfContained={selfContained}" : "",
publishSelfContainedIsGlobal ? $"/p:PublishSelfContained={publishSelfContained}" : "",
};
publishCommand
.WithWorkingDirectory(Path.Combine(testAsset.Path, "MainProject"))
.Execute(args.ToArray())
.Should()
.Pass();
var properties = testProject.GetPropertyValues(testAsset.TestRoot, configuration: "Release", targetFramework: targetFramework);
if (resultShouldBeSelfContained)
{
Assert.True(bool.Parse(properties["SelfContained"]) == true);
}
}
[Fact]
public void ItFailsWith1193IfPublishSelfContainedHasInvalidValue()
{
var testAsset = _testAssetsManager
.CopyTestAsset("HelloWorld", identifier: "NET1193Failure")
.WithSource();
var publishCommand = new PublishCommand(testAsset);
publishCommand
.Execute("-p:PublishSelfContained=Invalid")
.Should()
.Fail()
.And.HaveStdOutContaining("NETSDK1193");
}
[Theory]
[InlineData("--sc=false")]
[InlineData("--self-contained=false")]
[InlineData("--no-self-contained")]
public void ItPublishesFrameworkDependentWithRid(string args)
{
var testAppName = "MSBuildTestApp";
var rid = EnvironmentInfo.GetCompatibleRid();
var outputDirectory = PublishApp(testAppName, rid, args);
outputDirectory.Should().OnlyHaveFiles(new[] {
$"{testAppName}{Constants.ExeSuffix}",
$"{testAppName}.dll",
$"{testAppName}.pdb",
$"{testAppName}.deps.json",
$"{testAppName}.runtimeconfig.json",
});
var outputProgram = Path.Combine(outputDirectory.FullName, $"{testAppName}{Constants.ExeSuffix}");
var command = new RunExeCommand(Log, outputProgram);
command.Execute()
.Should()
.Pass()
.And
.HaveStdOutContaining("Hello World");
}
[Theory]
[InlineData("--sc=false")]
[InlineData("--self-contained=false")]
[InlineData(null)]
[InlineData("--no-self-contained")]
public void ItPublishesFrameworkDependentWithoutRid(string args)
{
var testAppName = "MSBuildTestApp";
var outputDirectory = PublishApp(testAppName, rid: null, args: args);
outputDirectory.Should().OnlyHaveFiles(new[] {
$"{testAppName}{Constants.ExeSuffix}",
$"{testAppName}.dll",
$"{testAppName}.pdb",
$"{testAppName}.deps.json",
$"{testAppName}.runtimeconfig.json",
});
new DotnetCommand(Log)
.Execute(Path.Combine(outputDirectory.FullName, $"{testAppName}.dll"))
.Should().Pass()
.And.HaveStdOutContaining("Hello World");
}
[Theory]
[InlineData("--sc --no-self-contained")]
[InlineData("--self-contained --no-self-contained")]
[InlineData("--sc=true --no-self-contained")]
[InlineData("--self-contained=true --no-self-contained")]
public void ItFailsToPublishWithConflictingArgument(string args)
{
var testAppName = "MSBuildTestApp";
var rid = EnvironmentInfo.GetCompatibleRid();
var testInstance = _testAssetsManager.CopyTestAsset(testAppName, identifier: args)
.WithSource();
var testProjectDirectory = testInstance.Path;
new DotnetPublishCommand(Log)
.WithRuntime(rid)
.WithWorkingDirectory(testProjectDirectory)
.Execute(args.Split())
.Should().Fail()
.And.HaveStdErrContaining(CliStrings.SelfContainAndNoSelfContainedConflict);
}
private DirectoryInfo PublishApp(string testAppName, string rid, string args = null, [CallerMemberName] string callingMethod = "")
{
var testInstance = _testAssetsManager.CopyTestAsset(testAppName, callingMethod: callingMethod, identifier: $"{rid ?? "none"}_{args ?? "none"}")
.WithSource();
var testProjectDirectory = testInstance.Path;
new DotnetPublishCommand(Log)
.WithRuntime(rid)
.WithWorkingDirectory(testProjectDirectory)
.Execute(args?.Split() ?? Array.Empty<string>())
.Should().Pass();
var configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? _defaultConfiguration;
return new DirectoryInfo(OutputPathCalculator.FromProject(testProjectDirectory).GetPublishDirectory(configuration: configuration, runtimeIdentifier: rid));
}
[Fact]
public void ItPublishesAppWhenRestoringToSpecificPackageDirectory()
{
string dir = "pkgs";
string args = $"--packages {dir}";
var testInstance = _testAssetsManager.CopyTestAsset("TestAppSimple")
.WithSource()
.Restore(Log);
var rootDir = testInstance.Path;
new DotnetPublishCommand(Log)
.WithWorkingDirectory(rootDir)
.Execute("--no-restore")
.Should().Pass();
var configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? _defaultConfiguration;
var outputProgram = Path.Combine(OutputPathCalculator.FromProject(rootDir).GetPublishDirectory(configuration: configuration), $"TestAppSimple.dll");
new DotnetCommand(Log, outputProgram)
.Execute()
.Should().Pass()
.And.HaveStdOutContaining("Hello World");
}
[Fact]
public void ItFailsToPublishWithNoBuildIfNotPreviouslyBuilt()
{
var testInstance = _testAssetsManager.CopyTestAsset("TestAppSimple")
.WithSource()
.Restore(Log);
var rootPath = testInstance.Path;
new DotnetPublishCommand(Log)
.WithWorkingDirectory(rootPath)
.Execute("--no-build")
.Should()
.Fail()
.And.HaveStdOutContaining("MSB3030"); // "Could not copy ___ because it was not found."
}
[Theory]
[InlineData(false)]
[InlineData(true)]
public void ItPublishesSuccessfullyWithNoBuildIfPreviouslyBuilt(bool selfContained)
{
var testInstance = _testAssetsManager.CopyTestAsset("TestAppSimple", identifier: selfContained.ToString())
.WithSource();
var rootPath = testInstance.Path;
var rid = selfContained ? EnvironmentInfo.GetCompatibleRid() : "";
var ridArgs = selfContained ? $"-r {rid}".Split() : Array.Empty<string>();
var ridAndConfigurationArgs = ridArgs.ToList().Concat(new List<string> { "-c", "Release" });
new DotnetBuildCommand(Log, rootPath)
.Execute(ridAndConfigurationArgs)
.Should()
.Pass();
new DotnetPublishCommand(Log, "--no-build")
.WithWorkingDirectory(rootPath)
.Execute(ridArgs)
.Should()
.Pass();
var configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? _defaultConfiguration;
var outputProgram = Path.Combine(OutputPathCalculator.FromProject(rootPath).GetPublishDirectory(configuration: configuration, runtimeIdentifier: rid), $"TestAppSimple.dll");
new DotnetCommand(Log, outputProgram)
.Execute()
.Should()
.Pass()
.And.HaveStdOutContaining("Hello World");
}
[Fact]
public void ItFailsToPublishWithNoBuildIfPreviouslyBuiltWithoutRid()
{
var testInstance = _testAssetsManager.CopyTestAsset("TestAppSimple")
.WithSource();
var rootPath = testInstance.Path;
new BuildCommand(testInstance)
.Execute()
.Should()
.Pass();
new DotnetPublishCommand(Log)
.WithWorkingDirectory(rootPath)
.Execute("-r", "win-x64", "--no-build")
.Should()
.Fail();
}
[Fact]
public void DotnetPublishDoesNotPrintCopyrightInfo()
{
var testInstance = _testAssetsManager.CopyTestAsset("MSBuildTestApp")
.WithSource();
var cmd = new DotnetPublishCommand(Log)
.WithWorkingDirectory(testInstance.Path)
.Execute("--nologo");
cmd.Should().Pass();
if (!TestContext.IsLocalized())
{
cmd.Should().NotHaveStdOutContaining("Copyright (C) Microsoft Corporation. All rights reserved.");
}
}
[Fact]
public void DotnetPublishAllowsPublishOutputDir()
{
var testInstance = _testAssetsManager.CopyTestAsset("TestAppSimple")
.WithSource()
.Restore(Log);
var rootDir = testInstance.Path;
new DotnetPublishCommand(Log)
.WithWorkingDirectory(rootDir)
.Execute("--no-restore", "-o", "publish")
.Should()
.Pass();
}
[Fact]
public void A_PublishRelease_property_does_not_override_other_command_configuration()
{
var helloWorldAsset = _testAssetsManager
.CopyTestAsset("HelloWorld", "PublishPropertiesHelloWorld")
.WithSource();
File.WriteAllText(helloWorldAsset.Path + "/Directory.Build.props", "<Project><PropertyGroup><PublishRelease>true</PublishRelease></PropertyGroup></Project>");
// Another command, which should not be affected by PublishRelease
new BuildCommand(helloWorldAsset)
.Execute();
var expectedAssetPath = Path.Combine(helloWorldAsset.Path, "bin", "Release");
Assert.False(Directory.Exists(expectedAssetPath));
}
}
}
|