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 some checks for merged test groups #89521

Merged
merged 22 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
baba1b4
First attempt at first rules
markples Jul 25, 2023
0caf13d
Fix CLRTestExecutionArguments in CLRTest.Execute.Batch.targets, impro…
markples Jul 25, 2023
453e637
XUWG: Display exceptions in stdout, factor a bit
markples Jul 25, 2023
8c7bc27
JIT/opt/Devirtualization/box2: Use Task.Run to de-async Main and then…
markples Jul 25, 2023
e0f9528
hfa_nested_f64_interop_cpp.csproj: No RequiresProcessIsolation on lib…
markples Jul 25, 2023
b2cbac0
Runtime_82535: Use Fact, remove tabs
markples Jul 25, 2023
11d7bd2
JIT/Methodical/delegate: Use Fact, leave exception for harness
markples Jul 25, 2023
305808c
b08046cs: Remove Environment.ExitCode, improve logic
markples Jul 25, 2023
c79f25e
Runtime_75832: Use Assert.Throws
markples Jul 26, 2023
0d5f37f
Factor XUWG
markples Jul 26, 2023
fa6db9c
typos
markples Jul 26, 2023
4df2ebf
Make XUW1001 a warning
markples Jul 26, 2023
40753c8
Fix box2.cs
markples Jul 26, 2023
3dd47f2
Reinstate RefXUWG disjuncts in D.B.t
markples Jul 27, 2023
d6b3353
Merge remote-tracking branch 'origin/start-merged-checks' into start-…
markples Jul 27, 2023
41a8dcc
Add flush for consistency
markples Jul 27, 2023
31e281f
Limit new checks to merged test groups
markples Jul 27, 2023
b9eeedb
box2 - make class public
markples Jul 27, 2023
2b0269f
Remove check that any tests exist
markples Jul 27, 2023
985534e
Revert "Reenable a test which doesn't seem to fail any more. (#85576)"
markples Jul 27, 2023
a5bab7b
Merge remote-tracking branch 'dotnet/main' into start-merged-checks
markples Jul 27, 2023
7969174
static for Descriptor; only write entrypoints for apps
markples Jul 27, 2023
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
16 changes: 9 additions & 7 deletions src/tests/Common/CLRTest.Execute.Batch.targets
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ IF NOT "%CLRTestExitCode%"=="%CLRTestExpectedExitCode%" (
:TakeLock
md %lockFolder%
IF NOT "!ERRORLEVEL!"=="0" (
timeout /t 10 /nobreak
goto :TakeLock
timeout /t 10 /nobreak
goto :TakeLock
)
Exit /b 2

Expand Down Expand Up @@ -403,15 +403,17 @@ IF /I [%1] == [-%(Identity)] set cond=1
IF /I [%1] == [/%(Identity)] set cond=1
IF %cond% EQU 1 (
%(Command)
shift
IF /I [%(HasParam)] == [true] shift
goto NextArg
shift
IF /I [%(HasParam)] == [true] shift
goto NextArg
)','
')

:ExtraArgs
if NOT "%1" == "" (
set CLRTestExecutionArguments=%*
goto :ArgsDone
set CLRTestExecutionArguments=%CLRTestExecutionArguments% %1
shift
goto :ExtraArgs
)

goto ArgsDone
Expand Down
21 changes: 21 additions & 0 deletions src/tests/Common/XUnitWrapperGenerator/Descriptors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.CodeAnalysis;

namespace XUnitWrapperGenerator;

public static class Descriptors
{
public static readonly DiagnosticDescriptor XUWG1001 =
new DiagnosticDescriptor(
"XUW1001",
"Projects in merged tests group should not have entry points",
"Projects in merged tests group should not have entry points. Convert to Facts or Theories.",
"XUnitWrapperGenerator",
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
}
10 changes: 3 additions & 7 deletions src/tests/Common/XUnitWrapperGenerator/ITestInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -415,22 +415,18 @@ public CodeBuilder WrapTestExecutionWithReporting(CodeBuilder testExecutionExpre
builder.AppendLine("try");
using (builder.NewBracesScope())
{
builder.AppendLine($"System.Console.WriteLine(\"{{0:HH:mm:ss.fff}} Running test: {{1}}\", System.DateTime.Now, {test.TestNameExpression});");
builder.AppendLine($"{_summaryLocalIdentifier}.ReportStartingTest({test.TestNameExpression}, System.Console.Out);");
builder.AppendLine($"{_outputRecorderIdentifier}.ResetTestOutput();");
builder.Append(testExecutionExpression);

builder.AppendLine($"{_summaryLocalIdentifier}.ReportPassedTest({test.TestNameExpression}, \"{test.ContainingType}\", @\"{test.Method}\","
+ $" stopwatch.Elapsed - testStart, {_outputRecorderIdentifier}.GetTestOutput(), tempLogSw, statsCsvSw);");

builder.AppendLine($"System.Console.WriteLine(\"{{0:HH:mm:ss.fff}} Passed test: {{1}}\", System.DateTime.Now, {test.TestNameExpression});");
+ $" stopwatch.Elapsed - testStart, {_outputRecorderIdentifier}.GetTestOutput(), System.Console.Out, tempLogSw, statsCsvSw);");
}
builder.AppendLine("catch (System.Exception ex)");
using (builder.NewBracesScope())
{
builder.AppendLine($"{_summaryLocalIdentifier}.ReportFailedTest({test.TestNameExpression}, \"{test.ContainingType}\", @\"{test.Method}\","
+ $" stopwatch.Elapsed - testStart, ex, {_outputRecorderIdentifier}.GetTestOutput(), tempLogSw, statsCsvSw);");

builder.AppendLine($"System.Console.WriteLine(\"{{0:HH:mm:ss.fff}} Failed test: {{1}}\", System.DateTime.Now, {test.TestNameExpression});");
+ $" stopwatch.Elapsed - testStart, ex, {_outputRecorderIdentifier}.GetTestOutput(), System.Console.Out, tempLogSw, statsCsvSw);");
}
}
builder.AppendLine("else");
Expand Down
3 changes: 3 additions & 0 deletions src/tests/Common/XUnitWrapperGenerator/OptionsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace XUnitWrapperGenerator;

public static class OptionsHelper
{
private const string InMergedTestDirectoryOption = "build_property.InMergedTestDirectory";
private const string IsMergedTestRunnerAssemblyOption = "build_property.IsMergedTestRunnerAssembly";
private const string PriorityOption = "build_property.Priority";
private const string RuntimeFlavorOption = "build_property.RuntimeFlavor";
Expand All @@ -29,6 +30,8 @@ private static bool GetBoolOption(this AnalyzerConfigOptions options, string key
? result : 0;
}

internal static bool InMergedTestDirectory(this AnalyzerConfigOptions options) => options.GetBoolOption(InMergedTestDirectoryOption);

internal static bool IsMergedTestRunnerAssembly(this AnalyzerConfigOptions options) => options.GetBoolOption(IsMergedTestRunnerAssemblyOption);

internal static int? Priority(this AnalyzerConfigOptions options) => options.GetIntOption(PriorityOption);
Expand Down
37 changes: 37 additions & 0 deletions src/tests/Common/XUnitWrapperGenerator/RoslynUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace XUnitWrapperGenerator
{
internal class RoslynUtils
{
/// <summary>
/// Returns the Main method that would serve as the entry point of the assembly, ignoring
/// whether the current target is an executable.
/// </summary>
/// <remarks>
/// Replacement for CSharpCompilation.GetEntryPoint() which only works for executables.
/// Replacement for its helpers that are internal.
///
/// Intended for the analyzer that is trying to find Main methods that won't be called in
/// merged test groups. Ignores details such as SynthesizedSimpleProgramEntryPointSymbol.
/// Ignores top-level statements as (1) in exes, they will generate an error for conflicting
/// with the auto-generated main, and (2) in libs, they will generate an error for existing
/// at all.
/// </remarks>
internal static IEnumerable<IMethodSymbol> GetPossibleEntryPoints(Compilation comp, CancellationToken cancellationToken)
=> comp
.GetSymbolsWithName(WellKnownMemberNames.EntryPointMethodName, SymbolFilter.Member)
.OfType<IMethodSymbol>()
.Where(m => m.IsStatic && !m.IsAbstract && !m.IsVirtual);
}
}
96 changes: 70 additions & 26 deletions src/tests/Common/XUnitWrapperGenerator/XUnitWrapperGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text;
Expand All @@ -15,6 +16,22 @@

namespace XUnitWrapperGenerator;

internal struct CompData
{
internal CompData(string assemblyName, IMethodSymbol? entryPoint, IEnumerable<IMethodSymbol> possibleEntryPoints, OutputKind outputKind)
{
AssemblyName = assemblyName;
EntryPoint = entryPoint;
PossibleEntryPoints = possibleEntryPoints;
OutputKind = outputKind;
}

public string AssemblyName { get; private set; }
public IMethodSymbol? EntryPoint { get; private set; }
public IEnumerable<IMethodSymbol> PossibleEntryPoints { get; private set; }
public OutputKind OutputKind { get; private set; }
}

[Generator]
public sealed class XUnitWrapperGenerator : IIncrementalGenerator
{
Expand Down Expand Up @@ -58,9 +75,11 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
return aliasMap.ToImmutable();
}).WithComparer(new ImmutableDictionaryValueComparer<string, string>(EqualityComparer<string>.Default));

var assemblyName = context.CompilationProvider.Select((comp, ct) => comp.Assembly.MetadataName);

var alwaysWriteEntryPoint = context.CompilationProvider.Select((comp, ct) => comp.Options.OutputKind == OutputKind.ConsoleApplication && comp.GetEntryPoint(ct) is null);
var compData = context.CompilationProvider.Select((comp, ct) => new CompData(
assemblyName: comp.Assembly.MetadataName,
entryPoint: comp.GetEntryPoint(ct),
possibleEntryPoints: RoslynUtils.GetPossibleEntryPoints(comp, ct),
outputKind: comp.Options.OutputKind));

var testsInSource =
methodsInSource
Expand Down Expand Up @@ -112,40 +131,65 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Collect()
.Combine(context.AnalyzerConfigOptionsProvider)
.Combine(aliasMap)
.Combine(assemblyName)
.Combine(alwaysWriteEntryPoint),
.Combine(compData),
static (context, data) =>
{
var ((((methods, configOptions), aliasMap), assemblyName), alwaysWriteEntryPoint) = data;
var (((methods, configOptions), aliasMap), compData) = data;

if (methods.Length == 0 && !alwaysWriteEntryPoint)
bool inMergedTestDirectory = configOptions.GlobalOptions.InMergedTestDirectory();
if (inMergedTestDirectory)
{
// If we have no test methods, assume that this project is not migrated to the new system yet
// and that we shouldn't generate a no-op Main method.
return;
CheckNoEntryPoint(context, compData);
}

bool isMergedTestRunnerAssembly = configOptions.GlobalOptions.IsMergedTestRunnerAssembly();
configOptions.GlobalOptions.TryGetValue("build_property.TargetOS", out string? targetOS);

if (isMergedTestRunnerAssembly)
if (compData.OutputKind != OutputKind.ConsoleApplication)
{
if (targetOS?.ToLowerInvariant() is "ios" or "iossimulator" or "tvos" or "tvossimulator" or "maccatalyst" or "android" or "browser")
{
context.AddSource("XHarnessRunner.g.cs", GenerateXHarnessTestRunner(methods, aliasMap, assemblyName));
}
else
{
context.AddSource("FullRunner.g.cs", GenerateFullTestRunner(methods, aliasMap, assemblyName));
}
return;
}
else

bool alwaysWriteEntryPoint = (compData.EntryPoint is null);
if (methods.IsEmpty && !alwaysWriteEntryPoint)
{
context.AddSource("SimpleRunner.g.cs", GenerateStandaloneSimpleTestRunner(methods, aliasMap));
// If we have no test methods, assume that this project is not migrated to the new system yet
// and that we shouldn't generate a no-op Main method.
return;
}

AddRunnerSource(context, methods, configOptions, aliasMap, compData);
});
}

private static void AddRunnerSource(SourceProductionContext context, ImmutableArray<ITestInfo> methods, AnalyzerConfigOptionsProvider configOptions, ImmutableDictionary<string, string> aliasMap, CompData compData)
{
bool isMergedTestRunnerAssembly = configOptions.GlobalOptions.IsMergedTestRunnerAssembly();
configOptions.GlobalOptions.TryGetValue("build_property.TargetOS", out string? targetOS);
string assemblyName = compData.AssemblyName;

if (isMergedTestRunnerAssembly)
{
if (targetOS?.ToLowerInvariant() is "ios" or "iossimulator" or "tvos" or "tvossimulator" or "maccatalyst" or "android" or "browser")
{
context.AddSource("XHarnessRunner.g.cs", GenerateXHarnessTestRunner(methods, aliasMap, assemblyName));
}
else
{
context.AddSource("FullRunner.g.cs", GenerateFullTestRunner(methods, aliasMap, assemblyName));
}
}
else
{
context.AddSource("SimpleRunner.g.cs", GenerateStandaloneSimpleTestRunner(methods, aliasMap));
}
}

private static void CheckNoEntryPoint(SourceProductionContext context, CompData compData)
{
foreach (IMethodSymbol entryPoint in compData.PossibleEntryPoints)
{
context.ReportDiagnostic(Diagnostic.Create(Descriptors.XUWG1001, entryPoint.Locations[0]));
}
}

private static void AppendAliasMap(CodeBuilder builder, ImmutableDictionary<string, string> aliasMap)
{
bool didOutput = false;
Expand Down Expand Up @@ -312,7 +356,7 @@ private static string GenerateXHarnessTestRunner(ImmutableArray<ITestInfo> testI
builder.AppendLine("System.Collections.Generic.HashSet<string> testExclusionList = XUnitWrapperLibrary.TestFilter.LoadTestExclusionList();");
builder.AppendLine($@"return await XHarnessRunnerLibrary.RunnerEntryPoint.RunTests(RunTests, ""{assemblyName}"", args.Length != 0 ? args[0] : null, testExclusionList);");
}
builder.AppendLine("catch(System.Exception ex)");
builder.AppendLine("catch (System.Exception ex)");
using (builder.NewBracesScope())
{
builder.AppendLine("System.Console.WriteLine(ex.ToString());");
Expand Down Expand Up @@ -435,7 +479,7 @@ private static string GenerateStandaloneSimpleTestRunner(ImmutableArray<ITestInf
builder.Append(testInfo.GenerateTestExecution(reporter));
}
}
builder.AppendLine("catch(System.Exception ex)");
builder.AppendLine("catch (System.Exception ex)");
using (builder.NewBracesScope())
{
builder.AppendLine("System.Console.WriteLine(ex.ToString());");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<CompilerVisibleProperty Include="TargetArchitecture" />
<CompilerVisibleProperty Include="Priority" />
<!-- Properties that influence test harness generation -->
<CompilerVisibleProperty Include="InMergedTestDirectory" />
<CompilerVisibleProperty Include="IsMergedTestRunnerAssembly" />
<CompilerVisibleProperty Include="TestFilter" />
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="IsOutOfProcessTestAssembly" />
Expand Down
13 changes: 13 additions & 0 deletions src/tests/Common/XUnitWrapperLibrary/TestSummary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,18 @@ public void WriteFooterToTempLog(StreamWriter tempLogSw)
tempLogSw.WriteLine("</assembly>");
}

public void ReportStartingTest(string name, TextWriter outTw)
{
outTw.WriteLine("{0:HH:mm:ss.fff} Running test: {1}", System.DateTime.Now, name);
outTw.Flush();
}

public void ReportPassedTest(string name,
string containingTypeName,
string methodName,
TimeSpan duration,
string output,
TextWriter outTw,
StreamWriter tempLogSw,
StreamWriter statsCsvSw)
{
Expand All @@ -133,8 +140,10 @@ public void ReportPassedTest(string name,
var result = new TestResult(name, containingTypeName, methodName, duration, null, null, output);
_testResults.Add(result);

outTw.WriteLine($"{0:HH:mm:ss.fff} Passed test: {1}", System.DateTime.Now, name);
Copy link
Member

Choose a reason for hiding this comment

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

@markples This line results in printing "HH:mm:ssfff Passed test: 1" always -- presumably it shouldn't be a string interpolation.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, that's leftover from the original

builder.AppendLine($"System.Console.WriteLine(\"{{0:HH:mm:ss.fff}} Running test: {{1}}\", System.DateTime.Now, {test.TestNameExpression});");

but was for the outer level. It's weird though; I thought that I looked at the output.

statsCsvSw.WriteLine($"{TotalTests},{PassedTests},{FailedTests},{SkippedTests}");
tempLogSw.WriteLine(result.ToXmlString());
outTw.Flush();
statsCsvSw.Flush();
tempLogSw.Flush();
}
Expand All @@ -145,6 +154,7 @@ public void ReportFailedTest(string name,
TimeSpan duration,
Exception ex,
string output,
TextWriter outTw,
StreamWriter tempLogSw,
StreamWriter statsCsvSw)
{
Expand All @@ -153,8 +163,11 @@ public void ReportFailedTest(string name,
var result = new TestResult(name, containingTypeName, methodName, duration, ex, null, output);
_testResults.Add(result);

outTw.WriteLine(ex);
outTw.WriteLine("{0:HH:mm:ss.fff} Failed test: {1}", System.DateTime.Now, name);
statsCsvSw.WriteLine($"{TotalTests},{PassedTests},{FailedTests},{SkippedTests}");
tempLogSw.WriteLine(result.ToXmlString());
outTw.Flush();
statsCsvSw.Flush();
tempLogSw.Flush();
}
Expand Down
2 changes: 1 addition & 1 deletion src/tests/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@
</ItemGroup>
</Target>

<PropertyGroup Condition="'$(Language)' == 'C#' and ('$(BuildAsStandalone)' == 'true' or '$(RequiresProcessIsolation)' == 'true' or '$(IsMergedTestRunnerAssembly)' == 'true')">
<PropertyGroup Condition="'$(Language)' == 'C#' and ('$(BuildAsStandalone)' == 'true' or '$(RequiresProcessIsolation)' == 'true' or '$(InMergedTestDirectory)' == 'true' or '$(IsMergedTestRunnerAssembly)' == 'true')">
<ReferenceXUnitWrapperGenerator Condition="'$(ReferenceXUnitWrapperGenerator)' == ''">true</ReferenceXUnitWrapperGenerator>
</PropertyGroup>

Expand Down
Loading