diff --git a/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchFrameworkDiscoverer.cs b/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchFrameworkDiscoverer.cs
new file mode 100644
index 0000000000..cb03fc02a2
--- /dev/null
+++ b/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchFrameworkDiscoverer.cs
@@ -0,0 +1,163 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.ComponentModel;
+using System.Linq;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Silk.NET.SilkTouch.TestFramework;
+
+public sealed class SilkTouchFrameworkDiscoverer : XunitTestFrameworkDiscoverer
+{
+ public SilkTouchFrameworkDiscoverer(
+ IAssemblyInfo assemblyInfo,
+ ISourceInformationProvider sourceProvider,
+ IMessageSink diagnosticMessageSink,
+ IXunitTestCollectionFactory? collectionFactory = null)
+ : base(
+ assemblyInfo,
+ sourceProvider,
+ diagnosticMessageSink,
+ collectionFactory)
+ {
+ }
+
+ protected override bool FindTestsForMethod
+ (
+ ITestMethod testMethod,
+ bool includeSourceInformation,
+ IMessageBus messageBus,
+ ITestFrameworkDiscoveryOptions discoveryOptions
+ )
+ {
+ var traits = testMethod.Method.GetCustomAttributes(typeof(TraitAttribute))
+ .Select
+ (
+ x =>
+ {
+ var args = x.GetConstructorArguments().ToArray();
+ var name = (string) args[0];
+ var value = (string) args[1];
+ return (name, value);
+ }
+ );
+ foreach (var (name, value) in traits)
+ {
+ if (name is "Category" &&
+ value is not "Integration" and not "Scraper" and not "Symbols" and not "Emitter" and not "TypeStore" and not "Type Resolution")
+ {
+ return this.ReportDiscoveredTestCase
+ (
+ (ITestCase) new ExecutionErrorTestCase
+ (
+ this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, TestMethodDisplayOptions.None,
+ testMethod,
+ "Category " + value +
+ " is not a valid category. Allowed values are \"Integration\", \"Scraper\", \"Symbols\", \"Emitter\"."
+ ), includeSourceInformation, messageBus
+ );
+ }
+
+ if (name is "Source Language" &&
+ value is not "C++")
+ {
+ return this.ReportDiscoveredTestCase
+ (
+ (ITestCase) new ExecutionErrorTestCase
+ (
+ this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, TestMethodDisplayOptions.None,
+ testMethod,
+ "Source Language " + value +
+ " is not a valid language. Allowed values are \"C++\"."
+ ), includeSourceInformation, messageBus
+ );
+ }
+
+ if (name is "Target Language" &&
+ value is not "C#")
+ {
+ return this.ReportDiscoveredTestCase
+ (
+ (ITestCase) new ExecutionErrorTestCase
+ (
+ this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, TestMethodDisplayOptions.None,
+ testMethod,
+ "Target Language " + value +
+ " is not a valid language. Allowed values are \"C#\"."
+ ), includeSourceInformation, messageBus
+ );
+ }
+
+ if (name is "Feature")
+ {
+ if (!SilkTouchTestFramework.Features.TryGetValue(value, out var flag))
+ {
+ return this.ReportDiscoveredTestCase
+ (
+ (ITestCase) new ExecutionErrorTestCase
+ (
+ this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod,
+ TestMethodDisplayOptions.None, testMethod,
+ "Feature Flag " + value + " is not a valid flag. Allowed values are " + String.Join
+ (", ", SilkTouchTestFramework.Features.Keys.Select(x => "\"" + x + "\"")) + "."
+ ), includeSourceInformation, messageBus
+ );
+ }
+
+ if (!flag)
+ {
+ return this.ReportDiscoveredTestCase
+ (
+ (ITestCase) new DisabledTestCase
+ (
+ "Flag " + value + " is not enabled", this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod,
+ TestMethodDisplayOptions.None, testMethod
+ ), includeSourceInformation, messageBus
+ );
+ }
+ }
+ }
+ return base.FindTestsForMethod(testMethod, includeSourceInformation, messageBus, discoveryOptions);
+ }
+
+ private sealed class DisabledTestCase : XunitTestCase
+ {
+ private readonly string _skipReason;
+
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ [Obsolete
+ (
+ "Called by the de-serializer; should only be called by deriving classes for de-serialization purposes"
+ )]
+ public DisabledTestCase() : base()
+ {
+ _skipReason = "Generic Skip";
+ }
+
+ public DisabledTestCase
+ (
+ string skipReason,
+ IMessageSink diagnosticMessageSink,
+ TestMethodDisplay defaultMethodDisplay,
+ TestMethodDisplayOptions defaultMethodDisplayOptions,
+ ITestMethod testMethod,
+ object[]? testMethodArguments = null
+ ) : base
+ (
+ diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod,
+ testMethodArguments
+ )
+ {
+ _skipReason = skipReason;
+ }
+
+ protected override string GetSkipReason(IAttributeInfo factAttribute)
+ {
+ return _skipReason;
+ }
+ }
+}
diff --git a/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFramework.cs b/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFramework.cs
index 9c32e43bd2..d2b83d3d4c 100644
--- a/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFramework.cs
+++ b/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFramework.cs
@@ -1,9 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
+using System.Collections.Generic;
+using System.Reflection;
using System.Xml;
-using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
@@ -35,157 +32,8 @@ protected override ITestFrameworkDiscoverer CreateDiscoverer(
assemblyInfo,
SourceInformationProvider,
DiagnosticMessageSink);
- }
-
- public class SilkTouchFrameworkDiscoverer : XunitTestFrameworkDiscoverer
- {
- public SilkTouchFrameworkDiscoverer(
- IAssemblyInfo assemblyInfo,
- ISourceInformationProvider sourceProvider,
- IMessageSink diagnosticMessageSink,
- IXunitTestCollectionFactory? collectionFactory = null)
- : base(
- assemblyInfo,
- sourceProvider,
- diagnosticMessageSink,
- collectionFactory)
- {
- }
-
- protected override bool FindTestsForMethod
- (
- ITestMethod testMethod,
- bool includeSourceInformation,
- IMessageBus messageBus,
- ITestFrameworkDiscoveryOptions discoveryOptions
- )
- {
- var traits = testMethod.Method.GetCustomAttributes(typeof(TraitAttribute))
- .Select
- (
- x =>
- {
- var args = x.GetConstructorArguments().ToArray();
- var name = (string) args[0];
- var value = (string) args[1];
- return (name, value);
- }
- );
- foreach (var (name, value) in traits)
- {
- if (name is "Category" &&
- value is not "Integration" and not "Scraper" and not "Symbols" and not "Emitter" and not "TypeStore" and not "Type Resolution")
- {
- return this.ReportDiscoveredTestCase
- (
- (ITestCase) new ExecutionErrorTestCase
- (
- this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, TestMethodDisplayOptions.None,
- testMethod,
- "Category " + value +
- " is not a valid category. Allowed values are \"Integration\", \"Scraper\", \"Symbols\", \"Emitter\"."
- ), includeSourceInformation, messageBus
- );
- }
-
- if (name is "Source Language" &&
- value is not "C++")
- {
- return this.ReportDiscoveredTestCase
- (
- (ITestCase) new ExecutionErrorTestCase
- (
- this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, TestMethodDisplayOptions.None,
- testMethod,
- "Source Language " + value +
- " is not a valid language. Allowed values are \"C++\"."
- ), includeSourceInformation, messageBus
- );
- }
-
- if (name is "Target Language" &&
- value is not "C#")
- {
- return this.ReportDiscoveredTestCase
- (
- (ITestCase) new ExecutionErrorTestCase
- (
- this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod, TestMethodDisplayOptions.None,
- testMethod,
- "Target Language " + value +
- " is not a valid language. Allowed values are \"C#\"."
- ), includeSourceInformation, messageBus
- );
- }
- if (name is "Feature")
- {
- if (!SilkTouchTestFramework.Features.TryGetValue(value, out var flag))
- {
- return this.ReportDiscoveredTestCase
- (
- (ITestCase) new ExecutionErrorTestCase
- (
- this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod,
- TestMethodDisplayOptions.None, testMethod,
- "Feature Flag " + value + " is not a valid flag. Allowed values are " + String.Join
- (", ", SilkTouchTestFramework.Features.Keys.Select(x => "\"" + x + "\"")) + "."
- ), includeSourceInformation, messageBus
- );
- }
-
- if (!flag)
- {
- return this.ReportDiscoveredTestCase
- (
- (ITestCase) new DisabledTestCase
- (
- "Flag " + value + " is not enabled", this.DiagnosticMessageSink, TestMethodDisplay.ClassAndMethod,
- TestMethodDisplayOptions.None, testMethod
- ), includeSourceInformation, messageBus
- );
- }
- }
- }
- return base.FindTestsForMethod(testMethod, includeSourceInformation, messageBus, discoveryOptions);
- }
-
- private sealed class DisabledTestCase : XunitTestCase
- {
- private readonly string _skipReason;
-
- ///
- [EditorBrowsable(EditorBrowsableState.Never)]
- [Obsolete
- (
- "Called by the de-serializer; should only be called by deriving classes for de-serialization purposes"
- )]
- public DisabledTestCase() : base()
- {
- _skipReason = "Generic Skip";
- }
-
- public DisabledTestCase
- (
- string skipReason,
- IMessageSink diagnosticMessageSink,
- TestMethodDisplay defaultMethodDisplay,
- TestMethodDisplayOptions defaultMethodDisplayOptions,
- ITestMethod testMethod,
- object[]? testMethodArguments = null
- ) : base
- (
- diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod,
- testMethodArguments
- )
- {
- _skipReason = skipReason;
- }
-
- protected override string GetSkipReason(IAttributeInfo factAttribute)
- {
- return _skipReason;
- }
- }
+ protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName)
+ => new SilkTouchTestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink);
}
}
diff --git a/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFrameworkExecutor.cs b/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFrameworkExecutor.cs
new file mode 100644
index 0000000000..e37b522912
--- /dev/null
+++ b/tests/Silk.NET.SilkTouch.TestFramework/SilkTouchTestFrameworkExecutor.cs
@@ -0,0 +1,116 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// ATTRIBUTION:
+// THIS FILE IS A MODIFIED VERSION OF CODE FOUND AT
+// https://www.meziantou.net/parallelize-test-cases-execution-in-xunit.htm
+// AND https://github.com/meziantou/Meziantou.Xunit.ParallelTestFramework
+// WITH A NUGET PACKAGE AT https://www.nuget.org/packages/Meziantou.Xunit.ParallelTestFramework/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Silk.NET.SilkTouch.TestFramework;
+
+public sealed class SilkTouchTestFrameworkExecutor : XunitTestFrameworkExecutor
+{
+
+ public SilkTouchTestFrameworkExecutor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink) : base(assemblyName, sourceInformationProvider, diagnosticMessageSink)
+ {
+ }
+
+ protected override void RunTestCases
+ (IEnumerable testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions)
+ {
+ var newTestCases = AllInParallel(testCases);
+
+ base.RunTestCases(newTestCases, executionMessageSink, executionOptions);
+ }
+
+ private IEnumerable AllInParallel(IEnumerable testCases)
+ {
+ return testCases.Select
+ (
+ x =>
+ {
+ var oldTestMethod = x.TestMethod;
+ var oldTestClass = oldTestMethod.TestClass;
+ var oldTestCollection = oldTestMethod.TestClass.TestCollection;
+
+ if (oldTestCollection.CollectionDefinition != null || oldTestClass.Class.GetCustomAttributes
+ (typeof(CollectionAttribute))
+ .Any())
+ return x;
+
+ return AssignToNewCollection(x);
+ }
+ );
+ }
+
+ private IXunitTestCase AssignToNewCollection(IXunitTestCase testCase)
+ {
+ static TestMethodDisplay GetTestMethodDisplay(TestMethodTestCase testCase)
+ {
+ return (TestMethodDisplay)typeof(TestMethodTestCase)
+ .GetProperty("DefaultMethodDisplay", BindingFlags.Instance | BindingFlags.NonPublic)!
+ .GetValue(testCase)!;
+ }
+
+ static TestMethodDisplayOptions GetTestMethodDisplayOptions(TestMethodTestCase testCase)
+ {
+ return (TestMethodDisplayOptions)typeof(TestMethodTestCase)
+ .GetProperty("DefaultMethodDisplayOptions", BindingFlags.Instance | BindingFlags.NonPublic)!
+ .GetValue(testCase)!;
+ }
+
+ var oldTestMethod = testCase.TestMethod;
+ var oldTestClass = oldTestMethod.TestClass;
+ var oldTestCollection = oldTestMethod.TestClass.TestCollection;
+
+ // Create a new collection with a unique id for the test case.
+ var newTestCollection = new TestCollection
+ (
+ oldTestCollection.TestAssembly,
+ oldTestCollection.CollectionDefinition,
+ displayName: $"{oldTestCollection.DisplayName} {oldTestCollection.UniqueID}"
+ );
+ newTestCollection.UniqueID = Guid.NewGuid();
+
+ // Duplicate the test and assign it to the new collection
+ var newTestClass = new TestClass(newTestCollection, oldTestClass.Class);
+ var newTestMethod = new TestMethod(newTestClass, oldTestMethod.Method);
+ switch (testCase)
+ {
+ // Used by Theory having DisableDiscoveryEnumeration or non-serializable data
+ case XunitTheoryTestCase xunitTheoryTestCase:
+ return new XunitTheoryTestCase
+ (
+ DiagnosticMessageSink,
+ GetTestMethodDisplay(xunitTheoryTestCase),
+ GetTestMethodDisplayOptions(xunitTheoryTestCase),
+ newTestMethod
+ );
+
+ // Used by all other tests
+ case XunitTestCase xunitTestCase:
+ return new XunitTestCase
+ (
+ DiagnosticMessageSink,
+ GetTestMethodDisplay(xunitTestCase),
+ GetTestMethodDisplayOptions(xunitTestCase),
+ newTestMethod,
+ xunitTestCase.TestMethodArguments
+ );
+
+ // TODO If you use custom attribute, you may need to add cases here
+
+ default:
+ throw new ArgumentOutOfRangeException("Test case " + testCase.GetType() + " not supported");
+ }
+ }
+}
diff --git a/tests/Silk.NET.SilkTouch.Tests.Common/Fakers.cs b/tests/Silk.NET.SilkTouch.Tests.Common/Fakers.cs
index 927674fa4a..7bf42bd3d0 100644
--- a/tests/Silk.NET.SilkTouch.Tests.Common/Fakers.cs
+++ b/tests/Silk.NET.SilkTouch.Tests.Common/Fakers.cs
@@ -14,7 +14,7 @@ static Fakers()
Faker.DefaultStrictMode = true;
}
- public static int StandardGenerateCount { get; } = 10;
+ public static int StandardGenerateCount { get; } = 20;
public static Faker IdentifierSymbol { get; } = new Faker().SkipConstructor()
.RuleFor