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

Make SelfRegisteredExtensions and EntryPoint types part of namespace #4814

Merged
merged 10 commits into from
Jan 30, 2025
Merged
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 @@ -8,7 +8,7 @@

namespace Microsoft.Testing.Platform.MSBuild;

public sealed class TestingPlatformAutoRegisteredExtensions : Build.Utilities.Task
public sealed class TestingPlatformSelfRegisteredExtensions : Build.Utilities.Task
{
private const string DisplayNameMetadataName = "DisplayName";
private const string TypeFullNameMetadataName = "TypeFullName";
Expand All @@ -17,12 +17,12 @@ public sealed class TestingPlatformAutoRegisteredExtensions : Build.Utilities.Ta
private const string FSharpLanguageSymbol = "F#";
private const string VBLanguageSymbol = "VB";

public TestingPlatformAutoRegisteredExtensions()
public TestingPlatformSelfRegisteredExtensions()
: this(new FileSystem())
{
}

internal TestingPlatformAutoRegisteredExtensions(IFileSystem fileSystem)
internal TestingPlatformSelfRegisteredExtensions(IFileSystem fileSystem)
{
if (Environment.GetEnvironmentVariable("TESTINGPLATFORM_MSBUILD_LAUNCH_ATTACH_DEBUGGER") == "1")
{
Expand All @@ -33,16 +33,19 @@ internal TestingPlatformAutoRegisteredExtensions(IFileSystem fileSystem)
}

[Required]
public ITaskItem AutoRegisteredExtensionsSourcePath { get; set; }
public ITaskItem SelfRegisteredExtensionsSourcePath { get; set; }

[Required]
public ITaskItem Language { get; set; }

[Required]
public ITaskItem[] AutoRegisteredExtensionsBuilderHook { get; set; }
public ITaskItem[] SelfRegisteredExtensionsBuilderHook { get; set; }

[Required]
public string RootNamespace { get; set; }

[Output]
public ITaskItem AutoRegisteredExtensionsGeneratedFilePath { get; set; }
public ITaskItem SelfRegisteredExtensionsGeneratedFilePath { get; set; }

private readonly string _expectedItemSpec = """
Expected item spec:
Expand All @@ -63,16 +66,16 @@ static Contoso.BuilderHook.AddExtensions(Microsoft.Testing.Platform.Builder.Test

public override bool Execute()
{
Log.LogMessage(MessageImportance.Normal, $"AutoRegisteredExtensionsSourcePath: '{AutoRegisteredExtensionsSourcePath.ItemSpec}'");
Log.LogMessage(MessageImportance.Normal, $"SelfRegisteredExtensionsSourcePath: '{SelfRegisteredExtensionsSourcePath.ItemSpec}'");
Log.LogMessage(MessageImportance.Normal, $"Language: '{Language.ItemSpec}'");

if (AutoRegisteredExtensionsBuilderHook.Length > 0)
if (SelfRegisteredExtensionsBuilderHook.Length > 0)
{
StringBuilder stringBuilder = new();
stringBuilder.AppendLine("TestingPlatformExtensionFullTypeNames:");

// Distinct by ItemSpec and take the first one.
foreach (ITaskItem item in AutoRegisteredExtensionsBuilderHook.GroupBy(x => x.ItemSpec).Select(x => x.First()))
foreach (ITaskItem item in SelfRegisteredExtensionsBuilderHook.GroupBy(x => x.ItemSpec).Select(x => x.First()))
{
if (string.IsNullOrEmpty(item.GetMetadata(DisplayNameMetadataName)))
{
Expand All @@ -92,19 +95,19 @@ public override bool Execute()

if (!Log.HasLoggedErrors)
{
ITaskItem[] taskItems = Reorder(AutoRegisteredExtensionsBuilderHook);
ITaskItem[] taskItems = Reorder(SelfRegisteredExtensionsBuilderHook);

if (!Language.ItemSpec.Equals(CSharpLanguageSymbol, StringComparison.OrdinalIgnoreCase) &&
!Language.ItemSpec.Equals(VBLanguageSymbol, StringComparison.OrdinalIgnoreCase) &&
!Language.ItemSpec.Equals(FSharpLanguageSymbol, StringComparison.OrdinalIgnoreCase))
{
AutoRegisteredExtensionsGeneratedFilePath = default!;
SelfRegisteredExtensionsGeneratedFilePath = default!;
Log.LogError($"Language '{Language.ItemSpec}' is not supported.");
}
else
{
GenerateCode(Language.ItemSpec, taskItems, AutoRegisteredExtensionsSourcePath, _fileSystem, Log);
AutoRegisteredExtensionsGeneratedFilePath = AutoRegisteredExtensionsSourcePath;
GenerateCode(Language.ItemSpec, RootNamespace, taskItems, SelfRegisteredExtensionsSourcePath, _fileSystem, Log);
SelfRegisteredExtensionsGeneratedFilePath = SelfRegisteredExtensionsSourcePath;
}
}

Expand Down Expand Up @@ -134,7 +137,7 @@ private static ITaskItem[] Reorder(ITaskItem[] items)
return result.ToArray();
}

private static void GenerateCode(string language, ITaskItem[] taskItems, ITaskItem testingPlatformEntryPointSourcePath, IFileSystem fileSystem, TaskLoggingHelper taskLoggingHelper)
private static void GenerateCode(string language, string rootNamespace, ITaskItem[] taskItems, ITaskItem testingPlatformEntryPointSourcePath, IFileSystem fileSystem, TaskLoggingHelper taskLoggingHelper)
{
StringBuilder builder = new();

Expand All @@ -153,16 +156,17 @@ private static void GenerateCode(string language, ITaskItem[] taskItems, ITaskIt
}
}

string entryPointSource = GetSourceCode(language, builder.ToString());
taskLoggingHelper.LogMessage(MessageImportance.Normal, $"AutoRegisteredExtensions source:\n'{entryPointSource}'");
string entryPointSource = GetSourceCode(language, rootNamespace, builder.ToString());
taskLoggingHelper.LogMessage(MessageImportance.Normal, $"SelfRegisteredExtensions source:\n'{entryPointSource}'");
fileSystem.WriteAllText(testingPlatformEntryPointSourcePath.ItemSpec, entryPointSource);
}

private static string GetSourceCode(string language, string extensionsFragments)
private static string GetSourceCode(string language, string rootNamespace, string extensionsFragments)
{
if (language == CSharpLanguageSymbol)
{
return $$"""
return string.IsNullOrEmpty(rootNamespace)
? $$"""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Microsoft.Testing.Platform.MSBuild
Expand All @@ -177,11 +181,31 @@ public static void AddSelfRegisteredExtensions(this global::Microsoft.Testing.Pl
{{extensionsFragments}}
}
}
"""
: $$"""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Microsoft.Testing.Platform.MSBuild
// </auto-generated>
//------------------------------------------------------------------------------

namespace {{rootNamespace}}
{
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static class SelfRegisteredExtensions
{
public static void AddSelfRegisteredExtensions(this global::Microsoft.Testing.Platform.Builder.ITestApplicationBuilder builder, string[] args)
{
{{extensionsFragments}}
}
}
}
""";
}
else if (language == VBLanguageSymbol)
{
return $$"""
return string.IsNullOrEmpty(rootNamespace)
? $$"""
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated by Microsoft.Testing.Platform.MSBuild
Expand All @@ -190,18 +214,34 @@ public static void AddSelfRegisteredExtensions(this global::Microsoft.Testing.Pl

<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>
Friend Module SelfRegisteredExtensions

<System.Runtime.CompilerServices.Extension>
Public Sub AddSelfRegisteredExtensions(ByVal builder As Global.Microsoft.Testing.Platform.Builder.ITestApplicationBuilder, ByVal args As Global.System.String())
{{extensionsFragments}}
End Sub

End Module
"""
: $$"""
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated by Microsoft.Testing.Platform.MSBuild
' </auto-generated>
'------------------------------------------------------------------------------

Namespace {{rootNamespace}}
<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>
Friend Module SelfRegisteredExtensions
<System.Runtime.CompilerServices.Extension>
Public Sub AddSelfRegisteredExtensions(ByVal builder As Global.Microsoft.Testing.Platform.Builder.ITestApplicationBuilder, ByVal args As Global.System.String())
{{extensionsFragments}}
End Sub
End Module
End Namespace
""";
}
else if (language == FSharpLanguageSymbol)
{
return $$"""
return string.IsNullOrEmpty(rootNamespace)
? $$"""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Microsoft.Testing.Platform.MSBuild
Expand All @@ -212,6 +252,25 @@ namespace Microsoft.TestingPlatform.Extensions

open System.Runtime.CompilerServices

[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>]
[<Extension>]
type SelfRegisteredExtensions() =

[<Extension>]
static member AddSelfRegisteredExtensions (builder: Microsoft.Testing.Platform.Builder.ITestApplicationBuilder, args: string[]) =
{{(extensionsFragments.Length > 0 ? extensionsFragments : "()")}}
"""
: $$"""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Microsoft.Testing.Platform.MSBuild
// </auto-generated>
//------------------------------------------------------------------------------

namespace {{rootNamespace}}

open System.Runtime.CompilerServices

[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>]
[<Extension>]
type SelfRegisteredExtensions() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ internal TestingPlatformEntryPointTask(IFileSystem fileSystem)
[Required]
public ITaskItem Language { get; set; }

[Required]
public string RootNamespace { get; set; }

[Output]
public ITaskItem TestingPlatformEntryPointGeneratedFilePath { get; set; }

Expand All @@ -54,25 +57,26 @@ public override bool Execute()
}
else
{
GenerateEntryPoint(Language.ItemSpec, TestingPlatformEntryPointSourcePath, _fileSystem, Log);
GenerateEntryPoint(Language.ItemSpec, RootNamespace, TestingPlatformEntryPointSourcePath, _fileSystem, Log);
TestingPlatformEntryPointGeneratedFilePath = TestingPlatformEntryPointSourcePath;
}

return !Log.HasLoggedErrors;
}

private static void GenerateEntryPoint(string language, ITaskItem testingPlatformEntryPointSourcePath, IFileSystem fileSystem, TaskLoggingHelper taskLoggingHelper)
private static void GenerateEntryPoint(string language, string rootNamespace, ITaskItem testingPlatformEntryPointSourcePath, IFileSystem fileSystem, TaskLoggingHelper taskLoggingHelper)
{
string entryPointSource = GetEntryPointSourceCode(language);
string entryPointSource = GetEntryPointSourceCode(language, rootNamespace);
taskLoggingHelper.LogMessage(MessageImportance.Normal, $"Entrypoint source:\n'{entryPointSource}'");
fileSystem.WriteAllText(testingPlatformEntryPointSourcePath.ItemSpec, entryPointSource);
}

private static string GetEntryPointSourceCode(string language)
private static string GetEntryPointSourceCode(string language, string rootNamespace)
{
if (language == CSharpLanguageSymbol)
{
return """
return string.IsNullOrEmpty(rootNamespace)
? $$"""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Microsoft.Testing.Platform.MSBuild
Expand All @@ -92,11 +96,36 @@ internal sealed class TestingPlatformEntryPoint
}
}
}
"""
: $$"""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Microsoft.Testing.Platform.MSBuild
// </auto-generated>
//------------------------------------------------------------------------------

namespace {{rootNamespace}}
{
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal sealed class TestingPlatformEntryPoint
{
public static async global::System.Threading.Tasks.Task<int> Main(string[] args)
{
global::Microsoft.Testing.Platform.Builder.ITestApplicationBuilder builder = await global::Microsoft.Testing.Platform.Builder.TestApplication.CreateBuilderAsync(args);
SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args);
using (global::Microsoft.Testing.Platform.Builder.ITestApplication app = await builder.BuildAsync())
{
return await app.RunAsync();
}
}
}
}
""";
}
else if (language == VBLanguageSymbol)
{
return """
return string.IsNullOrEmpty(rootNamespace)
? $$"""
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated by Microsoft.Testing.Platform.MSBuild
Expand All @@ -119,28 +148,80 @@ End Using
End Function

End Module
"""
: $$"""
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated by Microsoft.Testing.Platform.MSBuild
' </auto-generated>
'------------------------------------------------------------------------------

Namespace {{rootNamespace}}
<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>
Module TestingPlatformEntryPoint

Function Main(args As Global.System.String()) As Global.System.Int32
Return MainAsync(args).Result
Evangelink marked this conversation as resolved.
Show resolved Hide resolved
End Function

Public Async Function MainAsync(ByVal args() As Global.System.String) As Global.System.Threading.Tasks.Task(Of Integer)
Dim builder = Await Global.Microsoft.Testing.Platform.Builder.TestApplication.CreateBuilderAsync(args)
SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args)
Using testApplication = Await builder.BuildAsync()
Return Await testApplication.RunAsync()
End Using
End Function

End Module
End Namespace
""";
}
else if (language == FSharpLanguageSymbol)
{
return """
return string.IsNullOrEmpty(rootNamespace)
? $$"""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Microsoft.Testing.Platform.MSBuild
// </auto-generated>
//------------------------------------------------------------------------------

[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>]
[<EntryPoint>]
let main args =
task {
let! builder = Microsoft.Testing.Platform.Builder.TestApplication.CreateBuilderAsync args
Microsoft.TestingPlatform.Extensions.SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args)
use! app = builder.BuildAsync()
return! app.RunAsync()
}
|> Async.AwaitTask
|> Async.RunSynchronously
module TestingPlatformEntryPoint =

[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>]
[<EntryPoint>]
let main args =
task {
let! builder = Microsoft.Testing.Platform.Builder.TestApplication.CreateBuilderAsync args
Microsoft.TestingPlatform.Extensions.SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args)
use! app = builder.BuildAsync()
return! app.RunAsync()
}
|> Async.AwaitTask
|> Async.RunSynchronously
"""
: $$"""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Microsoft.Testing.Platform.MSBuild
// </auto-generated>
//------------------------------------------------------------------------------

namespace {{rootNamespace}}

module TestingPlatformEntryPoint =

[<System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage>]
[<EntryPoint>]
let main args =
task {
let! builder = Microsoft.Testing.Platform.Builder.TestApplication.CreateBuilderAsync args
SelfRegisteredExtensions.AddSelfRegisteredExtensions(builder, args)
use! app = builder.BuildAsync()
return! app.RunAsync()
}
|> Async.AwaitTask
|> Async.RunSynchronously
""";
}

Expand Down
Loading
Loading