Skip to content

Commit

Permalink
is test project instead of xunit reference (#1528)
Browse files Browse the repository at this point in the history
  • Loading branch information
david-driscoll authored Apr 18, 2024
1 parent 389d40d commit 1965258
Show file tree
Hide file tree
Showing 18 changed files with 302 additions and 92 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.1;netstandard2.0;net6.0;net8.0</TargetFrameworks>
<TargetFramework>net8.0</TargetFramework>
<PackageDescription
>Adds support for loading configuration, services, logging, command line and more via simple and easy to setup assembly attributes</PackageDescription>
<PackageTags>$(PackageTags);reflection</PackageTags>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
<CompilerVisibleProperty Include="ExportConventionsNamespace" />
<CompilerVisibleProperty Include="ExportConventionsClassName" />
<CompilerVisibleProperty Include="ExportConventionsMethodName" />
<CompilerVisibleProperty Include="IsTestProject" />
</ItemGroup>
</Project>
37 changes: 20 additions & 17 deletions src/Conventions.Analyzers/ConventionAttributesGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,30 +88,31 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Create(context, "ImportConventions", ConventionConfigurationData.ImportsDefaults)
.Select((z, _) => !z.WasConfigured && z.Assembly ? z with { Assembly = false, } : z);

var importCandidates = context
.SyntaxProvider
.ForAttributeWithMetadataName(
"Rocket.Surgery.Conventions.ImportConventionsAttribute",
(node, _) => node is TypeDeclarationSyntax,
(syntaxContext, _) => syntaxContext.TargetNode
);

var hasAssemblyLoadContext = context.CompilationProvider
.Select((compilation, _) => compilation.GetTypeByMetadataName("System.Runtime.Loader.AssemblyLoadContext") is { });
var isTestProject = context.AnalyzerConfigOptionsProvider
.Select(
(provider, _) => provider.GlobalOptions.TryGetValue("build_property.IsTestProject", out var value)
&& bool.TryParse(value, out var v)
&& v
);

context.RegisterSourceOutput(
context
.CompilationProvider
.Combine(importCandidates.Collect())
.Combine(combinedExports.Collect())
.Combine(importConfigurationCandidate)
.Combine(exportConfigurationCandidate)
.Combine(hasAssemblyLoadContext)
.Combine(isTestProject)
.Select(
(z, _) => ( compilation: z.Left.Left.Left.Left.Left, hasExports: z.Left.Left.Left.Right.Any(),
exportedCandidates: z.Left.Left.Left.Left.Right,
importConfiguration: z.Left.Left.Right, exportConfiguration: z.Left.Right, hasAssemblyLoadContext: z.Right
)
(z, _) => (
compilation: z.Left.Left.Left.Left.Left,
hasExports: z.Left.Left.Left.Left.Right.Any(),
exportedCandidates: z.Left.Left.Left.Left.Right,
importConfiguration: z.Left.Left.Left.Right, exportConfiguration: z.Left.Left.Right, hasAssemblyLoadContext: z.Left.Right,
isTestProject: z.Right
)
),
static (productionContext, tuple) =>
{
Expand All @@ -120,8 +121,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
productionContext,
new(
tuple.compilation,
tuple.exportedCandidates,
tuple.hasExports,
tuple.isTestProject,
tuple.importConfiguration,
tuple.exportConfiguration
)
Expand Down Expand Up @@ -151,16 +152,18 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
getAssembliesSyntaxProvider
.Combine(getTypesSyntaxProvider)
.Combine(importConfigurationCandidate)
.Combine(isTestProject)
.Combine(context.CompilationProvider),
static (context, results) =>
{
AssemblyCollection.Collect(
context,
new(
results.Right,
results.Left.Right,
results.Left.Left.Left,
results.Left.Left.Right
results.Left.Left.Right,
results.Left.Left.Left.Left,
results.Left.Left.Left.Right,
results.Left.Right
)
);
}
Expand Down
76 changes: 53 additions & 23 deletions src/Conventions.Analyzers/Support/AssemblyCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ CollectRequest request
Token(SyntaxKind.PartialKeyword)
)
)
.AddMembers(GetAssembliesProviderMethod(privateAssemblies.Any()), assemblyProvider);
.AddMembers(GetAssembliesProviderMethod(privateAssemblies.Any(), request.IsTestProject), assemblyProvider);

cu = cu
.AddMembers(
Expand Down Expand Up @@ -263,7 +263,7 @@ HashSet<IAssemblySymbol> privateAssemblies
);
}

private static MethodDeclarationSyntax GetAssembliesProviderMethod(bool hasPrivateAssemblies)
private static MethodDeclarationSyntax GetAssembliesProviderMethod(bool hasPrivateAssemblies, bool referencesXUnit)
{
ArgumentSyntax[] args = hasPrivateAssemblies
?
Expand All @@ -281,34 +281,64 @@ private static MethodDeclarationSyntax GetAssembliesProviderMethod(bool hasPriva
]
: [];

return MethodDeclaration(IdentifierName("IAssemblyProvider"), Identifier("CreateAssemblyProvider"))
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))
.WithLeadingTrivia(
TriviaList(
Trivia(
PragmaWarningDirectiveTrivia(
Token(SyntaxKind.DisableKeyword),
true
)
.WithErrorCodes(
SingletonSeparatedList<ExpressionSyntax>(
IdentifierName("CA1822")
)
)
)
)
)
.WithParameterList(ParameterList(SingletonSeparatedList(Parameter(Identifier("builder")).WithType(IdentifierName("ConventionContextBuilder")))))
.WithExpressionBody(ArrowExpressionClause(ObjectCreationExpression(IdentifierName("AssemblyProvider")).AddArgumentListArguments(args)))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
var method = MethodDeclaration(IdentifierName("IAssemblyProvider"), Identifier("CreateAssemblyProvider"))
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword)))
.WithLeadingTrivia(
TriviaList(
Trivia(
PragmaWarningDirectiveTrivia(
Token(SyntaxKind.DisableKeyword),
true
)
.WithErrorCodes(
SingletonSeparatedList<ExpressionSyntax>(
IdentifierName("CA1822")
)
)
)
)
)
.WithParameterList(
ParameterList(SingletonSeparatedList(Parameter(Identifier("builder")).WithType(IdentifierName("ConventionContextBuilder"))))
);

if (!referencesXUnit)
{
return method
.WithExpressionBody(ArrowExpressionClause(ObjectCreationExpression(IdentifierName("AssemblyProvider")).AddArgumentListArguments(args)))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
}

return method.WithBody(
Block(
ExpressionStatement(
InvocationExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName("builder"), IdentifierName("Set")))
.WithArgumentList(
ArgumentList(
SingletonSeparatedList(
Argument(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("HostType"),
IdentifierName("UnitTest")
)
)
)
)
)
),
ReturnStatement(ObjectCreationExpression(IdentifierName("AssemblyProvider")).AddArgumentListArguments(args))
)
);
}

public record CollectRequest
(
Compilation Compilation,
ConventionConfigurationData ImportConfiguration,
ImmutableArray<(InvocationExpressionSyntax method, ExpressionSyntax selector, SemanticModel semanticModel)> GetAssemblies,
ImmutableArray<(InvocationExpressionSyntax method, ExpressionSyntax selector, SemanticModel semanticModel)> GetTypes
ImmutableArray<(InvocationExpressionSyntax method, ExpressionSyntax selector, SemanticModel semanticModel)> GetTypes,
bool IsTestProject
);

public record Request(Compilation Compilation, ImmutableArray<Item> Items, HashSet<IAssemblySymbol> PrivateAssemblies);
Expand Down
34 changes: 8 additions & 26 deletions src/Conventions.Analyzers/Support/ImportConventions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Immutable;
using System.Text;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Expand All @@ -15,18 +14,17 @@ public static void HandleConventionImports(
Request request
)
{
( var compilation, var importCandidates, var hasExports, var importConfiguration, var exportConfiguration ) = request;
var references = getReferences(compilation, hasExports && exportConfiguration.Assembly, exportConfiguration);
var references = getReferences(request.Compilation, request is { HasExports: true, ExportConfiguration.Assembly: true, }, request.ExportConfiguration);

var functionBody = references.Count == 0 ? Block(YieldStatement(SyntaxKind.YieldBreakStatement)) : addEnumerateExportStatements(references);

addAssemblySource(context, compilation, functionBody, importConfiguration);
addAssemblySource(context, functionBody, request.ImportConfiguration, request.IsTestProject);

static void addAssemblySource(
SourceProductionContext context,
Compilation compilation,
BlockSyntax syntax,
ConventionConfigurationData configurationData
ConventionConfigurationData configurationData,
bool referencesXUnit
)
{
var members =
Expand Down Expand Up @@ -102,24 +100,8 @@ ConventionConfigurationData configurationData
.WithLeadingTrivia(GetXmlSummary("The conventions imported into this assembly"))
);

var referencesXunit = compilation
.References
.Select(compilation.GetAssemblyOrModuleSymbol)
.Concat(
[compilation.Assembly,]
)
.Select(
symbol =>
{
if (symbol is IAssemblySymbol assemblySymbol)
return assemblySymbol;
if (symbol is IModuleSymbol moduleSymbol) return moduleSymbol.ContainingAssembly;
// ReSharper disable once NullableWarningSuppressionIsUsed
return null!;
}
)
.Any(z => z is { MetadataName: "xunit.core", });
if (referencesXunit)

if (referencesXUnit)
{
members = members.AddMembers(
MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier("Init"))
Expand Down Expand Up @@ -278,8 +260,8 @@ static BlockSyntax addEnumerateExportStatements(IReadOnlyCollection<string> refe
public record Request
(
Compilation Compilation,
ImmutableArray<SyntaxNode> ImportCandidates,
bool HasExports,
bool IsTestProject,
ConventionConfigurationData ImportConfiguration,
ConventionConfigurationData ExportConfiguration
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.1;netstandard2.0;net6.0;net8.0</TargetFrameworks>
<TargetFramework>net8.0</TargetFramework>
<PackageDescription
>Adds support for loading configuration, services, logging, command line and more via simple and easy to setup assembly attributes</PackageDescription>
<PackageTags>$(PackageTags);reflection</PackageTags>
Expand Down
2 changes: 2 additions & 0 deletions src/Conventions/ConventionContext.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Runtime.Loader;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Rocket.Surgery.Conventions.Extensions;
Expand Down Expand Up @@ -31,6 +32,7 @@ public static async ValueTask<IConventionContext> FromAsync(ConventionContextBui

private static ConventionContext FromInitInternal(ConventionContextBuilder builder)
{
builder.AddIfMissing(AssemblyLoadContext.Default);
// ReSharper disable once NullableWarningSuppressionIsUsed
var assemblyProvider = builder._conventionProviderFactory!.CreateAssemblyProvider(builder);
var provider = ConventionContextHelpers.CreateProvider(builder, assemblyProvider, builder.Get<ILogger>());
Expand Down
2 changes: 1 addition & 1 deletion src/Conventions/Rocket.Surgery.Conventions.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.1;netstandard2.0;net6.0;net8.0</TargetFrameworks>
<TargetFramework>net8.0</TargetFramework>
<PackageDescription
>Adds support for loading configuration, services, logging, command line and more via simple and easy to setup assembly attributes</PackageDescription>
<PackageTags>$(PackageTags);reflection</PackageTags>
Expand Down
2 changes: 0 additions & 2 deletions src/Hosting/RocketHostApplicationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Runtime.Loader;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
Expand Down Expand Up @@ -316,7 +315,6 @@ CancellationToken cancellationToken
contextBuilder.Properties["__configured__"] = true;

contextBuilder
.AddIfMissing(AssemblyLoadContext.Default)
.AddIfMissing(builder)
.AddIfMissing(builder.GetType(), builder)
.AddIfMissing(builder.Configuration)
Expand Down
2 changes: 0 additions & 2 deletions src/WebAssembly.Hosting/RocketWebAssemblyExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.Configuration;
using Rocket.Surgery.Conventions;
Expand Down Expand Up @@ -338,7 +337,6 @@ CancellationToken cancellationToken
)
{
conventionContext
.AddIfMissing(AssemblyLoadContext.Default)
.AddIfMissing(builder)
.AddIfMissing(builder.GetType(), builder)
.AddIfMissing<IConfiguration>(builder.Configuration)
Expand Down
38 changes: 20 additions & 18 deletions test/Analyzers.Tests/ImportConventionsGenericTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,6 @@ public async Task Should_Generate_Static_Assembly_Level_Method()
await Verify(result);
}

[Fact]
public async Task Should_Generate_Static_Assembly_Initializer_When_xunit_is_referenced()
{
var result = await WithGenericSharedDeps()
.AddSources(
@"
using Rocket.Surgery.Conventions;
[assembly: ImportConventions]
"
)
.AddReferences(typeof(FactAttribute))
.Build()
.GenerateAsync();

await Verify(result);
}

[Fact]
public async Task Should_Generate_Static_Assembly_Level_Method_Custom_Namespace()
{
Expand Down Expand Up @@ -194,6 +176,26 @@ public partial class Program
await Verify(result);
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task Should_Generate_Static_Assembly_Initializer_When_xunit_is_referenced(bool isTestProject)
{
var result = await WithGenericSharedDeps()
.AddSources(
@"
using Rocket.Surgery.Conventions;
[assembly: ImportConventions]
"
)
.AddGlobalOption("build_property.IsTestProject", isTestProject ? "true" : "false")
.Build()
.GenerateAsync();

await Verify(result).UseParameters(isTestProject);
}

public override async Task InitializeAsync()
{
await base.InitializeAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ namespace TestProject.Conventions
internal sealed partial class Imports
{
#pragma warning disable CA1822
public IAssemblyProvider CreateAssemblyProvider(ConventionContextBuilder builder) => new AssemblyProvider();
public IAssemblyProvider CreateAssemblyProvider(ConventionContextBuilder builder)
{
builder.Set(HostType.UnitTest);
return new AssemblyProvider();
}

[System.CodeDom.Compiler.GeneratedCode("Rocket.Surgery.Conventions.Analyzers", "version"), System.Runtime.CompilerServices.CompilerGenerated, System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
private class AssemblyProvider() : IAssemblyProvider
{
Expand Down
Loading

0 comments on commit 1965258

Please sign in to comment.