Skip to content

Cleanup usages of IsTestProject #49838

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<PropertyGroup Condition="'$(UseCurrentRuntimeIdentifier)' == ''">
<UseCurrentRuntimeIdentifier Condition="
'$(RuntimeIdentifier)' == '' and
'$(_IsExecutable)' == 'true' and '$(IsTestProject)' != 'true' and
'$(_IsExecutable)' == 'true' and
'$(IsRidAgnostic)' != 'true' and
'$(PackAsTool)' != true and
(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<!-- Set the IsRidAgnostic property if this project should NOT accept global RuntimeIdentifier and SelfContained
property values from referencing projects. -->
<PropertyGroup Condition="'$(IsRidAgnostic)' == ''">
<IsRidAgnostic Condition="('$(_IsExecutable)' == 'true' And '$(IsTestProject)' != 'true') Or
<IsRidAgnostic Condition="('$(_IsExecutable)' == 'true') Or
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<IsRidAgnostic Condition="('$(_IsExecutable)' == 'true') Or
<IsRidAgnostic Condition="('$(_IsExecutable)' == 'true' And ('$(IsTestProject)' != 'true' Or '$(IsTestingPlatformApplication) != 'true')) Or

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would try to avoid reading IsTestingPlatformApplication in evaluation if possible

'$(RuntimeIdentifier)' != '' Or
'$(RuntimeIdentifiers)' != ''">false</IsRidAgnostic>
<IsRidAgnostic Condition="'$(IsRidAgnostic)' == ''">true</IsRidAgnostic>
Expand Down Expand Up @@ -1292,30 +1292,35 @@ Copyright (c) .NET Foundation. All rights reserved.
<ShouldBeValidatedAsExecutableReference>false</ShouldBeValidatedAsExecutableReference>
</PropertyGroup>

<PropertyGroup Condition="'$(IsTestProject)' == 'true' And '$(ValidateExecutableReferencesMatchSelfContained)' == ''">
<!-- Don't generate an error if a test project references a self-contained Exe. Test projects
use an OutputType of Exe but will usually call APIs in a referenced Exe rather than try
to run it. -->
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
</PropertyGroup>

<PropertyGroup Condition="'$(IsTestProject)' == 'true'">
<!-- Don't generate an error if an Exe project references a test project. -->
<ShouldBeValidatedAsExecutableReference>false</ShouldBeValidatedAsExecutableReference>
</PropertyGroup>


<UsingTask TaskName="ValidateExecutableReferences" AssemblyFile="$(MicrosoftNETBuildTasksAssembly)" />

<PropertyGroup>
<_UseAttributeForTargetFrameworkInfoPropertyNames Condition="$([MSBuild]::VersionGreaterThanOrEquals($(MSBuildVersion), '17.0'))">true</_UseAttributeForTargetFrameworkInfoPropertyNames>
</PropertyGroup>

<!-- GetTargetFrameworksWithPlatformForSingleTargetFramework uses AdditionalTargetFrameworkInfoProperty to populate _AdditionalTargetFrameworkInfoPropertyWithValue -->
<!-- As we are modifying the value of ShouldBeValidatedAsExecutableReference here (which is part of AdditionalTargetFrameworkInfoProperty), we must run before GetTargetFrameworksWithPlatformForSingleTargetFramework -->
<Target Name="_CalculateIsVSTestTestProject" BeforeTargets="GetTargetFrameworksWithPlatformForSingleTargetFramework">
<PropertyGroup>
<_IsVSTestTestProject Condition="'$(IsTestProject)' == 'true' and '$(IsTestingPlatformApplication)' != 'true'">true</_IsVSTestTestProject>
<_IsVSTestTestProject Condition="'$(_IsVSTestTestProject)' == ''">false</_IsVSTestTestProject>

<!-- Don't generate an error if an Exe project references a test project. -->
<ShouldBeValidatedAsExecutableReference Condition="'$(_IsVSTestTestProject)' == 'true'">false</ShouldBeValidatedAsExecutableReference>

<!-- Don't generate an error if a test project references a self-contained Exe. Test projects
use an OutputType of Exe but will usually call APIs in a referenced Exe rather than try
to run it. -->
<ValidateExecutableReferencesMatchSelfContained Condition="'$(_IsVSTestTestProject)' == 'true' And '$(ValidateExecutableReferencesMatchSelfContained)' == ''">false</ValidateExecutableReferencesMatchSelfContained>
</PropertyGroup>
</Target>

<Target Name="ValidateExecutableReferences"
AfterTargets="_GetProjectReferenceTargetFrameworkProperties"
Condition="'$(ValidateExecutableReferencesMatchSelfContained)' != 'false'">
DependsOnTargets="_CalculateIsVSTestTestProject"
AfterTargets="_GetProjectReferenceTargetFrameworkProperties">

<ValidateExecutableReferences
Condition="'$(ValidateExecutableReferencesMatchSelfContained)' != 'false'"
SelfContained="$(SelfContained)"
IsExecutable="$(_IsExecutable)"
ReferencedProjects="@(_MSBuildProjectReferenceExistent)"
Expand Down
162 changes: 156 additions & 6 deletions test/Microsoft.NET.Build.Tests/ReferenceExeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,10 @@ public void ReferencedExeCanRunWhenPublishedWithTrimming(bool referenceExeInCode
}

[RequiresMSBuildVersionTheory("17.0.0.32901")]
[InlineData("xunit")]
[InlineData("mstest")]
public void TestProjectCanReferenceExe(string testTemplateName)
[CombinatorialData]
public void TestProjectCanReferenceExe(
[CombinatorialValues("xunit", "mstest")] string testTemplateName,
bool setSelfContainedProperty)
{
var testConsoleProject = new TestProject("ConsoleApp")
{
Expand All @@ -334,6 +335,11 @@ public void TestProjectCanReferenceExe(string testTemplateName)
RuntimeIdentifier = EnvironmentInfo.GetCompatibleRid()
};

if (setSelfContainedProperty)
{
testConsoleProject.SelfContained = "true";
}

var testAsset = _testAssetsManager.CreateTestProject(testConsoleProject, identifier: testTemplateName);

var testProjectDirectory = Path.Combine(testAsset.TestRoot, "TestProject");
Expand All @@ -359,10 +365,110 @@ public void TestProjectCanReferenceExe(string testTemplateName)

}

[Theory]
[CombinatorialData]
public void SelfContainedExecutableCannotBeReferencedByNonSelfContainedMTPTestProject(bool setIsTestingPlatformApplicationEarly)
{
// The setup of this test is as follows:
// ConsoleApp is a self-contained executable project.
// MTPTestProject is an executable test project that references ConsoleApp.
// Building MTPTestProject should fail because it references a self-contained executable project.
// A self-contained executable cannot be referenced by a non self-contained executable.
var testConsoleProjectSelfContained = new TestProject("ConsoleApp")
{
IsExe = true,
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
SelfContained = "true",
};

var mtpNotSelfContained = new TestProject("MTPTestProject")
{
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = true,
};

mtpNotSelfContained.AdditionalProperties["IsTestProject"] = "true";

if (setIsTestingPlatformApplicationEarly)
{
mtpNotSelfContained.AdditionalProperties["IsTestingPlatformApplication"] = "true";
}

mtpNotSelfContained.ReferencedProjects.Add(testConsoleProjectSelfContained);

var testAssetMTP = _testAssetsManager.CreateTestProject(mtpNotSelfContained);

var mtpProjectDirectory = Path.Combine(testAssetMTP.Path, "MTPTestProject");

if (!setIsTestingPlatformApplicationEarly)
{
File.WriteAllText(Path.Combine(mtpProjectDirectory, "Directory.Build.targets"), """
<Project>
<PropertyGroup>
<IsTestingPlatformApplication>true</IsTestingPlatformApplication>
</PropertyGroup>
</Project>
""");
}

var result = new BuildCommand(Log, mtpProjectDirectory).Execute();
result.Should().HaveStdOutContaining("NETSDK1151").And.ExitWith(1);
}

[Theory]
[CombinatorialData]
public void MTPNonSelfContainedExecutableCannotBeReferencedBySelfContained(bool setIsTestingPlatformApplicationEarly)
{
// The setup of this test is as follows:
// ConsoleApp is a self-contained executable project, which references a non-self-contained MTP executable test project.
// Building ConsoleApp should fail because it references a non-self-contained MTP executable project.
// A non self-contained executable cannot be referenced by a self-contained executable.
var testConsoleProjectSelfContained = new TestProject("ConsoleApp")
{
IsExe = true,
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
SelfContained = "true",
};

var mtpNotSelfContained = new TestProject("MTPTestProject")
{
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = true,
};

mtpNotSelfContained.AdditionalProperties["IsTestProject"] = "true";

if (setIsTestingPlatformApplicationEarly)
{
mtpNotSelfContained.AdditionalProperties["IsTestingPlatformApplication"] = "true";
}

testConsoleProjectSelfContained.ReferencedProjects.Add(mtpNotSelfContained);

var testAssetSelfContained = _testAssetsManager.CreateTestProject(testConsoleProjectSelfContained);

if (!setIsTestingPlatformApplicationEarly)
{
File.WriteAllText(Path.Combine(testAssetSelfContained.TestRoot, mtpNotSelfContained.Name, "Directory.Build.targets"), """
<Project>
<PropertyGroup>
<IsTestingPlatformApplication>true</IsTestingPlatformApplication>
</PropertyGroup>
</Project>
""");
}

var consoleAppDirectory = Path.Combine(testAssetSelfContained.Path, testConsoleProjectSelfContained.Name);

var result = new BuildCommand(Log, consoleAppDirectory).Execute();
result.Should().HaveStdOutContaining("NETSDK1150").And.ExitWith(1);
}

[RequiresMSBuildVersionTheory("17.0.0.32901")]
[InlineData("xunit")]
[InlineData("mstest")]
public void ExeProjectCanReferenceTestProject(string testTemplateName)
[CombinatorialData]
public void ExeProjectCanReferenceTestProject(
[CombinatorialValues("xunit", "mstest")] string testTemplateName,
bool setSelfContainedProperty)
{
var testConsoleProject = new TestProject("ConsoleApp")
{
Expand All @@ -371,6 +477,11 @@ public void ExeProjectCanReferenceTestProject(string testTemplateName)
RuntimeIdentifier = EnvironmentInfo.GetCompatibleRid()
};

if (setSelfContainedProperty)
{
testConsoleProject.SelfContained = "true";
}

var testAsset = _testAssetsManager.CreateTestProject(testConsoleProject, identifier: testTemplateName);

var testProjectDirectory = Path.Combine(testAsset.TestRoot, "TestProject");
Expand All @@ -396,5 +507,44 @@ public void ExeProjectCanReferenceTestProject(string testTemplateName)
.Should()
.Pass();
}

[Theory]
[CombinatorialData]
public void MTPCanBeBuiltAsSelfContained(bool setIsTestingPlatformApplicationEarly)
{
var mtpSelfContained = new TestProject("MTPTestProject")
{
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
IsExe = true,
SelfContained = "true",
};

mtpSelfContained.AdditionalProperties["IsTestProject"] = "true";

if (setIsTestingPlatformApplicationEarly)
{
mtpSelfContained.AdditionalProperties["IsTestingPlatformApplication"] = "true";
}

var testAssetMTP = _testAssetsManager.CreateTestProject(mtpSelfContained);

var mtpProjectDirectory = Path.Combine(testAssetMTP.Path, mtpSelfContained.Name);

if (!setIsTestingPlatformApplicationEarly)
{
File.WriteAllText(Path.Combine(mtpProjectDirectory, "Directory.Build.targets"), """
<Project>
<PropertyGroup>
<IsTestingPlatformApplication>true</IsTestingPlatformApplication>
</PropertyGroup>
</Project>
""");
}

new BuildCommand(Log, mtpProjectDirectory)
.Execute()
.Should()
.Pass();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ public TestProject([CallerMemberName] string? name = null)
/// </summary>
public bool IsWinExe { get; set; }


public string? ProjectSdk { get; set; }

/// <summary>
Expand Down