diff --git a/Directory.Packages.props b/Directory.Packages.props
index 79e723b..a1d7e52 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,10 +1,8 @@
-
true
true
-
@@ -12,8 +10,8 @@
+
-
@@ -28,9 +26,11 @@
+
+
+
-
diff --git a/Extensions.Test.sln b/Extensions.Test.sln
index 6a8fc56..2cce2b5 100644
--- a/Extensions.Test.sln
+++ b/Extensions.Test.sln
@@ -40,9 +40,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Extensions.MSTest
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Extensions.XUnit.Tests.PublicApi", "tests\NetEvolve.Extensions.XUnit.Tests.PublicApi\NetEvolve.Extensions.XUnit.Tests.PublicApi.csproj", "{4D92E42D-68F1-4092-BDB7-29F6265C8CEC}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetEvolve.Extensions.NUnit.Tests.PublicApi", "tests\NetEvolve.Extensions.NUnit.Tests.PublicApi\NetEvolve.Extensions.NUnit.Tests.PublicApi.csproj", "{4F4B90A9-9371-4D13-875B-331468D1E888}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Extensions.NUnit.Tests.PublicApi", "tests\NetEvolve.Extensions.NUnit.Tests.PublicApi\NetEvolve.Extensions.NUnit.Tests.PublicApi.csproj", "{4F4B90A9-9371-4D13-875B-331468D1E888}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetEvolve.Extensions.MSTest.Tests.PublicApi", "tests\NetEvolve.Extensions.MSTest.Tests.PublicApi\NetEvolve.Extensions.MSTest.Tests.PublicApi.csproj", "{37815304-2B2A-4EE1-A1A2-A947794ED7A5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Extensions.MSTest.Tests.PublicApi", "tests\NetEvolve.Extensions.MSTest.Tests.PublicApi\NetEvolve.Extensions.MSTest.Tests.PublicApi.csproj", "{37815304-2B2A-4EE1-A1A2-A947794ED7A5}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Extensions.XUnit.V3", "src\NetEvolve.Extensions.XUnit.V3\NetEvolve.Extensions.XUnit.V3.csproj", "{E59DDFAC-7E76-41B8-B347-344E2AB5046C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Extensions.XUnit.V3.Tests.Unit", "tests\NetEvolve.Extensions.XUnit.V3.Tests.Unit\NetEvolve.Extensions.XUnit.V3.Tests.Unit.csproj", "{8CB5E4DA-E255-40A2-97FA-834CE0CA7F17}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetEvolve.Extensions.XUnit.V3.Tests.PublicApi", "tests\NetEvolve.Extensions.XUnit.V3.Tests.PublicApi\NetEvolve.Extensions.XUnit.V3.Tests.PublicApi.csproj", "{852AA7AA-0F8B-4A13-8C56-D86753B3C054}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -86,6 +92,18 @@ Global
{37815304-2B2A-4EE1-A1A2-A947794ED7A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{37815304-2B2A-4EE1-A1A2-A947794ED7A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{37815304-2B2A-4EE1-A1A2-A947794ED7A5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E59DDFAC-7E76-41B8-B347-344E2AB5046C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E59DDFAC-7E76-41B8-B347-344E2AB5046C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E59DDFAC-7E76-41B8-B347-344E2AB5046C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E59DDFAC-7E76-41B8-B347-344E2AB5046C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8CB5E4DA-E255-40A2-97FA-834CE0CA7F17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8CB5E4DA-E255-40A2-97FA-834CE0CA7F17}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8CB5E4DA-E255-40A2-97FA-834CE0CA7F17}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8CB5E4DA-E255-40A2-97FA-834CE0CA7F17}.Release|Any CPU.Build.0 = Release|Any CPU
+ {852AA7AA-0F8B-4A13-8C56-D86753B3C054}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {852AA7AA-0F8B-4A13-8C56-D86753B3C054}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {852AA7AA-0F8B-4A13-8C56-D86753B3C054}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {852AA7AA-0F8B-4A13-8C56-D86753B3C054}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -100,6 +118,9 @@ Global
{4D92E42D-68F1-4092-BDB7-29F6265C8CEC} = {D67E420A-2329-4879-B82C-069039603B81}
{4F4B90A9-9371-4D13-875B-331468D1E888} = {D67E420A-2329-4879-B82C-069039603B81}
{37815304-2B2A-4EE1-A1A2-A947794ED7A5} = {D67E420A-2329-4879-B82C-069039603B81}
+ {E59DDFAC-7E76-41B8-B347-344E2AB5046C} = {19B4116B-14B4-436F-8A52-E71DB9CFCA7C}
+ {8CB5E4DA-E255-40A2-97FA-834CE0CA7F17} = {D67E420A-2329-4879-B82C-069039603B81}
+ {852AA7AA-0F8B-4A13-8C56-D86753B3C054} = {D67E420A-2329-4879-B82C-069039603B81}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EBB4607C-57F7-4F91-93B2-A444A3D33755}
diff --git a/README.md b/README.md
index cf4e9fe..50bf3bd 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
# NetEvolve.Extensions
Compatibility library for solutions using multiple .NET test frameworks.
-The following test frameworks are supported -
-[NetEvolve.Extensions.MSTest](https://www.nuget.org/packages/NetEvolve.Extensions.MSTest),
-[NetEvolve.Extensions.NUnit](https://www.nuget.org/packages/NetEvolve.Extensions.NUnit) &
-[NetEvolve.Extensions.XUnit](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit).
\ No newline at end of file
+The following test frameworks are supported
+- [MSTest](https://www.nuget.org/packages/NetEvolve.Extensions.MSTest),
+- [NUnit](https://www.nuget.org/packages/NetEvolve.Extensions.NUnit)
+- [XUnit](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit)
+- [XUnit.V3](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit.V3)
\ No newline at end of file
diff --git a/src/NetEvolve.Extensions.MSTest/AcceptanceTestAttribute.cs b/src/NetEvolve.Extensions.MSTest/AcceptanceTestAttribute.cs
index c30902b..c42b045 100644
--- a/src/NetEvolve.Extensions.MSTest/AcceptanceTestAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/AcceptanceTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as AcceptanceTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class AcceptanceTestAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.MSTest/ArchitectureTestAttribute.cs b/src/NetEvolve.Extensions.MSTest/ArchitectureTestAttribute.cs
index 722b964..3f58ad4 100644
--- a/src/NetEvolve.Extensions.MSTest/ArchitectureTestAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/ArchitectureTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as ArchitectureTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class ArchitectureTestAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.MSTest/CodedUITestAttribute.cs b/src/NetEvolve.Extensions.MSTest/CodedUITestAttribute.cs
index bc59200..75fe975 100644
--- a/src/NetEvolve.Extensions.MSTest/CodedUITestAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/CodedUITestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as CodedUITest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class CodedUITestAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.MSTest/EndToEndTestAttribute.cs b/src/NetEvolve.Extensions.MSTest/EndToEndTestAttribute.cs
index e58c3f0..ee969c2 100644
--- a/src/NetEvolve.Extensions.MSTest/EndToEndTestAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/EndToEndTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as EndToEndTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class EndToEndTestAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.MSTest/FunctionalTestAttribute.cs b/src/NetEvolve.Extensions.MSTest/FunctionalTestAttribute.cs
index 787c3b5..4a24593 100644
--- a/src/NetEvolve.Extensions.MSTest/FunctionalTestAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/FunctionalTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as FunctionalTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class FunctionalTestAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.MSTest/IntegrationTestAttribute.cs b/src/NetEvolve.Extensions.MSTest/IntegrationTestAttribute.cs
index 3f60540..f7b4f72 100644
--- a/src/NetEvolve.Extensions.MSTest/IntegrationTestAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/IntegrationTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as IntegrationTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class IntegrationTestAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.MSTest/Internal/TestTraitBaseAttribute.cs b/src/NetEvolve.Extensions.MSTest/Internal/TestTraitBaseAttribute.cs
index 0843abc..b339aba 100644
--- a/src/NetEvolve.Extensions.MSTest/Internal/TestTraitBaseAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/Internal/TestTraitBaseAttribute.cs
@@ -10,11 +10,6 @@
"IDE1006:Naming Styles",
Justification = "As designed."
)]
-[AttributeUsage(
- AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
- AllowMultiple = true,
- Inherited = true
-)]
public abstract class TestTraitBaseAttribute : TestCategoryBaseAttribute
{
///
@@ -22,5 +17,5 @@ public abstract class TestTraitBaseAttribute : TestCategoryBaseAttribute
///
protected TestTraitBaseAttribute(string categoryName)
- : base() => TestCategories = new List { categoryName };
+ : base() => TestCategories = [categoryName];
}
diff --git a/src/NetEvolve.Extensions.MSTest/PerformanceTestAttribute.cs b/src/NetEvolve.Extensions.MSTest/PerformanceTestAttribute.cs
index e059a5e..005692c 100644
--- a/src/NetEvolve.Extensions.MSTest/PerformanceTestAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/PerformanceTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as PerformanceTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class PerformanceTestAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.MSTest/PostDeploymentAttribute.cs b/src/NetEvolve.Extensions.MSTest/PostDeploymentAttribute.cs
index bca0f60..c58dffb 100644
--- a/src/NetEvolve.Extensions.MSTest/PostDeploymentAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/PostDeploymentAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as PostDeployment.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class PostDeploymentAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.MSTest/PreDeploymentAttribute.cs b/src/NetEvolve.Extensions.MSTest/PreDeploymentAttribute.cs
index 1309a2c..f79468d 100644
--- a/src/NetEvolve.Extensions.MSTest/PreDeploymentAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/PreDeploymentAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as PreDeployment.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class PreDeploymentAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.MSTest/README.md b/src/NetEvolve.Extensions.MSTest/README.md
index 7a05a75..dea585a 100644
--- a/src/NetEvolve.Extensions.MSTest/README.md
+++ b/src/NetEvolve.Extensions.MSTest/README.md
@@ -1,10 +1,11 @@
# NetEvolve.Extensions.MSTest
Compatibility library for solutions using multiple .NET test frameworks.
-The following test frameworks are supported -
-[MSTest](https://www.nuget.org/packages/NetEvolve.Extensions.MSTest),
-[NUnit](https://www.nuget.org/packages/NetEvolve.Extensions.NUnit) &
-[XUnit](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit).
+The following test frameworks are supported
+- [MSTest](https://www.nuget.org/packages/NetEvolve.Extensions.MSTest),
+- [NUnit](https://www.nuget.org/packages/NetEvolve.Extensions.NUnit)
+- [XUnit](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit)
+- [XUnit.V3](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit.V3)
## Basic functionality
diff --git a/src/NetEvolve.Extensions.MSTest/UnitTestAttribute.cs b/src/NetEvolve.Extensions.MSTest/UnitTestAttribute.cs
index ad6032c..074e91d 100644
--- a/src/NetEvolve.Extensions.MSTest/UnitTestAttribute.cs
+++ b/src/NetEvolve.Extensions.MSTest/UnitTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.MSTest;
+using System;
using NetEvolve.Extensions.MSTest.Internal;
///
/// Attribute used to decorate a test class or method as UnitTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class UnitTestAttribute : TestTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.NUnit/AcceptanceTestAttribute.cs b/src/NetEvolve.Extensions.NUnit/AcceptanceTestAttribute.cs
index 0a4be3a..67c6490 100644
--- a/src/NetEvolve.Extensions.NUnit/AcceptanceTestAttribute.cs
+++ b/src/NetEvolve.Extensions.NUnit/AcceptanceTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.NUnit;
+using System;
using global::NUnit.Framework;
///
/// Attribute used to decorate a test class or method as AcceptanceTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class AcceptanceTestAttribute : CategoryAttribute
{
///
diff --git a/src/NetEvolve.Extensions.NUnit/ArchitectureTestAttribute.cs b/src/NetEvolve.Extensions.NUnit/ArchitectureTestAttribute.cs
index fec2579..8a594a5 100644
--- a/src/NetEvolve.Extensions.NUnit/ArchitectureTestAttribute.cs
+++ b/src/NetEvolve.Extensions.NUnit/ArchitectureTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.NUnit;
+using System;
using global::NUnit.Framework;
///
/// Attribute used to decorate a test class or method as ArchitectureTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class ArchitectureTestAttribute : CategoryAttribute
{
///
diff --git a/src/NetEvolve.Extensions.NUnit/CodedUITestAttribute.cs b/src/NetEvolve.Extensions.NUnit/CodedUITestAttribute.cs
index 5bcf46c..f073e55 100644
--- a/src/NetEvolve.Extensions.NUnit/CodedUITestAttribute.cs
+++ b/src/NetEvolve.Extensions.NUnit/CodedUITestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.NUnit;
+using System;
using global::NUnit.Framework;
///
/// Attribute used to decorate a test class or method as CodedUITest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class CodedUITestAttribute : CategoryAttribute
{
///
diff --git a/src/NetEvolve.Extensions.NUnit/EndToEndTestAttribute.cs b/src/NetEvolve.Extensions.NUnit/EndToEndTestAttribute.cs
index 53dc6d1..1e42369 100644
--- a/src/NetEvolve.Extensions.NUnit/EndToEndTestAttribute.cs
+++ b/src/NetEvolve.Extensions.NUnit/EndToEndTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.NUnit;
+using System;
using global::NUnit.Framework;
///
/// Attribute used to decorate a test class or method as EndToEndTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class EndToEndTestAttribute : CategoryAttribute
{
///
diff --git a/src/NetEvolve.Extensions.NUnit/FunctionalTestAttribute.cs b/src/NetEvolve.Extensions.NUnit/FunctionalTestAttribute.cs
index 65acf68..38d73f8 100644
--- a/src/NetEvolve.Extensions.NUnit/FunctionalTestAttribute.cs
+++ b/src/NetEvolve.Extensions.NUnit/FunctionalTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.NUnit;
+using System;
using global::NUnit.Framework;
///
/// Attribute used to decorate a test class or method as FunctionalTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class FunctionalTestAttribute : CategoryAttribute
{
///
diff --git a/src/NetEvolve.Extensions.NUnit/PerformanceTestAttribute.cs b/src/NetEvolve.Extensions.NUnit/PerformanceTestAttribute.cs
index 7379632..202acf7 100644
--- a/src/NetEvolve.Extensions.NUnit/PerformanceTestAttribute.cs
+++ b/src/NetEvolve.Extensions.NUnit/PerformanceTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.NUnit;
+using System;
using global::NUnit.Framework;
///
/// Attribute used to decorate a test class or method as PerformanceTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class PerformanceTestAttribute : CategoryAttribute
{
///
diff --git a/src/NetEvolve.Extensions.NUnit/PostDeploymentAttribute.cs b/src/NetEvolve.Extensions.NUnit/PostDeploymentAttribute.cs
index 15b7058..8eeef5a 100644
--- a/src/NetEvolve.Extensions.NUnit/PostDeploymentAttribute.cs
+++ b/src/NetEvolve.Extensions.NUnit/PostDeploymentAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.NUnit;
+using System;
using global::NUnit.Framework;
///
/// Attribute used to decorate a test class or method as PostDeployment.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class PostDeploymentAttribute : CategoryAttribute
{
///
diff --git a/src/NetEvolve.Extensions.NUnit/PreDeploymentAttribute.cs b/src/NetEvolve.Extensions.NUnit/PreDeploymentAttribute.cs
index c1d944c..b549f61 100644
--- a/src/NetEvolve.Extensions.NUnit/PreDeploymentAttribute.cs
+++ b/src/NetEvolve.Extensions.NUnit/PreDeploymentAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.NUnit;
+using System;
using global::NUnit.Framework;
///
/// Attribute used to decorate a test class or method as PreDeployment.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class PreDeploymentAttribute : CategoryAttribute
{
///
diff --git a/src/NetEvolve.Extensions.NUnit/README.md b/src/NetEvolve.Extensions.NUnit/README.md
index 1909a7f..4e948d5 100644
--- a/src/NetEvolve.Extensions.NUnit/README.md
+++ b/src/NetEvolve.Extensions.NUnit/README.md
@@ -1,10 +1,11 @@
# NetEvolve.Extensions.NUnit
Compatibility library for solutions using multiple .NET test frameworks.
-The following test frameworks are supported -
-[MSTest](https://www.nuget.org/packages/NetEvolve.Extensions.MSTest),
-[NUnit](https://www.nuget.org/packages/NetEvolve.Extensions.NUnit) &
-[XUnit](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit).
+The following test frameworks are supported
+- [MSTest](https://www.nuget.org/packages/NetEvolve.Extensions.MSTest),
+- [NUnit](https://www.nuget.org/packages/NetEvolve.Extensions.NUnit)
+- [XUnit](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit)
+- [XUnit.V3](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit.V3)
## Basic functionality
diff --git a/src/NetEvolve.Extensions.NUnit/UnitTestAttribute.cs b/src/NetEvolve.Extensions.NUnit/UnitTestAttribute.cs
index e68cd03..85f0ebe 100644
--- a/src/NetEvolve.Extensions.NUnit/UnitTestAttribute.cs
+++ b/src/NetEvolve.Extensions.NUnit/UnitTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.NUnit;
+using System;
using global::NUnit.Framework;
///
/// Attribute used to decorate a test class or method as UnitTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class UnitTestAttribute : CategoryAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit.V3/AcceptanceTestAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/AcceptanceTestAttribute.cs
new file mode 100644
index 0000000..6d0bc3b
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/AcceptanceTestAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as AcceptanceTest.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class AcceptanceTestAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AcceptanceTestAttribute()
+ : base(Internals.AcceptanceTest) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/ArchitectureTestAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/ArchitectureTestAttribute.cs
new file mode 100644
index 0000000..9f3b9e5
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/ArchitectureTestAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as ArchitectureTest.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class ArchitectureTestAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ArchitectureTestAttribute()
+ : base(Internals.ArchitectureTest) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/BugAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/BugAttribute.cs
new file mode 100644
index 0000000..6077435
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/BugAttribute.cs
@@ -0,0 +1,31 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as Bug, with optional Id.
+///
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
+public sealed class BugAttribute : CategoryWithIdTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public BugAttribute()
+ : base(Internals.Bug, null) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Bug Id
+ public BugAttribute(string? id)
+ : base(Internals.Bug, id) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Bug Id
+ public BugAttribute(long id)
+ : base(Internals.Bug, id) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/CodedUITestAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/CodedUITestAttribute.cs
new file mode 100644
index 0000000..86530a3
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/CodedUITestAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as CodedUITest.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class CodedUITestAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public CodedUITestAttribute()
+ : base(Internals.CodedUITest) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/EndToEndTestAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/EndToEndTestAttribute.cs
new file mode 100644
index 0000000..26804ab
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/EndToEndTestAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as EndToEndTest.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class EndToEndTestAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public EndToEndTestAttribute()
+ : base(Internals.EndToEndTest) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/EpicAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/EpicAttribute.cs
new file mode 100644
index 0000000..4099cc5
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/EpicAttribute.cs
@@ -0,0 +1,31 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as Epic, with optional Id
+///
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
+public sealed class EpicAttribute : CategoryWithIdTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public EpicAttribute()
+ : base(Internals.Epic, null) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Bug Id
+ public EpicAttribute(string? id)
+ : base(Internals.Epic, id) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Bug Id
+ public EpicAttribute(long id)
+ : base(Internals.Epic, id) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/FeatureAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/FeatureAttribute.cs
new file mode 100644
index 0000000..963c39c
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/FeatureAttribute.cs
@@ -0,0 +1,31 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as Feature, with optional Id
+///
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
+public sealed class FeatureAttribute : CategoryWithIdTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public FeatureAttribute()
+ : base(Internals.Feature, null) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Feature Id
+ public FeatureAttribute(string? id)
+ : base(Internals.Feature, id) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Feature Id
+ public FeatureAttribute(long id)
+ : base(Internals.Feature, id) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/FunctionalTestAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/FunctionalTestAttribute.cs
new file mode 100644
index 0000000..b6e239f
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/FunctionalTestAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as FunctionalTest.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class FunctionalTestAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public FunctionalTestAttribute()
+ : base(Internals.FunctionalTest) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/IntegrationTestAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/IntegrationTestAttribute.cs
new file mode 100644
index 0000000..c8927fc
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/IntegrationTestAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as IntegrationTest.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class IntegrationTestAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public IntegrationTestAttribute()
+ : base(Internals.IntegrationTest) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/Internal/CategoryTraitBaseAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/Internal/CategoryTraitBaseAttribute.cs
new file mode 100644
index 0000000..290ac68
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/Internal/CategoryTraitBaseAttribute.cs
@@ -0,0 +1,39 @@
+namespace NetEvolve.Extensions.XUnit.V3.Internal;
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using Xunit.Internal;
+using Xunit.v3;
+
+///
+/// Abstract class implementation of .
+/// Provides property .
+///
+[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "As designed.")]
+public abstract class CategoryTraitBaseAttribute : Attribute, ITraitAttribute
+{
+ ///
+ /// Gets the category value of the trait.
+ ///
+ public string Category { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ protected CategoryTraitBaseAttribute(string category) => Category = category;
+
+ ///
+ public IReadOnlyCollection> GetTraits()
+ {
+ var result = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ if (!string.IsNullOrWhiteSpace(Category))
+ {
+ result.Add(Internals.TestCategory, Category);
+ }
+
+ return result.CastOrToReadOnlyCollection();
+ }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/Internal/CategoryWithIdTraitBaseAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/Internal/CategoryWithIdTraitBaseAttribute.cs
new file mode 100644
index 0000000..f6e4201
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/Internal/CategoryWithIdTraitBaseAttribute.cs
@@ -0,0 +1,79 @@
+namespace NetEvolve.Extensions.XUnit.V3.Internal;
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using NetEvolve.Extensions.XUnit.V3;
+using Xunit.Internal;
+using Xunit.v3;
+
+///
+///
+/// Abstract class implementation of .
+/// Provides basic functionality for category / id based testing.
+///
+///
+/// Like:
+///
+///
+///
+///
+///
+///
+///
+///
+///
+///
+[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "As designed.")]
+public abstract class CategoryWithIdTraitBaseAttribute : Attribute, ITraitAttribute
+{
+ ///
+ /// Gets the category value of the trait.
+ ///
+ public string Category { get; }
+
+ ///
+ /// Gets the Id
+ ///
+ public string? Id { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Category
+ /// Id
+ protected CategoryWithIdTraitBaseAttribute(string category, string? id)
+ {
+ Category = category;
+ Id = id;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Category
+ /// Id
+ protected CategoryWithIdTraitBaseAttribute(string category, long id)
+ {
+ Category = category;
+ Id = $"{id}";
+ }
+
+ ///
+ public IReadOnlyCollection> GetTraits()
+ {
+ var result = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ if (!string.IsNullOrWhiteSpace(Category))
+ {
+ result.Add(Internals.TestCategory, Category);
+
+ if (!string.IsNullOrWhiteSpace(Id))
+ {
+ result.Add(Category, Id);
+ }
+ }
+
+ return result.CastOrToReadOnlyCollection();
+ }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/Internal/CultureAttributeBase.cs b/src/NetEvolve.Extensions.XUnit.V3/Internal/CultureAttributeBase.cs
new file mode 100644
index 0000000..968eb3d
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/Internal/CultureAttributeBase.cs
@@ -0,0 +1,87 @@
+namespace NetEvolve.Extensions.XUnit.V3.Internal;
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Threading.Tasks;
+using Xunit.v3;
+
+///
+/// Abstract class implementation of .
+/// Provides basic functionality for culture-based testing.
+///
+[AttributeUsage(
+ AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true,
+ Inherited = true
+)]
+//[TraitDiscoverer(Namespaces.CultureTraitDiscoverer, Namespaces.Assembly)]
+#pragma warning disable S3376 // Attribute, EventArgs, and Exception type names should end with the type being extended
+#pragma warning disable CA1710 // Identifiers should have correct suffix
+public abstract class CultureAttributeBase : Attribute, IBeforeAfterTestAttribute, ITraitAttribute
+#pragma warning restore CA1710 // Identifiers should have correct suffix
+#pragma warning restore S3376 // Attribute, EventArgs, and Exception type names should end with the type being extended
+{
+ private readonly CultureInfo _culture;
+
+ private CultureInfo? _originalCulture;
+ private bool _changed;
+
+ ///
+ /// Category
+ ///
+ public string Category { get; }
+
+ ///
+ /// Culture
+ ///
+ public string Culture { get; }
+
+ ///
+ protected CultureAttributeBase(string category, string culture)
+ {
+ Category = category;
+ Culture = culture;
+ _culture = CreateCultureInfo(culture);
+ }
+
+ ///
+ public virtual ValueTask After(MethodInfo methodUnderTest, IXunitTest test)
+ {
+ if (_changed)
+ {
+ _ = SetCulture(_originalCulture!);
+ }
+
+ return new ValueTask();
+ }
+
+ ///
+ public virtual ValueTask Before(MethodInfo methodUnderTest, IXunitTest test)
+ {
+ _originalCulture = CultureInfo.CurrentCulture;
+
+ _changed = SetCulture(_culture);
+
+ return new ValueTask();
+ }
+
+ private protected static CultureInfo CreateCultureInfo(string culture) =>
+ new CultureInfo(culture, false);
+
+ private protected virtual bool SetCulture(CultureInfo culture)
+ {
+ if (CultureInfo.CurrentCulture != culture)
+ {
+ CultureInfo.CurrentCulture = culture;
+ CultureInfo.DefaultThreadCurrentCulture = culture;
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ public abstract IReadOnlyCollection> GetTraits();
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/Internals.cs b/src/NetEvolve.Extensions.XUnit.V3/Internals.cs
new file mode 100644
index 0000000..5d2d3d7
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/Internals.cs
@@ -0,0 +1,112 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+///
+/// All internal names
+///
+internal static class Internals
+{
+ ///
+ /// Id-Property
+ ///
+ public const string Id = nameof(Id);
+
+ ///
+ /// Culture
+ ///
+ public const string Culture = nameof(Culture);
+
+ ///
+ /// UI Culture
+ ///
+ public const string UICulture = nameof(UICulture);
+
+ ///
+ /// Test Category
+ ///
+ public const string Category = nameof(Category);
+
+ ///
+ /// Test Category
+ ///
+ public const string TestCategory = nameof(TestCategory);
+
+ ///
+ /// Bugs
+ ///
+ public const string Bug = nameof(Bug);
+
+ ///
+ /// Epics
+ ///
+ public const string Epic = nameof(Epic);
+
+ ///
+ /// Features
+ ///
+ public const string Feature = nameof(Feature);
+
+ ///
+ /// Issues
+ ///
+ public const string Issue = nameof(Issue);
+
+ ///
+ /// PostDeployments
+ ///
+ public const string PostDeployment = nameof(PostDeployment);
+
+ ///
+ /// PreDeployments
+ ///
+ public const string PreDeployment = nameof(PreDeployment);
+
+ ///
+ /// UnitTests
+ ///
+ public const string UnitTest = nameof(UnitTest);
+
+ ///
+ /// UserStories
+ ///
+ public const string UserStory = nameof(UserStory);
+
+ ///
+ /// WorkItems
+ ///
+ public const string WorkItem = nameof(WorkItem);
+
+ ///
+ /// AcceptanceTests
+ ///
+ public const string AcceptanceTest = nameof(AcceptanceTest);
+
+ ///
+ /// FunctionalTests
+ ///
+ public const string FunctionalTest = nameof(FunctionalTest);
+
+ ///
+ /// IntegrationTests
+ ///
+ public const string IntegrationTest = nameof(IntegrationTest);
+
+ ///
+ /// EndToEndTests
+ ///
+ public const string EndToEndTest = nameof(EndToEndTest);
+
+ ///
+ /// IntegrationTests
+ ///
+ public const string PerformanceTest = nameof(PerformanceTest);
+
+ ///
+ /// ArchitectureTest
+ ///
+ public const string ArchitectureTest = nameof(ArchitectureTest);
+
+ ///
+ /// CodedUITest
+ ///
+ public const string CodedUITest = nameof(CodedUITest);
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/IssueAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/IssueAttribute.cs
new file mode 100644
index 0000000..2960130
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/IssueAttribute.cs
@@ -0,0 +1,31 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as Issue, with optional Id
+///
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
+public sealed class IssueAttribute : CategoryWithIdTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public IssueAttribute()
+ : base(Internals.Issue, null) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Issue Id
+ public IssueAttribute(string? id)
+ : base(Internals.Issue, id) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Issue Id
+ public IssueAttribute(long id)
+ : base(Internals.Issue, id) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/NetEvolve.Extensions.XUnit.V3.csproj b/src/NetEvolve.Extensions.XUnit.V3/NetEvolve.Extensions.XUnit.V3.csproj
new file mode 100644
index 0000000..37c262b
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/NetEvolve.Extensions.XUnit.V3.csproj
@@ -0,0 +1,14 @@
+
+
+
+ netstandard2.0;net6.0
+
+ $(NoWarn);NU5104
+ $(NoWarn);nullable
+
+
+
+
+
+
+
diff --git a/src/NetEvolve.Extensions.XUnit.V3/PerformanceTestAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/PerformanceTestAttribute.cs
new file mode 100644
index 0000000..5020744
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/PerformanceTestAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as PerformanceTest.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class PerformanceTestAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PerformanceTestAttribute()
+ : base(Internals.PerformanceTest) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/PostDeploymentAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/PostDeploymentAttribute.cs
new file mode 100644
index 0000000..94a9cd3
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/PostDeploymentAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method with TestCategory PostDeployment.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class PostDeploymentAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PostDeploymentAttribute()
+ : base(Internals.PostDeployment) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/PreDeploymentAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/PreDeploymentAttribute.cs
new file mode 100644
index 0000000..a35e406
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/PreDeploymentAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method with TestCategory PreDeployment.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class PreDeploymentAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PreDeploymentAttribute()
+ : base(Internals.PreDeployment) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/README.md b/src/NetEvolve.Extensions.XUnit.V3/README.md
new file mode 100644
index 0000000..0c254e3
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/README.md
@@ -0,0 +1,48 @@
+# NetEvolve.Extensions.XUnit.V3
+
+Compatibility library for solutions using multiple .NET test frameworks.
+The following test frameworks are supported
+- [MSTest](https://www.nuget.org/packages/NetEvolve.Extensions.MSTest),
+- [NUnit](https://www.nuget.org/packages/NetEvolve.Extensions.NUnit)
+- [XUnit](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit)
+- [XUnit.V3](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit.V3)
+
+## Basic functionality
+
+For consistent usage and addressing of use cases like
+`dotnet test -c Release --filter TestCategory=IntegrationTest`,
+the following attributes are provided in this library in the namespace `NetEvolve.Extensions.XUnit`.
+
+- `AcceptanceTestAttribute`
+- `ArchitectureTestAttribute`
+- `BugAttribute`
+- `EndToEndTestAttribute`
+- `EpicAttribute`
+- `FeatureAttribute`
+- `FunctionalTestAttribute`
+- `IntegrationTestAttribute`
+- `IssueAttribute`
+- `PerformanceTestAttribute`
+- `PostDeploymentTestAttribute`
+- `PreDeploymentTestAttribute`
+- `UnitTestAttribute`
+- `UserStoryAttribute`
+- `WorkItemAttribute`
+
+### Applying
+These can be applied on assembly, class or method definitions as follows.
+
+```cs
+[assembly: AcceptanceTest] // Mark all test methods of this assembly as AcceptanceTest
+
+[AcceptanceTest] // Mark all test methods of this class as AcceptanceTest
+public partial class FantasticTest
+{
+ [Fact]
+ [AcceptanceTest] // Alternatively, only one method can be selected.
+ public void I_am_Ironman()
+ {
+ Assert.Fail();
+ }
+}
+```
\ No newline at end of file
diff --git a/src/NetEvolve.Extensions.XUnit.V3/SetCultureAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/SetCultureAttribute.cs
new file mode 100644
index 0000000..60615ec
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/SetCultureAttribute.cs
@@ -0,0 +1,100 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Reflection;
+using System.Threading.Tasks;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+using Xunit.Internal;
+using Xunit.v3;
+
+///
+/// Based on the value passed as culture, the marked test is executed.
+///
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false)]
+public sealed class SetCultureAttribute : CultureAttributeBase
+{
+ private readonly CultureInfo _uiCulture;
+ private CultureInfo? _originalUICulture;
+ private bool _changed;
+
+ ///
+ /// UI culture
+ ///
+ public string? UICulture { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SetCultureAttribute()
+ : this(string.Empty, string.Empty) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Culture to use.
+ public SetCultureAttribute(string culture)
+ : this(culture, culture) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Culture to use.
+ /// UI culture to use.
+ public SetCultureAttribute(string culture, string? uiCulture)
+ : base("SetCulture", culture)
+ {
+ if (string.IsNullOrWhiteSpace(uiCulture))
+ {
+ uiCulture = string.Empty;
+ }
+
+ _uiCulture = CreateCultureInfo(uiCulture!);
+ }
+
+ ///
+ public override async ValueTask After(MethodInfo methodUnderTest, IXunitTest test)
+ {
+ await base.After(methodUnderTest, test).ConfigureAwait(false);
+
+ if (_changed)
+ {
+ _ = SetUICulture(_originalUICulture!);
+ }
+ }
+
+ ///
+ public override async ValueTask Before(MethodInfo methodUnderTest, IXunitTest test)
+ {
+ await base.Before(methodUnderTest, test).ConfigureAwait(false);
+
+ _originalUICulture = CultureInfo.CurrentUICulture;
+ _changed = SetUICulture(_uiCulture);
+ }
+
+ private static bool SetUICulture(CultureInfo culture)
+ {
+ if (CultureInfo.CurrentUICulture != culture)
+ {
+ CultureInfo.CurrentUICulture = culture;
+ CultureInfo.DefaultThreadCurrentUICulture = culture;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ public override IReadOnlyCollection> GetTraits()
+ {
+ var result = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "SetCulture", Culture },
+ { "SetUICulture", Culture },
+ };
+
+ return result.CastOrToReadOnlyList();
+ }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/SetUICultureAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/SetUICultureAttribute.cs
new file mode 100644
index 0000000..9948dc3
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/SetUICultureAttribute.cs
@@ -0,0 +1,50 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+using Xunit.Internal;
+
+///
+/// Based on the value passed as UI culture, the marked test is executed.
+///
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false)]
+public sealed class SetUICultureAttribute : CultureAttributeBase
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SetUICultureAttribute()
+ : base("SetUICulture", string.Empty) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// UI culture to use.
+ public SetUICultureAttribute(string culture)
+ : base("SetUICulture", culture) { }
+
+ private protected override bool SetCulture(CultureInfo culture)
+ {
+ if (CultureInfo.CurrentUICulture != culture)
+ {
+ CultureInfo.CurrentUICulture = culture;
+ CultureInfo.DefaultThreadCurrentUICulture = culture;
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ public override IReadOnlyCollection> GetTraits()
+ {
+ var result = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "SetUICulture", Culture },
+ };
+
+ return result.CastOrToReadOnlyList();
+ }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/UnitTestAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/UnitTestAttribute.cs
new file mode 100644
index 0000000..02b6fb2
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/UnitTestAttribute.cs
@@ -0,0 +1,20 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as UnitTest.
+///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
+public sealed class UnitTestAttribute : CategoryTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public UnitTestAttribute()
+ : base(Internals.UnitTest) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/UserStoryAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/UserStoryAttribute.cs
new file mode 100644
index 0000000..6083857
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/UserStoryAttribute.cs
@@ -0,0 +1,31 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as UserStory, with optional Id
+///
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
+public sealed class UserStoryAttribute : CategoryWithIdTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public UserStoryAttribute()
+ : base(Internals.UserStory, null) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// UserStory Id
+ public UserStoryAttribute(string? id)
+ : base(Internals.UserStory, id) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// UserStory Id
+ public UserStoryAttribute(long id)
+ : base(Internals.UserStory, id) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit.V3/WorkItemAttribute.cs b/src/NetEvolve.Extensions.XUnit.V3/WorkItemAttribute.cs
new file mode 100644
index 0000000..ab2ace7
--- /dev/null
+++ b/src/NetEvolve.Extensions.XUnit.V3/WorkItemAttribute.cs
@@ -0,0 +1,31 @@
+namespace NetEvolve.Extensions.XUnit.V3;
+
+using System;
+using NetEvolve.Extensions.XUnit.V3.Internal;
+
+///
+/// Attribute used to decorate a test class or method as WorkItem, with optional Id
+///
+[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
+public sealed class WorkItemAttribute : CategoryWithIdTraitBaseAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public WorkItemAttribute()
+ : base(Internals.WorkItem, null) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// WorkItem Id
+ public WorkItemAttribute(string? id)
+ : base(Internals.WorkItem, id) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// WorkItem Id
+ public WorkItemAttribute(long id)
+ : base(Internals.WorkItem, id) { }
+}
diff --git a/src/NetEvolve.Extensions.XUnit/AcceptanceTestAttribute.cs b/src/NetEvolve.Extensions.XUnit/AcceptanceTestAttribute.cs
index 1190a19..3450e5c 100644
--- a/src/NetEvolve.Extensions.XUnit/AcceptanceTestAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/AcceptanceTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as AcceptanceTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class AcceptanceTestAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/ArchitectureTestAttribute.cs b/src/NetEvolve.Extensions.XUnit/ArchitectureTestAttribute.cs
index 6c8754b..41c7420 100644
--- a/src/NetEvolve.Extensions.XUnit/ArchitectureTestAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/ArchitectureTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as ArchitectureTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class ArchitectureTestAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/CodedUITestAttribute.cs b/src/NetEvolve.Extensions.XUnit/CodedUITestAttribute.cs
index 63ac6f1..286d8c8 100644
--- a/src/NetEvolve.Extensions.XUnit/CodedUITestAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/CodedUITestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as CodedUITest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class CodedUITestAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/EndToEndTestAttribute.cs b/src/NetEvolve.Extensions.XUnit/EndToEndTestAttribute.cs
index ca76a12..59b7d3f 100644
--- a/src/NetEvolve.Extensions.XUnit/EndToEndTestAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/EndToEndTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as EndToEndTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class EndToEndTestAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/EpicAttribute.cs b/src/NetEvolve.Extensions.XUnit/EpicAttribute.cs
index 5e65fd2..98d35ff 100644
--- a/src/NetEvolve.Extensions.XUnit/EpicAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/EpicAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as Epic, with optional Id
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class EpicAttribute : CategoryWithIdTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/FeatureAttribute.cs b/src/NetEvolve.Extensions.XUnit/FeatureAttribute.cs
index 70f6081..b52c887 100644
--- a/src/NetEvolve.Extensions.XUnit/FeatureAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/FeatureAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as Feature, with optional Id
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class FeatureAttribute : CategoryWithIdTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/FunctionalTestAttribute.cs b/src/NetEvolve.Extensions.XUnit/FunctionalTestAttribute.cs
index cf59f90..8eaa7a6 100644
--- a/src/NetEvolve.Extensions.XUnit/FunctionalTestAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/FunctionalTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as FunctionalTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class FunctionalTestAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/IntegrationTestAttribute.cs b/src/NetEvolve.Extensions.XUnit/IntegrationTestAttribute.cs
index a4b727a..ec20cc8 100644
--- a/src/NetEvolve.Extensions.XUnit/IntegrationTestAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/IntegrationTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as IntegrationTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class IntegrationTestAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/Internal/CategoryTraitBaseAttribute.cs b/src/NetEvolve.Extensions.XUnit/Internal/CategoryTraitBaseAttribute.cs
index f586aed..e0350cc 100644
--- a/src/NetEvolve.Extensions.XUnit/Internal/CategoryTraitBaseAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/Internal/CategoryTraitBaseAttribute.cs
@@ -9,11 +9,6 @@
/// Abstract class implementation of .
/// Provides property .
///
-[AttributeUsage(
- AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
- AllowMultiple = true,
- Inherited = true
-)]
[TraitDiscoverer(Namespaces.CategoryTraitDiscoverer, Namespaces.Assembly)]
[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "As designed.")]
public abstract class CategoryTraitBaseAttribute : Attribute, ITraitAttribute
diff --git a/src/NetEvolve.Extensions.XUnit/Internal/CategoryWithIdTraitBaseAttribute.cs b/src/NetEvolve.Extensions.XUnit/Internal/CategoryWithIdTraitBaseAttribute.cs
index 23ab439..99de57f 100644
--- a/src/NetEvolve.Extensions.XUnit/Internal/CategoryWithIdTraitBaseAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/Internal/CategoryWithIdTraitBaseAttribute.cs
@@ -21,11 +21,6 @@
///
///
///
-[AttributeUsage(
- AttributeTargets.Class | AttributeTargets.Method,
- AllowMultiple = true,
- Inherited = true
-)]
[TraitDiscoverer(Namespaces.CategoryTraitDiscoverer, Namespaces.Assembly)]
[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "As designed.")]
public abstract class CategoryWithIdTraitBaseAttribute : Attribute, ITraitAttribute
diff --git a/src/NetEvolve.Extensions.XUnit/IssueAttribute.cs b/src/NetEvolve.Extensions.XUnit/IssueAttribute.cs
index cc1c4cd..bfeaf23 100644
--- a/src/NetEvolve.Extensions.XUnit/IssueAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/IssueAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as Issue, with optional Id
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class IssueAttribute : CategoryWithIdTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/PerformanceTestAttribute.cs b/src/NetEvolve.Extensions.XUnit/PerformanceTestAttribute.cs
index 9ed02fb..accaa0a 100644
--- a/src/NetEvolve.Extensions.XUnit/PerformanceTestAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/PerformanceTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as PerformanceTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class PerformanceTestAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/PostDeploymentAttribute.cs b/src/NetEvolve.Extensions.XUnit/PostDeploymentAttribute.cs
index 7f69ad7..350ed4a 100644
--- a/src/NetEvolve.Extensions.XUnit/PostDeploymentAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/PostDeploymentAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method with TestCategory PostDeployment.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class PostDeploymentAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/PreDeploymentAttribute.cs b/src/NetEvolve.Extensions.XUnit/PreDeploymentAttribute.cs
index 6d55f66..06765eb 100644
--- a/src/NetEvolve.Extensions.XUnit/PreDeploymentAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/PreDeploymentAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method with TestCategory PreDeployment.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class PreDeploymentAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/README.md b/src/NetEvolve.Extensions.XUnit/README.md
index b3e3009..8bddfcf 100644
--- a/src/NetEvolve.Extensions.XUnit/README.md
+++ b/src/NetEvolve.Extensions.XUnit/README.md
@@ -1,10 +1,11 @@
# NetEvolve.Extensions.XUnit
Compatibility library for solutions using multiple .NET test frameworks.
-The following test frameworks are supported -
-[MSTest](https://www.nuget.org/packages/NetEvolve.Extensions.MSTest),
-[NUnit](https://www.nuget.org/packages/NetEvolve.Extensions.NUnit) &
-[XUnit](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit).
+The following test frameworks are supported
+- [MSTest](https://www.nuget.org/packages/NetEvolve.Extensions.MSTest),
+- [NUnit](https://www.nuget.org/packages/NetEvolve.Extensions.NUnit)
+- [XUnit](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit)
+- [XUnit.V3](https://www.nuget.org/packages/NetEvolve.Extensions.XUnit.V3)
## Basic functionality
diff --git a/src/NetEvolve.Extensions.XUnit/UnitTestAttribute.cs b/src/NetEvolve.Extensions.XUnit/UnitTestAttribute.cs
index f562e82..7032448 100644
--- a/src/NetEvolve.Extensions.XUnit/UnitTestAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/UnitTestAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as UnitTest.
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class UnitTestAttribute : CategoryTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/UserStoryAttribute.cs b/src/NetEvolve.Extensions.XUnit/UserStoryAttribute.cs
index d242e19..779c5d3 100644
--- a/src/NetEvolve.Extensions.XUnit/UserStoryAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/UserStoryAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as UserStory, with optional Id
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class UserStoryAttribute : CategoryWithIdTraitBaseAttribute
{
///
diff --git a/src/NetEvolve.Extensions.XUnit/WorkItemAttribute.cs b/src/NetEvolve.Extensions.XUnit/WorkItemAttribute.cs
index b74747a..6b8479a 100644
--- a/src/NetEvolve.Extensions.XUnit/WorkItemAttribute.cs
+++ b/src/NetEvolve.Extensions.XUnit/WorkItemAttribute.cs
@@ -1,10 +1,15 @@
namespace NetEvolve.Extensions.XUnit;
+using System;
using NetEvolve.Extensions.XUnit.Internal;
///
/// Attribute used to decorate a test class or method as WorkItem, with optional Id
///
+[AttributeUsage(
+ AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method,
+ AllowMultiple = true
+)]
public sealed class WorkItemAttribute : CategoryWithIdTraitBaseAttribute
{
///
diff --git a/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/Predefined.cs b/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/Predefined.cs
index 4abac83..30eb4ef 100644
--- a/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/Predefined.cs
+++ b/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/Predefined.cs
@@ -23,7 +23,7 @@ public static void Init()
}
);
- VerifierSettings.AutoVerify(includeBuildServer: false);
VerifierSettings.SortPropertiesAlphabetically();
+ VerifierSettings.SortJsonObjects();
}
}
diff --git a/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/PublicApiTests.cs b/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/PublicApiTests.cs
index d26f608..d32262d 100644
--- a/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/PublicApiTests.cs
+++ b/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/PublicApiTests.cs
@@ -29,6 +29,7 @@ public Task PublicApi_HasNotChanged_Expected()
typeof(CLSCompliantAttribute).FullName!,
typeof(AssemblyMetadataAttribute).FullName!,
typeof(NeutralResourcesLanguageAttribute).FullName!,
+ typeof(AttributeUsageAttribute).FullName!,
],
IncludeTypes = types,
};
diff --git a/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt b/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
index ea74e0f..b605413 100644
--- a/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
+++ b/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
@@ -8,7 +8,6 @@
{
public ArchitectureTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class BugAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public BugAttribute() { }
@@ -23,14 +22,12 @@
{
public EndToEndTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class EpicAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public EpicAttribute() { }
public EpicAttribute(long id) { }
public EpicAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class FeatureAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public FeatureAttribute() { }
@@ -45,7 +42,6 @@
{
public IntegrationTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class IssueAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public IssueAttribute() { }
@@ -68,14 +64,12 @@
{
public UnitTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class UserStoryAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public UserStoryAttribute() { }
public UserStoryAttribute(long id) { }
public UserStoryAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class WorkItemAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public WorkItemAttribute() { }
@@ -90,7 +84,6 @@ namespace NetEvolve.Extensions.MSTest.Internal
protected TestCategoryWithIdBaseAttribute(string categoryName, string? id = null) { }
public string? Id { get; }
}
- [System.AttributeUsage(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
public abstract class TestTraitBaseAttribute : Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryBaseAttribute
{
protected TestTraitBaseAttribute(string categoryName) { }
diff --git a/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt b/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
index ea74e0f..b605413 100644
--- a/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
+++ b/tests/NetEvolve.Extensions.MSTest.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
@@ -8,7 +8,6 @@
{
public ArchitectureTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class BugAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public BugAttribute() { }
@@ -23,14 +22,12 @@
{
public EndToEndTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class EpicAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public EpicAttribute() { }
public EpicAttribute(long id) { }
public EpicAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class FeatureAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public FeatureAttribute() { }
@@ -45,7 +42,6 @@
{
public IntegrationTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class IssueAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public IssueAttribute() { }
@@ -68,14 +64,12 @@
{
public UnitTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class UserStoryAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public UserStoryAttribute() { }
public UserStoryAttribute(long id) { }
public UserStoryAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class WorkItemAttribute : NetEvolve.Extensions.MSTest.Internal.TestCategoryWithIdBaseAttribute
{
public WorkItemAttribute() { }
@@ -90,7 +84,6 @@ namespace NetEvolve.Extensions.MSTest.Internal
protected TestCategoryWithIdBaseAttribute(string categoryName, string? id = null) { }
public string? Id { get; }
}
- [System.AttributeUsage(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
public abstract class TestTraitBaseAttribute : Microsoft.VisualStudio.TestTools.UnitTesting.TestCategoryBaseAttribute
{
protected TestTraitBaseAttribute(string categoryName) { }
diff --git a/tests/NetEvolve.Extensions.MSTest.Tests.Unit/AttributeTestsBase.cs b/tests/NetEvolve.Extensions.MSTest.Tests.Unit/AttributeTestsBase.cs
index 26b7a05..f8099df 100644
--- a/tests/NetEvolve.Extensions.MSTest.Tests.Unit/AttributeTestsBase.cs
+++ b/tests/NetEvolve.Extensions.MSTest.Tests.Unit/AttributeTestsBase.cs
@@ -36,25 +36,27 @@ protected IEnumerable> GetProperties(
if (methodInfo is null)
{
- return Enumerable.Empty>();
+ return [];
}
var categories = GetTestCategoryBaseAttributes(methodInfo).ToArray();
if (categories.Length == 0)
{
- categories = categories.Concat(GetTestCategoryBaseAttributes(owningType)).ToArray();
+ categories = [.. categories, .. GetTestCategoryBaseAttributes(owningType)];
}
if (categories.Length == 0)
{
- categories = categories
- .Concat(GetTestCategoryBaseAttributes(owningType.Module.Assembly))
- .ToArray();
+ categories =
+ [
+ .. categories,
+ .. GetTestCategoryBaseAttributes(owningType.Module.Assembly),
+ ];
}
if (categories.Length == 0)
{
- return Array.Empty>();
+ return [];
}
return categories
@@ -62,7 +64,7 @@ protected IEnumerable> GetProperties(
.Distinct();
}
- private IEnumerable> GetTestCategoryBaseAttributes(
+ private static IEnumerable> GetTestCategoryBaseAttributes(
Assembly assembly
)
{
@@ -107,7 +109,7 @@ attribute is TestCategoryWithIdBaseAttribute attributeWithId
}
}
- private IEnumerable> GetTestCategoryBaseAttributes(
+ private static IEnumerable> GetTestCategoryBaseAttributes(
MemberInfo? member
)
{
diff --git a/tests/NetEvolve.Extensions.MSTest.Tests.Unit/Predefined.cs b/tests/NetEvolve.Extensions.MSTest.Tests.Unit/Predefined.cs
index 12bb3d5..d6a6808 100644
--- a/tests/NetEvolve.Extensions.MSTest.Tests.Unit/Predefined.cs
+++ b/tests/NetEvolve.Extensions.MSTest.Tests.Unit/Predefined.cs
@@ -24,7 +24,7 @@ public static void Init()
}
);
- VerifierSettings.AutoVerify(includeBuildServer: false);
VerifierSettings.SortPropertiesAlphabetically();
+ VerifierSettings.SortJsonObjects();
}
}
diff --git a/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/Predefined.cs b/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/Predefined.cs
index 53c3d6d..0586666 100644
--- a/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/Predefined.cs
+++ b/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/Predefined.cs
@@ -23,7 +23,7 @@ public static void Init()
}
);
- VerifierSettings.AutoVerify(includeBuildServer: false);
VerifierSettings.SortPropertiesAlphabetically();
+ VerifierSettings.SortJsonObjects();
}
}
diff --git a/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/PublicApiTests.cs b/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/PublicApiTests.cs
index 0cf339a..cd0e33b 100644
--- a/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/PublicApiTests.cs
+++ b/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/PublicApiTests.cs
@@ -29,6 +29,7 @@ public Task PublicApi_HasNotChanged_Expected()
typeof(CLSCompliantAttribute).FullName!,
typeof(AssemblyMetadataAttribute).FullName!,
typeof(NeutralResourcesLanguageAttribute).FullName!,
+ typeof(AttributeUsageAttribute).FullName!,
],
IncludeTypes = types,
};
diff --git a/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt b/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
index 01f3cbf..54b9b1f 100644
--- a/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
+++ b/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
@@ -8,7 +8,6 @@
{
public ArchitectureTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class BugAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public BugAttribute() { }
@@ -31,14 +30,12 @@
{
public EndToEndTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class EpicAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public EpicAttribute() { }
public EpicAttribute(long id) { }
public EpicAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class FeatureAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public FeatureAttribute() { }
@@ -49,19 +46,16 @@
{
public FunctionalTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
public sealed class IntegrationTestAttribute : NUnit.Framework.CategoryAttribute
{
public IntegrationTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class IssueAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public IssueAttribute() { }
public IssueAttribute(long id) { }
public IssueAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple=false, Inherited=false)]
public sealed class MaxLevelOfParallelismAttribute : NUnit.Framework.PropertyAttribute
{
public MaxLevelOfParallelismAttribute(int level) { }
@@ -82,14 +76,12 @@
{
public UnitTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class UserStoryAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public UserStoryAttribute() { }
public UserStoryAttribute(long id) { }
public UserStoryAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class WorkItemAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public WorkItemAttribute() { }
diff --git a/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt b/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
index 01f3cbf..54b9b1f 100644
--- a/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
+++ b/tests/NetEvolve.Extensions.NUnit.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
@@ -8,7 +8,6 @@
{
public ArchitectureTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class BugAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public BugAttribute() { }
@@ -31,14 +30,12 @@
{
public EndToEndTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class EpicAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public EpicAttribute() { }
public EpicAttribute(long id) { }
public EpicAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class FeatureAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public FeatureAttribute() { }
@@ -49,19 +46,16 @@
{
public FunctionalTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
public sealed class IntegrationTestAttribute : NUnit.Framework.CategoryAttribute
{
public IntegrationTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class IssueAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public IssueAttribute() { }
public IssueAttribute(long id) { }
public IssueAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Assembly, AllowMultiple=false, Inherited=false)]
public sealed class MaxLevelOfParallelismAttribute : NUnit.Framework.PropertyAttribute
{
public MaxLevelOfParallelismAttribute(int level) { }
@@ -82,14 +76,12 @@
{
public UnitTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class UserStoryAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public UserStoryAttribute() { }
public UserStoryAttribute(long id) { }
public UserStoryAttribute(string? id) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class WorkItemAttribute : NetEvolve.Extensions.NUnit.Internal.CategoryIdBaseAttribute
{
public WorkItemAttribute() { }
diff --git a/tests/NetEvolve.Extensions.NUnit.Tests.Unit/AttributeTestsBase.cs b/tests/NetEvolve.Extensions.NUnit.Tests.Unit/AttributeTestsBase.cs
index 36c7db1..620a19c 100644
--- a/tests/NetEvolve.Extensions.NUnit.Tests.Unit/AttributeTestsBase.cs
+++ b/tests/NetEvolve.Extensions.NUnit.Tests.Unit/AttributeTestsBase.cs
@@ -19,14 +19,14 @@
[TestFixture]
public abstract class AttributeTestsBase
{
- private static readonly List _excludeKeys = new List
- {
+ private static readonly List _excludeKeys =
+ [
PropertyNames.AppDomain,
PropertyNames.JoinType,
PropertyNames.ProcessId,
PropertyNames.ProviderStackTrace,
PropertyNames.SkipReason,
- };
+ ];
///
/// Gets the Traits from the given Method name
@@ -39,7 +39,7 @@ protected IEnumerable> GetProperties(
{
if (methodName is null)
{
- return Enumerable.Empty>();
+ return [];
}
var classType = GetType();
@@ -50,7 +50,7 @@ protected IEnumerable> GetProperties(
if (methodInfo is null)
{
- return Enumerable.Empty>();
+ return [];
}
var test = new DefaultTestCaseBuilder().BuildFrom(new MethodWrapper(classType, methodInfo));
diff --git a/tests/NetEvolve.Extensions.NUnit.Tests.Unit/Predefined.cs b/tests/NetEvolve.Extensions.NUnit.Tests.Unit/Predefined.cs
index 103fde4..45924f2 100644
--- a/tests/NetEvolve.Extensions.NUnit.Tests.Unit/Predefined.cs
+++ b/tests/NetEvolve.Extensions.NUnit.Tests.Unit/Predefined.cs
@@ -24,7 +24,7 @@ public static void Init()
}
);
- VerifierSettings.AutoVerify(includeBuildServer: false);
VerifierSettings.SortPropertiesAlphabetically();
+ VerifierSettings.SortJsonObjects();
}
}
diff --git a/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/Predefined.cs b/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/Predefined.cs
index 2dde612..b9415af 100644
--- a/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/Predefined.cs
+++ b/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/Predefined.cs
@@ -23,7 +23,7 @@ public static void Init()
}
);
- VerifierSettings.AutoVerify(includeBuildServer: false);
VerifierSettings.SortPropertiesAlphabetically();
+ VerifierSettings.SortJsonObjects();
}
}
diff --git a/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/PublicApiTests.cs b/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/PublicApiTests.cs
index 52c6738..1ec4421 100644
--- a/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/PublicApiTests.cs
+++ b/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/PublicApiTests.cs
@@ -29,6 +29,7 @@ public Task PublicApi_HasNotChanged_Expected()
typeof(CLSCompliantAttribute).FullName!,
typeof(AssemblyMetadataAttribute).FullName!,
typeof(NeutralResourcesLanguageAttribute).FullName!,
+ typeof(AttributeUsageAttribute).FullName!,
],
IncludeTypes = types,
};
diff --git a/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt b/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
index 3803386..2c584ac 100644
--- a/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
+++ b/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
@@ -8,7 +8,6 @@
{
public ArchitectureTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class BugAttribute : NetEvolve.Extensions.XUnit.Internal.CategoryWithIdTraitBaseAttribute
{
public BugAttribute() { }
@@ -61,7 +60,6 @@
{
public PreDeploymentAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, Inherited=false)]
public sealed class SetCultureAttribute : NetEvolve.Extensions.XUnit.Internal.CultureAttributeBase
{
public SetCultureAttribute() { }
@@ -71,7 +69,6 @@
public override void After(System.Reflection.MethodInfo methodUnderTest) { }
public override void Before(System.Reflection.MethodInfo methodUnderTest) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, Inherited=false)]
public sealed class SetUICultureAttribute : NetEvolve.Extensions.XUnit.Internal.CultureAttributeBase
{
public SetUICultureAttribute() { }
@@ -96,7 +93,6 @@
}
namespace NetEvolve.Extensions.XUnit.Internal
{
- [System.AttributeUsage(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
[Xunit.Sdk.TraitDiscoverer("NetEvolve.Extensions.XUnit.Internal.CategoryTraitDiscoverer", "NetEvolve.Extensions.XUnit")]
public abstract class CategoryTraitBaseAttribute : System.Attribute, Xunit.Sdk.ITraitAttribute
{
@@ -108,7 +104,6 @@ namespace NetEvolve.Extensions.XUnit.Internal
public CategoryTraitDiscoverer() { }
public override System.Collections.Generic.IEnumerable> GetTraits(Xunit.Abstractions.IAttributeInfo traitAttribute) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
[Xunit.Sdk.TraitDiscoverer("NetEvolve.Extensions.XUnit.Internal.CategoryTraitDiscoverer", "NetEvolve.Extensions.XUnit")]
public abstract class CategoryWithIdTraitBaseAttribute : System.Attribute, Xunit.Sdk.ITraitAttribute
{
@@ -117,7 +112,6 @@ namespace NetEvolve.Extensions.XUnit.Internal
public string Category { get; }
public string? Id { get; }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
[Xunit.Sdk.TraitDiscoverer("NetEvolve.Extensions.XUnit.Internal.CultureTraitDiscoverer", "NetEvolve.Extensions.XUnit")]
public abstract class CultureAttributeBase : Xunit.Sdk.BeforeAfterTestAttribute, Xunit.Sdk.ITraitAttribute
{
diff --git a/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt b/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
index 3803386..2c584ac 100644
--- a/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
+++ b/tests/NetEvolve.Extensions.XUnit.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
@@ -8,7 +8,6 @@
{
public ArchitectureTestAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public sealed class BugAttribute : NetEvolve.Extensions.XUnit.Internal.CategoryWithIdTraitBaseAttribute
{
public BugAttribute() { }
@@ -61,7 +60,6 @@
{
public PreDeploymentAttribute() { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, Inherited=false)]
public sealed class SetCultureAttribute : NetEvolve.Extensions.XUnit.Internal.CultureAttributeBase
{
public SetCultureAttribute() { }
@@ -71,7 +69,6 @@
public override void After(System.Reflection.MethodInfo methodUnderTest) { }
public override void Before(System.Reflection.MethodInfo methodUnderTest) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, Inherited=false)]
public sealed class SetUICultureAttribute : NetEvolve.Extensions.XUnit.Internal.CultureAttributeBase
{
public SetUICultureAttribute() { }
@@ -96,7 +93,6 @@
}
namespace NetEvolve.Extensions.XUnit.Internal
{
- [System.AttributeUsage(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
[Xunit.Sdk.TraitDiscoverer("NetEvolve.Extensions.XUnit.Internal.CategoryTraitDiscoverer", "NetEvolve.Extensions.XUnit")]
public abstract class CategoryTraitBaseAttribute : System.Attribute, Xunit.Sdk.ITraitAttribute
{
@@ -108,7 +104,6 @@ namespace NetEvolve.Extensions.XUnit.Internal
public CategoryTraitDiscoverer() { }
public override System.Collections.Generic.IEnumerable> GetTraits(Xunit.Abstractions.IAttributeInfo traitAttribute) { }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
[Xunit.Sdk.TraitDiscoverer("NetEvolve.Extensions.XUnit.Internal.CategoryTraitDiscoverer", "NetEvolve.Extensions.XUnit")]
public abstract class CategoryWithIdTraitBaseAttribute : System.Attribute, Xunit.Sdk.ITraitAttribute
{
@@ -117,7 +112,6 @@ namespace NetEvolve.Extensions.XUnit.Internal
public string Category { get; }
public string? Id { get; }
}
- [System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true, Inherited=true)]
[Xunit.Sdk.TraitDiscoverer("NetEvolve.Extensions.XUnit.Internal.CultureTraitDiscoverer", "NetEvolve.Extensions.XUnit")]
public abstract class CultureAttributeBase : Xunit.Sdk.BeforeAfterTestAttribute, Xunit.Sdk.ITraitAttribute
{
diff --git a/tests/NetEvolve.Extensions.XUnit.Tests.Unit/AttributeTestsBase.cs b/tests/NetEvolve.Extensions.XUnit.Tests.Unit/AttributeTestsBase.cs
index 8f3d2d1..0d114b9 100644
--- a/tests/NetEvolve.Extensions.XUnit.Tests.Unit/AttributeTestsBase.cs
+++ b/tests/NetEvolve.Extensions.XUnit.Tests.Unit/AttributeTestsBase.cs
@@ -25,9 +25,9 @@ protected IEnumerable> GetTraits(
[CallerMemberName] string? methodName = null
)
{
- if (methodName == null)
+ if (methodName is null)
{
- return Enumerable.Empty>();
+ return [];
}
var classType = GetType();
@@ -38,7 +38,7 @@ protected IEnumerable> GetTraits(
if (methodInfo is null)
{
- return Enumerable.Empty>();
+ return [];
}
var messageSink = new NullMessageSink();
@@ -73,7 +73,7 @@ IMessageSink messageSink
var discovererAttributeData = FindDiscovererAttributeType(
traitAttributeType.GetTypeInfo()
);
- if (discovererAttributeData == null)
+ if (discovererAttributeData is null)
{
continue;
}
@@ -82,13 +82,13 @@ IMessageSink messageSink
messageSink,
Reflector.Wrap(discovererAttributeData)
);
- if (discoverer == null)
+ if (discoverer is null)
{
continue;
}
var traits = discoverer.GetTraits(Reflector.Wrap(traitAttributeData));
- if (traits != null)
+ if (traits is not null)
{
result.AddRange(traits);
}
@@ -105,7 +105,7 @@ IMessageSink messageSink
{
result = typeChecking.CustomAttributes.FirstOrDefault(isTraitDiscovererAttribute);
typeChecking = traitAttribute.BaseType.GetTypeInfo();
- } while (result == null && typeChecking != null);
+ } while (result is null && typeChecking is not null);
return result;
diff --git a/tests/NetEvolve.Extensions.XUnit.Tests.Unit/Predefined.cs b/tests/NetEvolve.Extensions.XUnit.Tests.Unit/Predefined.cs
index 7db355c..797ef60 100644
--- a/tests/NetEvolve.Extensions.XUnit.Tests.Unit/Predefined.cs
+++ b/tests/NetEvolve.Extensions.XUnit.Tests.Unit/Predefined.cs
@@ -24,7 +24,7 @@ public static void Init()
}
);
- VerifierSettings.AutoVerify(includeBuildServer: false);
VerifierSettings.SortPropertiesAlphabetically();
+ VerifierSettings.SortJsonObjects();
}
}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi.csproj b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi.csproj
new file mode 100644
index 0000000..0f68ce8
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi.csproj
@@ -0,0 +1,33 @@
+
+
+
+ $(NetEvolve_TestTargetFrameworks)
+ enable
+ Exe
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/Predefined.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/Predefined.cs
new file mode 100644
index 0000000..eecc879
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/Predefined.cs
@@ -0,0 +1,29 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.PublicApi;
+
+using System.IO;
+using System.Runtime.CompilerServices;
+using VerifyTests;
+using VerifyXunit;
+
+internal static class Predefined
+{
+ [ModuleInitializer]
+ public static void Init()
+ {
+ Verifier.DerivePathInfo(
+ (sourceFile, projectDirectory, type, method) =>
+ {
+ var directory = Path.Combine(
+ projectDirectory,
+ "_snapshots",
+ Namer.TargetFrameworkNameAndVersion
+ );
+ _ = Directory.CreateDirectory(directory);
+ return new(directory, type.Name, method.Name);
+ }
+ );
+
+ VerifierSettings.SortPropertiesAlphabetically();
+ VerifierSettings.SortJsonObjects();
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/PublicApiTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/PublicApiTests.cs
new file mode 100644
index 0000000..92c2e35
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/PublicApiTests.cs
@@ -0,0 +1,52 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.PublicApi;
+
+using System;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+using System.Threading.Tasks;
+using PublicApiGenerator;
+
+public class PublicApiTests
+{
+ [Fact]
+ public Task PublicApi_HasNotChanged_Expected()
+ {
+ var assembly = typeof(AcceptanceTestAttribute).Assembly;
+ var types = assembly.GetTypes().Where(IsVisibleToIntelliSense).ToArray();
+
+ var options = new ApiGeneratorOptions
+ {
+ ExcludeAttributes =
+ [
+ typeof(InternalsVisibleToAttribute).FullName!,
+ "System.Runtime.CompilerServices.IsByRefLikeAttribute",
+ typeof(TargetFrameworkAttribute).FullName!,
+ typeof(CLSCompliantAttribute).FullName!,
+ typeof(AssemblyMetadataAttribute).FullName!,
+ typeof(NeutralResourcesLanguageAttribute).FullName!,
+ typeof(AttributeUsageAttribute).FullName!,
+ ],
+ IncludeTypes = types,
+ };
+
+ var publicApi = assembly.GeneratePublicApi(options);
+
+ return Verify(publicApi);
+ }
+
+ private static bool IsVisibleToIntelliSense(Type type)
+ {
+ var browsable = type.GetCustomAttribute();
+ if (browsable is null || browsable.Browsable)
+ {
+ return true;
+ }
+
+ var editorBrowsable = type.GetCustomAttribute();
+ return editorBrowsable is null || editorBrowsable.State != EditorBrowsableState.Never;
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
new file mode 100644
index 0000000..953dc14
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/_snapshots/DotNet6_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
@@ -0,0 +1,121 @@
+namespace NetEvolve.Extensions.XUnit.V3
+{
+ public sealed class AcceptanceTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public AcceptanceTestAttribute() { }
+ }
+ public sealed class ArchitectureTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public ArchitectureTestAttribute() { }
+ }
+ public sealed class BugAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public BugAttribute() { }
+ public BugAttribute(long id) { }
+ public BugAttribute(string? id) { }
+ }
+ public sealed class CodedUITestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public CodedUITestAttribute() { }
+ }
+ public sealed class EndToEndTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public EndToEndTestAttribute() { }
+ }
+ public sealed class EpicAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public EpicAttribute() { }
+ public EpicAttribute(long id) { }
+ public EpicAttribute(string? id) { }
+ }
+ public sealed class FeatureAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public FeatureAttribute() { }
+ public FeatureAttribute(long id) { }
+ public FeatureAttribute(string? id) { }
+ }
+ public sealed class FunctionalTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public FunctionalTestAttribute() { }
+ }
+ public sealed class IntegrationTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public IntegrationTestAttribute() { }
+ }
+ public sealed class IssueAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public IssueAttribute() { }
+ public IssueAttribute(long id) { }
+ public IssueAttribute(string? id) { }
+ }
+ public sealed class PerformanceTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public PerformanceTestAttribute() { }
+ }
+ public sealed class PostDeploymentAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public PostDeploymentAttribute() { }
+ }
+ public sealed class PreDeploymentAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public PreDeploymentAttribute() { }
+ }
+ public sealed class SetCultureAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CultureAttributeBase
+ {
+ public SetCultureAttribute() { }
+ public SetCultureAttribute(string culture) { }
+ public SetCultureAttribute(string culture, string? uiCulture) { }
+ public string? UICulture { get; }
+ public override System.Threading.Tasks.ValueTask After(System.Reflection.MethodInfo methodUnderTest, Xunit.v3.IXunitTest test) { }
+ public override System.Threading.Tasks.ValueTask Before(System.Reflection.MethodInfo methodUnderTest, Xunit.v3.IXunitTest test) { }
+ public override System.Collections.Generic.IReadOnlyCollection> GetTraits() { }
+ }
+ public sealed class SetUICultureAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CultureAttributeBase
+ {
+ public SetUICultureAttribute() { }
+ public SetUICultureAttribute(string culture) { }
+ public override System.Collections.Generic.IReadOnlyCollection> GetTraits() { }
+ }
+ public sealed class UnitTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public UnitTestAttribute() { }
+ }
+ public sealed class UserStoryAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public UserStoryAttribute() { }
+ public UserStoryAttribute(long id) { }
+ public UserStoryAttribute(string? id) { }
+ }
+ public sealed class WorkItemAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public WorkItemAttribute() { }
+ public WorkItemAttribute(long id) { }
+ public WorkItemAttribute(string? id) { }
+ }
+}
+namespace NetEvolve.Extensions.XUnit.V3.Internal
+{
+ public abstract class CategoryTraitBaseAttribute : System.Attribute, Xunit.v3.ITraitAttribute
+ {
+ protected CategoryTraitBaseAttribute(string category) { }
+ public string Category { get; }
+ public System.Collections.Generic.IReadOnlyCollection> GetTraits() { }
+ }
+ public abstract class CategoryWithIdTraitBaseAttribute : System.Attribute, Xunit.v3.ITraitAttribute
+ {
+ protected CategoryWithIdTraitBaseAttribute(string category, long id) { }
+ protected CategoryWithIdTraitBaseAttribute(string category, string? id) { }
+ public string Category { get; }
+ public string? Id { get; }
+ public System.Collections.Generic.IReadOnlyCollection> GetTraits() { }
+ }
+ public abstract class CultureAttributeBase : System.Attribute, Xunit.v3.IBeforeAfterTestAttribute, Xunit.v3.ITraitAttribute
+ {
+ protected CultureAttributeBase(string category, string culture) { }
+ public string Category { get; }
+ public string Culture { get; }
+ public virtual System.Threading.Tasks.ValueTask After(System.Reflection.MethodInfo methodUnderTest, Xunit.v3.IXunitTest test) { }
+ public virtual System.Threading.Tasks.ValueTask Before(System.Reflection.MethodInfo methodUnderTest, Xunit.v3.IXunitTest test) { }
+ public abstract System.Collections.Generic.IReadOnlyCollection> GetTraits();
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
new file mode 100644
index 0000000..953dc14
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.PublicApi/_snapshots/DotNet8_0/PublicApiTests.PublicApi_HasNotChanged_Expected.verified.txt
@@ -0,0 +1,121 @@
+namespace NetEvolve.Extensions.XUnit.V3
+{
+ public sealed class AcceptanceTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public AcceptanceTestAttribute() { }
+ }
+ public sealed class ArchitectureTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public ArchitectureTestAttribute() { }
+ }
+ public sealed class BugAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public BugAttribute() { }
+ public BugAttribute(long id) { }
+ public BugAttribute(string? id) { }
+ }
+ public sealed class CodedUITestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public CodedUITestAttribute() { }
+ }
+ public sealed class EndToEndTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public EndToEndTestAttribute() { }
+ }
+ public sealed class EpicAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public EpicAttribute() { }
+ public EpicAttribute(long id) { }
+ public EpicAttribute(string? id) { }
+ }
+ public sealed class FeatureAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public FeatureAttribute() { }
+ public FeatureAttribute(long id) { }
+ public FeatureAttribute(string? id) { }
+ }
+ public sealed class FunctionalTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public FunctionalTestAttribute() { }
+ }
+ public sealed class IntegrationTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public IntegrationTestAttribute() { }
+ }
+ public sealed class IssueAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public IssueAttribute() { }
+ public IssueAttribute(long id) { }
+ public IssueAttribute(string? id) { }
+ }
+ public sealed class PerformanceTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public PerformanceTestAttribute() { }
+ }
+ public sealed class PostDeploymentAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public PostDeploymentAttribute() { }
+ }
+ public sealed class PreDeploymentAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public PreDeploymentAttribute() { }
+ }
+ public sealed class SetCultureAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CultureAttributeBase
+ {
+ public SetCultureAttribute() { }
+ public SetCultureAttribute(string culture) { }
+ public SetCultureAttribute(string culture, string? uiCulture) { }
+ public string? UICulture { get; }
+ public override System.Threading.Tasks.ValueTask After(System.Reflection.MethodInfo methodUnderTest, Xunit.v3.IXunitTest test) { }
+ public override System.Threading.Tasks.ValueTask Before(System.Reflection.MethodInfo methodUnderTest, Xunit.v3.IXunitTest test) { }
+ public override System.Collections.Generic.IReadOnlyCollection> GetTraits() { }
+ }
+ public sealed class SetUICultureAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CultureAttributeBase
+ {
+ public SetUICultureAttribute() { }
+ public SetUICultureAttribute(string culture) { }
+ public override System.Collections.Generic.IReadOnlyCollection> GetTraits() { }
+ }
+ public sealed class UnitTestAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryTraitBaseAttribute
+ {
+ public UnitTestAttribute() { }
+ }
+ public sealed class UserStoryAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public UserStoryAttribute() { }
+ public UserStoryAttribute(long id) { }
+ public UserStoryAttribute(string? id) { }
+ }
+ public sealed class WorkItemAttribute : NetEvolve.Extensions.XUnit.V3.Internal.CategoryWithIdTraitBaseAttribute
+ {
+ public WorkItemAttribute() { }
+ public WorkItemAttribute(long id) { }
+ public WorkItemAttribute(string? id) { }
+ }
+}
+namespace NetEvolve.Extensions.XUnit.V3.Internal
+{
+ public abstract class CategoryTraitBaseAttribute : System.Attribute, Xunit.v3.ITraitAttribute
+ {
+ protected CategoryTraitBaseAttribute(string category) { }
+ public string Category { get; }
+ public System.Collections.Generic.IReadOnlyCollection> GetTraits() { }
+ }
+ public abstract class CategoryWithIdTraitBaseAttribute : System.Attribute, Xunit.v3.ITraitAttribute
+ {
+ protected CategoryWithIdTraitBaseAttribute(string category, long id) { }
+ protected CategoryWithIdTraitBaseAttribute(string category, string? id) { }
+ public string Category { get; }
+ public string? Id { get; }
+ public System.Collections.Generic.IReadOnlyCollection> GetTraits() { }
+ }
+ public abstract class CultureAttributeBase : System.Attribute, Xunit.v3.IBeforeAfterTestAttribute, Xunit.v3.ITraitAttribute
+ {
+ protected CultureAttributeBase(string category, string culture) { }
+ public string Category { get; }
+ public string Culture { get; }
+ public virtual System.Threading.Tasks.ValueTask After(System.Reflection.MethodInfo methodUnderTest, Xunit.v3.IXunitTest test) { }
+ public virtual System.Threading.Tasks.ValueTask Before(System.Reflection.MethodInfo methodUnderTest, Xunit.v3.IXunitTest test) { }
+ public abstract System.Collections.Generic.IReadOnlyCollection> GetTraits();
+ }
+}
\ No newline at end of file
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/AcceptanceTestAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/AcceptanceTestAttributeTests.cs
new file mode 100644
index 0000000..84ef1a4
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/AcceptanceTestAttributeTests.cs
@@ -0,0 +1,27 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class AcceptanceTestAttributeTests : AttributeTestsBase
+{
+ [Theory]
+ [AcceptanceTest]
+ [InlineData(nameof(AcceptanceTest_without_parameters))]
+ [InlineData(nameof(AcceptanceTest_without_or_invalid_parameters))]
+ public async Task AcceptanceTest_without_or_invalid_parameters(string methodName)
+ {
+ var traits = GetTraits(methodName);
+
+ _ = await Verify(traits).UseParameters(methodName);
+ }
+
+ [AcceptanceTest]
+ protected void AcceptanceTest_without_parameters() => throw new NotSupportedException();
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/ArchitectureTestAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/ArchitectureTestAttributeTests.cs
new file mode 100644
index 0000000..c72b58e
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/ArchitectureTestAttributeTests.cs
@@ -0,0 +1,27 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class ArchitectureTestAttributeTests : AttributeTestsBase
+{
+ [Theory]
+ [ArchitectureTest]
+ [InlineData(nameof(ArchitectureTest_without_parameters))]
+ [InlineData(nameof(ArchitectureTest_without_or_invalid_parameters))]
+ public async Task ArchitectureTest_without_or_invalid_parameters(string methodName)
+ {
+ var traits = GetTraits(methodName);
+
+ _ = await Verify(traits).UseParameters(methodName);
+ }
+
+ [ArchitectureTest]
+ protected void ArchitectureTest_without_parameters() => throw new NotSupportedException();
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/AttributeTestsBase.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/AttributeTestsBase.cs
new file mode 100644
index 0000000..c4d02c7
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/AttributeTestsBase.cs
@@ -0,0 +1,62 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using VerifyTests;
+using VerifyXunit;
+using Xunit.Internal;
+using Xunit.Sdk;
+using Xunit.v3;
+
+///
+/// Base class for Trait Attribute tests
+///
+[ExcludeFromCodeCoverage]
+public abstract class AttributeTestsBase
+{
+ ///
+ /// Gets the Traits from the given Method name
+ ///
+ /// Name of the caller Method
+ /// List of
+ protected IEnumerable> GetTraits(
+ [CallerMemberName] string? methodName = null
+ )
+ {
+ if (methodName is null)
+ {
+ return [];
+ }
+
+ var classType = GetType();
+
+ var methodInfo = classType.GetMethod(
+ methodName,
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
+ );
+
+ if (methodInfo is null)
+ {
+ return [];
+ }
+
+ var assemblyTraits = ExtensibilityPointFactory.GetAssemblyTraits(classType.Assembly);
+ var classTraits = ExtensibilityPointFactory.GetClassTraits(classType, assemblyTraits);
+ var methodTraits = ExtensibilityPointFactory.GetMethodTraits(methodInfo, classTraits);
+
+ var result = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ foreach (var trait in methodTraits)
+ {
+ result.Add(trait.Key, string.Join(", ", trait.Value));
+ }
+
+ return [.. result];
+ }
+
+ protected static SettingsTask Verify(T traits) => Verifier.Verify(traits);
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/BugAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/BugAttributeTests.cs
new file mode 100644
index 0000000..759111c
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/BugAttributeTests.cs
@@ -0,0 +1,49 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class BugAttributeTests : AttributeTestsBase
+{
+ ///
+ /// Tests the case of methods with without additional information.
+ ///
+ [Fact]
+ [Bug]
+ [Bug("")]
+ public async Task Bug_without_Id()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with numeric id.
+ ///
+ [Fact]
+ [Bug(123456)]
+ public async Task Bug_with_LongId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with id.
+ ///
+ [Fact]
+ [Bug("123456")]
+ public async Task Bug_with_StringId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/CodedUITestAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/CodedUITestAttributeTests.cs
new file mode 100644
index 0000000..57ee773
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/CodedUITestAttributeTests.cs
@@ -0,0 +1,27 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class CodedUITestAttributeTests : AttributeTestsBase
+{
+ [Theory]
+ [CodedUITest]
+ [InlineData(nameof(CodedUITest_without_parameters))]
+ [InlineData(nameof(CodedUITest_without_or_invalid_parameters))]
+ public async Task CodedUITest_without_or_invalid_parameters(string methodName)
+ {
+ var traits = GetTraits(methodName);
+
+ _ = await Verify(traits).UseParameters(methodName);
+ }
+
+ [CodedUITest]
+ protected void CodedUITest_without_parameters() => throw new NotSupportedException();
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/EndToEndTestAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/EndToEndTestAttributeTests.cs
new file mode 100644
index 0000000..1212dda
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/EndToEndTestAttributeTests.cs
@@ -0,0 +1,27 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class EndToEndTestAttributeTests : AttributeTestsBase
+{
+ [Theory]
+ [EndToEndTest]
+ [InlineData(nameof(EndToEndTest_without_parameters))]
+ [InlineData(nameof(EndToEndTest_without_or_invalid_parameters))]
+ public async Task EndToEndTest_without_or_invalid_parameters(string methodName)
+ {
+ var traits = GetTraits(methodName);
+
+ _ = await Verify(traits).UseParameters(methodName);
+ }
+
+ [EndToEndTest]
+ protected void EndToEndTest_without_parameters() => throw new NotSupportedException();
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/EpicAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/EpicAttributeTests.cs
new file mode 100644
index 0000000..b2b23e7
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/EpicAttributeTests.cs
@@ -0,0 +1,49 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class EpicAttributeTests : AttributeTestsBase
+{
+ ///
+ /// Tests the case of methods with without additional information.
+ ///
+ [Fact]
+ [Epic]
+ [Epic("")]
+ public async Task Epic_without_Id()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with numeric id.
+ ///
+ [Fact]
+ [Epic(123456)]
+ public async Task Epic_with_LongId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with id.
+ ///
+ [Fact]
+ [Epic("123456")]
+ public async Task Epic_with_StringId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/FeatureAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/FeatureAttributeTests.cs
new file mode 100644
index 0000000..d02136d
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/FeatureAttributeTests.cs
@@ -0,0 +1,49 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class FeatureAttributeTests : AttributeTestsBase
+{
+ ///
+ /// Tests the case of methods with without additional information.
+ ///
+ [Fact]
+ [Feature]
+ [Feature("")]
+ public async Task Feature_without_Id()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with numeric id.
+ ///
+ [Fact]
+ [Feature(123456)]
+ public async Task Feature_with_LongId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with id.
+ ///
+ [Fact]
+ [Feature("123456")]
+ public async Task Feature_with_StringId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/FunctionalTestAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/FunctionalTestAttributeTests.cs
new file mode 100644
index 0000000..5908f8c
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/FunctionalTestAttributeTests.cs
@@ -0,0 +1,27 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class FunctionalTestAttributeTests : AttributeTestsBase
+{
+ [Theory]
+ [FunctionalTest]
+ [InlineData(nameof(FunctionalTest_without_parameters))]
+ [InlineData(nameof(FunctionalTest_without_or_invalid_parameters))]
+ public async Task FunctionalTest_without_or_invalid_parameters(string methodName)
+ {
+ var traits = GetTraits(methodName);
+
+ _ = await Verify(traits).UseParameters(methodName);
+ }
+
+ [FunctionalTest]
+ protected void FunctionalTest_without_parameters() => throw new NotSupportedException();
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/IntegrationTestAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/IntegrationTestAttributeTests.cs
new file mode 100644
index 0000000..664f22c
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/IntegrationTestAttributeTests.cs
@@ -0,0 +1,27 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class IntegrationTestAttributeTests : AttributeTestsBase
+{
+ [Theory]
+ [IntegrationTest]
+ [InlineData(nameof(IntegrationTest_without_parameters))]
+ [InlineData(nameof(IntegrationTest_without_or_invalid_parameters))]
+ public async Task IntegrationTest_without_or_invalid_parameters(string methodName)
+ {
+ var traits = GetTraits(methodName);
+
+ _ = await Verify(traits).UseParameters(methodName);
+ }
+
+ [IntegrationTest]
+ protected void IntegrationTest_without_parameters() => throw new NotSupportedException();
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/IssueAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/IssueAttributeTests.cs
new file mode 100644
index 0000000..f54d29d
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/IssueAttributeTests.cs
@@ -0,0 +1,49 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class IssueAttributeTests : AttributeTestsBase
+{
+ ///
+ /// Tests the case of methods with without additional information.
+ ///
+ [Fact]
+ [Issue]
+ [Issue("")]
+ public async Task Issue_without_Id()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with numeric id.
+ ///
+ [Fact]
+ [Issue(123456)]
+ public async Task Issue_with_LongId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with id.
+ ///
+ [Fact]
+ [Issue("123456")]
+ public async Task Issue_with_StringId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/NetEvolve.Extensions.XUnit.V3.Tests.Unit.csproj b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/NetEvolve.Extensions.XUnit.V3.Tests.Unit.csproj
new file mode 100644
index 0000000..d3d4752
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/NetEvolve.Extensions.XUnit.V3.Tests.Unit.csproj
@@ -0,0 +1,24 @@
+
+
+
+ $(NetEvolve_TestTargetFrameworks)
+ Exe
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/PerformanceTestAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/PerformanceTestAttributeTests.cs
new file mode 100644
index 0000000..768ec67
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/PerformanceTestAttributeTests.cs
@@ -0,0 +1,27 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class PerformanceTestAttributeTests : AttributeTestsBase
+{
+ [Theory]
+ [PerformanceTest]
+ [InlineData(nameof(PerformanceTest_without_parameters))]
+ [InlineData(nameof(PerformanceTest_without_or_invalid_parameters))]
+ public async Task PerformanceTest_without_or_invalid_parameters(string methodName)
+ {
+ var traits = GetTraits(methodName);
+
+ _ = await Verify(traits).UseParameters(methodName);
+ }
+
+ [PerformanceTest]
+ protected void PerformanceTest_without_parameters() => throw new NotSupportedException();
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/PostDeploymentAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/PostDeploymentAttributeTests.cs
new file mode 100644
index 0000000..cc87c6e
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/PostDeploymentAttributeTests.cs
@@ -0,0 +1,24 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class PostDeploymentAttributeTests : AttributeTestsBase
+{
+ ///
+ /// Tests the case of methods with .
+ ///
+ [Fact]
+ [PostDeployment]
+ public async Task PostDeployment_Expected()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/PreDeploymentAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/PreDeploymentAttributeTests.cs
new file mode 100644
index 0000000..baf94fd
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/PreDeploymentAttributeTests.cs
@@ -0,0 +1,24 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class PreDeploymentAttributeTests : AttributeTestsBase
+{
+ ///
+ /// Tests the case of methods with .
+ ///
+ [Fact]
+ [PreDeployment]
+ public async Task PreDeployment_Expected()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Predefined.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Predefined.cs
new file mode 100644
index 0000000..5218ea9
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Predefined.cs
@@ -0,0 +1,30 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System.IO;
+using System.Runtime.CompilerServices;
+using VerifyTests;
+using VerifyXunit;
+
+internal static class Predefined
+{
+ [ModuleInitializer]
+ public static void Init()
+ {
+ Verifier.DerivePathInfo(
+ (sourceFile, projectDirectory, type, method) =>
+ {
+ var directory = Path.Combine(
+ projectDirectory,
+ "..",
+ "_snapshots",
+ Namer.TargetFrameworkNameAndVersion
+ );
+ _ = Directory.CreateDirectory(directory);
+ return new(directory, type.Name, method.Name);
+ }
+ );
+
+ VerifierSettings.SortPropertiesAlphabetically();
+ VerifierSettings.SortJsonObjects();
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/SetCultureAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/SetCultureAttributeTests.cs
new file mode 100644
index 0000000..7117037
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/SetCultureAttributeTests.cs
@@ -0,0 +1,64 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Threading.Tasks;
+using Xunit;
+
+[ExcludeFromCodeCoverage]
+public class SetCultureAttributeTests : AttributeTestsBase
+{
+ [Fact]
+ [SetCulture("en")]
+ public async Task Execute_English()
+ {
+ var traits = GetTraits();
+ var translations = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "Translation", Translations.HelloWorld },
+ };
+
+ _ = await Verify(traits.Union(translations));
+ }
+
+ [Fact]
+ [SetCulture]
+ public async Task Execute_Invariant()
+ {
+ var traits = GetTraits();
+ var translations = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "Translation", Translations.HelloWorld },
+ };
+
+ _ = await Verify(traits.Union(translations));
+ }
+
+ [Fact]
+ [SetCulture("de")]
+ public async Task Execute_German()
+ {
+ var traits = GetTraits();
+ var translations = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "Translation", Translations.HelloWorld },
+ };
+
+ _ = await Verify(traits.Union(translations));
+ }
+
+ [Fact]
+ [SetCulture("de-DE")]
+ public async Task Execute_German_Germany()
+ {
+ var traits = GetTraits();
+ var translations = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "Translation", Translations.HelloWorld },
+ };
+
+ _ = await Verify(traits.Union(translations));
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/SetUICultureAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/SetUICultureAttributeTests.cs
new file mode 100644
index 0000000..f02c920
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/SetUICultureAttributeTests.cs
@@ -0,0 +1,64 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Threading.Tasks;
+using Xunit;
+
+[ExcludeFromCodeCoverage]
+public class SetUICultureAttributeTests : AttributeTestsBase
+{
+ [Fact(Skip = "Flaky, will deal with this later.")]
+ [SetUICulture("en")]
+ public async Task Execute_English()
+ {
+ var traits = GetTraits();
+ var translations = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "Translation", Translations.HelloWorld },
+ };
+
+ _ = await Verify(traits.Union(translations));
+ }
+
+ [Fact]
+ [SetUICulture]
+ public async Task Execute_Invariant()
+ {
+ var traits = GetTraits();
+ var translations = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "Translation", Translations.HelloWorld },
+ };
+
+ _ = await Verify(traits.Union(translations));
+ }
+
+ [Fact(Skip = "Flaky, will deal with this later.")]
+ [SetUICulture("de")]
+ public async Task Execute_German()
+ {
+ var traits = GetTraits();
+ var translations = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "Translation", Translations.HelloWorld },
+ };
+
+ _ = await Verify(traits.Union(translations));
+ }
+
+ [Fact]
+ [SetUICulture("de-DE")]
+ public async Task Execute_German_Germany()
+ {
+ var traits = GetTraits();
+ var translations = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { "Translation", Translations.HelloWorld },
+ };
+
+ _ = await Verify(traits.Union(translations));
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Translations.Designer.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Translations.Designer.cs
new file mode 100644
index 0000000..091ca67
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Translations.Designer.cs
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Translations {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Translations() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NetEvolve.Extensions.XUnit.V3.Tests.Unit.Translations", typeof(Translations).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Hello World!.
+ ///
+ internal static string HelloWorld {
+ get {
+ return ResourceManager.GetString("HelloWorld", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Translations.de.resx b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Translations.de.resx
new file mode 100644
index 0000000..fd4242b
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Translations.de.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Hallo Welt!
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Translations.resx b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Translations.resx
new file mode 100644
index 0000000..f36015b
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/Translations.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Hello World!
+
+
\ No newline at end of file
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/UnitTestAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/UnitTestAttributeTests.cs
new file mode 100644
index 0000000..f201a8f
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/UnitTestAttributeTests.cs
@@ -0,0 +1,27 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class UnitTestAttributeTests : AttributeTestsBase
+{
+ [Theory]
+ [UnitTest]
+ [InlineData(nameof(UnitTest_without_parameters))]
+ [InlineData(nameof(UnitTest_without_or_invalid_parameters))]
+ public async Task UnitTest_without_or_invalid_parameters(string methodName)
+ {
+ var traits = GetTraits(methodName);
+
+ _ = await Verify(traits).UseParameters(methodName);
+ }
+
+ [UnitTest]
+ protected void UnitTest_without_parameters() => throw new NotSupportedException();
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/UserStoryAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/UserStoryAttributeTests.cs
new file mode 100644
index 0000000..3d94667
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/UserStoryAttributeTests.cs
@@ -0,0 +1,49 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class UserStoryAttributeTests : AttributeTestsBase
+{
+ ///
+ /// Tests the case of methods with without additional information.
+ ///
+ [Fact]
+ [UserStory]
+ [UserStory("")]
+ public async Task UserStory_without_Id()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with numeric id.
+ ///
+ [Fact]
+ [UserStory(123456)]
+ public async Task UserStory_with_LongId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with id.
+ ///
+ [Fact]
+ [UserStory("123456")]
+ public async Task UserStory_with_StringId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+}
diff --git a/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/WorkItemAttributeTests.cs b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/WorkItemAttributeTests.cs
new file mode 100644
index 0000000..8475d12
--- /dev/null
+++ b/tests/NetEvolve.Extensions.XUnit.V3.Tests.Unit/WorkItemAttributeTests.cs
@@ -0,0 +1,49 @@
+namespace NetEvolve.Extensions.XUnit.V3.Tests.Unit;
+
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Xunit;
+
+///
+/// Unit tests for .
+///
+[ExcludeFromCodeCoverage]
+public class WorkItemAttributeTests : AttributeTestsBase
+{
+ ///
+ /// Tests the case of methods with without additional information.
+ ///
+ [Fact]
+ [WorkItem]
+ [WorkItem("")]
+ public async Task WorkItem_without_Id()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with numeric id.
+ ///
+ [Fact]
+ [WorkItem(123456)]
+ public async Task WorkItem_with_LongId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+
+ ///
+ /// Tests the case of methods with with numeric id.
+ ///
+ [Fact]
+ [WorkItem("123456")]
+ public async Task WorkItem_with_StringId()
+ {
+ var traits = GetTraits();
+
+ _ = await Verify(traits);
+ }
+}