From 9e03742af20c20bba2051184e736be283c09654a Mon Sep 17 00:00:00 2001 From: bUnit bot Date: Wed, 20 Dec 2023 12:26:11 +0000 Subject: [PATCH 01/53] Set version to '1.27-preview' --- version.json | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/version.json b/version.json index 4548a18c8..da1b5579f 100644 --- a/version.json +++ b/version.json @@ -1,25 +1,25 @@ { - "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "1.26-preview", - "assemblyVersion": { - "precision": "revision" - }, - "nuGetPackageVersion": { - "semVer": 2.0 - }, - "publicReleaseRefSpec": [ - "^refs/heads/stable$" - ], - "cloudBuild": { - "buildNumber": { - "enabled": true - } - }, - "release": { - "branchName": "release/v{version}", - "firstUnstableTag": "preview" - }, - "pathFilters": [ - "./src" - ] -} + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", + "version": "1.27-preview", + "assemblyVersion": { + "precision": "revision" + }, + "nuGetPackageVersion": { + "semVer": 2.0 + }, + "publicReleaseRefSpec": [ + "^refs/heads/stable$" + ], + "cloudBuild": { + "buildNumber": { + "enabled": true + } + }, + "release": { + "branchName": "release/v{version}", + "firstUnstableTag": "preview" + }, + "pathFilters": [ + "./src" + ] +} \ No newline at end of file From d546c4ec7c8144b7220dcf59df97c9c8dfd6d45c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:32:12 +0000 Subject: [PATCH 02/53] build(deps): Bump SonarAnalyzer.CSharp from 9.15.0.81779 to 9.16.0.82469 Bumps [SonarAnalyzer.CSharp](https://github.com/SonarSource/sonar-dotnet) from 9.15.0.81779 to 9.16.0.82469. - [Release notes](https://github.com/SonarSource/sonar-dotnet/releases) - [Commits](https://github.com/SonarSource/sonar-dotnet/compare/9.15.0.81779...9.16.0.82469) --- updated-dependencies: - dependency-name: SonarAnalyzer.CSharp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 09558ade0..f973e1df9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -51,7 +51,7 @@ - + Date: Fri, 22 Dec 2023 14:01:42 +0100 Subject: [PATCH 03/53] docs: Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e433af4a9..a339ea270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to **bUnit** will be documented in this file. The project ad ### Changed -- Upgraded AngleSharp to 1.0.7. +- Upgraded AngleSharp to 1.0.7. Info: The usage of `AngleSharpWrappers` is not needed anymore. Any usage of `Unwrap` should not be needed anymore. ### Fixed From c2e2bdc92c02886861773a2d57c283cbbc3c1876 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Thu, 28 Dec 2023 10:56:29 +0100 Subject: [PATCH 04/53] fix: Wrong output for gemerator package --- src/bunit.generators/bunit.generators.csproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bunit.generators/bunit.generators.csproj b/src/bunit.generators/bunit.generators.csproj index bbeed6794..026e13df4 100644 --- a/src/bunit.generators/bunit.generators.csproj +++ b/src/bunit.generators/bunit.generators.csproj @@ -64,6 +64,11 @@ + + + + + From 3adb978ae91f6a127c3c96633f77e4fae067844d Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Thu, 28 Dec 2023 10:58:15 +0100 Subject: [PATCH 05/53] chore: Update packages --- tests/bunit.core.tests/bunit.core.tests.csproj | 2 +- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- tests/bunit.testassets/bunit.testassets.csproj | 4 ++-- tests/bunit.web.query.tests/bunit.web.query.tests.csproj | 2 +- tests/bunit.web.tests/bunit.web.tests.csproj | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/bunit.core.tests/bunit.core.tests.csproj b/tests/bunit.core.tests/bunit.core.tests.csproj index 192c36268..613edf9b3 100644 --- a/tests/bunit.core.tests/bunit.core.tests.csproj +++ b/tests/bunit.core.tests/bunit.core.tests.csproj @@ -13,7 +13,7 @@ - + all diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index 676482c74..98f2d4047 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -25,7 +25,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/tests/bunit.testassets/bunit.testassets.csproj b/tests/bunit.testassets/bunit.testassets.csproj index 9e8d0128d..2775be374 100644 --- a/tests/bunit.testassets/bunit.testassets.csproj +++ b/tests/bunit.testassets/bunit.testassets.csproj @@ -16,9 +16,9 @@ - + - + diff --git a/tests/bunit.web.query.tests/bunit.web.query.tests.csproj b/tests/bunit.web.query.tests/bunit.web.query.tests.csproj index e6b1405cd..8df6aadf4 100644 --- a/tests/bunit.web.query.tests/bunit.web.query.tests.csproj +++ b/tests/bunit.web.query.tests/bunit.web.query.tests.csproj @@ -14,7 +14,7 @@ - + all diff --git a/tests/bunit.web.tests/bunit.web.tests.csproj b/tests/bunit.web.tests/bunit.web.tests.csproj index 9fbb0639e..1355576b0 100644 --- a/tests/bunit.web.tests/bunit.web.tests.csproj +++ b/tests/bunit.web.tests/bunit.web.tests.csproj @@ -13,7 +13,7 @@ - + all From 58f7180780c30aae548453eccfc285528f6e6c06 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Thu, 28 Dec 2023 12:44:46 +0100 Subject: [PATCH 06/53] refactor: Added indicator for auto-generated code and nullability+ --- .../AddStubMethodStubGenerator/AddStubGenerator.cs | 3 ++- .../StubComponentBuilder.cs | 5 +++-- .../ComponentStubAttribute.cs | 4 +++- .../ComponentStubAttributeGenerator.cs | 5 +++-- src/bunit.generators/Web.Stubs/HeaderProvider.cs | 13 +++++++++++++ 5 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 src/bunit.generators/Web.Stubs/HeaderProvider.cs diff --git a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs index 6ecd2c44e..ae654b913 100644 --- a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs @@ -124,7 +124,8 @@ public InterceptsLocationAttribute(string filePath, int line, int column) """; // Generate the interceptor - var interceptorSource = new StringBuilder(); + var interceptorSource = new StringBuilder(1000); + interceptorSource.AppendLine(HeaderProvider.Header); interceptorSource.AppendLine(attribute); interceptorSource.AppendLine(); interceptorSource.AppendLine("namespace Bunit"); diff --git a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/StubComponentBuilder.cs b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/StubComponentBuilder.cs index 5042ad1bb..b65e9f42f 100644 --- a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/StubComponentBuilder.cs +++ b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/StubComponentBuilder.cs @@ -13,8 +13,9 @@ public static bool GenerateStubComponent(AddStubClassInfo classInfo, SourceProdu { var hasSomethingToStub = false; var targetTypeSymbol = (INamedTypeSymbol)classInfo!.TargetType; - var sourceBuilder = new StringBuilder(); + var sourceBuilder = new StringBuilder(1000); + sourceBuilder.AppendLine(HeaderProvider.Header); sourceBuilder.AppendLine($"namespace {classInfo.TargetTypeNamespace};"); sourceBuilder.AppendLine(); sourceBuilder.AppendLine($"internal partial class {classInfo.StubClassName} : global::Microsoft.AspNetCore.Components.ComponentBase"); @@ -39,7 +40,7 @@ public static bool GenerateStubComponent(AddStubClassInfo classInfo, SourceProdu var attributeLine = GetAttributeLine(member); sourceBuilder.AppendLine(attributeLine); - sourceBuilder.AppendLine($"\tpublic {propertyType} {propertyName} {{ get; set; }}"); + sourceBuilder.AppendLine($"\tpublic {propertyType} {propertyName} {{ get; set; }} = default!;"); } sourceBuilder.AppendLine("}"); diff --git a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttribute.cs b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttribute.cs index 68eb77224..f8c809770 100644 --- a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttribute.cs +++ b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttribute.cs @@ -2,7 +2,9 @@ namespace Bunit.Web.Stubs.AttributeStubGenerator; internal static class ComponentStubAttribute { - public static string ComponentStubAttributeSource = """ + public static string ComponentStubAttributeSource = $$""" + {{HeaderProvider.Header}} + #if NET5_0_OR_GREATER namespace Bunit; diff --git a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs index 3a40031dc..ea24b4465 100644 --- a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs @@ -73,8 +73,9 @@ private static void Execute(StubClassInfo classInfo, SourceProductionContext con { var hasSomethingToStub = false; var targetTypeSymbol = (INamedTypeSymbol)classInfo!.TargetType; - var sourceBuilder = new StringBuilder(); + var sourceBuilder = new StringBuilder(1000); + sourceBuilder.AppendLine(HeaderProvider.Header); sourceBuilder.AppendLine($"namespace {classInfo.Namespace};"); sourceBuilder.AppendLine( @@ -104,7 +105,7 @@ private static void Execute(StubClassInfo classInfo, SourceProductionContext con : "\t[global::Microsoft.AspNetCore.Components.CascadingParameter]"; sourceBuilder.AppendLine(attributeLine); - sourceBuilder.AppendLine($"\tpublic {propertyType} {propertyName} {{ get; set; }}"); + sourceBuilder.AppendLine($"\tpublic {propertyType} {propertyName} {{ get; set; }} = default!;"); } sourceBuilder.AppendLine("}"); diff --git a/src/bunit.generators/Web.Stubs/HeaderProvider.cs b/src/bunit.generators/Web.Stubs/HeaderProvider.cs new file mode 100644 index 000000000..9604138a1 --- /dev/null +++ b/src/bunit.generators/Web.Stubs/HeaderProvider.cs @@ -0,0 +1,13 @@ +namespace Bunit.Web.Stubs; + +internal static class HeaderProvider +{ + public const string Header = """ + // + // This code was generated by bunit.generators. + // Changes to this file may cause incorrect behavior and will be lost if + // the code is regenerated. + // + #nullable enable + """; +} From 8d47edd84970a2c7115711715d08fabc24e96021 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 15:29:25 +0000 Subject: [PATCH 07/53] build(deps): Bump Verify.Xunit from 22.8.0 to 22.11.1 Bumps [Verify.Xunit](https://github.com/VerifyTests/Verify) from 22.8.0 to 22.11.1. - [Release notes](https://github.com/VerifyTests/Verify/releases) - [Commits](https://github.com/VerifyTests/Verify/commits/22.11.1) --- updated-dependencies: - dependency-name: Verify.Xunit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index 98f2d4047..23f1615f8 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + From 9314f8926e8c83a4584f58723601e0f4b26f1414 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:01:34 +0000 Subject: [PATCH 08/53] build(deps): Bump Verify.Xunit from 22.11.1 to 22.11.2 Bumps [Verify.Xunit](https://github.com/VerifyTests/Verify) from 22.11.1 to 22.11.2. - [Release notes](https://github.com/VerifyTests/Verify/releases) - [Commits](https://github.com/VerifyTests/Verify/commits) --- updated-dependencies: - dependency-name: Verify.Xunit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index 23f1615f8..f0713d526 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + From 8323b3a4a6571065884d40b51ae0fc9d776dca72 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 5 Jan 2024 13:45:19 +0100 Subject: [PATCH 09/53] refactor: Remove pragma --- .../AttributeStubGenerator/ComponentStubAttributeGenerator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs index ea24b4465..eb73f442d 100644 --- a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs @@ -39,7 +39,6 @@ private static bool IsClassWithComponentStubAttribute(SyntaxNode s) => private static StubClassInfo GetStubClassInfo(GeneratorAttributeSyntaxContext context) { -#pragma warning disable RS1035 foreach (var attribute in context.TargetSymbol.GetAttributes()) { if (context.TargetSymbol is not ITypeSymbol stubbedType) From f7fb121b020f28f12153a893a2396d79c77f7fe8 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 5 Jan 2024 14:23:00 +0100 Subject: [PATCH 10/53] feat: Add diagnostics for source generators --- docs/site/docs/extensions/bunit-generators.md | 8 +++ .../ComponentStubAttributeGenerator.cs | 58 +++++++++++++++++-- .../Web.Stub/AddStubGeneratorTests.cs | 4 +- 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/docs/site/docs/extensions/bunit-generators.md b/docs/site/docs/extensions/bunit-generators.md index 0f43d389a..8f24f1681 100644 --- a/docs/site/docs/extensions/bunit-generators.md +++ b/docs/site/docs/extensions/bunit-generators.md @@ -82,3 +82,11 @@ internal partial class ThirdPartyStub { } ``` Current limitations of this approach is that he stubbed type is not allowed to be nested inside the test class. + +## Reported Diagnostics +The generators will report a range of diagnostics to help understanding what issue is present. The following table shows the diagnostics that are reported. + +| Diagnostic ID | Error | Severity | Description | +| ------------- | ----------------------------------------------- | -------- | ---------------------------------------------------------------------------- | +| BUNIT0001 | Stubbing nested classes ({0}) is not supported. | Warning | Types annotated with `ComponentStub` can not be nested inside another class. | +| BUNIT0002 | Class ({0}) is not partial. | Warning | Types annotated with `ComponentStub` must be partial. | \ No newline at end of file diff --git a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs index eb73f442d..7e1fcd90a 100644 --- a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Text; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; @@ -49,6 +50,7 @@ private static StubClassInfo GetStubClassInfo(GeneratorAttributeSyntaxContext co var namespaceName = stubbedType.ContainingNamespace.ToDisplayString(); var className = context.TargetSymbol.Name; var visibility = context.TargetSymbol.DeclaredAccessibility.ToString().ToLower(); + var isPartial = ((ClassDeclarationSyntax)context.TargetNode).Modifiers.Any(SyntaxKind.PartialKeyword); var originalTypeToStub = attribute.AttributeClass?.TypeArguments.FirstOrDefault(); if (originalTypeToStub is null) @@ -61,7 +63,9 @@ private static StubClassInfo GetStubClassInfo(GeneratorAttributeSyntaxContext co ClassName = className, Namespace = namespaceName, TargetType = originalTypeToStub, - Visibility = visibility + Visibility = visibility, + IsNestedClass = context.TargetSymbol.ContainingType is not null, + IsPartial = isPartial, }; } @@ -70,6 +74,11 @@ private static StubClassInfo GetStubClassInfo(GeneratorAttributeSyntaxContext co private static void Execute(StubClassInfo classInfo, SourceProductionContext context) { + if (CheckDiagnostics(classInfo, context)) + { + return; + } + var hasSomethingToStub = false; var targetTypeSymbol = (INamedTypeSymbol)classInfo!.TargetType; var sourceBuilder = new StringBuilder(1000); @@ -97,11 +106,7 @@ private static void Execute(StubClassInfo classInfo, SourceProductionContext con var propertyType = member.Type.ToDisplayString(); var propertyName = member.Name; - var isParameterAttribute = member.GetAttributes().Any(attr => - attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.ParameterAttribute"); - var attributeLine = isParameterAttribute - ? "\t[global::Microsoft.AspNetCore.Components.Parameter]" - : "\t[global::Microsoft.AspNetCore.Components.CascadingParameter]"; + var attributeLine = GetAttributeLineForMember(member); sourceBuilder.AppendLine(attributeLine); sourceBuilder.AppendLine($"\tpublic {propertyType} {propertyName} {{ get; set; }} = default!;"); @@ -113,6 +118,45 @@ private static void Execute(StubClassInfo classInfo, SourceProductionContext con { context.AddSource($"{classInfo.ClassName}.g.cs", sourceBuilder.ToString()); } + + static string GetAttributeLineForMember(ISymbol member) + { + var isParameterAttribute = member.GetAttributes().Any(attr => + attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.ParameterAttribute"); + var attributeLine = isParameterAttribute + ? "\t[global::Microsoft.AspNetCore.Components.Parameter]" + : "\t[global::Microsoft.AspNetCore.Components.CascadingParameter]"; + return attributeLine; + } + } + + private static bool CheckDiagnostics(StubClassInfo classInfo, SourceProductionContext context) + { + if (classInfo.IsNestedClass) + { + context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor( + "BUNIT0001", + "Stubbing nested classes is not supported", + "Stubbing nested classes ({0}) is not supported.", + "Bunit", DiagnosticSeverity.Warning, true), + Location.None, + classInfo.TargetType.ToDisplayString())); + return true; + } + + if (!classInfo.IsPartial) + { + context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor( + "BUNIT0002", + "Stubbing non-partial classes is not supported", + "Class ({0}) is not partial.", + "Bunit", DiagnosticSeverity.Warning, true), + Location.None, + classInfo.TargetType.ToDisplayString())); + return true; + } + + return false; } } @@ -122,4 +166,6 @@ internal sealed class StubClassInfo public string Namespace { get; set; } public ITypeSymbol TargetType { get; set; } public string Visibility { get; set; } + public bool IsNestedClass { get; set; } + public bool IsPartial { get; set; } } diff --git a/tests/bunit.generators.tests/Web.Stub/AddStubGeneratorTests.cs b/tests/bunit.generators.tests/Web.Stub/AddStubGeneratorTests.cs index d9ed14f4b..df54ed6f2 100644 --- a/tests/bunit.generators.tests/Web.Stub/AddStubGeneratorTests.cs +++ b/tests/bunit.generators.tests/Web.Stub/AddStubGeneratorTests.cs @@ -64,6 +64,4 @@ public void Generated_stub_via_attribute_has_same_parameters() } [ComponentStub] -public partial class ButtonComponentStub -{ -} \ No newline at end of file +public partial class ButtonComponentStub; \ No newline at end of file From c8ba524447c3dae3d1a9dd0668397aa63c984fc4 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 5 Jan 2024 15:58:21 +0100 Subject: [PATCH 11/53] feat: add help url for diagnostics --- .../ComponentStubAttributeGenerator.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs index 7e1fcd90a..da97e8065 100644 --- a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs @@ -132,13 +132,17 @@ static string GetAttributeLineForMember(ISymbol member) private static bool CheckDiagnostics(StubClassInfo classInfo, SourceProductionContext context) { + const string helpUrl = "https://bunit.dev/docs/extensions/bunit-generators.html"; + if (classInfo.IsNestedClass) { context.ReportDiagnostic(Diagnostic.Create(new DiagnosticDescriptor( "BUNIT0001", "Stubbing nested classes is not supported", "Stubbing nested classes ({0}) is not supported.", - "Bunit", DiagnosticSeverity.Warning, true), + "Bunit", DiagnosticSeverity.Warning, + isEnabledByDefault: true, + helpLinkUri: helpUrl), Location.None, classInfo.TargetType.ToDisplayString())); return true; @@ -150,7 +154,9 @@ private static bool CheckDiagnostics(StubClassInfo classInfo, SourceProductionCo "BUNIT0002", "Stubbing non-partial classes is not supported", "Class ({0}) is not partial.", - "Bunit", DiagnosticSeverity.Warning, true), + "Bunit", DiagnosticSeverity.Warning, + isEnabledByDefault: true, + helpLinkUri: helpUrl), Location.None, classInfo.TargetType.ToDisplayString())); return true; From 53a2e5867d616d83c9c911d7accbdf218d4a33a9 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Mon, 8 Jan 2024 19:42:56 +0100 Subject: [PATCH 12/53] chore: Update packages --- benchmark/bunit.benchmarks/bunit.benchmarks.csproj | 4 ++-- tests/bunit.core.tests/bunit.core.tests.csproj | 2 +- tests/bunit.generators.tests/bunit.generators.tests.csproj | 4 ++-- tests/bunit.testassets/bunit.testassets.csproj | 4 ++-- tests/bunit.web.query.tests/bunit.web.query.tests.csproj | 2 +- tests/bunit.web.tests/Rendering/BunitHtmlParserTest.cs | 5 ++--- tests/bunit.web.tests/bunit.web.tests.csproj | 2 +- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/benchmark/bunit.benchmarks/bunit.benchmarks.csproj b/benchmark/bunit.benchmarks/bunit.benchmarks.csproj index 506c96889..ffeb33523 100644 --- a/benchmark/bunit.benchmarks/bunit.benchmarks.csproj +++ b/benchmark/bunit.benchmarks/bunit.benchmarks.csproj @@ -8,7 +8,7 @@ - + @@ -17,4 +17,4 @@ - \ No newline at end of file + diff --git a/tests/bunit.core.tests/bunit.core.tests.csproj b/tests/bunit.core.tests/bunit.core.tests.csproj index 613edf9b3..d0857fd3b 100644 --- a/tests/bunit.core.tests/bunit.core.tests.csproj +++ b/tests/bunit.core.tests/bunit.core.tests.csproj @@ -13,7 +13,7 @@ - + all diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index f0713d526..b782fc2ef 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + @@ -25,7 +25,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/tests/bunit.testassets/bunit.testassets.csproj b/tests/bunit.testassets/bunit.testassets.csproj index 2775be374..0ab17db61 100644 --- a/tests/bunit.testassets/bunit.testassets.csproj +++ b/tests/bunit.testassets/bunit.testassets.csproj @@ -16,9 +16,9 @@ - + - + diff --git a/tests/bunit.web.query.tests/bunit.web.query.tests.csproj b/tests/bunit.web.query.tests/bunit.web.query.tests.csproj index 8df6aadf4..c67d408f3 100644 --- a/tests/bunit.web.query.tests/bunit.web.query.tests.csproj +++ b/tests/bunit.web.query.tests/bunit.web.query.tests.csproj @@ -14,7 +14,7 @@ - + all diff --git a/tests/bunit.web.tests/Rendering/BunitHtmlParserTest.cs b/tests/bunit.web.tests/Rendering/BunitHtmlParserTest.cs index 6004ae3c1..3c33fb802 100644 --- a/tests/bunit.web.tests/Rendering/BunitHtmlParserTest.cs +++ b/tests/bunit.web.tests/Rendering/BunitHtmlParserTest.cs @@ -28,9 +28,8 @@ public class BunitHtmlParserTest // "frame","frameset","image","isindex" // not supported }; - public static readonly IEnumerable BodyHtmlAndSpecialElements = BodyHtmlElements - .Clone() - .AddRange("html", "head", "body"); + public static readonly IEnumerable BodyHtmlAndSpecialElements = + TheoryDataExtensions.AddRange(BodyHtmlElements.Clone(), "html", "head", "body"); public static readonly TheoryData SvgElements = new TheoryData { diff --git a/tests/bunit.web.tests/bunit.web.tests.csproj b/tests/bunit.web.tests/bunit.web.tests.csproj index 1355576b0..258a4cb85 100644 --- a/tests/bunit.web.tests/bunit.web.tests.csproj +++ b/tests/bunit.web.tests/bunit.web.tests.csproj @@ -13,7 +13,7 @@ - + all From 177fb2614d10052373ef183256b55c9a6a2d846c Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Mon, 8 Jan 2024 19:51:25 +0100 Subject: [PATCH 13/53] chore: Update Verify.Xunit --- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index b782fc2ef..332f36906 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + From 4929971effd624a8bedda78ed87c1e0e69a4c6d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:01:32 +0000 Subject: [PATCH 14/53] build(deps): Bump System.Text.Json from 8.0.0 to 8.0.1 Bumps [System.Text.Json](https://github.com/dotnet/runtime) from 8.0.0 to 8.0.1. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/commits) --- updated-dependencies: - dependency-name: System.Text.Json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- tests/bunit.testassets/bunit.testassets.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.testassets/bunit.testassets.csproj b/tests/bunit.testassets/bunit.testassets.csproj index 0ab17db61..ae48020c4 100644 --- a/tests/bunit.testassets/bunit.testassets.csproj +++ b/tests/bunit.testassets/bunit.testassets.csproj @@ -25,7 +25,7 @@ - + From 62bab18e1d7e1a513b682bc072a4205fd0bd3ea0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:44:25 +0000 Subject: [PATCH 15/53] build(deps): Bump Meziantou.Polyfill from 1.0.31 to 1.0.32 Bumps [Meziantou.Polyfill](https://github.com/meziantou/Meziantou.Polyfill) from 1.0.31 to 1.0.32. - [Commits](https://github.com/meziantou/Meziantou.Polyfill/commits) --- updated-dependencies: - dependency-name: Meziantou.Polyfill dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- src/bunit.generators.internal/bunit.generators.internal.csproj | 2 +- src/bunit.generators/bunit.generators.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bunit.generators.internal/bunit.generators.internal.csproj b/src/bunit.generators.internal/bunit.generators.internal.csproj index 07fc4bb5c..9436e10ab 100644 --- a/src/bunit.generators.internal/bunit.generators.internal.csproj +++ b/src/bunit.generators.internal/bunit.generators.internal.csproj @@ -21,7 +21,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers diff --git a/src/bunit.generators/bunit.generators.csproj b/src/bunit.generators/bunit.generators.csproj index 026e13df4..8f23cf244 100644 --- a/src/bunit.generators/bunit.generators.csproj +++ b/src/bunit.generators/bunit.generators.csproj @@ -75,7 +75,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers From ebdde9bb3c2f1936fd9c3c1bf8bba6357899ecff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:37:54 +0000 Subject: [PATCH 16/53] build(deps): Bump Verify.Xunit from 22.11.4 to 22.11.5 Bumps [Verify.Xunit](https://github.com/VerifyTests/Verify) from 22.11.4 to 22.11.5. - [Release notes](https://github.com/VerifyTests/Verify/releases) - [Commits](https://github.com/VerifyTests/Verify/compare/22.11.4...22.11.5) --- updated-dependencies: - dependency-name: Verify.Xunit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index 332f36906..d8162e9bf 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + From 5f6404463ee091069321c22a835f5701e74bf8a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jan 2024 15:51:42 +0000 Subject: [PATCH 17/53] build(deps): Bump docfx from 2.74.1 to 2.75.0 Bumps [docfx](https://github.com/dotnet/docfx) from 2.74.1 to 2.75.0. - [Release notes](https://github.com/dotnet/docfx/releases) - [Changelog](https://github.com/dotnet/docfx/blob/main/RELEASENOTE.md) - [Commits](https://github.com/dotnet/docfx/compare/v2.74.1...v2.75.0) --- updated-dependencies: - dependency-name: docfx dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 3003ce6c5..01917f084 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "docfx": { - "version": "2.74.1", + "version": "2.75.0", "commands": [ "docfx" ] From 604e98dec13259413cd3b3b0cc6e3a04aaadccb0 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 26 Jan 2024 15:52:38 +0100 Subject: [PATCH 18/53] Perf generators (#1357) * refactor: Use records for stub-generators * refactor: Avoid ISymbols due to caching * refactor: Centralize attribute generator --- .../AddStubGenerator.cs | 77 ++++++++++++++-- .../StubComponentBuilder.cs | 87 ------------------- .../Web.Stubs/AttributeLineGenerator.cs | 43 +++++++++ .../ComponentStubAttributeGenerator.cs | 70 ++++++++------- .../Web.Stub/Components/ButtonComponent.cs | 1 + 5 files changed, 157 insertions(+), 121 deletions(-) delete mode 100644 src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/StubComponentBuilder.cs create mode 100644 src/bunit.generators/Web.Stubs/AttributeLineGenerator.cs diff --git a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs index ae654b913..40e0574d3 100644 --- a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs @@ -59,11 +59,18 @@ private static AddStubClassInfo GetStubClassInfo(GeneratorSyntaxContext context) var line = lineSpan.StartLinePosition.Line + 1; var column = lineSpan.Span.Start.Character + context.Node.ToString().IndexOf("AddStub", StringComparison.Ordinal) + 1; + var properties = symbol.GetMembers() + .OfType() + .Where(IsParameterOrCascadingParameter) + .Select(CreateFromProperty) + .ToImmutableArray(); + return new AddStubClassInfo { StubClassName = $"{symbol.Name}Stub", TargetTypeNamespace = symbol.ContainingNamespace.ToDisplayString(), - TargetType = symbol, + TargetTypeName = symbol.ToDisplayString(), + Properties = properties, Path = path, Line = line, Column = column, @@ -89,6 +96,23 @@ static string GetInterceptorFilePath(SyntaxTree tree, Compilation compilation) { return compilation.Options.SourceReferenceResolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath; } + + static bool IsParameterOrCascadingParameter(ISymbol member) + { + return member.GetAttributes().Any(attr => + attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.ParameterAttribute" || + attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.CascadingParameterAttribute"); + } + + static StubPropertyInfo CreateFromProperty(IPropertySymbol member) + { + return new StubPropertyInfo + { + Name = member.Name, + Type = member.Type.ToDisplayString(), + AttributeLine = AttributeLineGenerator.GetAttributeLine(member), + }; + } } private static void Execute(ImmutableArray classInfos, SourceProductionContext context) @@ -96,7 +120,7 @@ private static void Execute(ImmutableArray classInfos, SourceP foreach (var stubClassGrouped in classInfos.GroupBy(c => c.UniqueQualifier)) { var stubbedComponentGroup = stubClassGrouped.First(); - var didStubComponent = StubComponentBuilder.GenerateStubComponent(stubbedComponentGroup, context); + var didStubComponent = GenerateStubComponent(stubbedComponentGroup, context); if (didStubComponent) { GenerateInterceptorCode(stubbedComponentGroup, stubClassGrouped, context); @@ -144,22 +168,65 @@ public InterceptsLocationAttribute(string filePath, int line, int column) interceptorSource.AppendLine("\t\t\twhere TComponent : global::Microsoft.AspNetCore.Components.IComponent"); interceptorSource.AppendLine("\t\t{"); interceptorSource.AppendLine( - $"\t\t\treturn factories.Add();"); + $"\t\t\treturn factories.Add();"); interceptorSource.AppendLine("\t\t}"); interceptorSource.AppendLine("\t}"); interceptorSource.AppendLine("}"); context.AddSource($"Interceptor{stubbedComponentGroup.StubClassName}.g.cs", interceptorSource.ToString()); } + + private static bool GenerateStubComponent(AddStubClassInfo classInfo, SourceProductionContext context) + { + var hasSomethingToStub = false; + var sourceBuilder = new StringBuilder(1000); + + sourceBuilder.AppendLine(HeaderProvider.Header); + sourceBuilder.AppendLine($"namespace {classInfo.TargetTypeNamespace};"); + sourceBuilder.AppendLine(); + sourceBuilder.AppendLine($"internal partial class {classInfo.StubClassName} : global::Microsoft.AspNetCore.Components.ComponentBase"); + sourceBuilder.Append("{"); + + foreach (var member in classInfo.Properties) + { + sourceBuilder.AppendLine(); + + hasSomethingToStub = true; + var propertyType = member.Type; + var propertyName = member.Name; + + var attributeLine = member.AttributeLine; + sourceBuilder.AppendLine(attributeLine); + + sourceBuilder.AppendLine($"\tpublic {propertyType} {propertyName} {{ get; set; }} = default!;"); + } + + sourceBuilder.AppendLine("}"); + + if (hasSomethingToStub) + { + context.AddSource($"{classInfo.StubClassName}.g.cs", sourceBuilder.ToString()); + } + + return hasSomethingToStub; + } } -internal sealed class AddStubClassInfo +internal sealed record AddStubClassInfo { public string StubClassName { get; set; } public string TargetTypeNamespace { get; set; } + public string TargetTypeName { get; set; } public string UniqueQualifier => $"{TargetTypeNamespace}.{StubClassName}"; - public ITypeSymbol TargetType { get; set; } + public ImmutableArray Properties { get; set; } = ImmutableArray.Empty; public string Path { get; set; } public int Line { get; set; } public int Column { get; set; } } + +internal sealed record StubPropertyInfo +{ + public string Name { get; set; } + public string Type { get; set; } + public string AttributeLine { get; set; } +} diff --git a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/StubComponentBuilder.cs b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/StubComponentBuilder.cs deleted file mode 100644 index b65e9f42f..000000000 --- a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/StubComponentBuilder.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.Linq; -using System.Text; -using Microsoft.CodeAnalysis; - -namespace Bunit.Web.Stubs.AddStubMethodStubGenerator; - -internal static class StubComponentBuilder -{ - private const string CascadingParameterAttributeQualifier = "Microsoft.AspNetCore.Components.CascadingParameterAttribute"; - private const string ParameterAttributeQualifier = "Microsoft.AspNetCore.Components.ParameterAttribute"; - - public static bool GenerateStubComponent(AddStubClassInfo classInfo, SourceProductionContext context) - { - var hasSomethingToStub = false; - var targetTypeSymbol = (INamedTypeSymbol)classInfo!.TargetType; - var sourceBuilder = new StringBuilder(1000); - - sourceBuilder.AppendLine(HeaderProvider.Header); - sourceBuilder.AppendLine($"namespace {classInfo.TargetTypeNamespace};"); - sourceBuilder.AppendLine(); - sourceBuilder.AppendLine($"internal partial class {classInfo.StubClassName} : global::Microsoft.AspNetCore.Components.ComponentBase"); - sourceBuilder.Append("{"); - - foreach (var member in targetTypeSymbol - .GetMembers() - .OfType() - .Where(p => p.GetAttributes() - .Any(attr => - attr.AttributeClass?.ToDisplayString() == - ParameterAttributeQualifier || - attr.AttributeClass?.ToDisplayString() == - CascadingParameterAttributeQualifier))) - { - sourceBuilder.AppendLine(); - - hasSomethingToStub = true; - var propertyType = member.Type.ToDisplayString(); - var propertyName = member.Name; - - var attributeLine = GetAttributeLine(member); - sourceBuilder.AppendLine(attributeLine); - - sourceBuilder.AppendLine($"\tpublic {propertyType} {propertyName} {{ get; set; }} = default!;"); - } - - sourceBuilder.AppendLine("}"); - - if (hasSomethingToStub) - { - context.AddSource($"{classInfo.StubClassName}.g.cs", sourceBuilder.ToString()); - } - - return hasSomethingToStub; - - string GetAttributeLine(ISymbol member) - { - var attribute = member.GetAttributes().First(attr => - attr.AttributeClass?.ToDisplayString() == ParameterAttributeQualifier || - attr.AttributeClass?.ToDisplayString() == CascadingParameterAttributeQualifier); - - var attributeLine = new StringBuilder("\t["); - if (attribute.AttributeClass?.ToDisplayString() == ParameterAttributeQualifier) - { - attributeLine.Append($"global::{ParameterAttributeQualifier}"); - var captureUnmatchedValuesArg = attribute.NamedArguments - .FirstOrDefault(arg => arg.Key == "CaptureUnmatchedValues").Value; - if (captureUnmatchedValuesArg.Value is bool captureUnmatchedValues) - { - var captureString = captureUnmatchedValues ? "true" : "false"; - attributeLine.Append($"(CaptureUnmatchedValues = {captureString})"); - } - } - else if (attribute.AttributeClass?.ToDisplayString() == CascadingParameterAttributeQualifier) - { - attributeLine.Append($"global::{CascadingParameterAttributeQualifier}"); - var nameArg = attribute.NamedArguments.FirstOrDefault(arg => arg.Key == "Name").Value; - if (!nameArg.IsNull) - { - attributeLine.Append($"(Name = \"{nameArg.Value}\")"); - } - } - - attributeLine.Append("]"); - return attributeLine.ToString(); - } - } -} diff --git a/src/bunit.generators/Web.Stubs/AttributeLineGenerator.cs b/src/bunit.generators/Web.Stubs/AttributeLineGenerator.cs new file mode 100644 index 000000000..8c69433e0 --- /dev/null +++ b/src/bunit.generators/Web.Stubs/AttributeLineGenerator.cs @@ -0,0 +1,43 @@ +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; + +namespace Bunit.Web.Stubs; + +internal static class AttributeLineGenerator +{ + private const string CascadingParameterAttributeQualifier = "Microsoft.AspNetCore.Components.CascadingParameterAttribute"; + private const string ParameterAttributeQualifier = "Microsoft.AspNetCore.Components.ParameterAttribute"; + + public static string GetAttributeLine(ISymbol member) + { + var attribute = member.GetAttributes().First(attr => + attr.AttributeClass?.ToDisplayString() == ParameterAttributeQualifier || + attr.AttributeClass?.ToDisplayString() == CascadingParameterAttributeQualifier); + + var attributeLine = new StringBuilder("\t["); + if (attribute.AttributeClass?.ToDisplayString() == ParameterAttributeQualifier) + { + attributeLine.Append($"global::{ParameterAttributeQualifier}"); + var captureUnmatchedValuesArg = attribute.NamedArguments + .FirstOrDefault(arg => arg.Key == "CaptureUnmatchedValues").Value; + if (captureUnmatchedValuesArg.Value is bool captureUnmatchedValues) + { + var captureString = captureUnmatchedValues ? "true" : "false"; + attributeLine.Append($"(CaptureUnmatchedValues = {captureString})"); + } + } + else if (attribute.AttributeClass?.ToDisplayString() == CascadingParameterAttributeQualifier) + { + attributeLine.Append($"global::{CascadingParameterAttributeQualifier}"); + var nameArg = attribute.NamedArguments.FirstOrDefault(arg => arg.Key == "Name").Value; + if (!nameArg.IsNull) + { + attributeLine.Append($"(Name = \"{nameArg.Value}\")"); + } + } + + attributeLine.Append("]"); + return attributeLine.ToString(); + } +} diff --git a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs index da97e8065..214c87f5c 100644 --- a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; @@ -58,18 +59,42 @@ private static StubClassInfo GetStubClassInfo(GeneratorAttributeSyntaxContext co continue; } + var parameter = attribute.AttributeClass!.TypeArguments + .SelectMany(s => s.GetMembers()) + .OfType() + .Where(IsParameterOrCascadingParameter) + .Select(CreateFromProperty) + .ToImmutableArray(); + return new StubClassInfo { ClassName = className, Namespace = namespaceName, - TargetType = originalTypeToStub, Visibility = visibility, IsNestedClass = context.TargetSymbol.ContainingType is not null, IsPartial = isPartial, + Properties = parameter, }; } return null; + + static bool IsParameterOrCascadingParameter(ISymbol member) + { + return member.GetAttributes().Any(attr => + attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.ParameterAttribute" || + attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.CascadingParameterAttribute"); + } + + static StubPropertyInfo CreateFromProperty(IPropertySymbol member) + { + return new StubPropertyInfo + { + Name = member.Name, + Type = member.Type.ToDisplayString(), + AttributeLine = AttributeLineGenerator.GetAttributeLine(member), + }; + } } private static void Execute(StubClassInfo classInfo, SourceProductionContext context) @@ -80,7 +105,6 @@ private static void Execute(StubClassInfo classInfo, SourceProductionContext con } var hasSomethingToStub = false; - var targetTypeSymbol = (INamedTypeSymbol)classInfo!.TargetType; var sourceBuilder = new StringBuilder(1000); sourceBuilder.AppendLine(HeaderProvider.Header); @@ -90,25 +114,15 @@ private static void Execute(StubClassInfo classInfo, SourceProductionContext con $"{classInfo.Visibility} partial class {classInfo.ClassName} : global::Microsoft.AspNetCore.Components.ComponentBase"); sourceBuilder.Append("{"); - foreach (var member in targetTypeSymbol - .GetMembers() - .OfType() - .Where(p => p.GetAttributes() - .Any(attr => - attr.AttributeClass?.ToDisplayString() == - "Microsoft.AspNetCore.Components.ParameterAttribute" || - attr.AttributeClass?.ToDisplayString() == - "Microsoft.AspNetCore.Components.CascadingParameterAttribute"))) + foreach (var member in classInfo.Properties) { sourceBuilder.AppendLine(); hasSomethingToStub = true; - var propertyType = member.Type.ToDisplayString(); + var propertyType = member.Type; var propertyName = member.Name; - var attributeLine = GetAttributeLineForMember(member); - - sourceBuilder.AppendLine(attributeLine); + sourceBuilder.AppendLine(member.AttributeLine); sourceBuilder.AppendLine($"\tpublic {propertyType} {propertyName} {{ get; set; }} = default!;"); } @@ -118,16 +132,6 @@ private static void Execute(StubClassInfo classInfo, SourceProductionContext con { context.AddSource($"{classInfo.ClassName}.g.cs", sourceBuilder.ToString()); } - - static string GetAttributeLineForMember(ISymbol member) - { - var isParameterAttribute = member.GetAttributes().Any(attr => - attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.ParameterAttribute"); - var attributeLine = isParameterAttribute - ? "\t[global::Microsoft.AspNetCore.Components.Parameter]" - : "\t[global::Microsoft.AspNetCore.Components.CascadingParameter]"; - return attributeLine; - } } private static bool CheckDiagnostics(StubClassInfo classInfo, SourceProductionContext context) @@ -144,7 +148,7 @@ private static bool CheckDiagnostics(StubClassInfo classInfo, SourceProductionCo isEnabledByDefault: true, helpLinkUri: helpUrl), Location.None, - classInfo.TargetType.ToDisplayString())); + classInfo.ClassName)); return true; } @@ -158,7 +162,7 @@ private static bool CheckDiagnostics(StubClassInfo classInfo, SourceProductionCo isEnabledByDefault: true, helpLinkUri: helpUrl), Location.None, - classInfo.TargetType.ToDisplayString())); + classInfo.ClassName)); return true; } @@ -166,12 +170,20 @@ private static bool CheckDiagnostics(StubClassInfo classInfo, SourceProductionCo } } -internal sealed class StubClassInfo +internal sealed record StubClassInfo { public string ClassName { get; set; } public string Namespace { get; set; } - public ITypeSymbol TargetType { get; set; } + public ImmutableArray Properties { get; set; } = ImmutableArray.Empty; public string Visibility { get; set; } public bool IsNestedClass { get; set; } public bool IsPartial { get; set; } } + +internal sealed record StubPropertyInfo +{ + public string Name { get; set; } + public string Type { get; set; } + public string AttributeLine { get; set; } +} + diff --git a/tests/bunit.generators.tests/Web.Stub/Components/ButtonComponent.cs b/tests/bunit.generators.tests/Web.Stub/Components/ButtonComponent.cs index 9ff0e7ac8..e338ad709 100644 --- a/tests/bunit.generators.tests/Web.Stub/Components/ButtonComponent.cs +++ b/tests/bunit.generators.tests/Web.Stub/Components/ButtonComponent.cs @@ -7,5 +7,6 @@ public class ButtonComponent : ComponentBase { [Parameter] public string Text { get; set; } [Parameter] public EventCallback OnClick { get; set; } + [CascadingParameter(Name = "Test")] public string Cascading { get; set; } [Required] public string Unused { get; set; } } From 0fb7d2f906cf579224b3dbb493f96f6fc10a0b41 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 26 Jan 2024 16:12:56 +0100 Subject: [PATCH 19/53] fix: Remove flakiness from DisposeComponents test --- .../bunit.core.tests/TestContextBaseTest.net5.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/bunit.core.tests/TestContextBaseTest.net5.cs b/tests/bunit.core.tests/TestContextBaseTest.net5.cs index 7d7b58225..8734977d7 100644 --- a/tests/bunit.core.tests/TestContextBaseTest.net5.cs +++ b/tests/bunit.core.tests/TestContextBaseTest.net5.cs @@ -50,12 +50,16 @@ public void Test0003() [Fact(DisplayName = "DisposeComponents captures exceptions from DisposeAsync in Renderer.UnhandledException")] public async Task Test201() { - RenderComponent(); + var tcs = new TaskCompletionSource(); + var expected = new NotSupportedException(); + RenderComponent( + ps => ps.Add(p => p.DisposedTask, tcs.Task)); DisposeComponents(); - var exception = await Renderer.UnhandledException; - exception.ShouldBeOfType(); + tcs.SetException(expected); + var actual = await Renderer.UnhandledException; + actual.ShouldBeSameAs(expected); } [Fact(DisplayName = "DisposeComponents calls DisposeAsync on rendered components")] @@ -140,10 +144,12 @@ public void Dispose() private sealed class AsyncThrowExceptionComponent : ComponentBase, IAsyncDisposable { + [Parameter] + public Task DisposedTask { get; set; } + public async ValueTask DisposeAsync() { - await Task.Delay(30); - throw new NotSupportedException(); + await DisposedTask; } } From a702beadeb38093b869113de3776d059f21daaff Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 26 Jan 2024 16:18:06 +0100 Subject: [PATCH 20/53] chore: Bump Packages --- Directory.Build.props | 2 +- .../bunit.generators.internal.csproj | 2 +- src/bunit.generators/bunit.generators.csproj | 2 +- tests/bunit.core.tests/bunit.core.tests.csproj | 2 +- tests/bunit.generators.tests/bunit.generators.tests.csproj | 4 ++-- tests/bunit.testassets/bunit.testassets.csproj | 4 ++-- tests/bunit.web.query.tests/bunit.web.query.tests.csproj | 2 +- tests/bunit.web.tests/bunit.web.tests.csproj | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index f973e1df9..c5ca4d6f4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -51,7 +51,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers diff --git a/src/bunit.generators/bunit.generators.csproj b/src/bunit.generators/bunit.generators.csproj index 8f23cf244..d2dc52496 100644 --- a/src/bunit.generators/bunit.generators.csproj +++ b/src/bunit.generators/bunit.generators.csproj @@ -75,7 +75,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers diff --git a/tests/bunit.core.tests/bunit.core.tests.csproj b/tests/bunit.core.tests/bunit.core.tests.csproj index d0857fd3b..ee364e456 100644 --- a/tests/bunit.core.tests/bunit.core.tests.csproj +++ b/tests/bunit.core.tests/bunit.core.tests.csproj @@ -13,7 +13,7 @@ - + all diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index d8162e9bf..8050d754d 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + @@ -25,7 +25,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/tests/bunit.testassets/bunit.testassets.csproj b/tests/bunit.testassets/bunit.testassets.csproj index ae48020c4..eb1d22ce3 100644 --- a/tests/bunit.testassets/bunit.testassets.csproj +++ b/tests/bunit.testassets/bunit.testassets.csproj @@ -16,9 +16,9 @@ - + - + diff --git a/tests/bunit.web.query.tests/bunit.web.query.tests.csproj b/tests/bunit.web.query.tests/bunit.web.query.tests.csproj index c67d408f3..e10987eef 100644 --- a/tests/bunit.web.query.tests/bunit.web.query.tests.csproj +++ b/tests/bunit.web.query.tests/bunit.web.query.tests.csproj @@ -14,7 +14,7 @@ - + all diff --git a/tests/bunit.web.tests/bunit.web.tests.csproj b/tests/bunit.web.tests/bunit.web.tests.csproj index 258a4cb85..032f62692 100644 --- a/tests/bunit.web.tests/bunit.web.tests.csproj +++ b/tests/bunit.web.tests/bunit.web.tests.csproj @@ -13,7 +13,7 @@ - + all From cdfbad724c256badf0e9ac1d7c47bb9279eadf7c Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 26 Jan 2024 16:31:27 +0100 Subject: [PATCH 21/53] fix: Remove obsolete attribute --- .../Web.AngleSharp/WrapperElementsGeneratorTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/bunit.generators.tests/Web.AngleSharp/WrapperElementsGeneratorTest.cs b/tests/bunit.generators.tests/Web.AngleSharp/WrapperElementsGeneratorTest.cs index 61dbb3a2c..cb9ef0eab 100644 --- a/tests/bunit.generators.tests/Web.AngleSharp/WrapperElementsGeneratorTest.cs +++ b/tests/bunit.generators.tests/Web.AngleSharp/WrapperElementsGeneratorTest.cs @@ -5,7 +5,6 @@ namespace Bunit.Web.AngleSharp; -[UsesVerify] public class WrapperElementsGeneratorTest { [Fact] From df0c3bba27b0ba7f77be85e357ad3f07a3c98433 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 15:17:23 +0000 Subject: [PATCH 22/53] build(deps): Bump docfx from 2.75.0 to 2.75.1 Bumps [docfx](https://github.com/dotnet/docfx) from 2.75.0 to 2.75.1. - [Release notes](https://github.com/dotnet/docfx/releases) - [Changelog](https://github.com/dotnet/docfx/blob/main/RELEASENOTE.md) - [Commits](https://github.com/dotnet/docfx/compare/v2.75.0...v2.75.1) --- updated-dependencies: - dependency-name: docfx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 01917f084..3fd61e106 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "docfx": { - "version": "2.75.0", + "version": "2.75.1", "commands": [ "docfx" ] From 4b8adc068336d226548d94548c01baa898cda015 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jan 2024 15:29:59 +0000 Subject: [PATCH 23/53] build(deps): Bump actions/dependency-review-action from 3 to 4 Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 3 to 4. - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c84ee234..c8b031dac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -245,7 +245,7 @@ jobs: - name: 'Checkout Repository' uses: actions/checkout@v4 - name: 'Dependency Review' - uses: actions/dependency-review-action@v3 + uses: actions/dependency-review-action@v4 release-preview: if: github.event_name == 'workflow_dispatch' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/v2') From 5d4e35fb62dad89dc40ab4fb66ba4b332fcec983 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:25:59 +0000 Subject: [PATCH 24/53] build(deps): Bump SonarAnalyzer.CSharp from 9.18.0.83559 to 9.19.0.84025 Bumps [SonarAnalyzer.CSharp](https://github.com/SonarSource/sonar-dotnet) from 9.18.0.83559 to 9.19.0.84025. - [Release notes](https://github.com/SonarSource/sonar-dotnet/releases) - [Commits](https://github.com/SonarSource/sonar-dotnet/compare/9.18.0.83559...9.19.0.84025) --- updated-dependencies: - dependency-name: SonarAnalyzer.CSharp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index c5ca4d6f4..aeb8358d6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -51,7 +51,7 @@ - + Date: Mon, 29 Jan 2024 15:25:14 +0000 Subject: [PATCH 25/53] build(deps): Bump dotnet/nbgv from 0.4.1 to 0.4.2 Bumps [dotnet/nbgv](https://github.com/dotnet/nbgv) from 0.4.1 to 0.4.2. - [Release notes](https://github.com/dotnet/nbgv/releases) - [Commits](https://github.com/dotnet/nbgv/compare/v0.4.1...v0.4.2) --- updated-dependencies: - dependency-name: dotnet/nbgv dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 6 +++--- .github/workflows/docs-deploy.yml | 2 +- .github/workflows/prepare-release.yml | 2 +- .github/workflows/release.yml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8b031dac..41e2529de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: 8.0.x - name: ⚙️ Setup GIT versioning - uses: dotnet/nbgv@v0.4.1 + uses: dotnet/nbgv@v0.4.2 with: setAllVars: true @@ -163,7 +163,7 @@ jobs: path: ${{ env.NUGET_DIRECTORY }} - name: ⚙️ Setup GIT versioning - uses: dotnet/nbgv@v0.4.1 + uses: dotnet/nbgv@v0.4.2 with: setAllVars: true @@ -211,7 +211,7 @@ jobs: 8.0.x - name: ⚙️ Setup GIT versioning - uses: dotnet/nbgv@v0.4.1 + uses: dotnet/nbgv@v0.4.2 with: setAllVars: true diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index a70c1844c..15d36e299 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -50,7 +50,7 @@ jobs: git config --global commit.gpgsign true - name: ⚙️ Setup GIT versioning - uses: dotnet/nbgv@v0.4.1 + uses: dotnet/nbgv@v0.4.2 with: setAllVars: true diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index e51ef4796..2c1aa0bd2 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -49,7 +49,7 @@ jobs: git config --global commit.gpgsign true - name: ⚙️ Setup GIT versioning - uses: dotnet/nbgv@v0.4.1 + uses: dotnet/nbgv@v0.4.2 with: setAllVars: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0c0bc702c..7ec265456 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: git config --global commit.gpgsign true - name: ⚙️ Setup GIT versioning - uses: dotnet/nbgv@v0.4.1 + uses: dotnet/nbgv@v0.4.2 with: setAllVars: true From 77e8c54ed3a2034f25527ffe9e23ad6a8658ca04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Jan 2024 15:14:14 +0000 Subject: [PATCH 26/53] build(deps): Bump docfx from 2.75.1 to 2.75.2 Bumps [docfx](https://github.com/dotnet/docfx) from 2.75.1 to 2.75.2. - [Release notes](https://github.com/dotnet/docfx/releases) - [Changelog](https://github.com/dotnet/docfx/blob/main/RELEASENOTE.md) - [Commits](https://github.com/dotnet/docfx/compare/v2.75.1...v2.75.2) --- updated-dependencies: - dependency-name: docfx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 3fd61e106..4009280ee 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "docfx": { - "version": "2.75.1", + "version": "2.75.2", "commands": [ "docfx" ] From 2722acaecd420283fff54a20571330747aa151f0 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Sun, 4 Feb 2024 16:51:01 +0100 Subject: [PATCH 27/53] feat: Enable support for SupplyFrom cascading attributes --- .../AddStubGenerator.cs | 4 +- .../Web.Stubs/AttributeLineGenerator.cs | 47 +++++++++++++++---- .../ComponentStubAttributeGenerator.cs | 4 +- .../Web.Stubs/SupportedAttributes.cs | 17 +++++++ 4 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 src/bunit.generators/Web.Stubs/SupportedAttributes.cs diff --git a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs index 40e0574d3..907dd6e78 100644 --- a/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AddStubMethodStubGenerator/AddStubGenerator.cs @@ -99,9 +99,7 @@ static string GetInterceptorFilePath(SyntaxTree tree, Compilation compilation) static bool IsParameterOrCascadingParameter(ISymbol member) { - return member.GetAttributes().Any(attr => - attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.ParameterAttribute" || - attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.CascadingParameterAttribute"); + return member.GetAttributes().Any(SupportedAttributes.IsSupportedAttribute); } static StubPropertyInfo CreateFromProperty(IPropertySymbol member) diff --git a/src/bunit.generators/Web.Stubs/AttributeLineGenerator.cs b/src/bunit.generators/Web.Stubs/AttributeLineGenerator.cs index 8c69433e0..8185929a2 100644 --- a/src/bunit.generators/Web.Stubs/AttributeLineGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AttributeLineGenerator.cs @@ -6,19 +6,14 @@ namespace Bunit.Web.Stubs; internal static class AttributeLineGenerator { - private const string CascadingParameterAttributeQualifier = "Microsoft.AspNetCore.Components.CascadingParameterAttribute"; - private const string ParameterAttributeQualifier = "Microsoft.AspNetCore.Components.ParameterAttribute"; - public static string GetAttributeLine(ISymbol member) { - var attribute = member.GetAttributes().First(attr => - attr.AttributeClass?.ToDisplayString() == ParameterAttributeQualifier || - attr.AttributeClass?.ToDisplayString() == CascadingParameterAttributeQualifier); + var attribute = member.GetAttributes().First(SupportedAttributes.IsSupportedAttribute); var attributeLine = new StringBuilder("\t["); - if (attribute.AttributeClass?.ToDisplayString() == ParameterAttributeQualifier) + if (attribute.AttributeClass?.ToDisplayString() == SupportedAttributes.ParameterAttributeQualifier) { - attributeLine.Append($"global::{ParameterAttributeQualifier}"); + attributeLine.Append($"global::{SupportedAttributes.ParameterAttributeQualifier}"); var captureUnmatchedValuesArg = attribute.NamedArguments .FirstOrDefault(arg => arg.Key == "CaptureUnmatchedValues").Value; if (captureUnmatchedValuesArg.Value is bool captureUnmatchedValues) @@ -27,9 +22,41 @@ public static string GetAttributeLine(ISymbol member) attributeLine.Append($"(CaptureUnmatchedValues = {captureString})"); } } - else if (attribute.AttributeClass?.ToDisplayString() == CascadingParameterAttributeQualifier) + else if (attribute.AttributeClass?.ToDisplayString() == SupportedAttributes.CascadingParameterAttributeQualifier) + { + attributeLine.Append($"global::{SupportedAttributes.CascadingParameterAttributeQualifier}"); + var nameArg = attribute.NamedArguments.FirstOrDefault(arg => arg.Key == "Name").Value; + if (!nameArg.IsNull) + { + attributeLine.Append($"(Name = \"{nameArg.Value}\")"); + } + } + else if (attribute.AttributeClass?.ToDisplayString() == SupportedAttributes.SupplyParameterFromQueryAttributeQualifier) + { + attributeLine.Append($"global::{SupportedAttributes.SupplyParameterFromQueryAttributeQualifier}"); + var nameArg = attribute.NamedArguments.FirstOrDefault(arg => arg.Key == "Name").Value; + if (!nameArg.IsNull) + { + attributeLine.Append($"(Name = \"{nameArg.Value}\")"); + } + } + else if (attribute.AttributeClass?.ToDisplayString() == SupportedAttributes.SupplyParameterFromFormAttributeQualifier) + { + attributeLine.Append($"global::{SupportedAttributes.SupplyParameterFromFormAttributeQualifier}"); + var nameArg = attribute.NamedArguments.FirstOrDefault(arg => arg.Key == "Name").Value; + if (!nameArg.IsNull) + { + attributeLine.Append($"(Name = \"{nameArg.Value}\")"); + } + var formNameArg = attribute.NamedArguments.FirstOrDefault(arg => arg.Key == "FormName").Value; + if (!formNameArg.IsNull) + { + attributeLine.Append($", (FormName = \"{formNameArg.Value}\")"); + } + } + else if (attribute.AttributeClass?.ToDisplayString() == SupportedAttributes.SupplyParameterFromQueryAttributeQualifier) { - attributeLine.Append($"global::{CascadingParameterAttributeQualifier}"); + attributeLine.Append($"global::{SupportedAttributes.SupplyParameterFromQueryAttributeQualifier}"); var nameArg = attribute.NamedArguments.FirstOrDefault(arg => arg.Key == "Name").Value; if (!nameArg.IsNull) { diff --git a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs index 214c87f5c..df91cc095 100644 --- a/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs +++ b/src/bunit.generators/Web.Stubs/AttributeStubGenerator/ComponentStubAttributeGenerator.cs @@ -81,9 +81,7 @@ private static StubClassInfo GetStubClassInfo(GeneratorAttributeSyntaxContext co static bool IsParameterOrCascadingParameter(ISymbol member) { - return member.GetAttributes().Any(attr => - attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.ParameterAttribute" || - attr.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.Components.CascadingParameterAttribute"); + return member.GetAttributes().Any(SupportedAttributes.IsSupportedAttribute); } static StubPropertyInfo CreateFromProperty(IPropertySymbol member) diff --git a/src/bunit.generators/Web.Stubs/SupportedAttributes.cs b/src/bunit.generators/Web.Stubs/SupportedAttributes.cs new file mode 100644 index 000000000..b50e2f767 --- /dev/null +++ b/src/bunit.generators/Web.Stubs/SupportedAttributes.cs @@ -0,0 +1,17 @@ +using Microsoft.CodeAnalysis; + +namespace Bunit.Web.Stubs; + +internal static class SupportedAttributes +{ + public const string CascadingParameterAttributeQualifier = "Microsoft.AspNetCore.Components.CascadingParameterAttribute"; + public const string ParameterAttributeQualifier = "Microsoft.AspNetCore.Components.ParameterAttribute"; + public const string SupplyParameterFromQueryAttributeQualifier = "Microsoft.AspNetCore.Components.SupplyParameterFromQueryAttribute"; + public const string SupplyParameterFromFormAttributeQualifier = "Microsoft.AspNetCore.Components.SupplyParameterFromFormAttribute"; + + public static bool IsSupportedAttribute(AttributeData attribute) + { + var displayString = attribute.AttributeClass?.ToDisplayString(); + return displayString is ParameterAttributeQualifier or CascadingParameterAttributeQualifier or SupplyParameterFromQueryAttributeQualifier or SupplyParameterFromFormAttributeQualifier; + } +} From 9126213ab72cf0830c3a105be750a81e63d81bff Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Sat, 3 Feb 2024 15:45:29 +0100 Subject: [PATCH 28/53] docs: Fix links and formatting --- docs/site/docs/test-doubles/mocking-localizer.md | 6 +++++- docs/site/docs/toc.md | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/site/docs/test-doubles/mocking-localizer.md b/docs/site/docs/test-doubles/mocking-localizer.md index ab93f0500..4a6dbbbde 100644 --- a/docs/site/docs/test-doubles/mocking-localizer.md +++ b/docs/site/docs/test-doubles/mocking-localizer.md @@ -4,11 +4,15 @@ title: Mocking Localization via IStringLocalizer ---

There are just two steps. First in your setup add the following:

+ ```csharp TestContext.Services.AddLocalization(); ``` +

Then in your test code, when you need the localized string to compare, you write the following:

+ ```csharp var localizer = ctx.Services.GetService>(); - ``` +``` +

Where SharedStrings.cs (you can name this anything you want) that has the resource files such as `SharedStrings.en.resx`

diff --git a/docs/site/docs/toc.md b/docs/site/docs/toc.md index 09fdb5a18..327afde06 100644 --- a/docs/site/docs/toc.md +++ b/docs/site/docs/toc.md @@ -25,6 +25,7 @@ ## [Emulating IJSRuntime](xref:emulating-ijsruntime) ## [Faking authorization](xref:faking-auth) ## [Mocking HttpClient](xref:mocking-httpclient) +## [Mocking Localizer](xref:mocking-localizer) ## [Faking PersistentComponentState](xref:faking-persistentcomponentstate) ## [Faking NavigationManager](xref:fake-navigation-manager) ## [Faking IWebAssemblyHostEnvironment](xref:fake-webassemblyhostenvironment) From e69f7171b6494f24ed442f739e6ce6d7c6ce2645 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 15:20:00 +0000 Subject: [PATCH 29/53] build(deps): Bump Verify.Xunit from 23.0.1 to 23.1.0 Bumps [Verify.Xunit](https://github.com/VerifyTests/Verify) from 23.0.1 to 23.1.0. - [Release notes](https://github.com/VerifyTests/Verify/releases) - [Commits](https://github.com/VerifyTests/Verify/compare/23.0.1...23.1.0) --- updated-dependencies: - dependency-name: Verify.Xunit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index 8050d754d..3e1f40dd8 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + From ac0b0b72cffe8407d3d959804e6f06ab8da6303f Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Wed, 7 Feb 2024 16:50:04 +0100 Subject: [PATCH 30/53] chore: Bump version and remove redundant project reference --- src/bunit.template/template/Company.BlazorTests1.csproj | 2 +- tests/Directory.Build.props | 2 +- tests/bunit.generators.tests/bunit.generators.tests.csproj | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bunit.template/template/Company.BlazorTests1.csproj b/src/bunit.template/template/Company.BlazorTests1.csproj index 34d70d70d..ae8decb6e 100644 --- a/src/bunit.template/template/Company.BlazorTests1.csproj +++ b/src/bunit.template/template/Company.BlazorTests1.csproj @@ -17,7 +17,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 1c6784b04..fad5b9744 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -17,7 +17,7 @@ - + diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index 3e1f40dd8..ac5c8a94a 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -13,7 +13,6 @@ - From 27f8bb6c2317480a94e883f26dfd085cb44ed546 Mon Sep 17 00:00:00 2001 From: Egil Hansen Date: Tue, 13 Feb 2024 09:31:02 +0000 Subject: [PATCH 31/53] ci: remove blame from test runs --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41e2529de..154c35a14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,7 +134,7 @@ jobs: 8.0.x - name: 🧪 Run unit tests - run: dotnet test -c release --blame --blame-crash --blame-hang + run: dotnet test -c release - name: 📛 Upload hang- and crash-dumps on test failure if: failure() From e2597955279a410f1ef1659c8fcd6d484a19b23f Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Wed, 14 Feb 2024 11:37:11 +0100 Subject: [PATCH 32/53] feat: Added support for keyed services (#1374) --- .github/workflows/ci.yml | 4 +- CHANGELOG.md | 3 ++ src/bunit.core/TestServiceProvider.cs | 33 +++++++++++++++ tests/.editorconfig | 1 + .../TestServiceProviderTest.cs | 42 +++++++++++++++++++ .../bunit.generators.tests.csproj | 7 ++-- 6 files changed, 85 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 154c35a14..a80cc4156 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,7 +109,7 @@ jobs: - name: Validate package shell: pwsh run: meziantou.validate-nuget-package (Get-ChildItem "${{ env.NUGET_DIRECTORY }}/*.nupkg") --excluded-rules IconMustBeSet - + run-test: strategy: fail-fast: false @@ -134,7 +134,7 @@ jobs: 8.0.x - name: 🧪 Run unit tests - run: dotnet test -c release + run: dotnet test -c release --blame --blame-crash --blame-hang - name: 📛 Upload hang- and crash-dumps on test failure if: failure() diff --git a/CHANGELOG.md b/CHANGELOG.md index a339ea270..cdcd9f79e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ All notable changes to **bUnit** will be documented in this file. The project ad ## [Unreleased] +### Added +- Support for `IKeyedServiceProvider` in net8.0. Reported by [@ViRuSTriNiTy](https://github.com/ViRuSTriNiTy). By [@linkdotnet](https://github.com/linkdotnet). + ## [1.26.64] - 2023-12-20 ### Changed diff --git a/src/bunit.core/TestServiceProvider.cs b/src/bunit.core/TestServiceProvider.cs index d68187bd8..f4734786b 100644 --- a/src/bunit.core/TestServiceProvider.cs +++ b/src/bunit.core/TestServiceProvider.cs @@ -6,7 +6,11 @@ namespace Bunit; /// Represents a and /// as a single type used for test purposes. /// +#if !NET8_0_OR_GREATER public sealed class TestServiceProvider : IServiceProvider, IServiceCollection, IDisposable, IAsyncDisposable +#else +public sealed class TestServiceProvider : IKeyedServiceProvider, IServiceCollection, IDisposable, IAsyncDisposable +#endif { private static readonly ServiceProviderOptions DefaultServiceProviderOptions = new() { ValidateScopes = true }; private readonly IServiceCollection serviceCollection; @@ -230,6 +234,35 @@ public bool Remove(ServiceDescriptor item) return serviceCollection.Remove(item); } +#if NET8_0_OR_GREATER + /// + public object? GetKeyedService(Type serviceType, object? serviceKey) + { + if (serviceProvider is null) + InitializeProvider(); + + if (serviceProvider is IKeyedServiceProvider keyedServiceProvider) + { + var value = keyedServiceProvider.GetKeyedService(serviceType, serviceKey); + if (value is not null) + return value; + } + + if (fallbackServiceProvider is IKeyedServiceProvider fallbackKeyedServiceProvider) + return fallbackKeyedServiceProvider.GetKeyedService(serviceType, serviceKey); + + return default; + } + + /// + public object GetRequiredKeyedService(Type serviceType, object? serviceKey) + { + var service = GetKeyedService(serviceType, serviceKey) ?? throw new InvalidOperationException($"No service for type '{serviceType}' and key '{serviceKey}' has been registered."); + + return service; + } +#endif + private void CheckInitializedAndThrow() { if (IsProviderInitialized) diff --git a/tests/.editorconfig b/tests/.editorconfig index b17df213a..173e0bbfd 100644 --- a/tests/.editorconfig +++ b/tests/.editorconfig @@ -42,6 +42,7 @@ dotnet_diagnostic.CA2007.severity = none # https://github.com/atc-net dotnet_diagnostic.CA1819.severity = suggestion # CA1819: Properties should not return arrays dotnet_diagnostic.CA1849.severity = suggestion # CA1849: Call async methods when in an async method +dotnet_diagnostic.CA2255.severity = suggestion # CA2255: The 'ModuleInitializer' attribute is only intended to be used in application code or advanced source generator scenarios dotnet_diagnostic.xUnit1026.severity = none # xUnit1026: Theory methods should use all of their parameters dotnet_diagnostic.xUnit1034.severity = none # xUnit1034: Null should not be used for type parameter dotnet_diagnostic.S1144.severity = suggestion # S1144: Unused private types or members should be removed diff --git a/tests/bunit.core.tests/TestServiceProviderTest.cs b/tests/bunit.core.tests/TestServiceProviderTest.cs index 92b5ba293..bb30995b0 100644 --- a/tests/bunit.core.tests/TestServiceProviderTest.cs +++ b/tests/bunit.core.tests/TestServiceProviderTest.cs @@ -296,6 +296,40 @@ public void Test039() dummyServiceProvider.ResolvedTestServices.ShouldContain(result); dummyServiceProvider.ResolvedTestServices.Count.ShouldBe(1); } + +#if NET8_0_OR_GREATER + [Fact(DisplayName = "Should resolve keyed service from container")] + public void Test040() + { + using var ctx = new TestContext(); + ctx.Services.AddKeyedScoped("Key"); + + var cut = ctx.RenderComponent(); + + cut.Instance.Service.ShouldNotBeNull(); + } + + [Fact(DisplayName = "Should resolved keyed service from fallback service provider")] + public void Test041() + { + using var ctx = new TestContext(); + var fallbackCollection = new ServiceCollection(); + fallbackCollection.AddKeyedScoped("Key"); + ctx.Services.AddFallbackServiceProvider(fallbackCollection.BuildServiceProvider()); + + var cut = ctx.RenderComponent(); + + cut.Instance.Service.ShouldNotBeNull(); + } + + [Fact(DisplayName = "Throw an exception if required keyed service is not found")] + public void Test042() + { + using var ctx = new TestContext(); + + Should.Throw(() => ctx.RenderComponent()); + } +#endif private sealed class DummyService { } @@ -381,4 +415,12 @@ public DummyServiceProviderFactoryContainerBuilder CreateBuilder(IServiceCollect public IServiceProvider CreateServiceProvider(DummyServiceProviderFactoryContainerBuilder containerBuilder) => containerBuilder.Build(); } + +#if NET8_0_OR_GREATER + private sealed class ComponentWithKeyedService : ComponentBase + { + [Inject(Key = "Key")] + public DummyService Service { get; set; } + } +#endif } diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index ac5c8a94a..d2e4b4984 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -3,7 +3,7 @@ net8.0 Bunit - Bunit.Web.AngleSharp.Tests + Bunit.Generator.Tests true true false @@ -13,11 +13,12 @@ + - + @@ -25,7 +26,7 @@ - + all runtime; build; native; contentfiles; analyzers From 3cbfc499f3323bf78c6b5393e3c1012727c8b98c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 15:04:06 +0000 Subject: [PATCH 33/53] build(deps): Bump thomaseizinger/keep-a-changelog-new-release Bumps [thomaseizinger/keep-a-changelog-new-release](https://github.com/thomaseizinger/keep-a-changelog-new-release) from 1.3.0 to 2.0.0. - [Release notes](https://github.com/thomaseizinger/keep-a-changelog-new-release/releases) - [Changelog](https://github.com/thomaseizinger/keep-a-changelog-new-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/thomaseizinger/keep-a-changelog-new-release/compare/1.3.0...2.0.0) --- updated-dependencies: - dependency-name: thomaseizinger/keep-a-changelog-new-release dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7ec265456..783d43855 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,7 +64,7 @@ jobs: 8.0.x - name: 🛠️ Update changelog - uses: thomaseizinger/keep-a-changelog-new-release@1.3.0 + uses: thomaseizinger/keep-a-changelog-new-release@2.0.0 with: version: ${{ env.NBGV_SemVer2 }} From 706483bcbf130b81820928d44d31b15fc174f7ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Feb 2024 15:27:22 +0000 Subject: [PATCH 34/53] build(deps): Bump Verify.Xunit from 23.1.0 to 23.2.0 Bumps [Verify.Xunit](https://github.com/VerifyTests/Verify) from 23.1.0 to 23.2.0. - [Release notes](https://github.com/VerifyTests/Verify/releases) - [Commits](https://github.com/VerifyTests/Verify/compare/23.1.0...23.2.0) --- updated-dependencies: - dependency-name: Verify.Xunit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index d2e4b4984..7a4906ba5 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + From 6ba8b1f8251dad621d5c39202ec2bca777d2af71 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:22:24 +0000 Subject: [PATCH 35/53] build(deps): Bump docfx from 2.75.2 to 2.75.3 Bumps [docfx](https://github.com/dotnet/docfx) from 2.75.2 to 2.75.3. - [Release notes](https://github.com/dotnet/docfx/releases) - [Changelog](https://github.com/dotnet/docfx/blob/main/RELEASENOTE.md) - [Commits](https://github.com/dotnet/docfx/compare/v2.75.2...v2.75.3) --- updated-dependencies: - dependency-name: docfx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 4009280ee..b592b0e01 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "docfx": { - "version": "2.75.2", + "version": "2.75.3", "commands": [ "docfx" ] From 465e2cc4ea31ea1501dca26475121ce5bc0ea7dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 15:44:07 +0000 Subject: [PATCH 36/53] build(deps): Bump xunit from 2.6.6 to 2.7.0 Bumps [xunit](https://github.com/xunit/xunit) from 2.6.6 to 2.7.0. - [Commits](https://github.com/xunit/xunit/compare/2.6.6...2.7.0) --- updated-dependencies: - dependency-name: xunit dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tests/bunit.core.tests/bunit.core.tests.csproj | 2 +- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- tests/bunit.web.query.tests/bunit.web.query.tests.csproj | 2 +- tests/bunit.web.tests/bunit.web.tests.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/bunit.core.tests/bunit.core.tests.csproj b/tests/bunit.core.tests/bunit.core.tests.csproj index ee364e456..132cf6392 100644 --- a/tests/bunit.core.tests/bunit.core.tests.csproj +++ b/tests/bunit.core.tests/bunit.core.tests.csproj @@ -13,7 +13,7 @@ - + all diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index 7a4906ba5..ee03f3678 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -25,7 +25,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/tests/bunit.web.query.tests/bunit.web.query.tests.csproj b/tests/bunit.web.query.tests/bunit.web.query.tests.csproj index e10987eef..822b7f489 100644 --- a/tests/bunit.web.query.tests/bunit.web.query.tests.csproj +++ b/tests/bunit.web.query.tests/bunit.web.query.tests.csproj @@ -14,7 +14,7 @@ - + all diff --git a/tests/bunit.web.tests/bunit.web.tests.csproj b/tests/bunit.web.tests/bunit.web.tests.csproj index 032f62692..fe88e0b42 100644 --- a/tests/bunit.web.tests/bunit.web.tests.csproj +++ b/tests/bunit.web.tests/bunit.web.tests.csproj @@ -13,7 +13,7 @@ - + all From d97c47cac423bda3b24a795bc04e166837e5704d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Feb 2024 15:56:21 +0000 Subject: [PATCH 37/53] build(deps): Bump SonarAnalyzer.CSharp from 9.19.0.84025 to 9.20.0.85982 Bumps [SonarAnalyzer.CSharp](https://github.com/SonarSource/sonar-dotnet) from 9.19.0.84025 to 9.20.0.85982. - [Release notes](https://github.com/SonarSource/sonar-dotnet/releases) - [Commits](https://github.com/SonarSource/sonar-dotnet/compare/9.19.0.84025...9.20.0.85982) --- updated-dependencies: - dependency-name: SonarAnalyzer.CSharp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index aeb8358d6..183f74e64 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -51,7 +51,7 @@ - + Date: Wed, 21 Feb 2024 16:05:33 +0000 Subject: [PATCH 38/53] build(deps): Bump coverlet.msbuild from 6.0.0 to 6.0.1 Bumps [coverlet.msbuild](https://github.com/coverlet-coverage/coverlet) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/coverlet-coverage/coverlet/releases) - [Commits](https://github.com/coverlet-coverage/coverlet/compare/v6.0.0...v6.0.1) --- updated-dependencies: - dependency-name: coverlet.msbuild dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- tests/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index fad5b9744..87288e352 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -20,7 +20,7 @@ - + From 8f99afa6269b16439b33c400ef07d64d3f3a9b38 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 16 Feb 2024 14:50:06 +0100 Subject: [PATCH 39/53] feat: Support supplying parameters as query string fixes #1368 --- CHANGELOG.md | 3 ++ .../ComponentParameterCollectionBuilder.cs | 54 ++++++++++++++++++- .../RenderedComponentRenderExtensions.cs | 2 +- .../RenderedFragmentInvokeAsyncExtensions.cs | 32 ++++++++--- .../WaitForHelpers/WaitForHelper.cs | 3 +- src/bunit.core/TestContextBase.cs | 8 ++- .../FakePersistentComponentState.cs | 7 +-- .../Extensions/RenderedFragmentExtensions.cs | 4 +- .../TestServiceProviderExtensions.cs | 11 ++-- src/bunit.web/Rendering/BunitHtmlParser.cs | 8 +-- src/bunit.web/TestContext.cs | 18 +++++++ .../FakeNavigationManager.cs | 12 ++--- ...omponentParameterCollectionBuilderTests.cs | 46 ++++++++++++++++ .../Rendering/TestRendererTest.cs | 48 +++++++++-------- .../GeneralEventDispatchExtensionsTest.cs | 1 - 15 files changed, 200 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdcd9f79e..10396a984 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ All notable changes to **bUnit** will be documented in this file. The project ad ### Added - Support for `IKeyedServiceProvider` in net8.0. Reported by [@ViRuSTriNiTy](https://github.com/ViRuSTriNiTy). By [@linkdotnet](https://github.com/linkdotnet). +### Fixed +- Support for `SupplyFromQueryParameter` in net8.0. Reported by [@aayjaychan](https://github.com/aayjaychan). Fixed by [@egil](https://github.com/egil) and [@linkdotnet](https://github.com/linkdotnet). + ## [1.26.64] - 2023-12-20 ### Changed diff --git a/src/bunit.core/ComponentParameterCollectionBuilder.cs b/src/bunit.core/ComponentParameterCollectionBuilder.cs index f0a93b335..f4c1fa04e 100644 --- a/src/bunit.core/ComponentParameterCollectionBuilder.cs +++ b/src/bunit.core/ComponentParameterCollectionBuilder.cs @@ -1,6 +1,8 @@ using System.Linq.Expressions; using System.Reflection; +using System.Runtime.CompilerServices; using Bunit.Extensions; +using Bunit.Rendering; namespace Bunit; @@ -48,7 +50,11 @@ public ComponentParameterCollectionBuilder(ActionThis . public ComponentParameterCollectionBuilder Add(Expression> parameterSelector, [AllowNull] TValue value) { +#if !NET8_0_OR_GREATER var (name, cascadingValueName, isCascading) = GetParameterInfo(parameterSelector); +#else + var (name, cascadingValueName, isCascading) = GetParameterInfo(parameterSelector, value); +#endif return isCascading ? AddCascadingValueParameter(cascadingValueName, value) : AddParameter(name, value); @@ -338,7 +344,11 @@ public ComponentParameterCollectionBuilder Bind( Action changedAction, Expression>? valueExpression = null) { + #if !NET8_0_OR_GREATER var (parameterName, _, isCascading) = GetParameterInfo(parameterSelector); + #else + var (parameterName, _, isCascading) = GetParameterInfo(parameterSelector, initialValue); + #endif if (isCascading) throw new ArgumentException("Using Bind with a cascading parameter is not allowed.", parameterName); @@ -393,7 +403,7 @@ static string TrimEnd(string source, string value) /// or a . /// /// - /// This is an untyped version of the method. Always + /// This is an untyped version of this method named . Always /// prefer the strongly typed Add methods whenever possible. /// /// Value type. @@ -426,7 +436,12 @@ public bool TryAdd(string name, [AllowNull] TValue value) /// The created . public ComponentParameterCollection Build() => parameters; - private static (string Name, string? CascadingValueName, bool IsCascading) GetParameterInfo(Expression> parameterSelector) + private static (string Name, string? CascadingValueName, bool IsCascading) GetParameterInfo( + Expression> parameterSelector +#if NET8_0_OR_GREATER + , object? value +#endif + ) { if (parameterSelector is null) throw new ArgumentNullException(nameof(parameterSelector)); @@ -439,12 +454,47 @@ private static (string Name, string? CascadingValueName, bool IsCascading) GetPa : propInfoCandidate; var paramAttr = propertyInfo?.GetCustomAttribute(inherit: true); + #if !NET8_0_OR_GREATER var cascadingParamAttr = propertyInfo?.GetCustomAttribute(inherit: true); if (propertyInfo is null || (paramAttr is null && cascadingParamAttr is null)) throw new ArgumentException($"The parameter selector '{parameterSelector}' does not resolve to a public property on the component '{typeof(TComponent)}' with a [Parameter] or [CascadingParameter] attribute.", nameof(parameterSelector)); return (propertyInfo.Name, CascadingValueName: cascadingParamAttr?.Name, IsCascading: cascadingParamAttr is not null); + #else + var cascadingParamAttrBase = propertyInfo?.GetCustomAttribute(inherit: true); + + if (propertyInfo is null || (paramAttr is null && cascadingParamAttrBase is null)) + throw new ArgumentException($"The parameter selector '{parameterSelector}' does not resolve to a public property on the component '{typeof(TComponent)}' with a [Parameter] or [CascadingParameter]attribute.", nameof(parameterSelector)); + + if (cascadingParamAttrBase is null) + return (propertyInfo.Name, CascadingValueName: null, IsCascading: false); + + var name = cascadingParamAttrBase switch + { + CascadingParameterAttribute cpa => cpa.Name, + SupplyParameterFromQueryAttribute s => throw CreateErrorMessageForSupplyFromQuery(value, propertyInfo, s.Name), + _ => throw new NotSupportedException($"The type '{cascadingParamAttrBase.GetType()}' is not supported"), + }; + + return (propertyInfo.Name, CascadingValueName: name, IsCascading: true); + + static ArgumentException CreateErrorMessageForSupplyFromQuery( + object? value, + MemberInfo propertyInfo, + string? name) + { + var cascadingParameterName = name ?? propertyInfo.Name; + + return new ArgumentException($""" + To pass a value to a SupplyParameterFromQuery parameter, use the NavigationManager and navigate to the URI. + For example: + + var uri = NavigationManager.GetUriWithQueryParameter("{cascadingParameterName}", "{value}"); + NavigationManager.NavigateTo(uri); + """); + } + #endif } private static bool HasChildContentParameter() diff --git a/src/bunit.core/Extensions/RenderedComponentRenderExtensions.cs b/src/bunit.core/Extensions/RenderedComponentRenderExtensions.cs index dbe36c1d3..5e01c233b 100644 --- a/src/bunit.core/Extensions/RenderedComponentRenderExtensions.cs +++ b/src/bunit.core/Extensions/RenderedComponentRenderExtensions.cs @@ -29,7 +29,7 @@ public static void SetParametersAndRender(this IRenderedComponentBas if (renderedComponent is null) throw new ArgumentNullException(nameof(renderedComponent)); - var renderer = renderedComponent.Services.GetRequiredService(); + var renderer = (TestRenderer)renderedComponent.Services.GetRequiredService().Renderer; try { diff --git a/src/bunit.core/Extensions/RenderedFragmentInvokeAsyncExtensions.cs b/src/bunit.core/Extensions/RenderedFragmentInvokeAsyncExtensions.cs index 7abaee89b..d9078b673 100644 --- a/src/bunit.core/Extensions/RenderedFragmentInvokeAsyncExtensions.cs +++ b/src/bunit.core/Extensions/RenderedFragmentInvokeAsyncExtensions.cs @@ -18,8 +18,12 @@ public static Task InvokeAsync(this IRenderedFragmentBase renderedFragment, Acti if (renderedFragment is null) throw new ArgumentNullException(nameof(renderedFragment)); - return renderedFragment.Services.GetRequiredService() - .Dispatcher.InvokeAsync(workItem); + return renderedFragment + .Services + .GetRequiredService() + .Renderer + .Dispatcher + .InvokeAsync(workItem); } /// @@ -33,8 +37,12 @@ public static Task InvokeAsync(this IRenderedFragmentBase renderedFragment, Func if (renderedFragment is null) throw new ArgumentNullException(nameof(renderedFragment)); - return renderedFragment.Services.GetRequiredService() - .Dispatcher.InvokeAsync(workItem); + return renderedFragment + .Services + .GetRequiredService() + .Renderer + .Dispatcher + .InvokeAsync(workItem); } /// @@ -48,8 +56,12 @@ public static Task InvokeAsync(this IRenderedFragmentBase renderedFragment if (renderedFragment is null) throw new ArgumentNullException(nameof(renderedFragment)); - return renderedFragment.Services.GetRequiredService() - .Dispatcher.InvokeAsync(workItem); + return renderedFragment + .Services + .GetRequiredService() + .Renderer + .Dispatcher + .InvokeAsync(workItem); } /// @@ -63,7 +75,11 @@ public static Task InvokeAsync(this IRenderedFragmentBase renderedFragment if (renderedFragment is null) throw new ArgumentNullException(nameof(renderedFragment)); - return renderedFragment.Services.GetRequiredService() - .Dispatcher.InvokeAsync(workItem); + return renderedFragment + .Services + .GetRequiredService() + .Renderer + .Dispatcher + .InvokeAsync(workItem); } } diff --git a/src/bunit.core/Extensions/WaitForHelpers/WaitForHelper.cs b/src/bunit.core/Extensions/WaitForHelpers/WaitForHelper.cs index 3bb6ebd79..033c8c27a 100644 --- a/src/bunit.core/Extensions/WaitForHelpers/WaitForHelper.cs +++ b/src/bunit.core/Extensions/WaitForHelpers/WaitForHelper.cs @@ -56,7 +56,8 @@ protected WaitForHelper( logger = renderedFragment.Services.CreateLogger>(); renderer = (TestRenderer)renderedFragment .Services - .GetRequiredService(); + .GetRequiredService() + .Renderer; checkPassedCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); timer = new Timer(_ => { diff --git a/src/bunit.core/TestContextBase.cs b/src/bunit.core/TestContextBase.cs index 3f311f05c..345bc8cbb 100644 --- a/src/bunit.core/TestContextBase.cs +++ b/src/bunit.core/TestContextBase.cs @@ -19,7 +19,13 @@ public abstract class TestContextBase : IDisposable /// /// Gets the renderer used by the test context. /// - public ITestRenderer Renderer => testRenderer ??= Services.GetRequiredService(); + public ITestRenderer Renderer => testRenderer ??= CreateTestRenderer(); + + /// + /// Hey YouTube, I'm a comment! + /// + /// + protected abstract ITestRenderer CreateTestRenderer(); /// /// Gets the service collection and service provider that is used when a diff --git a/src/bunit.core/TestDoubles/PersistentComponentState/FakePersistentComponentState.cs b/src/bunit.core/TestDoubles/PersistentComponentState/FakePersistentComponentState.cs index b787794c0..ff69fbf08 100644 --- a/src/bunit.core/TestDoubles/PersistentComponentState/FakePersistentComponentState.cs +++ b/src/bunit.core/TestDoubles/PersistentComponentState/FakePersistentComponentState.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Threading.Tasks; +using Bunit.Rendering; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Infrastructure; using Microsoft.AspNetCore.Components.RenderTree; @@ -23,7 +24,7 @@ public sealed class FakePersistentComponentState }; private readonly FakePersistentComponentStateStore store; private readonly Lazy manager; - private readonly Lazy renderer; + private readonly Lazy renderer; /// /// Initializes a new instance of the class. @@ -33,7 +34,7 @@ internal FakePersistentComponentState(IServiceProvider services) { store = new FakePersistentComponentStateStore(); manager = new Lazy(() => services.GetRequiredService()); - renderer = new Lazy(() => services.GetRequiredService()); + renderer = new Lazy(() => services.GetRequiredService().Renderer); } /// @@ -48,7 +49,7 @@ internal FakePersistentComponentState(IServiceProvider services) /// public void TriggerOnPersisting() { - manager.Value.PersistStateAsync(store, renderer.Value); + manager.Value.PersistStateAsync(store, (Renderer)renderer.Value); manager.Value.RestoreStateAsync(store); } diff --git a/src/bunit.web/Extensions/RenderedFragmentExtensions.cs b/src/bunit.web/Extensions/RenderedFragmentExtensions.cs index b4801c279..7c0da6a25 100644 --- a/src/bunit.web/Extensions/RenderedFragmentExtensions.cs +++ b/src/bunit.web/Extensions/RenderedFragmentExtensions.cs @@ -58,7 +58,7 @@ public static IRenderedComponent FindComponent(this IRen if (renderedFragment is null) throw new ArgumentNullException(nameof(renderedFragment)); - var renderer = renderedFragment.Services.GetRequiredService(); + var renderer = renderedFragment.Services.GetRequiredService().Renderer; return (IRenderedComponent)renderer.FindComponent(renderedFragment); } @@ -74,7 +74,7 @@ public static IReadOnlyList> FindComponents(); + var renderer = renderedFragment.Services.GetRequiredService().Renderer; var components = renderer.FindComponents(renderedFragment); return components.OfType>().ToArray(); diff --git a/src/bunit.web/Extensions/TestServiceProviderExtensions.cs b/src/bunit.web/Extensions/TestServiceProviderExtensions.cs index 3eb44f69a..1b23ec835 100644 --- a/src/bunit.web/Extensions/TestServiceProviderExtensions.cs +++ b/src/bunit.web/Extensions/TestServiceProviderExtensions.cs @@ -38,7 +38,7 @@ public static IServiceCollection AddDefaultTestContextServices(this IServiceColl // bUnits fake Navigation Manager services.AddSingleton(); - services.AddSingleton(s => s.GetRequiredService()); + services.AddScoped(s => s.GetRequiredService()); services.AddSingleton(); // bUnits fake WebAssemblyHostEnvironment @@ -48,14 +48,11 @@ public static IServiceCollection AddDefaultTestContextServices(this IServiceColl #if NET8_0_OR_GREATER // bUnits fake ScrollToLocationHash services.AddSingleton(); + services.AddSupplyValueFromQueryProvider(); #endif - + // bUnit specific services - services.AddSingleton(testContext); - services.AddSingleton(); - services.AddSingleton(s => s.GetRequiredService()); - services.AddSingleton(s => s.GetRequiredService()); - services.AddSingleton(s => s.GetRequiredService()); + services.AddSingleton(testContext); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/bunit.web/Rendering/BunitHtmlParser.cs b/src/bunit.web/Rendering/BunitHtmlParser.cs index c6edf2971..9580764ff 100644 --- a/src/bunit.web/Rendering/BunitHtmlParser.cs +++ b/src/bunit.web/Rendering/BunitHtmlParser.cs @@ -32,13 +32,13 @@ public BunitHtmlParser() /// /// Initializes a new instance of the class - /// with a AngleSharp context that includes a the registered. + /// with a AngleSharp context registered. /// - public BunitHtmlParser(ITestRenderer testRenderer, HtmlComparer htmlComparer, TestContextBase testContext) + public BunitHtmlParser(HtmlComparer htmlComparer, TestContextBase testContext) : this(Configuration.Default.WithCss() - .With(testRenderer ?? throw new ArgumentNullException(nameof(testRenderer))) .With(htmlComparer ?? throw new ArgumentNullException(nameof(htmlComparer))) - .With(testContext ?? throw new ArgumentNullException(nameof(testContext)))) + .With(testContext ?? throw new ArgumentNullException(nameof(testContext))) + .With(testContext.Renderer)) { } private BunitHtmlParser(IConfiguration angleSharpConfiguration) diff --git a/src/bunit.web/TestContext.cs b/src/bunit.web/TestContext.cs index 950b3df81..315aa4ddf 100644 --- a/src/bunit.web/TestContext.cs +++ b/src/bunit.web/TestContext.cs @@ -1,4 +1,6 @@ using Bunit.Extensions; +using Bunit.Rendering; +using Microsoft.Extensions.Logging; namespace Bunit; @@ -78,4 +80,20 @@ public virtual IRenderedFragment Render(RenderFragment renderFragment) /// C# from .razor files. /// protected virtual void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder builder) { } + + /// + protected override ITestRenderer CreateTestRenderer() + { + var renderedComponentActivator = Services.GetRequiredService(); + var logger = Services.GetRequiredService(); +#if !NET5_0_OR_GREATER + return new WebTestRenderer(renderedComponentActivator, Services, logger); +#else + var componentActivator = Services.GetService(); + return componentActivator is null + ? new WebTestRenderer(renderedComponentActivator, Services, logger) + : new WebTestRenderer(renderedComponentActivator, Services, logger, componentActivator); +#endif + + } } diff --git a/src/bunit.web/TestDoubles/NavigationManager/FakeNavigationManager.cs b/src/bunit.web/TestDoubles/NavigationManager/FakeNavigationManager.cs index d60bdcf58..574807cf3 100644 --- a/src/bunit.web/TestDoubles/NavigationManager/FakeNavigationManager.cs +++ b/src/bunit.web/TestDoubles/NavigationManager/FakeNavigationManager.cs @@ -11,7 +11,7 @@ namespace Bunit.TestDoubles; /// public sealed class FakeNavigationManager : NavigationManager { - private readonly ITestRenderer renderer; + private readonly TestContextBase testContextBase; private readonly Stack history = new(); /// @@ -27,9 +27,9 @@ public sealed class FakeNavigationManager : NavigationManager /// Initializes a new instance of the class. /// [SuppressMessage("Minor Code Smell", "S1075:URIs should not be hardcoded", Justification = "By design. Fake navigation manager defaults to local host as base URI.")] - public FakeNavigationManager(ITestRenderer renderer) + public FakeNavigationManager(TestContextBase testContextBase) { - this.renderer = renderer ?? throw new ArgumentNullException(nameof(renderer)); + this.testContextBase = testContextBase; Initialize("http://localhost/", "http://localhost/"); } @@ -48,7 +48,7 @@ protected override void NavigateToCore(string uri, bool forceLoad) Uri = ToAbsoluteUri(uri).OriginalString; history.Push(new NavigationHistory(uri, new NavigationOptions(forceLoad))); - renderer.Dispatcher.InvokeAsync(() => + testContextBase.Renderer.Dispatcher.InvokeAsync(() => { Uri = absoluteUri.OriginalString; @@ -87,9 +87,9 @@ protected override void NavigateToCore(string uri, NavigationOptions options) #if NET7_0_OR_GREATER HistoryEntryState = options.ForceLoad ? null : options.HistoryEntryState; - renderer.Dispatcher.InvokeAsync(async () => + testContextBase.Renderer.Dispatcher.InvokeAsync(async () => #else - renderer.Dispatcher.InvokeAsync(() => + testContextBase.Renderer.Dispatcher.InvokeAsync(() => #endif { Uri = absoluteUri.OriginalString; diff --git a/tests/bunit.core.tests/ComponentParameterCollectionBuilderTests.cs b/tests/bunit.core.tests/ComponentParameterCollectionBuilderTests.cs index 01298e43b..52b596924 100644 --- a/tests/bunit.core.tests/ComponentParameterCollectionBuilderTests.cs +++ b/tests/bunit.core.tests/ComponentParameterCollectionBuilderTests.cs @@ -695,6 +695,38 @@ public void Test314() action.ShouldNotThrow(); } + +#if NET8_0_OR_GREATER + [Fact(DisplayName = "Supplying query string should be reflected in component parameter")] + public void Test315() + { + var navigationManager = Services.GetRequiredService(); + var uri = navigationManager.GetUriWithQueryParameter("Query", "Test"); + navigationManager.NavigateTo(uri); + + var cut = RenderComponent(); + + cut.Instance.Query.ShouldBe("Test"); + } + + [Fact(DisplayName = "Throws an exception if a SupplyFromQueryParameter is passed as parameter")] + public void Test316() + { + Action action = () => RenderComponent( + ps => ps.Add(p => p.Query, "Foo")); + + action.ShouldThrow() + .Message + .ShouldBe(""" + To pass a value to a SupplyParameterFromQuery parameter, use the NavigationManager and navigate to the URI. + For example: + + var uri = NavigationManager.GetUriWithQueryParameter("Query", "Foo"); + NavigationManager.NavigateTo(uri); + """); + } + +#endif #pragma warning disable S1144 // Unused private types or members should be removed private class Params : ComponentBase @@ -772,4 +804,18 @@ private sealed class ValidNamesComponent : ComponentBase [Parameter] public Expression> FacialExpressionExpression { get; set; } } #pragma warning restore S1144 // Unused private types or members should be removed + +#if NET8_0_OR_GREATER + private sealed class SupplyFromQueryParameterComponent : ComponentBase + { + [SupplyParameterFromQuery] public string Query { get; set; } + [CascadingParameter] public int Size { get; set; } + + public override Task SetParametersAsync(ParameterView parameters) + { + Console.WriteLine(); + return base.SetParametersAsync(parameters); + } + } +#endif } diff --git a/tests/bunit.core.tests/Rendering/TestRendererTest.cs b/tests/bunit.core.tests/Rendering/TestRendererTest.cs index eb14abd0a..06ba766c5 100644 --- a/tests/bunit.core.tests/Rendering/TestRendererTest.cs +++ b/tests/bunit.core.tests/Rendering/TestRendererTest.cs @@ -1,5 +1,6 @@ using Bunit.Extensions; using Bunit.TestAssets.RenderModes; +using Microsoft.Extensions.Logging.Abstractions; using static Bunit.ComponentParameterFactory; namespace Bunit.Rendering; @@ -15,7 +16,7 @@ public TestRendererTest(ITestOutputHelper outputHelper) [Fact(DisplayName = "RenderFragment re-throws exception from component")] public void Test004() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); RenderFragment throwingFragment = b => { b.OpenComponent(0); b.CloseComponent(); }; Should.Throw(() => sut.RenderFragment(throwingFragment)) @@ -25,7 +26,7 @@ public void Test004() [Fact(DisplayName = "RenderComponent re-throws exception from component")] public void Test003() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); Should.Throw(() => sut.RenderComponent()) .Message.ShouldBe(ThrowsDuringSetParams.EXCEPTION.Message); @@ -35,7 +36,7 @@ public void Test003() public void Test001() { const string MARKUP = "

hello world

"; - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = (IRenderedFragment)sut.RenderFragment(builder => builder.AddMarkupContent(0, MARKUP)); @@ -46,7 +47,7 @@ public void Test001() [Fact(DisplayName = "Can render component without children and no parameters")] public void Test002() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent(); @@ -59,7 +60,7 @@ public void Test002() public void Test005() { const string VALUE = "FOO BAR"; - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent((nameof(HasParams.Value), VALUE)); @@ -72,7 +73,7 @@ public void Test006() const string PARENT_VALUE = "PARENT"; const string CHILD_VALUE = "CHILD"; - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent( (nameof(HasParams.Value), PARENT_VALUE), @@ -85,7 +86,7 @@ public void Test006() [Fact(DisplayName = "Rendered component gets RenderCount updated on re-render")] public async Task Test010() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent(); @@ -101,7 +102,7 @@ public async Task Test011() { // arrange const string EXPECTED = "NOW VALUE"; - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent(); cut.RenderCount.ShouldBe(1); @@ -121,7 +122,7 @@ public void Test020() const string PARENT_VALUE = "PARENT"; const string CHILD_VALUE = "CHILD"; - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent( (nameof(HasParams.Value), PARENT_VALUE), @@ -138,7 +139,7 @@ public void Test020() [Fact(DisplayName = "FindComponent throws if parentComponent parameter is null")] public void Test021() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); Should.Throw(() => sut.FindComponent(null!)); } @@ -146,7 +147,7 @@ public void Test021() [Fact(DisplayName = "FindComponent throws if component is not found")] public void Test022() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent(); Should.Throw(() => sut.FindComponent(cut)); @@ -155,7 +156,7 @@ public void Test022() [Fact(DisplayName = "FindComponent returns same rendered component when called multiple times")] public void Test023() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent( ChildContent()); @@ -174,7 +175,7 @@ public void Test030() const string PARENT_VALUE = nameof(PARENT_VALUE); const string CHILD_VALUE = nameof(CHILD_VALUE); - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent( (nameof(HasParams.Value), GRAND_PARENT_VALUE), @@ -199,7 +200,7 @@ public void Test030() [Fact(DisplayName = "FindComponents throws if parentComponent parameter is null")] public void Test031() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); Should.Throw(() => sut.FindComponents(null!)); } @@ -208,7 +209,7 @@ public void Test031() public void Test032() { // arrange - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent( ChildContent( ChildContent())); @@ -224,7 +225,7 @@ public void Test032() [Fact(DisplayName = "Retrieved rendered child component with FindComponent gets updated on re-render")] public async Task Test040() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var parent = sut.RenderComponent( ChildContent()); @@ -243,7 +244,7 @@ public async Task Test040() [Fact(DisplayName = "Retrieved rendered child component with FindComponents gets updated on re-render")] public async Task Test041() { - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var parent = sut.RenderComponent( ChildContent()); @@ -263,7 +264,7 @@ public async Task Test041() public async Task Test050() { // arrange - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent( ChildContent()); @@ -281,7 +282,7 @@ public async Task Test050() public async Task Test060() { // arrange - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent( ChildContent()); @@ -299,7 +300,7 @@ public async Task Test060() public async Task Test061() { // arrange - var sut = Services.GetRequiredService(); + var sut = CreateRenderer(); var cut = sut.RenderComponent( ChildContent( @@ -318,7 +319,7 @@ public async Task Test061() [Fact(DisplayName = "When test renderer is disposed, so is all rendered components")] public void Test070() { - var sut = (TestRenderer)Services.GetRequiredService(); + var sut = (TestRenderer)CreateRenderer(); var cut = sut.RenderComponent(); sut.Dispose(); @@ -515,6 +516,11 @@ public void Test211() } #endif + private ITestRenderer CreateRenderer() => new WebTestRenderer( + Services.GetRequiredService(), + Services, + NullLoggerFactory.Instance); + internal sealed class LifeCycleMethodInvokeCounter : ComponentBase { public int InitilizedCount { get; private set; } diff --git a/tests/bunit.web.tests/EventDispatchExtensions/GeneralEventDispatchExtensionsTest.cs b/tests/bunit.web.tests/EventDispatchExtensions/GeneralEventDispatchExtensionsTest.cs index 5f0e551cf..6d693c7aa 100644 --- a/tests/bunit.web.tests/EventDispatchExtensions/GeneralEventDispatchExtensionsTest.cs +++ b/tests/bunit.web.tests/EventDispatchExtensions/GeneralEventDispatchExtensionsTest.cs @@ -57,7 +57,6 @@ public void Test003() elmMock.GetAttribute(Arg.Any()).Returns("1"); elmMock.Owner.Returns(docMock); docMock.Context.Returns(ctxMock); - ctxMock.GetService().Returns(x => null!); Should.Throw(() => elmMock.TriggerEventAsync("click", EventArgs.Empty)); } From f8d4a8c9c311a63db77c5ba2b6ca204a5b93b692 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 23 Feb 2024 21:51:40 +0100 Subject: [PATCH 40/53] docs: Added examples for query strings in net8 --- .../passing-parameters-to-components.md | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/site/docs/providing-input/passing-parameters-to-components.md b/docs/site/docs/providing-input/passing-parameters-to-components.md index 522638aaf..75827867d 100644 --- a/docs/site/docs/providing-input/passing-parameters-to-components.md +++ b/docs/site/docs/providing-input/passing-parameters-to-components.md @@ -466,6 +466,36 @@ When rendering a `RenderFragment` using the 's `Add` can be used. However, from .NET 8 onwards `SupplyParameterFromQuery` can be used without the need to be a `Parameter`. If it used without ther `Parameter` attribute, the can be used. + +```razor +@code { + [SupplyParameterFromQuery] + public string Name { get; set; } +} +``` + +A simple example of how to test a component that receives parameters from the query string: + +```razor +@inherits TestContext + +@code { + [Fact] + public void Component_receives_parameters_from_query_string() + { + var navigationManager = Services.GetRequiredService(); + var uri = navigationManager.GetUriWithQueryParameter("Name", "bUnit"); + navigationManager.NavigateTo(uri); + + var cut = RenderComponent(); + + cut.Instance.Name.ShouldBe("bUnit"); + } +} +``` + ## Further Reading - From 156822b6c5707996b7a396e62bf7907497cb014c Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 23 Feb 2024 21:52:25 +0100 Subject: [PATCH 41/53] Revert "docs: Added examples for query strings in net8" This reverts commit f8d4a8c9c311a63db77c5ba2b6ca204a5b93b692. --- .../passing-parameters-to-components.md | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/docs/site/docs/providing-input/passing-parameters-to-components.md b/docs/site/docs/providing-input/passing-parameters-to-components.md index 75827867d..522638aaf 100644 --- a/docs/site/docs/providing-input/passing-parameters-to-components.md +++ b/docs/site/docs/providing-input/passing-parameters-to-components.md @@ -466,36 +466,6 @@ When rendering a `RenderFragment` using the 's `Add` can be used. However, from .NET 8 onwards `SupplyParameterFromQuery` can be used without the need to be a `Parameter`. If it used without ther `Parameter` attribute, the can be used. - -```razor -@code { - [SupplyParameterFromQuery] - public string Name { get; set; } -} -``` - -A simple example of how to test a component that receives parameters from the query string: - -```razor -@inherits TestContext - -@code { - [Fact] - public void Component_receives_parameters_from_query_string() - { - var navigationManager = Services.GetRequiredService(); - var uri = navigationManager.GetUriWithQueryParameter("Name", "bUnit"); - navigationManager.NavigateTo(uri); - - var cut = RenderComponent(); - - cut.Instance.Name.ShouldBe("bUnit"); - } -} -``` - ## Further Reading - From 29cbac09bb83a24c11880beb51016bc61e26c9c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:23:09 +0000 Subject: [PATCH 42/53] build(deps): Bump xunit.assert from 2.6.6 to 2.7.0 Bumps [xunit.assert](https://github.com/xunit/xunit) from 2.6.6 to 2.7.0. - [Commits](https://github.com/xunit/xunit/compare/2.6.6...2.7.0) --- updated-dependencies: - dependency-name: xunit.assert dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tests/bunit.testassets/bunit.testassets.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.testassets/bunit.testassets.csproj b/tests/bunit.testassets/bunit.testassets.csproj index eb1d22ce3..a4217fbfc 100644 --- a/tests/bunit.testassets/bunit.testassets.csproj +++ b/tests/bunit.testassets/bunit.testassets.csproj @@ -18,7 +18,7 @@ - + From ab5512bd3ada542f675968d8a912a00d33560749 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:09:56 +0000 Subject: [PATCH 43/53] build(deps): Bump xunit.extensibility.execution from 2.6.6 to 2.7.0 Bumps [xunit.extensibility.execution](https://github.com/xunit/xunit) from 2.6.6 to 2.7.0. - [Commits](https://github.com/xunit/xunit/compare/2.6.6...2.7.0) --- updated-dependencies: - dependency-name: xunit.extensibility.execution dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tests/bunit.testassets/bunit.testassets.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.testassets/bunit.testassets.csproj b/tests/bunit.testassets/bunit.testassets.csproj index a4217fbfc..a733f45c6 100644 --- a/tests/bunit.testassets/bunit.testassets.csproj +++ b/tests/bunit.testassets/bunit.testassets.csproj @@ -16,7 +16,7 @@ - + From 8ccc74c55e21085906a896006cf0956bbdb1fe08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Feb 2024 15:52:27 +0000 Subject: [PATCH 44/53] build(deps): Bump Verify.Xunit and xunit.extensibility.execution Bumps [Verify.Xunit](https://github.com/VerifyTests/Verify) and [xunit.extensibility.execution](https://github.com/xunit/xunit). These dependencies needed to be updated together. Updates `Verify.Xunit` from 23.2.0 to 23.2.1 - [Release notes](https://github.com/VerifyTests/Verify/releases) - [Commits](https://github.com/VerifyTests/Verify/compare/23.2.0...23.2.1) Updates `xunit.extensibility.execution` from 2.6.6 to 2.7.0 - [Commits](https://github.com/xunit/xunit/compare/2.6.6...2.7.0) --- updated-dependencies: - dependency-name: Verify.Xunit dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: xunit.extensibility.execution dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index ee03f3678..a55fe75c4 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + From e1ccc758d885b3b566099bacd7ba05948f625f2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 15:14:54 +0000 Subject: [PATCH 45/53] build(deps): Bump System.Text.Json from 8.0.1 to 8.0.2 Bumps [System.Text.Json](https://github.com/dotnet/runtime) from 8.0.1 to 8.0.2. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v8.0.1...v8.0.2) --- updated-dependencies: - dependency-name: System.Text.Json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- tests/bunit.testassets/bunit.testassets.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.testassets/bunit.testassets.csproj b/tests/bunit.testassets/bunit.testassets.csproj index a733f45c6..d2fdb9963 100644 --- a/tests/bunit.testassets/bunit.testassets.csproj +++ b/tests/bunit.testassets/bunit.testassets.csproj @@ -25,7 +25,7 @@ - + From 67e61b605c47d60141dfbe73cd1b1539ee326ecb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Feb 2024 16:03:40 +0000 Subject: [PATCH 46/53] build(deps): Bump Verify.Xunit from 23.2.1 to 23.2.2 Bumps [Verify.Xunit](https://github.com/VerifyTests/Verify) from 23.2.1 to 23.2.2. - [Release notes](https://github.com/VerifyTests/Verify/releases) - [Commits](https://github.com/VerifyTests/Verify/commits) --- updated-dependencies: - dependency-name: Verify.Xunit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- tests/bunit.generators.tests/bunit.generators.tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bunit.generators.tests/bunit.generators.tests.csproj b/tests/bunit.generators.tests/bunit.generators.tests.csproj index a55fe75c4..dd148fcf9 100644 --- a/tests/bunit.generators.tests/bunit.generators.tests.csproj +++ b/tests/bunit.generators.tests/bunit.generators.tests.csproj @@ -17,7 +17,7 @@ - + From 772f87405a31639c8876decefe3b79b97c182097 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Feb 2024 15:09:39 +0000 Subject: [PATCH 47/53] build(deps): Bump Meziantou.Polyfill from 1.0.33 to 1.0.35 Bumps [Meziantou.Polyfill](https://github.com/meziantou/Meziantou.Polyfill) from 1.0.33 to 1.0.35. - [Commits](https://github.com/meziantou/Meziantou.Polyfill/commits) --- updated-dependencies: - dependency-name: Meziantou.Polyfill dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- src/bunit.generators.internal/bunit.generators.internal.csproj | 2 +- src/bunit.generators/bunit.generators.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bunit.generators.internal/bunit.generators.internal.csproj b/src/bunit.generators.internal/bunit.generators.internal.csproj index db02a95f0..464e7006d 100644 --- a/src/bunit.generators.internal/bunit.generators.internal.csproj +++ b/src/bunit.generators.internal/bunit.generators.internal.csproj @@ -21,7 +21,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers diff --git a/src/bunit.generators/bunit.generators.csproj b/src/bunit.generators/bunit.generators.csproj index d2dc52496..b4c5b5805 100644 --- a/src/bunit.generators/bunit.generators.csproj +++ b/src/bunit.generators/bunit.generators.csproj @@ -75,7 +75,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers From 20479f679eb2f70aa779a6c7703439c8db103db7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 15:49:25 +0000 Subject: [PATCH 48/53] build(deps): Bump Meziantou.Polyfill from 1.0.35 to 1.0.36 Bumps [Meziantou.Polyfill](https://github.com/meziantou/Meziantou.Polyfill) from 1.0.35 to 1.0.36. - [Commits](https://github.com/meziantou/Meziantou.Polyfill/commits) --- updated-dependencies: - dependency-name: Meziantou.Polyfill dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- src/bunit.generators.internal/bunit.generators.internal.csproj | 2 +- src/bunit.generators/bunit.generators.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bunit.generators.internal/bunit.generators.internal.csproj b/src/bunit.generators.internal/bunit.generators.internal.csproj index 464e7006d..ef7414330 100644 --- a/src/bunit.generators.internal/bunit.generators.internal.csproj +++ b/src/bunit.generators.internal/bunit.generators.internal.csproj @@ -21,7 +21,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers diff --git a/src/bunit.generators/bunit.generators.csproj b/src/bunit.generators/bunit.generators.csproj index b4c5b5805..a43bf6de0 100644 --- a/src/bunit.generators/bunit.generators.csproj +++ b/src/bunit.generators/bunit.generators.csproj @@ -75,7 +75,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers From 5d4c79912d36d633b2bf789a6cd5448ec2d622d9 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Thu, 29 Feb 2024 21:02:52 +0100 Subject: [PATCH 49/53] chore: Update AngleSharp dependencies for net6 and higher --- src/bunit.web/bunit.web.csproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bunit.web/bunit.web.csproj b/src/bunit.web/bunit.web.csproj index 7da767341..10f9fe0c3 100644 --- a/src/bunit.web/bunit.web.csproj +++ b/src/bunit.web/bunit.web.csproj @@ -44,8 +44,8 @@ - - + + @@ -55,8 +55,8 @@ - - + + @@ -66,8 +66,8 @@ - - + + From 7568c1775ad42024a146fcfdb4924a132e0b910c Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Fri, 23 Feb 2024 21:52:52 +0100 Subject: [PATCH 50/53] docs: Added examples for query strings in net8 --- .../passing-parameters-to-components.md | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/site/docs/providing-input/passing-parameters-to-components.md b/docs/site/docs/providing-input/passing-parameters-to-components.md index 522638aaf..75827867d 100644 --- a/docs/site/docs/providing-input/passing-parameters-to-components.md +++ b/docs/site/docs/providing-input/passing-parameters-to-components.md @@ -466,6 +466,36 @@ When rendering a `RenderFragment` using the 's `Add` can be used. However, from .NET 8 onwards `SupplyParameterFromQuery` can be used without the need to be a `Parameter`. If it used without ther `Parameter` attribute, the can be used. + +```razor +@code { + [SupplyParameterFromQuery] + public string Name { get; set; } +} +``` + +A simple example of how to test a component that receives parameters from the query string: + +```razor +@inherits TestContext + +@code { + [Fact] + public void Component_receives_parameters_from_query_string() + { + var navigationManager = Services.GetRequiredService(); + var uri = navigationManager.GetUriWithQueryParameter("Name", "bUnit"); + navigationManager.NavigateTo(uri); + + var cut = RenderComponent(); + + cut.Instance.Name.ShouldBe("bUnit"); + } +} +``` + ## Further Reading - From 80a80105873e0ed1fc2fb00cb7dd36214047dce1 Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Tue, 27 Feb 2024 16:57:44 +0100 Subject: [PATCH 51/53] Update docs/site/docs/providing-input/passing-parameters-to-components.md Co-authored-by: Egil Hansen --- .../providing-input/passing-parameters-to-components.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/site/docs/providing-input/passing-parameters-to-components.md b/docs/site/docs/providing-input/passing-parameters-to-components.md index 75827867d..4db2fccf1 100644 --- a/docs/site/docs/providing-input/passing-parameters-to-components.md +++ b/docs/site/docs/providing-input/passing-parameters-to-components.md @@ -467,7 +467,11 @@ When rendering a `RenderFragment` using the 's `Add` can be used. However, from .NET 8 onwards `SupplyParameterFromQuery` can be used without the need to be a `Parameter`. If it used without ther `Parameter` attribute, the can be used. +In .NET 6 and later, components can receive parameters from a query string if the parameter is annotated with the `[SupplyParameterFromQuery]` attribute in addition to the `[Parameter]` attribute. + +In .NET 8 however, the `[Parameter]` attribute is no longer required, which means a value cannot be passed to the component during testing using the normal methods, e.g. the 's `Add` method, if a component parameter is only annotated with the `[SupplyParameterFromQuery]` attribute. Instead, pass a query string parameters by setting it using the . + +For example: ```razor @code { From b859378d2303ad740e6fd879310c70de8416e26e Mon Sep 17 00:00:00 2001 From: Steven Giesel Date: Sat, 2 Mar 2024 17:02:11 +0100 Subject: [PATCH 52/53] feat: Added support for net9.0 (#1404) * feat: Added support for net9.0 * ci: include .net 9 sdk in workflow * chore: replace verfication file reference in solution with ci. * note about .net 9 support in v1 --------- Co-authored-by: Egil Hansen --- .github/workflows/ci.yml | 3 +++ .github/workflows/docs-deploy.yml | 1 + .github/workflows/release.yml | 1 + CHANGELOG.md | 1 + Directory.Build.props | 1 + bunit.sln | 4 ++-- global.json | 2 +- src/bunit.core/bunit.core.csproj | 12 +++++++++--- src/bunit.web.query/bunit.web.query.csproj | 10 ++++++++-- .../Implementation/BunitJSObjectReference.cs | 5 ++++- .../JSInterop/Implementation/BunitJSRuntime.net5.cs | 2 +- src/bunit.web/JSInterop/JSRuntimeInvocation.cs | 1 + src/bunit.web/bunit.web.csproj | 13 ++++++++++++- src/bunit/bunit.csproj | 6 +++--- tests/bunit.core.tests/bunit.core.tests.csproj | 2 +- tests/bunit.testassets/bunit.testassets.csproj | 8 +++++++- .../bunit.web.query.tests.csproj | 2 +- .../JSInterop/BunitJSInteropTest.net5.cs | 2 +- .../JSInterop/BunitJSObjectReferenceTest.cs | 8 ++++++-- tests/bunit.web.tests/bunit.web.tests.csproj | 2 +- 20 files changed, 65 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a80cc4156..54d6979c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,7 @@ jobs: 6.0.x 7.0.x 8.0.x + 9.0.x - name: ⚙️ Setup GIT versioning uses: dotnet/nbgv@v0.4.2 @@ -132,6 +133,7 @@ jobs: 6.0.x 7.0.x 8.0.x + 9.0.x - name: 🧪 Run unit tests run: dotnet test -c release --blame --blame-crash --blame-hang @@ -209,6 +211,7 @@ jobs: 6.0.x 7.0.x 8.0.x + 9.0.x - name: ⚙️ Setup GIT versioning uses: dotnet/nbgv@v0.4.2 diff --git a/.github/workflows/docs-deploy.yml b/.github/workflows/docs-deploy.yml index 15d36e299..f4b361a34 100644 --- a/.github/workflows/docs-deploy.yml +++ b/.github/workflows/docs-deploy.yml @@ -77,6 +77,7 @@ jobs: 6.0.x 7.0.x 8.0.x + 9.0.x - name: 🎨 Setup color run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 783d43855..9fd8108cf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -62,6 +62,7 @@ jobs: 6.0.x 7.0.x 8.0.x + 9.0.x - name: 🛠️ Update changelog uses: thomaseizinger/keep-a-changelog-new-release@2.0.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 10396a984..df93341ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to **bUnit** will be documented in this file. The project ad ### Added - Support for `IKeyedServiceProvider` in net8.0. Reported by [@ViRuSTriNiTy](https://github.com/ViRuSTriNiTy). By [@linkdotnet](https://github.com/linkdotnet). +- Support for `net9.0`. NOTE, there is no commitment as of now to support net9.0 in bUnit v1. However. Support for net9.0 may move to a future v2 release of bUnit and be deprecated in v1. However, allowing bUnit to build and work with net9.0 previews allows our users to keep testing! ### Fixed - Support for `SupplyFromQueryParameter` in net8.0. Reported by [@aayjaychan](https://github.com/aayjaychan). Fixed by [@egil](https://github.com/egil) and [@linkdotnet](https://github.com/linkdotnet). diff --git a/Directory.Build.props b/Directory.Build.props index 183f74e64..09f9fb2ef 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,6 +7,7 @@ 6.0.* 7.0.* 8.0.* + 9.0.0-* diff --git a/bunit.sln b/bunit.sln index e97a9e7c6..89b8e8094 100644 --- a/bunit.sln +++ b/bunit.sln @@ -48,11 +48,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.testassets", "tests\b EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".workflows", ".workflows", "{3B2F3419-5336-4147-A212-E19091195203}" ProjectSection(SolutionItems) = preProject + .github\workflows\ci.yml = .github\workflows\ci.yml .github\workflows\docs-deploy.yml = .github\workflows\docs-deploy.yml .github\workflows\prepare-release.yml = .github\workflows\prepare-release.yml .github\workflows\release-preview.yml = .github\workflows\release-preview.yml .github\workflows\release.yml = .github\workflows\release.yml - .github\workflows\verification.yml = .github\workflows\verification.yml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmark", "benchmark", "{F6084D31-2A92-4794-A47E-A8F2254E6970}" @@ -72,7 +72,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.generators.internal", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.generators.tests", "tests\bunit.generators.tests\bunit.generators.tests.csproj", "{09046981-D9EC-4295-8502-721AC54E1F12}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.generators", "src\bunit.generators\bunit.generators.csproj", "{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.generators", "src\bunit.generators\bunit.generators.csproj", "{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/global.json b/global.json index 18562b58c..83105ca8e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { "rollForward": "latestMajor", - "allowPrerelease": false + "allowPrerelease": true } } diff --git a/src/bunit.core/bunit.core.csproj b/src/bunit.core/bunit.core.csproj index a65412011..e1e8b2818 100644 --- a/src/bunit.core/bunit.core.csproj +++ b/src/bunit.core/bunit.core.csproj @@ -1,11 +1,11 @@ - netstandard2.1;net5.0;net6.0;net7.0;net8.0 + netstandard2.1;net5.0;net6.0;net7.0;net8.0;net9.0 Bunit Bunit.Core - + bunit.core bUnit.core @@ -44,4 +44,10 @@ - \ No newline at end of file + + + + + + + diff --git a/src/bunit.web.query/bunit.web.query.csproj b/src/bunit.web.query/bunit.web.query.csproj index 51b813572..46f303535 100644 --- a/src/bunit.web.query/bunit.web.query.csproj +++ b/src/bunit.web.query/bunit.web.query.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net5.0;net6.0;net7.0;net8.0 + netstandard2.1;net5.0;net6.0;net7.0;net8.0;net9.0 Bunit Bunit.Web.Query @@ -44,4 +44,10 @@ - \ No newline at end of file + + + + + + + diff --git a/src/bunit.web/JSInterop/Implementation/BunitJSObjectReference.cs b/src/bunit.web/JSInterop/Implementation/BunitJSObjectReference.cs index b0ee62734..49ab896a1 100644 --- a/src/bunit.web/JSInterop/Implementation/BunitJSObjectReference.cs +++ b/src/bunit.web/JSInterop/Implementation/BunitJSObjectReference.cs @@ -9,7 +9,10 @@ namespace Bunit; [SuppressMessage("Minor Code Smell", "S1939:Inheritance list should not be redundant", Justification = "By design. To make it obvious that both is implemented.")] -internal sealed class BunitJSObjectReference : IJSObjectReference, IJSInProcessObjectReference, IJSUnmarshalledObjectReference +internal sealed class BunitJSObjectReference : IJSObjectReference, IJSInProcessObjectReference +#if !NET9_0_OR_GREATER + , IJSUnmarshalledObjectReference +#endif { private BunitJSInterop JSInterop { get; } diff --git a/src/bunit.web/JSInterop/Implementation/BunitJSRuntime.net5.cs b/src/bunit.web/JSInterop/Implementation/BunitJSRuntime.net5.cs index 0dcc0303c..f2f466d58 100644 --- a/src/bunit.web/JSInterop/Implementation/BunitJSRuntime.net5.cs +++ b/src/bunit.web/JSInterop/Implementation/BunitJSRuntime.net5.cs @@ -1,4 +1,4 @@ -#if NET5_0_OR_GREATER +#if NET5_0_OR_GREATER && !NET9_0_OR_GREATER using System; using Bunit.JSInterop.Implementation; using Microsoft.JSInterop; diff --git a/src/bunit.web/JSInterop/JSRuntimeInvocation.cs b/src/bunit.web/JSInterop/JSRuntimeInvocation.cs index c3deb91a5..d30350a2d 100644 --- a/src/bunit.web/JSInterop/JSRuntimeInvocation.cs +++ b/src/bunit.web/JSInterop/JSRuntimeInvocation.cs @@ -3,6 +3,7 @@ namespace Bunit; /// /// Represents an invocation of JavaScript via the JSRuntime Mock. /// +[Serializable] public readonly struct JSRuntimeInvocation : IEquatable { /// diff --git a/src/bunit.web/bunit.web.csproj b/src/bunit.web/bunit.web.csproj index 10f9fe0c3..67a137951 100644 --- a/src/bunit.web/bunit.web.csproj +++ b/src/bunit.web/bunit.web.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net5.0;net6.0;net7.0;net8.0 + netstandard2.1;net5.0;net6.0;net7.0;net8.0;net9.0 Bunit Bunit.Web