diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index ea0502d..23c9fa7 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -8,7 +8,8 @@ updates:
- package-ecosystem: "github-actions"
directories: [".github/workflows", ".github/actions/**"]
schedule:
- interval: "daily"
+ # interval: "daily"
+ interval: "weekly"
groups:
github-actions:
patterns:
@@ -17,7 +18,8 @@ updates:
- package-ecosystem: "nuget"
directory: "/" # Location of solution/project files
schedule:
- interval: "daily"
+ # interval: "daily"
+ interval: "weekly"
groups:
nuget:
patterns:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index d15c0e8..61982d5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,9 +2,11 @@ name: Test
on:
push:
- branches: [ main ]
- pull_request:
- branches: [ main ]
+ branches:
+ - '**'
+ # branches: [ main ]
+ # pull_request:
+ # branches: [ main ]
permissions:
contents: read
diff --git a/FEFF.TestFixtures.slnx b/FEFF.TestFixtures.slnx
index 65eceab..fc0f88b 100644
--- a/FEFF.TestFixtures.slnx
+++ b/FEFF.TestFixtures.slnx
@@ -14,17 +14,20 @@
+
+
+
\ No newline at end of file
diff --git a/NuGet.Config b/NuGet.Config
new file mode 100644
index 0000000..b641abc
--- /dev/null
+++ b/NuGet.Config
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/docs/articles/02.advanced/advanced-fixture-registration.md b/docs/articles/02.advanced/advanced-fixture-registration.md
index be7b19a..4cd90e2 100644
--- a/docs/articles/02.advanced/advanced-fixture-registration.md
+++ b/docs/articles/02.advanced/advanced-fixture-registration.md
@@ -50,7 +50,7 @@ This approach gives you full control over how the fixture and its dependencies a
Fixtures that implement `IFixtureRegistrar` can expose configuration options through the `Microsoft.Extensions.Options` pattern. See the dedicated article for a complete walkthrough:
-π [Configuring Fixtures](configuring-fixtures.md) - Learn how to add configuration support to fixtures like `TmpDirectoryFixture`.
+π [Options Pattern](configuring-fixtures/options-pattern.md) - Learn how to add configuration support to fixtures like `TmpDirectoryFixture`.
## When to Use Advanced Registration
diff --git a/docs/articles/02.advanced/configuring-fixtures.md b/docs/articles/02.advanced/configuring-fixtures/options-pattern.md
similarity index 72%
rename from docs/articles/02.advanced/configuring-fixtures.md
rename to docs/articles/02.advanced/configuring-fixtures/options-pattern.md
index 9e6b5f6..8e55324 100644
--- a/docs/articles/02.advanced/configuring-fixtures.md
+++ b/docs/articles/02.advanced/configuring-fixtures/options-pattern.md
@@ -1,4 +1,4 @@
-# Configuring Fixtures
+# Options Pattern
Fixtures that implement `IFixtureRegistrar` can expose configuration options through the standard `Microsoft.Extensions.Options` pattern. This article demonstrates how to add configuration support to a fixture using `TmpDirectoryFixture` as an example.
@@ -18,41 +18,41 @@ The `TmpDirectoryFixture` provides a unique temporary directory for each test sc
Create an `Options` class and any supporting enums:
```csharp
+///
+/// Specifies the behavior when the fixture is disposed.
+///
+public enum DisposeType
+{
///
- /// Specifies the behavior when the fixture is disposed.
+ /// Deletes the temporary directory and its contents on disposal.
///
- public enum DisposeType
- {
- ///
- /// Deletes the temporary directory and its contents on disposal.
- ///
- Delete,
-
- ///
- /// Skips deletion of the temporary directory on disposal.
- ///
- ///
- /// Can be used for optimization in CI environments.
- ///
- Skip
- }
+ Delete,
///
- /// Configuration options for TmpDirectoryFixture.
+ /// Skips deletion of the temporary directory on disposal.
///
- public class Options
- {
- ///
- /// Gets or sets whether the temporary directory should be deleted on disposal.
- /// Defaults to DisposeType.Delete.
- ///
- public DisposeType DisposeType { get; set; } = DisposeType.Delete;
-
- ///
- /// Gets or sets the prefix for the temporary directory name.
- ///
- public string? Prefix { get; set; }
- }
+ ///
+ /// Can be used for optimization in CI environments.
+ ///
+ Skip
+}
+
+///
+/// Configuration options for TmpDirectoryFixture.
+///
+public class Options
+{
+ ///
+ /// Gets or sets whether the temporary directory should be deleted on disposal.
+ /// Defaults to DisposeType.Delete.
+ ///
+ public DisposeType DisposeType { get; set; } = DisposeType.Delete;
+
+ ///
+ /// Gets or sets the prefix for the temporary directory name.
+ ///
+ public string? Prefix { get; set; }
+}
```
### Step 2: Register Options with DI
@@ -89,27 +89,26 @@ This enables:
Inject `IOptions` into the fixture constructor:
```csharp
- private readonly Options _opts;
- public string Path { get; }
+private readonly Options _opts;
+public string Path { get; }
+
+public TmpDirectoryFixture(IOptions opts)
+{
+ _opts = opts.Value;
+ Path = Directory.CreateTempSubdirectory(_opts.Prefix).FullName;
+}
- public TmpDirectoryFixture(IOptions opts)
+public void Dispose()
+{
+ if (_opts.DisposeType != DisposeType.Delete)
+ return;
+
+ try
{
- _opts = opts.Value;
- Path = Directory.CreateTempSubdirectory(_opts.Prefix).FullName;
+ Directory.Delete(Path, true);
}
-
- public void Dispose()
+ catch (DirectoryNotFoundException)
{
- if (_opts.DisposeType != DisposeType.Delete)
- return;
-
- try
- {
- Directory.Delete(Path, true);
- }
- catch (DirectoryNotFoundException)
- {
- }
}
}
```
@@ -162,3 +161,5 @@ var manager = new FixtureManagerBuilder()
| [TmpDirectoryFixture.cs](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/src/FEFF.TestFixtures/Fixtures/TmpDirectoryFixture.cs) | Complete source code example |
| [TmpDirectoryFixtureTests.cs](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/tests/FEFF.TestFixtures.Tests/Fixtures/TmpDirectoryFixtureTests.cs) | Unit tests for TmpDirectoryFixture |
| [OptionsConfigurationTests.cs](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/tests/FEFF.TestFixtures.Tests/EngineTests/OptionsConfigurationTests.cs) | Tests for options configuration patterns |
+| [Parameterization Pattern](parameterization-pattern.md) | Alternative generic type-based configuration |
+| [Selecting Configuration Method](selecting-configuration-method.md) | Comparison of configuration approaches |
diff --git a/docs/articles/02.advanced/fixture-parameterization.md b/docs/articles/02.advanced/configuring-fixtures/parameterization-pattern.md
similarity index 67%
rename from docs/articles/02.advanced/fixture-parameterization.md
rename to docs/articles/02.advanced/configuring-fixtures/parameterization-pattern.md
index bffc074..e918145 100644
--- a/docs/articles/02.advanced/fixture-parameterization.md
+++ b/docs/articles/02.advanced/configuring-fixtures/parameterization-pattern.md
@@ -1,16 +1,20 @@
-# Fixture Parameterization
-
-Fixture parameterization allows you to create fixture instances with concrete argument values by defining options types that supply configuration data. This pattern is essential when you need the same fixture to behave differently across tests based on custom parameters.
+# Generic Parameterization Pattern
## Overview
-While standard fixtures are created with default behavior, parameterized fixtures accept configuration through a dedicated options type. This options type is itself a fixture, enabling dependency injection and test isolation.
+Fixture parameterization lets you pass values to a fixture that are required but not known when the fixture is created. Instead of hardcoding configuration inside the fixture, you supply it from the outside.
+
+This is useful when:
-The pattern consists of three components:
+- Different tests need the same fixture to behave differently
+- Configuration values (connection strings, endpoints, flags) are decided at test time, not when the fixture is written
+- The same fixture is reused across test suites with different settings
-1. **Options Interface** - Defines the contract for configuration data
-2. **Options Fixture** - Implements the interface with concrete values
-3. **Parameterized Fixture** - Consumes the options fixture via constructor injection of generic type parameter
+The pattern uses three pieces:
+
+1. **Options Interface** β defines what values the fixture needs
+2. **Options Fixture** β provides the actual values
+3. **Parameterized Fixture** β receives the values through its constructor
## Example: TmpDatabaseNameFixture
@@ -66,8 +70,8 @@ public class OptionsFixture : ITmpDatabaseNameFixtureOptions
```
The options fixture can:
-- Return hardcoded values
-- Read from environment variables
+
+- Return hardcoded or calculated values
- Depend on other fixtures for dynamic configuration
### Step 4: Use the Parameterized Fixture
@@ -82,7 +86,7 @@ var fixtureInstance = TestContext.Current.GetFeffFixture [!TIP]
-> Single `OptionsFixture` class can implement multiple different interfaces to parameterize multiple fixtures used in a test suite.
+> A single `OptionsFixture` class can implement multiple different interfaces to parameterize multiple fixtures used in a test suite.
## Benefits of Fixture Parameterization
@@ -95,8 +99,8 @@ The generic type parameter `OptionsFixture` tells `TmpDatabaseNameFixture` which
| Resource | Description |
|----------|-------------|
-| [TmpDatabaseNameFixture.cs](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/src/FEFF.TestFixtures.AspNetCore/Fixtures/TmpDatabaseNameFixture.cs) | Parameterized fixture implementation |
-| [ITmpDatabaseNameFixtureOptions.cs](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/src/FEFF.TestFixtures.AspNetCore/Fixtures/TmpDatabaseNameFixture.cs) | Options interface definition |
+| [TmpDatabaseNameFixture.cs](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/src/FEFF.TestFixtures.AspNetCore/Fixtures/TmpDatabaseNameFixture.cs) | Parameterized fixture and options interface |
| [ApiTests.cs](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/examples/ExampleTests.AspNetCore/ApiTests.cs) | Example usage in API tests |
| [TmpDatabaseNameFixtureTests.cs](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/tests/FEFF.TestFixtures.Tests/FixturesTests/FEFF.TestFixtures.AspNetCore/TmpDatabaseNameFixtureTests.cs) | Unit tests for parameterization |
-| [Configuring Fixtures](configuring-fixtures.md) | Alternative configuration via environment variables |
+| [Options Pattern](options-pattern.md) | Alternative configuration via environment variables |
+| [Selecting Configuration Method](selecting-configuration-method.md) | Comparison with Options Pattern |
diff --git a/docs/articles/02.advanced/configuring-fixtures/selecting-configuration-method.md b/docs/articles/02.advanced/configuring-fixtures/selecting-configuration-method.md
new file mode 100644
index 0000000..7dd74c0
--- /dev/null
+++ b/docs/articles/02.advanced/configuring-fixtures/selecting-configuration-method.md
@@ -0,0 +1,26 @@
+# Selecting Configuration Method
+
+The library provides two distinct ways to configure fixtures. Choose based on whether the configuration varies between tests or is controlled externally.
+
+| Aspect | [Parameterization Pattern](parameterization-pattern.md) | [Options Pattern](options-pattern.md) |
+|--------|----------------------------------------|---------------------------------------------------------------------|
+| **When to use** | Different tests or test suites need different behavior for the same fixture | Global or environment-specific settings (CI, debugging, local overrides) |
+| **Value requirement** | Fixture explicitly requires a value | Fixture should have default value |
+| **Mechanism** | Generic type parameter + options fixture interface | `Microsoft.Extensions.Options` bound to configuration (e.g., environment variables) |
+| **Discovery** | Compile-time via generic constraint | Runtime via `IOptions` and `IFixtureRegistrar` |
+| **Flexibility** | Per-test-suite variation by swapping the options fixture type | Global change without recompiling tests |
+| **Example scenario** | One test suite uses database `A`, another uses database `B`, via `TmpDatabaseNameFixture` vs `TmpDatabaseNameFixture` | Skipping temp directory cleanup on CI by setting `TmpDirectoryFixture__DisposeType=Skip` |
+
+## Decision Guide
+
+- **Use parameterization** when the fixture must behave differently across test classes or collections and the decision is made at design time. This keeps configuration type-safe and visible in test code.
+- **Use the options pattern** when you need operators or CI pipelines to adjust behavior without changing source code, or when a setting applies broadly across all tests using that fixture.
+
+The two patterns can coexist: a fixture may accept an options fixture for structural choices (which connection strings to redirect) while also using `IOptions` for operational tuning (cleanup behavior, timeouts).
+
+## See Also
+
+| Resource | Description |
+|----------|-------------|
+| [Parameterization Pattern](parameterization-pattern.md) | Generic type-based configuration |
+| [Options Pattern](options-pattern.md) | Environment variable-based configuration |
diff --git a/docs/articles/02.advanced/toc.yml b/docs/articles/02.advanced/toc.yml
index 359a1a3..a7f31fb 100644
--- a/docs/articles/02.advanced/toc.yml
+++ b/docs/articles/02.advanced/toc.yml
@@ -5,6 +5,10 @@
- name: Advanced Fixture Registration
href: advanced-fixture-registration.md
- name: Configuring Fixtures
- href: configuring-fixtures.md
-- name: Fixture Parameterization
- href: fixture-parameterization.md
+ items:
+ - name: Options Pattern
+ href: configuring-fixtures/options-pattern.md
+ - name: Generic Parameterization Pattern
+ href: configuring-fixtures/parameterization-pattern.md
+ - name: Selecting Configuration Method
+ href: configuring-fixtures/selecting-configuration-method.md
diff --git a/src/FEFF.TestFixtures.Abstractions/FEFF.TestFixtures.Abstractions.csproj b/src/FEFF.TestFixtures.Abstractions/FEFF.TestFixtures.Abstractions.csproj
index cbcee0b..201b5b4 100644
--- a/src/FEFF.TestFixtures.Abstractions/FEFF.TestFixtures.Abstractions.csproj
+++ b/src/FEFF.TestFixtures.Abstractions/FEFF.TestFixtures.Abstractions.csproj
@@ -16,6 +16,7 @@
+
diff --git a/src/FEFF.TestFixtures.Abstractions/Utils/ThrowHelper.cs b/src/FEFF.TestFixtures.Abstractions/Utils/ThrowHelper.cs
index db82f37..8a1a33f 100644
--- a/src/FEFF.TestFixtures.Abstractions/Utils/ThrowHelper.cs
+++ b/src/FEFF.TestFixtures.Abstractions/Utils/ThrowHelper.cs
@@ -30,17 +30,21 @@ public static void Assert(
/// Returns argument if it is not null.
/// Throws otherwise.
///
+ /// The type of the argument.
+ /// The value to check for null.
+ /// The name of the parameter (auto-populated).
+ /// The argument if not null.
///
/// It is convenient to wrap a complex expression with :
///
///
- /// var result = ThrowHelper.Ensure(anObject?.Nested?.Nested?.Value);
+ /// var result = ThrowHelper.EnsureNotNull(anObject?.Nested?.Nested?.Value);
///
///
/// Here:
///
- /// - The whole expression is serialized into error message, if expression is null.
- /// - The expression is calculated only once and is returned to consumer, if expression is NOT null.
+ /// - The whole expression is serialized into error message, if expression is null.
+ /// - The expression is calculated only once and is returned to consumer, if expression is NOT null.
///
///
///
diff --git a/src/FEFF.TestFixtures.AspNetCore.EF/DatabaseLifecycleFixture.cs b/src/FEFF.TestFixtures.AspNetCore.EF/DatabaseLifecycleFixture.cs
index b68d170..55c8917 100644
--- a/src/FEFF.TestFixtures.AspNetCore.EF/DatabaseLifecycleFixture.cs
+++ b/src/FEFF.TestFixtures.AspNetCore.EF/DatabaseLifecycleFixture.cs
@@ -27,7 +27,7 @@ public interface IDatabaseLifecycleFixture : IDatabaseLifecycleFixture
/// Gets the instance resolved from the service provider.
///
///
- /// Starts the application under test if not already running.
+ /// Accessing this property starts the application under test if not already running.
///
TContext LazyDbContext { get; }
}
@@ -39,8 +39,11 @@ public interface IDatabaseLifecycleFixture : IDatabaseLifecycleFixture
/// A fixture that manages Entity Framework Core database creation and deletion
/// for the lifetime of a test scope. The database is deleted on .
///
+///
+/// Note: EnsureDeleted may fail for admin databases. Consider using TmpDbNameFixture for such cases.
+///
/// The application entry point type.
-/// The type to manage.
+/// The type to manage.
[Fixture]
public sealed class DatabaseLifecycleFixture : IAsyncDisposable, IDatabaseLifecycleFixture
where TEntryPoint : class
@@ -70,6 +73,10 @@ public async ValueTask DisposeAsync()
return;
await LazyDbContext.Database.EnsureDeletedAsync().ConfigureAwait(false);
+// TODO:
+ // Log warning but do not throw to prevent test failures during cleanup
+ // This can happen when database is locked or inaccessible
+ // System.Console.Error.WriteLine($"[DatabaseLifecycleFixture] Warning: Failed to delete database: {ex.Message}");
}
///
diff --git a/src/FEFF.TestFixtures.AspNetCore.SignalR/Core/ChannelExtensions.cs b/src/FEFF.TestFixtures.AspNetCore.SignalR/Core/ChannelExtensions.cs
index cfa98a1..d828930 100644
--- a/src/FEFF.TestFixtures.AspNetCore.SignalR/Core/ChannelExtensions.cs
+++ b/src/FEFF.TestFixtures.AspNetCore.SignalR/Core/ChannelExtensions.cs
@@ -6,24 +6,32 @@ namespace FEFF.Extensions.Threading;
internal static class ChannelExtensions
{
+ ///
+ /// Attempts to read a value from the channel with a timeout.
+ ///
+ /// The type of the value to read.
+ /// The channel reader.
+ /// The timeout duration.
+ /// A token to cancel the operation.
+ /// The read value, or null if the timeout occurred.
public static async Task TryReadAsync(this ChannelReader src, TimeSpan timeout, CancellationToken cancellationToken)
where T : notnull
{
using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
timeoutCts.CancelAfter(timeout);
- var timeoutToken = timeoutCts.Token;
-
+ var timeoutToken = timeoutCts.Token;
+
try
{
- return await src.ReadAsync(timeoutToken);
+ return await src.ReadAsync(timeoutToken).ConfigureAwait(false);
}
- catch (OperationCanceledException e)
- when (e.CancellationToken == timeoutToken
+ catch (OperationCanceledException e)
+ when (e.CancellationToken == timeoutToken
&& timeoutCts.IsCancellationRequested == true
&& cancellationToken.IsCancellationRequested == false)
{
return default;
}
}
-}
+}
diff --git a/src/FEFF.TestFixtures.AspNetCore/FakeRandom/FakeRandom.cs b/src/FEFF.TestFixtures.AspNetCore/FakeRandom/FakeRandom.cs
index 5704a65..12d67f5 100644
--- a/src/FEFF.TestFixtures.AspNetCore/FakeRandom/FakeRandom.cs
+++ b/src/FEFF.TestFixtures.AspNetCore/FakeRandom/FakeRandom.cs
@@ -2,7 +2,7 @@ namespace FEFF.TestFixtures.AspNetCore.Randomness;
///
/// A configurable random number generator for testing.
-/// All public methods ARE threadsafe via lock().
+/// All public methods are thread-safe via lock().
///
///
/// The default behavior uses a constant seed. Additional strategies such as
@@ -118,7 +118,7 @@ private int NextI32Internal(INextStrategy int32Next, int min, int max)
///
public override int Next()
{
- lock(_lock)
+ lock (_lock)
{
// just do as other "Assert arguments" pattern
var def = base.Next();
@@ -137,7 +137,7 @@ public override int Next()
///
public override int Next(int maxValue)
{
- lock(_lock)
+ lock (_lock)
{
// Assert arguments
var def = base.Next(maxValue);
@@ -153,7 +153,7 @@ public override int Next(int maxValue)
///
public override int Next(int minValue, int maxValue)
{
- lock(_lock)
+ lock (_lock)
{
// Assert arguments
var def = base.Next(minValue, maxValue);
@@ -185,7 +185,7 @@ private long NextI64Internal(INextStrategy int64Next, long min, long max)
///
public override long NextInt64()
{
- lock(_lock)
+ lock (_lock)
{
var def = base.NextInt64();
var strategy = Int64Next;
@@ -199,7 +199,7 @@ public override long NextInt64()
///
public override long NextInt64(long maxValue)
{
- lock(_lock)
+ lock (_lock)
{
// Assert arguments
var def = base.NextInt64(maxValue);
@@ -214,7 +214,7 @@ public override long NextInt64(long maxValue)
///
public override long NextInt64(long minValue, long maxValue)
{
- lock(_lock)
+ lock (_lock)
{
// Assert arguments
var def = base.NextInt64(minValue, maxValue);
@@ -243,7 +243,7 @@ private float NextSingleInternal(INextStrategy singleNext)
///
public override float NextSingle()
{
- lock(_lock)
+ lock (_lock)
{
var def = base.NextSingle();
var strategy = SingleNext;
@@ -268,7 +268,7 @@ private double NextDoubleInternal(INextStrategy doubleNext)
///
public override double NextDouble()
{
- lock(_lock)
+ lock (_lock)
{
var def = base.NextDouble();
var strategy = DoubleNext;
@@ -291,7 +291,7 @@ public override void NextBytes(byte[] buffer)
///
public override void NextBytes(Span buffer)
{
- lock(_lock)
+ lock (_lock)
{
// Assert arguments
base.NextBytes(buffer);
diff --git a/src/FEFF.TestFixtures.Engine/Engine/FixtureManager.cs b/src/FEFF.TestFixtures.Engine/Engine/FixtureManager.cs
index 88f9dd3..6064a7a 100644
--- a/src/FEFF.TestFixtures.Engine/Engine/FixtureManager.cs
+++ b/src/FEFF.TestFixtures.Engine/Engine/FixtureManager.cs
@@ -18,7 +18,7 @@ public interface IFixtureScope
internal interface IFixtureManagerOptions
{
- ServiceProvider BuildServiceProvider();
+ ServiceProvider BuildServiceProvider();
}
///
@@ -36,11 +36,11 @@ public sealed class FixtureManager : IAsyncDisposable
#if NET9_0_OR_GREATER
private readonly Lock _lock = new();
#else
- private readonly Object _lock = new();
+ private readonly Object _lock = new();
#endif
- private bool _isDisposed;
-
- //TODO: public ctor
+ private bool _isDisposed;
+
+ //TODO: public ctor
///
/// Use for instance construction.
///
@@ -72,7 +72,7 @@ public IFixtureScope GetScope(string id)
var res = CreateScope();
_scopes[id] = res;
- return res;
+ return res;
}
}
@@ -108,11 +108,11 @@ public ValueTask RemoveScopeAsync(string scopeId)
{
FixtureScope scope;
lock (_lock)
- {
- //TODO: optimize
+ {
+ //TODO: optimize
if (_scopes.ContainsKey(scopeId) == false)
- return ValueTask.CompletedTask;
-
+ return ValueTask.CompletedTask;
+
scope = _scopes[scopeId];
_scopes.Remove(scopeId);
}
diff --git a/src/FEFF.TestFixtures.TUnit/packages.lock.json b/src/FEFF.TestFixtures.TUnit/packages.lock.json
index d85fe0a..471d442 100644
--- a/src/FEFF.TestFixtures.TUnit/packages.lock.json
+++ b/src/FEFF.TestFixtures.TUnit/packages.lock.json
@@ -1,6 +1,146 @@
{
"version": 1,
"dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[10.0.203, )",
+ "resolved": "10.0.203",
+ "contentHash": "R4Tvr1oACImMS+Y5M7NM07ll9QyJSKnki3Dvz8QwG1W6FEmd+9fmZXAF6BE6UPswHF6n0v41wgMQGlaudOspqA==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "10.0.203",
+ "Microsoft.SourceLink.Common": "10.0.203",
+ "System.IO.Hashing": "10.0.7"
+ }
+ },
+ "TUnit.Core": {
+ "type": "Direct",
+ "requested": "[1.40.10, )",
+ "resolved": "1.40.10",
+ "contentHash": "e09Mumq7XAnm2olh4/YzgrijNbJN5V0qMahFiyxblSrbibBv6uJFrEdaOZSn9wtds3zsE8mmcpTzCCm6MXEeXQ=="
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "10.0.203",
+ "contentHash": "m56WtzvIcL6t7JR3c7ogYitHizNM2QnRSo8yqxrQi+m5E/GGyDEmqymP+2p6YsFXn0j/Tzz67s4FQnrTLC7GKQ==",
+ "dependencies": {
+ "System.IO.Hashing": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "wZbGh7J8R1vXN525O6d8dlcDTxhRTnd5MyW4LdfP5S0tSnTwTCseYSrq6g0Mxh7W9xn8P/2xPuf0D/m6k2dy2w==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "t56nEgvECcyLPojZIUFWJknQQDAbgfTf9J+QMYJE1YYvVgz69vN6B/AKL8Grvj3Lcnp8kTpNqwmwFhb3YLJmtQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Binder": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "8bS1qIaRivny+WX+49pmeJ6iAylbtX8C0DLEcCQWZjdxQvLqaMssXiGD9P/6pYElrHbK5/nAHmjbQ8STqdMYeg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "TWto3imA+mJMLZI+5sbgLiFFoOFNFkizQYNaC5jTuiHKn3diwm1RN7mWDOEZN9kG2bixw7IvgpvtUG5/teSRzA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "91F/o3emPV/+xY/ip3s2LqDNF14kjttlVtq0BXgg6p4MnCzeSZxnUJm+t6WRrtD3JdGo88/oX+z7OwK4y8PZuw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "00SHUGTh2jSMvIr6x9Xwd2nE+B5/qFCO/9hDwUDhJsjYRDlADmaBZ7tqehXzBDsfjHSXJzuRHJzPYPPjphBQ7Q==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Options.ConfigurationExtensions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "IT7f+EMXZtkjatEcF+o6aOw/7OE4etRrMiDGEWH/iiTu2R3uhC4NEQJCfHiibtX45U3sIQ5Fh6tbb1qaOz3YAg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Configuration.Binder": "10.0.7",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Options": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "D5M0Jr551iTgwkZMN9rm0pSkgNLj5quUWQUmQPMZh7k/bnvZTnXRGfE2KuvXf1EEjt/ofD9yw9IumpgdP9QCnw=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "10.0.203",
+ "contentHash": "QYAnhBCOkT3ZUT/fHag11+bamwlbZ3U9Vi/WfKrD9emdUf1t3aqjWv0V2KtEGHSRSC81aBc8Oy/mvyGpEYd9Pg=="
+ },
+ "System.IO.Hashing": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "6hsjdSr4VOXSOnhALkYplHpAxnTG1J33YN42IB6nH2fEg4QnJqrZ4Ft+qn7mkrKAOYC8pCSFYwVWw6rQbmwgLQ=="
+ },
+ "System.Reflection.MetadataLoadContext": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "XDkKntYPUaANhLVdo7AHbrJ+QbUAY5u/T7lG5rHSx5kLxeHceoc3JcIMVAc/vZT+3rbwFYlrdnikxdi6G+2nvA=="
+ },
+ "feff.testfixtures": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.abstractions": {
+ "type": "Project",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.engine": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "[10.0.7, )",
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )",
+ "Microsoft.Extensions.Options": "[10.0.7, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )",
+ "System.Reflection.MetadataLoadContext": "[10.0.7, )"
+ }
+ }
+ },
"net8.0": {
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
diff --git a/src/FEFF.TestFixtures.XunitV4/Extension/Enums.cs b/src/FEFF.TestFixtures.XunitV4/Extension/Enums.cs
new file mode 100644
index 0000000..5b57709
--- /dev/null
+++ b/src/FEFF.TestFixtures.XunitV4/Extension/Enums.cs
@@ -0,0 +1,27 @@
+namespace FEFF.TestFixtures.Xunit.V4;
+
+///
+/// Defines the lifetime scope for a fixture in xUnit v3 tests.
+///
+public enum FixtureScopeType
+{
+ ///
+ /// The fixture is scoped to an individual test case.
+ ///
+ TestCase,
+
+ ///
+ /// The fixture is scoped to a test class.
+ ///
+ Class,
+
+ ///
+ /// The fixture is scoped to a test collection.
+ ///
+ Collection,
+
+ ///
+ /// The fixture is scoped to the entire test assembly.
+ ///
+ Assembly
+}
diff --git a/src/FEFF.TestFixtures.XunitV4/Extension/TestContextExtensions.cs b/src/FEFF.TestFixtures.XunitV4/Extension/TestContextExtensions.cs
new file mode 100644
index 0000000..6c9cf38
--- /dev/null
+++ b/src/FEFF.TestFixtures.XunitV4/Extension/TestContextExtensions.cs
@@ -0,0 +1,29 @@
+using FEFF.TestFixtures.Xunit.V4;
+using FEFF.TestFixtures.Xunit.V4.Internal;
+
+namespace Xunit.v3;
+
+///
+/// Extension methods for to resolve FEFF.TestFixtures fixtures in xUnit v3.
+///
+public static class TestContextExtensionsV4
+{
+ ///
+ /// Resolves a fixture from the specified scope within the test context.
+ ///
+ /// The type of fixture to resolve.
+ /// The current xUnit test context.
+ /// The lifetime scope for the fixture. Defaults to .
+ /// The resolved fixture instance.
+ /// Thrown when the extension is not properly registered.
+ public static T GetFeffFixture(this ITestContext ctx, FixtureScopeType scopeType = FixtureScopeType.TestCase)
+ where T : notnull
+ {
+ var scopeId = ScopeIdHelper.GetScopeId(ctx, scopeType);
+
+ return FixtureAdapter
+ .GetCurrent(ctx)
+ .GetScope(scopeId)
+ .GetFixture();
+ }
+}
diff --git a/src/FEFF.TestFixtures.XunitV4/Extension/TestFixturesExtensionAttribute.cs b/src/FEFF.TestFixtures.XunitV4/Extension/TestFixturesExtensionAttribute.cs
new file mode 100644
index 0000000..613c3cb
--- /dev/null
+++ b/src/FEFF.TestFixtures.XunitV4/Extension/TestFixturesExtensionAttribute.cs
@@ -0,0 +1,27 @@
+using FEFF.TestFixtures.Xunit.V4.Internal;
+using Xunit;
+using Xunit.v3;
+
+namespace FEFF.TestFixtures.Xunit.V4;
+
+//TODO: revert xml comment
+//TestContextExtensions.GetFeffFixture{T}
+
+///
+/// Manages for xUnit tests.
+/// Enables the use of .
+///
+///
+/// Apply this attribute at the assembly level in an AssemblyInfo.cs or any source file:
+/// [assembly: TestFixturesExtension]
+///
+// [AttributeUsage(AttributeTargets.Assembly)]
+public class TestFixturesExtensionAttribute : AssemblyFixtureAttribute
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TestFixturesExtensionAttribute() : base(typeof(FixtureAdapter))
+ {
+ }
+}
diff --git a/src/FEFF.TestFixtures.XunitV4/FEFF.TestFixtures.XunitV4.csproj b/src/FEFF.TestFixtures.XunitV4/FEFF.TestFixtures.XunitV4.csproj
new file mode 100644
index 0000000..d3deede
--- /dev/null
+++ b/src/FEFF.TestFixtures.XunitV4/FEFF.TestFixtures.XunitV4.csproj
@@ -0,0 +1,25 @@
+
+
+
+
+
+ true
+ preview
+ xUnit v4 extension, adds 'FEFF.TestFixtures'.
+ testing;fixtures;xUnit;xUnitV4;FEFF;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/FEFF.TestFixtures.XunitV4/Internal/FixtureAdapter.cs b/src/FEFF.TestFixtures.XunitV4/Internal/FixtureAdapter.cs
new file mode 100644
index 0000000..d37ecf3
--- /dev/null
+++ b/src/FEFF.TestFixtures.XunitV4/Internal/FixtureAdapter.cs
@@ -0,0 +1,112 @@
+using FEFF.Extensions;
+using FEFF.TestFixtures.Engine;
+using Xunit;
+using Xunit.v3;
+
+namespace FEFF.TestFixtures.Xunit.V4.Internal;
+
+///
+/// Adapter that integrates FEFF.TestFixtures with xUnit v4 lifecycle events.
+/// Manages the FixtureManager and handles scope creation/cleanup for test assemblies,
+/// collections, classes, and test cases.
+///
+internal class FixtureAdapter
+ : INotifyTestAssemblyLifecycleAsync
+ , INotifyTestCollectionLifecycleAsync
+ , INotifyTestClassLifecycleAsync
+ , INotifyTestCaseLifecycleAsync
+ , IAsyncDisposable
+{
+ private readonly FixtureManager _fixtureManager;
+
+ public FixtureAdapter()
+ {
+ _fixtureManager = new FixtureManagerBuilder().Build();
+ SetCurrent(TestContext.Current, this);
+ }
+
+ ///
+ public ValueTask DisposeAsync()
+ {
+ return _fixtureManager.DisposeAsync();
+ }
+
+ ///
+ public ValueTask OnTestAssemblyFinishedAsync(IXunitTestAssembly testAssembly)
+ {
+ ArgumentNullException.ThrowIfNull(testAssembly);
+ var id = ScopeIdHelper.GetScopeId(testAssembly);
+ return _fixtureManager.RemoveScopeAsync(id);
+ }
+
+ #region EventHandlers
+ ///
+ public ValueTask OnTestCollectionFinishedAsync(IXunitTestCollection testCollection)
+ {
+ ArgumentNullException.ThrowIfNull(testCollection);
+ var id = ScopeIdHelper.GetScopeId(testCollection);
+ return _fixtureManager.RemoveScopeAsync(id);
+ }
+
+ ///
+ public ValueTask OnTestClassFinishedAsync(IXunitTestClass testClass)
+ {
+ ArgumentNullException.ThrowIfNull(testClass);
+ var id = ScopeIdHelper.GetScopeId(testClass);
+ return _fixtureManager.RemoveScopeAsync(id);
+ }
+
+ ///
+ public ValueTask OnTestCaseFinishedAsync(IXunitTestCase testCase)
+ {
+ ArgumentNullException.ThrowIfNull(testCase);
+ var id = ScopeIdHelper.GetScopeId(testCase);
+ return _fixtureManager.RemoveScopeAsync(id);
+ }
+
+ ///
+ public ValueTask OnTestAssemblyStartingAsync(IXunitTestAssembly testAssembly) => ValueTask.CompletedTask;
+
+ ///
+ public ValueTask OnTestCaseStartingAsync(IXunitTestCase testCase) => ValueTask.CompletedTask;
+
+ ///
+ public ValueTask OnTestClassStartingAsync(IXunitTestClass testClass) => ValueTask.CompletedTask;
+
+ ///
+ public ValueTask OnTestCollectionStartingAsync(IXunitTestCollection testCollection) => ValueTask.CompletedTask;
+ #endregion
+
+ internal IFixtureScope GetScope(string scopeId)
+ {
+ return _fixtureManager.GetScope(scopeId);
+ }
+
+ #region static
+
+ private static void SetCurrent(ITestContext ctx, FixtureAdapter obj)
+ {
+ var key = GetKey(ctx);
+ var added = ctx.KeyValueStorage.TryAdd(key, obj);
+ if (added == false)
+ throw new InvalidOperationException("Another value exists in 'TestContext.KeyValueStorage'.");
+ }
+
+ private static string GetKey(ITestContext ctx)
+ {
+ var testAssembly = ctx.TestAssembly;
+ ThrowHelper.Assert(testAssembly is not null);
+
+ return $"{nameof(FixtureAdapter)}-{testAssembly.UniqueID}";
+ }
+
+ internal static FixtureAdapter GetCurrent(ITestContext ctx)
+ {
+ var key = GetKey(ctx);
+ _ = ctx.KeyValueStorage.TryGetValue(key, out var res);
+
+ return res as FixtureAdapter
+ ?? throw new InvalidOperationException($"Extension is not registered. Use '[assembly: {nameof(TestFixturesExtensionAttribute)}]'.");
+ }
+ #endregion
+}
diff --git a/src/FEFF.TestFixtures.XunitV4/Internal/ScopeIdHelper.cs b/src/FEFF.TestFixtures.XunitV4/Internal/ScopeIdHelper.cs
new file mode 100644
index 0000000..8ea9e66
--- /dev/null
+++ b/src/FEFF.TestFixtures.XunitV4/Internal/ScopeIdHelper.cs
@@ -0,0 +1,32 @@
+using FEFF.Extensions;
+using Xunit;
+using Xunit.Sdk;
+
+namespace FEFF.TestFixtures.Xunit.V4.Internal;
+
+internal static class ScopeIdHelper
+{
+ internal static string GetScopeId(ITestContext testContext, FixtureScopeType scopeType)
+ {
+ return scopeType switch
+ {
+ FixtureScopeType.TestCase => GetScopeId(ThrowHelper.EnsureNotNull(testContext.TestCase)),
+ FixtureScopeType.Class => GetScopeId(ThrowHelper.EnsureNotNull(testContext.TestClass)),
+ FixtureScopeType.Collection => GetScopeId(ThrowHelper.EnsureNotNull(testContext.TestCollection)),
+ FixtureScopeType.Assembly => GetScopeId(ThrowHelper.EnsureNotNull(testContext.TestAssembly)),
+ _ =>
+ throw EnumMatchException.From(scopeType)
+ };
+ }
+
+ internal static string GetScopeId(ITestCaseMetadata testCase) =>
+ GetScopeId(FixtureScopeType.TestCase, testCase.UniqueID);
+ internal static string GetScopeId(ITestClassMetadata testClass) =>
+ GetScopeId(FixtureScopeType.Class, testClass.UniqueID);
+ internal static string GetScopeId(ITestCollectionMetadata testCollection) =>
+ GetScopeId(FixtureScopeType.Collection, testCollection.UniqueID);
+ internal static string GetScopeId(IAssemblyMetadata testAssembly) =>
+ GetScopeId(FixtureScopeType.Assembly, testAssembly.UniqueID);
+
+ private static string GetScopeId(FixtureScopeType scopeType, string id) => $"{scopeType}-{id}";
+}
diff --git a/src/FEFF.TestFixtures.XunitV4/README.md b/src/FEFF.TestFixtures.XunitV4/README.md
new file mode 100644
index 0000000..c1460b7
--- /dev/null
+++ b/src/FEFF.TestFixtures.XunitV4/README.md
@@ -0,0 +1,59 @@
+# FEFF.TestFixtures.XunitV3
+
+PREVIEW! Xunit v4 integration for the **FEFF.TestFixtures** solution.
+Built against [Xunit-v3 4.0.0-pre.*](https://xunit.net/docs/using-ci-builds)
+
+## About
+
+Part of the **FEFF.TestFixtures** ecosystem β a framework-agnostic library for creating reusable test fixtures with scoped lifetimes. It replaces setup/teardown methods and the disposable pattern on test classes with composable, dependency-injected fixtures that can be shared across test projects.
+See the [main README](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/README.md) for full documentation.
+
+## This Package
+
+This package integrates the fixture engine with **Xunit v4**, enabling fixture resolution through the xUnit test context.
+
+### Quick Start
+
+1. Add the package to your test project:
+
+ ```bash
+ dotnet add package FEFF.TestFixtures.XunitV3
+ ```
+
+2. Enable the extension at the assembly level:
+
+ ```csharp
+ [assembly: FEFF.TestFixtures.Xunit.TestFixturesExtension]
+ ```
+
+3. Resolve fixtures in your tests:
+
+ ```csharp
+ var tmpDir = TestContext.Current.GetFeffFixture();
+ var scoped = TestContext.Current.GetFeffFixture(FixtureScopeType.Class);
+ ```
+
+### Supported Scopes
+
+| Scope | Description |
+|-------|-------------|
+| `TestCase` | Created and destroyed per test case |
+| `Class` | Shared across all tests in a test class |
+| `Collection` | Shared across all tests in a test collection |
+| `Assembly` | Shared across all tests in the assembly |
+
+## Examples
+
+- [Example](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/examples/ExampleTests.XunitV3/ExampleTests.cs)
+- [AspNetCore example](https://github.com/metacoder-feff/FEFF.TestFixtures/blob/main/examples/ExampleTests.AspNetCore/ApiTests.cs)
+
+## See Also
+
+| Package | Description |
+|---------|-------------|
+| [FEFF.TestFixtures](https://www.nuget.org/packages/FEFF.TestFixtures) | Core fixtures library |
+| [FEFF.TestFixtures.XunitV3](https://www.nuget.org/packages/FEFF.TestFixtures.XunitV3) | **current package** |
+| [FEFF.TestFixtures.TUnit](https://www.nuget.org/packages/FEFF.TestFixtures.TUnit) | TUnit integration |
+| [FEFF.TestFixtures.AspNetCore](https://www.nuget.org/packages/FEFF.TestFixtures.AspNetCore) | ASP.NET Core fixtures |
+| [FEFF.TestFixtures.AspNetCore.EF](https://www.nuget.org/packages/FEFF.TestFixtures.AspNetCore.EF) | EF Core database lifecycle fixture |
+| [FEFF.TestFixtures.AspNetCore.SignalR](https://www.nuget.org/packages/FEFF.TestFixtures.AspNetCore.SignalR) | SignalR testing fixture |
diff --git a/src/FEFF.TestFixtures.XunitV4/packages.lock.json b/src/FEFF.TestFixtures.XunitV4/packages.lock.json
new file mode 100644
index 0000000..a899d19
--- /dev/null
+++ b/src/FEFF.TestFixtures.XunitV4/packages.lock.json
@@ -0,0 +1,334 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[10.0.203, )",
+ "resolved": "10.0.203",
+ "contentHash": "R4Tvr1oACImMS+Y5M7NM07ll9QyJSKnki3Dvz8QwG1W6FEmd+9fmZXAF6BE6UPswHF6n0v41wgMQGlaudOspqA==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "10.0.203",
+ "Microsoft.SourceLink.Common": "10.0.203",
+ "System.IO.Hashing": "10.0.7"
+ }
+ },
+ "xunit.v3.extensibility.core": {
+ "type": "Direct",
+ "requested": "[4.0.0-pre.103, )",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "WVO4mpv2HErpqe5yqYXUXeVZz+Hx7E3JYrVdOMtVuirrXk3ls3i1zRoyGrhQY+thzY5K3beww/8h8B9Qis0S/Q==",
+ "dependencies": {
+ "xunit.v3.common": "[4.0.0-pre.103]"
+ }
+ },
+ "Microsoft.Bcl.AsyncInterfaces": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg=="
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "10.0.203",
+ "contentHash": "m56WtzvIcL6t7JR3c7ogYitHizNM2QnRSo8yqxrQi+m5E/GGyDEmqymP+2p6YsFXn0j/Tzz67s4FQnrTLC7GKQ==",
+ "dependencies": {
+ "System.IO.Hashing": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "wZbGh7J8R1vXN525O6d8dlcDTxhRTnd5MyW4LdfP5S0tSnTwTCseYSrq6g0Mxh7W9xn8P/2xPuf0D/m6k2dy2w==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "t56nEgvECcyLPojZIUFWJknQQDAbgfTf9J+QMYJE1YYvVgz69vN6B/AKL8Grvj3Lcnp8kTpNqwmwFhb3YLJmtQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Binder": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "8bS1qIaRivny+WX+49pmeJ6iAylbtX8C0DLEcCQWZjdxQvLqaMssXiGD9P/6pYElrHbK5/nAHmjbQ8STqdMYeg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "TWto3imA+mJMLZI+5sbgLiFFoOFNFkizQYNaC5jTuiHKn3diwm1RN7mWDOEZN9kG2bixw7IvgpvtUG5/teSRzA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "91F/o3emPV/+xY/ip3s2LqDNF14kjttlVtq0BXgg6p4MnCzeSZxnUJm+t6WRrtD3JdGo88/oX+z7OwK4y8PZuw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "00SHUGTh2jSMvIr6x9Xwd2nE+B5/qFCO/9hDwUDhJsjYRDlADmaBZ7tqehXzBDsfjHSXJzuRHJzPYPPjphBQ7Q==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Options.ConfigurationExtensions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "IT7f+EMXZtkjatEcF+o6aOw/7OE4etRrMiDGEWH/iiTu2R3uhC4NEQJCfHiibtX45U3sIQ5Fh6tbb1qaOz3YAg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Configuration.Binder": "10.0.7",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Options": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "D5M0Jr551iTgwkZMN9rm0pSkgNLj5quUWQUmQPMZh7k/bnvZTnXRGfE2KuvXf1EEjt/ofD9yw9IumpgdP9QCnw=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "10.0.203",
+ "contentHash": "QYAnhBCOkT3ZUT/fHag11+bamwlbZ3U9Vi/WfKrD9emdUf1t3aqjWv0V2KtEGHSRSC81aBc8Oy/mvyGpEYd9Pg=="
+ },
+ "System.IO.Hashing": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "6hsjdSr4VOXSOnhALkYplHpAxnTG1J33YN42IB6nH2fEg4QnJqrZ4Ft+qn7mkrKAOYC8pCSFYwVWw6rQbmwgLQ=="
+ },
+ "System.Reflection.MetadataLoadContext": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "XDkKntYPUaANhLVdo7AHbrJ+QbUAY5u/T7lG5rHSx5kLxeHceoc3JcIMVAc/vZT+3rbwFYlrdnikxdi6G+2nvA=="
+ },
+ "xunit.v3.common": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "9d6oYJqTNLG0/a2n2sR7i5ChJx9xV9DH287u1SqiFZ8imx+Cua7bMuObNANOlvEd5EpTXQjCOC+p9JoULdzF1w==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "6.0.0"
+ }
+ },
+ "feff.testfixtures": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.abstractions": {
+ "type": "Project",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.engine": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "[10.0.7, )",
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )",
+ "Microsoft.Extensions.Options": "[10.0.7, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )",
+ "System.Reflection.MetadataLoadContext": "[10.0.7, )"
+ }
+ }
+ },
+ "net8.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[10.0.203, )",
+ "resolved": "10.0.203",
+ "contentHash": "R4Tvr1oACImMS+Y5M7NM07ll9QyJSKnki3Dvz8QwG1W6FEmd+9fmZXAF6BE6UPswHF6n0v41wgMQGlaudOspqA==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "10.0.203",
+ "Microsoft.SourceLink.Common": "10.0.203",
+ "System.IO.Hashing": "10.0.7"
+ }
+ },
+ "xunit.v3.extensibility.core": {
+ "type": "Direct",
+ "requested": "[4.0.0-pre.103, )",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "WVO4mpv2HErpqe5yqYXUXeVZz+Hx7E3JYrVdOMtVuirrXk3ls3i1zRoyGrhQY+thzY5K3beww/8h8B9Qis0S/Q==",
+ "dependencies": {
+ "xunit.v3.common": "[4.0.0-pre.103]"
+ }
+ },
+ "Microsoft.Bcl.AsyncInterfaces": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg=="
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "10.0.203",
+ "contentHash": "m56WtzvIcL6t7JR3c7ogYitHizNM2QnRSo8yqxrQi+m5E/GGyDEmqymP+2p6YsFXn0j/Tzz67s4FQnrTLC7GKQ==",
+ "dependencies": {
+ "System.IO.Hashing": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "wZbGh7J8R1vXN525O6d8dlcDTxhRTnd5MyW4LdfP5S0tSnTwTCseYSrq6g0Mxh7W9xn8P/2xPuf0D/m6k2dy2w==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "t56nEgvECcyLPojZIUFWJknQQDAbgfTf9J+QMYJE1YYvVgz69vN6B/AKL8Grvj3Lcnp8kTpNqwmwFhb3YLJmtQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Binder": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "8bS1qIaRivny+WX+49pmeJ6iAylbtX8C0DLEcCQWZjdxQvLqaMssXiGD9P/6pYElrHbK5/nAHmjbQ8STqdMYeg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "TWto3imA+mJMLZI+5sbgLiFFoOFNFkizQYNaC5jTuiHKn3diwm1RN7mWDOEZN9kG2bixw7IvgpvtUG5/teSRzA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "91F/o3emPV/+xY/ip3s2LqDNF14kjttlVtq0BXgg6p4MnCzeSZxnUJm+t6WRrtD3JdGo88/oX+z7OwK4y8PZuw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "00SHUGTh2jSMvIr6x9Xwd2nE+B5/qFCO/9hDwUDhJsjYRDlADmaBZ7tqehXzBDsfjHSXJzuRHJzPYPPjphBQ7Q==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Options.ConfigurationExtensions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "IT7f+EMXZtkjatEcF+o6aOw/7OE4etRrMiDGEWH/iiTu2R3uhC4NEQJCfHiibtX45U3sIQ5Fh6tbb1qaOz3YAg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Configuration.Binder": "10.0.7",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Options": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "D5M0Jr551iTgwkZMN9rm0pSkgNLj5quUWQUmQPMZh7k/bnvZTnXRGfE2KuvXf1EEjt/ofD9yw9IumpgdP9QCnw=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "10.0.203",
+ "contentHash": "QYAnhBCOkT3ZUT/fHag11+bamwlbZ3U9Vi/WfKrD9emdUf1t3aqjWv0V2KtEGHSRSC81aBc8Oy/mvyGpEYd9Pg=="
+ },
+ "System.Collections.Immutable": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "0Ti4Jv1ga3eurH5HaCVsPybcBl+08YfzM9smqAJzHvqV494xK+0pSbytGrMTWhph+zsyKIaoGNiR5u3by5bj+A=="
+ },
+ "System.IO.Hashing": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "6hsjdSr4VOXSOnhALkYplHpAxnTG1J33YN42IB6nH2fEg4QnJqrZ4Ft+qn7mkrKAOYC8pCSFYwVWw6rQbmwgLQ=="
+ },
+ "System.Reflection.Metadata": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "FEBU/i3gHeleqayWrbWieI5MlepDBTcjAxMzjGbK7FwGtlpxGSU1Lt11W1/o4ExdqsNtboiVhT5s4kNtH3eqvw==",
+ "dependencies": {
+ "System.Collections.Immutable": "10.0.7"
+ }
+ },
+ "System.Reflection.MetadataLoadContext": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "XDkKntYPUaANhLVdo7AHbrJ+QbUAY5u/T7lG5rHSx5kLxeHceoc3JcIMVAc/vZT+3rbwFYlrdnikxdi6G+2nvA==",
+ "dependencies": {
+ "System.Collections.Immutable": "10.0.7",
+ "System.Reflection.Metadata": "10.0.7"
+ }
+ },
+ "xunit.v3.common": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "9d6oYJqTNLG0/a2n2sR7i5ChJx9xV9DH287u1SqiFZ8imx+Cua7bMuObNANOlvEd5EpTXQjCOC+p9JoULdzF1w==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "6.0.0"
+ }
+ },
+ "feff.testfixtures": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.abstractions": {
+ "type": "Project",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.engine": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "[10.0.7, )",
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )",
+ "Microsoft.Extensions.Options": "[10.0.7, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )",
+ "System.Reflection.MetadataLoadContext": "[10.0.7, )"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FEFF.TestFixtures/Fixtures/EnvironmentFixture.cs b/src/FEFF.TestFixtures/Fixtures/EnvironmentFixture.cs
index 243a9ed..c6f2476 100644
--- a/src/FEFF.TestFixtures/Fixtures/EnvironmentFixture.cs
+++ b/src/FEFF.TestFixtures/Fixtures/EnvironmentFixture.cs
@@ -18,10 +18,10 @@ public sealed class EnvironmentFixture : IDisposable
#if NET9_0_OR_GREATER
private static readonly Lock __lockObj = new();
#else
- private static readonly Object __lockObj = new();
+ private static readonly object __lockObj = new();
#endif
-
- // Disallow parallel environment variable saving or restoring process-wide
+
+ // Disallow parallel environment variable saving or restoring process-wide
private static volatile Env? __oldEnv;
///
@@ -41,20 +41,20 @@ public EnvironmentFixture()
lock (__lockObj)
{
if (__oldEnv != null)
- throw new InvalidOperationException($"'{nameof(EnvironmentFixture)}' mutates process environment and cannot be used in parallel. Ensure tests using this fixture run sequentially. For xUnit, consider using the [Collection] attribute on all test classes that will be part of a collection. Tests within the same collection run sequentially.");
-
+ throw new InvalidOperationException($"'{nameof(EnvironmentFixture)}' mutates process environment and cannot be used in parallel. Ensure tests using this fixture run sequentially. For xUnit, consider using the [Collection] attribute on all test classes that will be part of a collection. Tests within the same collection run sequentially.");
+
InitialSnapshot = EnvironmentHelper.GetEnvironmentVariables();
__oldEnv = InitialSnapshot;
}
- }
-
+ }
+
///
/// Same as .
/// This method is used not to forget to instantiate .
///
///
- /// Underling can be also be used instad of this.
+ /// Underlying can also be used instead of this.
///
/// The name of the environment variable.
/// The value to set for the environment variable.
diff --git a/tests/FEFF.TestFixtures.ApiVerification.Tests/ApiVerificationTests.cs b/tests/FEFF.TestFixtures.ApiVerification.Tests/ApiVerificationTests.cs
index 4727890..3455f54 100644
--- a/tests/FEFF.TestFixtures.ApiVerification.Tests/ApiVerificationTests.cs
+++ b/tests/FEFF.TestFixtures.ApiVerification.Tests/ApiVerificationTests.cs
@@ -20,6 +20,8 @@ public class ApiVerificationTests
[InlineData("FEFF.TestFixtures.AspNetCore.EF")]
[InlineData("FEFF.TestFixtures.AspNetCore.SignalR")]
[InlineData("FEFF.TestFixtures.XunitV3")]
+ // TODO: test without project reference
+ // [InlineData("FEFF.TestFixtures.XunitV4")]
[InlineData("FEFF.TestFixtures.TUnit")]
public Task API_should_not_change(string assemblyName)
{
diff --git a/tests/FEFF.TestFixtures.ApiVerification.Tests/FEFF.TestFixtures.ApiVerification.Tests.csproj b/tests/FEFF.TestFixtures.ApiVerification.Tests/FEFF.TestFixtures.ApiVerification.Tests.csproj
index 459e252..148d080 100644
--- a/tests/FEFF.TestFixtures.ApiVerification.Tests/FEFF.TestFixtures.ApiVerification.Tests.csproj
+++ b/tests/FEFF.TestFixtures.ApiVerification.Tests/FEFF.TestFixtures.ApiVerification.Tests.csproj
@@ -44,6 +44,7 @@
+
diff --git a/tests/FEFF.TestFixtures.ApiVerification.Tests/packages.lock.json b/tests/FEFF.TestFixtures.ApiVerification.Tests/packages.lock.json
index 497efca..a695074 100644
--- a/tests/FEFF.TestFixtures.ApiVerification.Tests/packages.lock.json
+++ b/tests/FEFF.TestFixtures.ApiVerification.Tests/packages.lock.json
@@ -627,8 +627,8 @@
},
"TUnit.Core": {
"type": "Transitive",
- "resolved": "1.40.5",
- "contentHash": "NcO9LzoVc0RAx5Qv3WWC+w9fxQ6ojC+i2ZQf9z+IH+mHP79jQmXls7O6d0auG8Wa5mUYzaTlM6LTjwcdWU6v/Q=="
+ "resolved": "1.40.10",
+ "contentHash": "e09Mumq7XAnm2olh4/YzgrijNbJN5V0qMahFiyxblSrbibBv6uJFrEdaOZSn9wtds3zsE8mmcpTzCCm6MXEeXQ=="
},
"Verify": {
"type": "Transitive",
@@ -700,7 +700,7 @@
"feff.testfixtures": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures.Abstractions": "[1.4.3, )",
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
"Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )"
}
},
@@ -713,7 +713,7 @@
"feff.testfixtures.aspnetcore": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures": "[1.4.3, )",
+ "FEFF.TestFixtures": "[0.0.1, )",
"Microsoft.AspNetCore.Mvc.Testing": "[10.0.7, )",
"Microsoft.Extensions.Diagnostics.Testing": "[10.5.0, )",
"Microsoft.Extensions.TimeProvider.Testing": "[10.5.0, )"
@@ -722,21 +722,21 @@
"feff.testfixtures.aspnetcore.ef": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures.AspNetCore": "[1.4.3, )",
+ "FEFF.TestFixtures.AspNetCore": "[0.0.1, )",
"Microsoft.EntityFrameworkCore": "[10.0.7, )"
}
},
"feff.testfixtures.aspnetcore.signalr": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures.AspNetCore": "[1.4.3, )",
+ "FEFF.TestFixtures.AspNetCore": "[0.0.1, )",
"Microsoft.AspNetCore.SignalR.Client": "[10.0.7, )"
}
},
"feff.testfixtures.engine": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures.Abstractions": "[1.4.3, )",
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "[10.0.7, )",
"Microsoft.Extensions.DependencyInjection": "[10.0.7, )",
"Microsoft.Extensions.Options": "[10.0.7, )",
@@ -747,18 +747,26 @@
"feff.testfixtures.tunit": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures": "[1.4.3, )",
- "FEFF.TestFixtures.Engine": "[1.4.3, )",
- "TUnit.Core": "[1.40.5, )"
+ "FEFF.TestFixtures": "[0.0.1, )",
+ "FEFF.TestFixtures.Engine": "[0.0.1, )",
+ "TUnit.Core": "[1.40.10, )"
}
},
"feff.testfixtures.xunitv3": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures": "[1.4.3, )",
- "FEFF.TestFixtures.Engine": "[1.4.3, )",
+ "FEFF.TestFixtures": "[0.0.1, )",
+ "FEFF.TestFixtures.Engine": "[0.0.1, )",
"xunit.v3.extensibility.core": "[3.2.2, )"
}
+ },
+ "feff.testfixtures.xunitv4": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures": "[0.0.1, )",
+ "FEFF.TestFixtures.Engine": "[0.0.1, )",
+ "TUnit.Core": "[1.40.10, )"
+ }
}
}
}
diff --git a/tests/FEFF.TestFixtures.TUnit.Tests/packages.lock.json b/tests/FEFF.TestFixtures.TUnit.Tests/packages.lock.json
index 77bcd31..523868b 100644
--- a/tests/FEFF.TestFixtures.TUnit.Tests/packages.lock.json
+++ b/tests/FEFF.TestFixtures.TUnit.Tests/packages.lock.json
@@ -32,14 +32,14 @@
"TUnit": {
"type": "Direct",
"requested": "[1.*, )",
- "resolved": "1.40.5",
- "contentHash": "5wEPNdEG3Ixwyo1p/dkyrXXygAAN05EANBYq1b9LwtR3dPCA1Hmx9KSyVNMplcBs73Iz0sags9rdIvCLq9BYHg==",
+ "resolved": "1.40.10",
+ "contentHash": "oM4E+wGh3J+PnKyEgs22wPnn6mxx/IhchfkE2wDRxI9Xqf7kt2HhwDlwpUnNytCd6aWgeSWRdD6kOkweWpn+LA==",
"dependencies": {
"Microsoft.Testing.Extensions.CodeCoverage": "18.6.2",
"Microsoft.Testing.Extensions.Telemetry": "2.2.1",
"Microsoft.Testing.Extensions.TrxReport": "2.2.1",
- "TUnit.Assertions": "1.40.5",
- "TUnit.Engine": "1.40.5"
+ "TUnit.Assertions": "1.40.10",
+ "TUnit.Engine": "1.40.10"
}
},
"EnumerableAsyncProcessor": {
@@ -187,30 +187,30 @@
},
"TUnit.Assertions": {
"type": "Transitive",
- "resolved": "1.40.5",
- "contentHash": "VPxokYwqZcUH9F4v6LoL3V3blQ1q6xG5lAJ2BAmqzqb/gZ9CeUp/QbJImdlH9nAuMEEffFKQ0xDYwYkkJhG3tw=="
+ "resolved": "1.40.10",
+ "contentHash": "DCqMyNB0WcvUO675JQEQEKCi4fK/1oXuq2DrWqIf3ErZGXbDtuG+22jXCOaoxIv5WyD9L65LAY5Q9/4ufN9mdA=="
},
"TUnit.Core": {
"type": "Transitive",
- "resolved": "1.40.5",
- "contentHash": "NcO9LzoVc0RAx5Qv3WWC+w9fxQ6ojC+i2ZQf9z+IH+mHP79jQmXls7O6d0auG8Wa5mUYzaTlM6LTjwcdWU6v/Q=="
+ "resolved": "1.40.10",
+ "contentHash": "e09Mumq7XAnm2olh4/YzgrijNbJN5V0qMahFiyxblSrbibBv6uJFrEdaOZSn9wtds3zsE8mmcpTzCCm6MXEeXQ=="
},
"TUnit.Engine": {
"type": "Transitive",
- "resolved": "1.40.5",
- "contentHash": "MkkFwplhGd+CyuqRTT2p4LOJeiiRyVE5QdQHLuOTtqQVELN8CZuNYRklCh3xuzT58fRHxD66x2flZwG8OETR2w==",
+ "resolved": "1.40.10",
+ "contentHash": "WeIdqoON5bZfW1oGdT+KdePkfo7VHAhOUpakOY52rRuajvnNlCuKMWmzCxElKnlOtMSE2MSpVumT0nxbkS4sEw==",
"dependencies": {
"EnumerableAsyncProcessor": "3.8.4",
"Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.2.1",
"Microsoft.Testing.Platform": "2.2.1",
"Microsoft.Testing.Platform.MSBuild": "2.2.1",
- "TUnit.Core": "1.40.5"
+ "TUnit.Core": "1.40.10"
}
},
"feff.testfixtures": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures.Abstractions": "[1.4.3, )",
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
"Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )"
}
},
@@ -223,7 +223,7 @@
"feff.testfixtures.engine": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures.Abstractions": "[1.4.3, )",
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "[10.0.7, )",
"Microsoft.Extensions.DependencyInjection": "[10.0.7, )",
"Microsoft.Extensions.Options": "[10.0.7, )",
@@ -234,16 +234,16 @@
"feff.testfixtures.tunit": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures": "[1.4.3, )",
- "FEFF.TestFixtures.Engine": "[1.4.3, )",
- "TUnit.Core": "[1.40.5, )"
+ "FEFF.TestFixtures": "[0.0.1, )",
+ "FEFF.TestFixtures.Engine": "[0.0.1, )",
+ "TUnit.Core": "[1.40.10, )"
}
},
"tunit.testsubject": {
"type": "Project",
"dependencies": {
"AwesomeAssertions": "[9.4.0, )",
- "FEFF.TestFixtures.TUnit": "[1.4.3, )",
+ "FEFF.TestFixtures.TUnit": "[0.0.1, )",
"Microsoft.Testing.Extensions.CodeCoverage": "[18.6.2, )",
"TUnit": "[1.*, )"
}
diff --git a/tests/FEFF.TestFixtures.XunitV4.Tests/FEFF.TestFixtures.XunitV4.Tests.csproj b/tests/FEFF.TestFixtures.XunitV4.Tests/FEFF.TestFixtures.XunitV4.Tests.csproj
new file mode 100644
index 0000000..915cd10
--- /dev/null
+++ b/tests/FEFF.TestFixtures.XunitV4.Tests/FEFF.TestFixtures.XunitV4.Tests.csproj
@@ -0,0 +1,21 @@
+
+
+
+ enable
+ enable
+ Exe
+ net10.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/FEFF.TestFixtures.XunitV4.Tests/XunitV4IntegrationTests.cs b/tests/FEFF.TestFixtures.XunitV4.Tests/XunitV4IntegrationTests.cs
new file mode 100644
index 0000000..a8d4c39
--- /dev/null
+++ b/tests/FEFF.TestFixtures.XunitV4.Tests/XunitV4IntegrationTests.cs
@@ -0,0 +1,84 @@
+ο»Ώusing System.Diagnostics;
+using System.Text;
+using AwesomeAssertions;
+using AwesomeAssertions.Json;
+using Xunit;
+
+namespace FEFF.TestFixtures.Xunit.V4.Tests;
+
+public class XunitV4IntegrationTests
+{
+ // Fixture creating is tested inside TestSubject
+ [Fact]
+ public async Task Fixtures__should_be_disposed()
+ {
+ // Arrange
+ var resultFile = TestSubjects.Infrastructure.ResultName;
+ var testSubject = TestSubjects.Infrastructure.AssemblyName;
+
+ TryDelete(resultFile);
+ File.Exists(resultFile).Should().BeFalse();
+
+ // Act
+ var pi = new ProcessStartInfo("dotnet")
+ {
+ Arguments = testSubject
+ };
+ var p = Process.Start(pi);
+ p.Should().NotBeNull();
+
+ using (p)
+ {
+ await p.WaitForExitAsync(TestContext.Current.CancellationToken);
+ p.HasExited.Should().BeTrue();
+ p.ExitCode.Should().Be(0);
+ }
+
+ // Assert
+ File.Exists(resultFile).Should().BeTrue();
+ var res = File.ReadAllLines(resultFile, Encoding.UTF8);
+
+ // Assert that all fixures are disposed (and created)
+ // order may varry because tests run in parallel
+ res.Should().BeEquivalentTo(
+ [
+ "TestFix:{'test':'TestMethod_1','collection':'','class':'TestSubject'}",
+ "TestFix:{'test':'TestMethod_1','collection':'collecion-a','class':'SecondTestSubject'}",
+ "TestFix:{'test':'TestMethod_2','collection':'','class':'TestSubject'}",
+ "TestFix:{'test':'TestMethod_2','collection':'collecion-a','class':'SecondTestSubject'}",
+ "ClassFix:{'collection':'','class':'TestSubject'}",
+ "ClassFix:{'collection':'collecion-a','class':'SecondTestSubject'}",
+ "CollectionFix:{'collection':''}", // default collection for 'TestSubject'
+ "TestFix:{'test':'TestMethod_2','collection':'collecion-a','class':'ThirdTestSubject'}",
+ "TestFix:{'test':'TestMethod_1','collection':'collecion-a','class':'ThirdTestSubject'}",
+ "ClassFix:{'collection':'collecion-a','class':'ThirdTestSubject'}",
+ "CollectionFix:{'collection':'collecion-a'}",
+ "AssemblyFix:{}",
+ "SingletonTester:{}",
+ ]);
+
+ // Assert that fixture disposal order depends on FixtureScope
+ // strict order checking
+ res.Should().ContainInOrder(
+ [
+ "TestFix:{'test':'TestMethod_1','collection':'collecion-a','class':'ThirdTestSubject'}",
+ "ClassFix:{'collection':'collecion-a','class':'ThirdTestSubject'}",
+ "CollectionFix:{'collection':'collecion-a'}",
+ "AssemblyFix:{}",
+ "SingletonTester:{}",
+ ]);
+
+
+ }
+
+ private static void TryDelete(string f)
+ {
+ try
+ {
+ new FileInfo(f).Delete();
+ }
+ catch (FileNotFoundException)
+ {
+ }
+ }
+}
diff --git a/tests/FEFF.TestFixtures.XunitV4.Tests/packages.lock.json b/tests/FEFF.TestFixtures.XunitV4.Tests/packages.lock.json
new file mode 100644
index 0000000..6045b0a
--- /dev/null
+++ b/tests/FEFF.TestFixtures.XunitV4.Tests/packages.lock.json
@@ -0,0 +1,288 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net10.0": {
+ "AwesomeAssertions": {
+ "type": "Direct",
+ "requested": "[9.4.0, )",
+ "resolved": "9.4.0",
+ "contentHash": "dJxkWiQ8D+xT6Gr2sSL83+Mar+Vpy2JTcUPxFcckpPJ8VYBfSgnk+zqpS6t7kcGnjz8NLyF14qfuoL4bKzzoew=="
+ },
+ "AwesomeAssertions.Json": {
+ "type": "Direct",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "h8xOiCwdKP45ezx9l2zwHNZm0YC0jambOQUKBz9aM9KPkuVingkM0DIOMTegS8o4RIJyvUfCTkvsVrK7dUqb+g==",
+ "dependencies": {
+ "AwesomeAssertions": "9.0.0",
+ "Newtonsoft.Json": "13.0.1"
+ }
+ },
+ "Microsoft.Testing.Extensions.CodeCoverage": {
+ "type": "Direct",
+ "requested": "[18.6.2, )",
+ "resolved": "18.6.2",
+ "contentHash": "vRDhB96XQyVdYFp4cQZOMz/lx0okfCdzTXPxGiuFhKx2yUL0FT/skTpnTv+7x13+tjNOcT39i2Ln3BYtslzf2w==",
+ "dependencies": {
+ "Microsoft.DiaSymReader": "2.2.5",
+ "Microsoft.Extensions.DependencyModel": "8.0.2",
+ "Microsoft.Testing.Platform": "2.1.0"
+ }
+ },
+ "xunit.v3.mtp-v2": {
+ "type": "Direct",
+ "requested": "[4.0.0-pre.103, )",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "mi6ZiojT2iUbiMUSDRdjovSOdrqqaeobH1ZttIPgEkf9bw0o22z8ioVxAe7MVlVyaS0NkgPeaBw79aWQ8hoVkQ==",
+ "dependencies": {
+ "xunit.analyzers": "2.0.0-pre.40",
+ "xunit.v3.assert": "[4.0.0-pre.103]",
+ "xunit.v3.core.mtp-v2": "[4.0.0-pre.103]"
+ }
+ },
+ "Microsoft.ApplicationInsights": {
+ "type": "Transitive",
+ "resolved": "2.23.0",
+ "contentHash": "nWArUZTdU7iqZLycLKWe0TDms48KKGE6pONH2terYNa8REXiqixrMOkf1sk5DHGMaUTqONU2YkS4SAXBhLStgw=="
+ },
+ "Microsoft.Bcl.AsyncInterfaces": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg=="
+ },
+ "Microsoft.DiaSymReader": {
+ "type": "Transitive",
+ "resolved": "2.2.5",
+ "contentHash": "Cq0DLpL8oQmXX3EUCClAYWDBy7Nf3Km6kmUw/eYWlYcTeC3g3Nekd/Z/ldsiy+Oi3xboanlQV9oaVCkgdLEhOQ=="
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "wZbGh7J8R1vXN525O6d8dlcDTxhRTnd5MyW4LdfP5S0tSnTwTCseYSrq6g0Mxh7W9xn8P/2xPuf0D/m6k2dy2w==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "t56nEgvECcyLPojZIUFWJknQQDAbgfTf9J+QMYJE1YYvVgz69vN6B/AKL8Grvj3Lcnp8kTpNqwmwFhb3YLJmtQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Binder": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "8bS1qIaRivny+WX+49pmeJ6iAylbtX8C0DLEcCQWZjdxQvLqaMssXiGD9P/6pYElrHbK5/nAHmjbQ8STqdMYeg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "TWto3imA+mJMLZI+5sbgLiFFoOFNFkizQYNaC5jTuiHKn3diwm1RN7mWDOEZN9kG2bixw7IvgpvtUG5/teSRzA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "91F/o3emPV/+xY/ip3s2LqDNF14kjttlVtq0BXgg6p4MnCzeSZxnUJm+t6WRrtD3JdGo88/oX+z7OwK4y8PZuw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw=="
+ },
+ "Microsoft.Extensions.DependencyModel": {
+ "type": "Transitive",
+ "resolved": "8.0.2",
+ "contentHash": "mUBDZZRgZrSyFOsJ2qJJ9fXfqd/kXJwf3AiDoqLD9m6TjY5OO/vLNOb9fb4juC0487eq4hcGN/M2Rh/CKS7QYw=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "00SHUGTh2jSMvIr6x9Xwd2nE+B5/qFCO/9hDwUDhJsjYRDlADmaBZ7tqehXzBDsfjHSXJzuRHJzPYPPjphBQ7Q==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Options.ConfigurationExtensions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "IT7f+EMXZtkjatEcF+o6aOw/7OE4etRrMiDGEWH/iiTu2R3uhC4NEQJCfHiibtX45U3sIQ5Fh6tbb1qaOz3YAg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Configuration.Binder": "10.0.7",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Options": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "D5M0Jr551iTgwkZMN9rm0pSkgNLj5quUWQUmQPMZh7k/bnvZTnXRGfE2KuvXf1EEjt/ofD9yw9IumpgdP9QCnw=="
+ },
+ "Microsoft.Testing.Extensions.Telemetry": {
+ "type": "Transitive",
+ "resolved": "2.2.1",
+ "contentHash": "7zB8BjffOyvqfHF26rFVPuK0w1fCf5+j1tLuhHIr76CqxXkGb+fMJtq6YNOV+m6qPytExHMXxluk3RgJ+dSIqw==",
+ "dependencies": {
+ "Microsoft.ApplicationInsights": "2.23.0",
+ "Microsoft.Testing.Platform": "2.2.1"
+ }
+ },
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.1",
+ "contentHash": "RD6D1Jx6cKDA5IHd1H2q8ylIuQG3PD+gdULI0JC8CvsRtaypFzTFpB5xDPuQi8o6kAkcM04cBhAiJPxZboNH2Q==",
+ "dependencies": {
+ "Microsoft.Testing.Platform": "2.2.1"
+ }
+ },
+ "Microsoft.Testing.Platform": {
+ "type": "Transitive",
+ "resolved": "2.2.1",
+ "contentHash": "9bbPuls/b6/vUFzxbSjJLZlJHyKBfOZE5kjIY+ITI2ASqlFPJhR83BdLydJeQOCLEZhEbrEcz5xtt1B69nwSVg=="
+ },
+ "Microsoft.Testing.Platform.MSBuild": {
+ "type": "Transitive",
+ "resolved": "2.2.1",
+ "contentHash": "CSJOcZHfKlTyPbS0CTJk6iEnU4gJC+eUA5z72UBnMDRdgVHYOmB8k9Y7jT233gZjnCOQiYFg3acQHRfu2H62nw==",
+ "dependencies": {
+ "Microsoft.Testing.Platform": "2.2.1"
+ }
+ },
+ "Microsoft.Win32.Registry": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg=="
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.1",
+ "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
+ },
+ "System.Reflection.MetadataLoadContext": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "XDkKntYPUaANhLVdo7AHbrJ+QbUAY5u/T7lG5rHSx5kLxeHceoc3JcIMVAc/vZT+3rbwFYlrdnikxdi6G+2nvA=="
+ },
+ "System.Security.AccessControl": {
+ "type": "Transitive",
+ "resolved": "6.0.1",
+ "contentHash": "IQ4NXP/B3Ayzvw0rDQzVTYsCKyy0Jp9KI6aYcK7UnGVlR9+Awz++TIPCQtPYfLJfOpm8ajowMR09V7quD3sEHw=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "2.0.0-pre.40",
+ "contentHash": "TCfW5P8EnzDta+ETuKil1R6pCv2mW/kYqdUTjRagdhEnFKeBHqLwHF+xLmsl5TeBAlx/VdGJR7/26YUZMf72aA=="
+ },
+ "xunit.v3.assert": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "vhke3b55zpgL9BwqlK3TmXMAPyVqD1MwHYu2jO35Jvb96Wrts0zL9pXWbrJrS1rny0pgoIeagAsguUGXjJpAag=="
+ },
+ "xunit.v3.common": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "9d6oYJqTNLG0/a2n2sR7i5ChJx9xV9DH287u1SqiFZ8imx+Cua7bMuObNANOlvEd5EpTXQjCOC+p9JoULdzF1w==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "6.0.0"
+ }
+ },
+ "xunit.v3.core.mtp-v2": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "vm5t24zX+N+cKGLA2pJVxHclVxhtXLXyhBWrZqjK8N8oo1WFDkPAcF2Toxc/VfF0r4DV4U8trZpl8WPNd8viZA==",
+ "dependencies": {
+ "Microsoft.Testing.Extensions.Telemetry": "2.2.1",
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.2.1",
+ "Microsoft.Testing.Platform": "2.2.1",
+ "Microsoft.Testing.Platform.MSBuild": "2.2.1",
+ "xunit.v3.extensibility.core": "[4.0.0-pre.103]",
+ "xunit.v3.runner.inproc.console": "[4.0.0-pre.103]"
+ }
+ },
+ "xunit.v3.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "WVO4mpv2HErpqe5yqYXUXeVZz+Hx7E3JYrVdOMtVuirrXk3ls3i1zRoyGrhQY+thzY5K3beww/8h8B9Qis0S/Q==",
+ "dependencies": {
+ "xunit.v3.common": "[4.0.0-pre.103]"
+ }
+ },
+ "xunit.v3.runner.common": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "eHOnqLu5g16Kbgi3m7cXzGbwEAtVbDCF0pla4u6xtQOuLXs129IazvDjnxoLZnKPt7uMZkfhIQIMojlI/kjrKA==",
+ "dependencies": {
+ "Microsoft.Win32.Registry": "[5.0.0]",
+ "System.Security.AccessControl": "[6.0.1]",
+ "xunit.v3.common": "[4.0.0-pre.103]"
+ }
+ },
+ "xunit.v3.runner.inproc.console": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "2M3cPwh5VXrnRDkhAbxCIhrDpZN44wxAuFg0Vl3gupORdUeZ4ya62sN7pzM99IRwABZ3lKp17UlFu11e04wfFw==",
+ "dependencies": {
+ "xunit.v3.extensibility.core": "[4.0.0-pre.103]",
+ "xunit.v3.runner.common": "[4.0.0-pre.103]"
+ }
+ },
+ "feff.testfixtures": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.abstractions": {
+ "type": "Project",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.engine": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "[10.0.7, )",
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )",
+ "Microsoft.Extensions.Options": "[10.0.7, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )",
+ "System.Reflection.MetadataLoadContext": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.xunitv4": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures": "[0.0.1, )",
+ "FEFF.TestFixtures.Engine": "[0.0.1, )",
+ "xunit.v3.extensibility.core": "[4.0.0-pre.103, )"
+ }
+ },
+ "xunitv4.testsubject": {
+ "type": "Project",
+ "dependencies": {
+ "AwesomeAssertions": "[9.4.0, )",
+ "FEFF.TestFixtures.XunitV4": "[0.0.1, )",
+ "Microsoft.Testing.Extensions.CodeCoverage": "[18.6.2, )",
+ "xunit.v3.mtp-v2": "[4.0.0-pre.103, )"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Files/API/FEFF.TestFixtures.Abstractions.verified.txt b/tests/Files/API/FEFF.TestFixtures.Abstractions.verified.txt
index 8c9cf72..e4df0f2 100644
--- a/tests/Files/API/FEFF.TestFixtures.Abstractions.verified.txt
+++ b/tests/Files/API/FEFF.TestFixtures.Abstractions.verified.txt
@@ -4,6 +4,7 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("FEFF.TestFixtures.Engine")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("FEFF.TestFixtures.TUnit")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("FEFF.TestFixtures.XunitV3")]
+[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("FEFF.TestFixtures.XunitV4")]
[assembly: System.Runtime.Versioning.TargetFramework(".NETCoreApp,Version=v10.0", FrameworkDisplayName=".NET 10.0")]
namespace FEFF.TestFixtures
{
diff --git a/tests/Subjects/TUnit.TestSubject/packages.lock.json b/tests/Subjects/TUnit.TestSubject/packages.lock.json
index 095f48d..1930499 100644
--- a/tests/Subjects/TUnit.TestSubject/packages.lock.json
+++ b/tests/Subjects/TUnit.TestSubject/packages.lock.json
@@ -22,14 +22,14 @@
"TUnit": {
"type": "Direct",
"requested": "[1.*, )",
- "resolved": "1.40.5",
- "contentHash": "5wEPNdEG3Ixwyo1p/dkyrXXygAAN05EANBYq1b9LwtR3dPCA1Hmx9KSyVNMplcBs73Iz0sags9rdIvCLq9BYHg==",
+ "resolved": "1.40.10",
+ "contentHash": "oM4E+wGh3J+PnKyEgs22wPnn6mxx/IhchfkE2wDRxI9Xqf7kt2HhwDlwpUnNytCd6aWgeSWRdD6kOkweWpn+LA==",
"dependencies": {
"Microsoft.Testing.Extensions.CodeCoverage": "18.6.2",
"Microsoft.Testing.Extensions.Telemetry": "2.2.1",
"Microsoft.Testing.Extensions.TrxReport": "2.2.1",
- "TUnit.Assertions": "1.40.5",
- "TUnit.Engine": "1.40.5"
+ "TUnit.Assertions": "1.40.10",
+ "TUnit.Engine": "1.40.10"
}
},
"EnumerableAsyncProcessor": {
@@ -172,30 +172,30 @@
},
"TUnit.Assertions": {
"type": "Transitive",
- "resolved": "1.40.5",
- "contentHash": "VPxokYwqZcUH9F4v6LoL3V3blQ1q6xG5lAJ2BAmqzqb/gZ9CeUp/QbJImdlH9nAuMEEffFKQ0xDYwYkkJhG3tw=="
+ "resolved": "1.40.10",
+ "contentHash": "DCqMyNB0WcvUO675JQEQEKCi4fK/1oXuq2DrWqIf3ErZGXbDtuG+22jXCOaoxIv5WyD9L65LAY5Q9/4ufN9mdA=="
},
"TUnit.Core": {
"type": "Transitive",
- "resolved": "1.40.5",
- "contentHash": "NcO9LzoVc0RAx5Qv3WWC+w9fxQ6ojC+i2ZQf9z+IH+mHP79jQmXls7O6d0auG8Wa5mUYzaTlM6LTjwcdWU6v/Q=="
+ "resolved": "1.40.10",
+ "contentHash": "e09Mumq7XAnm2olh4/YzgrijNbJN5V0qMahFiyxblSrbibBv6uJFrEdaOZSn9wtds3zsE8mmcpTzCCm6MXEeXQ=="
},
"TUnit.Engine": {
"type": "Transitive",
- "resolved": "1.40.5",
- "contentHash": "MkkFwplhGd+CyuqRTT2p4LOJeiiRyVE5QdQHLuOTtqQVELN8CZuNYRklCh3xuzT58fRHxD66x2flZwG8OETR2w==",
+ "resolved": "1.40.10",
+ "contentHash": "WeIdqoON5bZfW1oGdT+KdePkfo7VHAhOUpakOY52rRuajvnNlCuKMWmzCxElKnlOtMSE2MSpVumT0nxbkS4sEw==",
"dependencies": {
"EnumerableAsyncProcessor": "3.8.4",
"Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.2.1",
"Microsoft.Testing.Platform": "2.2.1",
"Microsoft.Testing.Platform.MSBuild": "2.2.1",
- "TUnit.Core": "1.40.5"
+ "TUnit.Core": "1.40.10"
}
},
"feff.testfixtures": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures.Abstractions": "[1.4.3, )",
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
"Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )"
}
},
@@ -208,7 +208,7 @@
"feff.testfixtures.engine": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures.Abstractions": "[1.4.3, )",
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "[10.0.7, )",
"Microsoft.Extensions.DependencyInjection": "[10.0.7, )",
"Microsoft.Extensions.Options": "[10.0.7, )",
@@ -219,9 +219,9 @@
"feff.testfixtures.tunit": {
"type": "Project",
"dependencies": {
- "FEFF.TestFixtures": "[1.4.3, )",
- "FEFF.TestFixtures.Engine": "[1.4.3, )",
- "TUnit.Core": "[1.40.5, )"
+ "FEFF.TestFixtures": "[0.0.1, )",
+ "FEFF.TestFixtures.Engine": "[0.0.1, )",
+ "TUnit.Core": "[1.40.10, )"
}
}
}
diff --git a/tests/Subjects/XunitV4.TestSubject/Infrastructure.cs b/tests/Subjects/XunitV4.TestSubject/Infrastructure.cs
new file mode 100644
index 0000000..8135abe
--- /dev/null
+++ b/tests/Subjects/XunitV4.TestSubject/Infrastructure.cs
@@ -0,0 +1,26 @@
+using System.Text;
+
+namespace FEFF.TestFixtures.Xunit.V4.TestSubjects;
+
+public static class Infrastructure
+{
+ public static string ResultName { get; } = GetFileName();
+ public static string AssemblyName => System.Reflection.Assembly.GetExecutingAssembly().Location;
+
+ private static readonly Lock _lock = new();
+
+ private static string GetFileName()
+ {
+ var fi = new FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
+ var d = fi.Directory!.FullName;
+ return Path.Combine(d, "test-subject-result.txt");
+ }
+
+ public static void Add(string s)
+ {
+ lock(_lock)
+ {
+ File.AppendAllLines(ResultName, [s], Encoding.UTF8);
+ }
+ }
+}
diff --git a/tests/Subjects/XunitV4.TestSubject/TestSubject.cs b/tests/Subjects/XunitV4.TestSubject/TestSubject.cs
new file mode 100644
index 0000000..5504546
--- /dev/null
+++ b/tests/Subjects/XunitV4.TestSubject/TestSubject.cs
@@ -0,0 +1,138 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using AwesomeAssertions;
+using FEFF.TestFixtures.Xunit.V4;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+using Xunit.v3;
+
+// register the extension
+[assembly: TestFixturesExtension]
+
+namespace FEFF.TestFixtures.Xunit.V4.TestSubjects;
+
+internal class BaseFix : IDisposable
+{
+ private readonly string? _testName;
+ private readonly JsonSerializerOptions _options = new()
+ {
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
+ WriteIndented = false,
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ };
+
+ public BaseFix()
+ {
+ // for simplier test
+ if(GetType() == typeof(AssemblyFix) || GetType() == typeof(SingletonTester))
+ {
+ _testName = "{}";
+ return;
+ }
+
+ var tst = TestContext.Current.TestMethod?.MethodName;
+ var cls = TestContext.Current.TestClass?.TestClassName;
+ var col = TestContext.Current.TestCollection?.TestCollectionDisplayName;
+
+ // for simplier test
+ if(cls != null)
+ cls = cls.Replace("FEFF.TestFixtures.Xunit.V4.TestSubjects.", "");
+
+ // remove default collection name for simplier test
+ if (col != null && col.StartsWith("Test collection for "))
+ col = "";
+
+ // first tst/cls may vary beacuse of parallel execution
+ if(GetType() == typeof(ClassFix))
+ tst = null;
+ if(GetType() == typeof(CollectionFix))
+ {
+ tst = null;
+ cls = null;
+ }
+
+ _testName = JsonSerializer.Serialize(
+ options: _options,
+ value: new
+ {
+ Test = tst,
+ Collection = col,
+ Class = cls,
+ })
+ .Replace("\"", "'") // for test convenience
+ ;
+
+ }
+
+ public void Dispose()
+ {
+ var name = this.GetType().Name;
+ Infrastructure.Add($"{name}:{_testName}");
+ }
+}
+
+[Fixture]
+class TestFix : BaseFix { }
+[Fixture]
+class ClassFix : BaseFix { }
+[Fixture]
+class CollectionFix : BaseFix { }
+[Fixture]
+class AssemblyFix : BaseFix { }
+
+class SingletonTester : BaseFix, IFixtureRegistrar
+{
+ public static bool IsDisposed { get; set; }
+
+ public static void RegisterFixture(IServiceCollection services)
+ {
+ services.AddSingleton();
+ }
+}
+
+public class TestSubject
+{
+ protected static T GetFixture(FixtureScopeType scopeType = FixtureScopeType.TestCase)
+ where T : notnull
+ {
+ return TestContext.Current.GetFeffFixture(scopeType);
+ }
+
+ [Fact]
+ //public void Fixtures__should_be_registered_and_materialized()
+ public void TestMethod_1()
+ {
+ var f1 = GetFixture();
+ var f2 = GetFixture(FixtureScopeType.Class);
+ var f3 = GetFixture(FixtureScopeType.Collection);
+ var f4 = GetFixture(FixtureScopeType.Assembly);
+ var s0 = GetFixture();
+
+ f1.Should().BeOfType();
+ f2.Should().BeOfType();
+ f3.Should().BeOfType();
+ f4.Should().BeOfType();
+ s0.Should().BeOfType();
+ }
+
+ [Fact]
+ // public void Second_test_method()
+ public void TestMethod_2()
+
+ {
+ var f1 = GetFixture();
+ var f2 = GetFixture(FixtureScopeType.Class);
+ var f3 = GetFixture(FixtureScopeType.Collection);
+ var f4 = GetFixture(FixtureScopeType.Assembly);
+
+ f1.Should().BeOfType();
+ f2.Should().BeOfType();
+ f3.Should().BeOfType();
+ f4.Should().BeOfType();
+ }
+}
+
+[Collection("collecion-a")]
+public class SecondTestSubject : TestSubject { }
+[Collection("collecion-a")]
+public class ThirdTestSubject : TestSubject { }
diff --git a/tests/Subjects/XunitV4.TestSubject/XunitV4.TestSubject.csproj b/tests/Subjects/XunitV4.TestSubject/XunitV4.TestSubject.csproj
new file mode 100644
index 0000000..a7879b6
--- /dev/null
+++ b/tests/Subjects/XunitV4.TestSubject/XunitV4.TestSubject.csproj
@@ -0,0 +1,20 @@
+
+
+
+ enable
+ enable
+ Exe
+ net10.0
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Subjects/XunitV4.TestSubject/packages.lock.json b/tests/Subjects/XunitV4.TestSubject/packages.lock.json
new file mode 100644
index 0000000..f464066
--- /dev/null
+++ b/tests/Subjects/XunitV4.TestSubject/packages.lock.json
@@ -0,0 +1,264 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net10.0": {
+ "AwesomeAssertions": {
+ "type": "Direct",
+ "requested": "[9.4.0, )",
+ "resolved": "9.4.0",
+ "contentHash": "dJxkWiQ8D+xT6Gr2sSL83+Mar+Vpy2JTcUPxFcckpPJ8VYBfSgnk+zqpS6t7kcGnjz8NLyF14qfuoL4bKzzoew=="
+ },
+ "Microsoft.Testing.Extensions.CodeCoverage": {
+ "type": "Direct",
+ "requested": "[18.6.2, )",
+ "resolved": "18.6.2",
+ "contentHash": "vRDhB96XQyVdYFp4cQZOMz/lx0okfCdzTXPxGiuFhKx2yUL0FT/skTpnTv+7x13+tjNOcT39i2Ln3BYtslzf2w==",
+ "dependencies": {
+ "Microsoft.DiaSymReader": "2.2.5",
+ "Microsoft.Extensions.DependencyModel": "8.0.2",
+ "Microsoft.Testing.Platform": "2.1.0"
+ }
+ },
+ "xunit.v3.mtp-v2": {
+ "type": "Direct",
+ "requested": "[4.0.0-pre.103, )",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "mi6ZiojT2iUbiMUSDRdjovSOdrqqaeobH1ZttIPgEkf9bw0o22z8ioVxAe7MVlVyaS0NkgPeaBw79aWQ8hoVkQ==",
+ "dependencies": {
+ "xunit.analyzers": "2.0.0-pre.40",
+ "xunit.v3.assert": "[4.0.0-pre.103]",
+ "xunit.v3.core.mtp-v2": "[4.0.0-pre.103]"
+ }
+ },
+ "Microsoft.ApplicationInsights": {
+ "type": "Transitive",
+ "resolved": "2.23.0",
+ "contentHash": "nWArUZTdU7iqZLycLKWe0TDms48KKGE6pONH2terYNa8REXiqixrMOkf1sk5DHGMaUTqONU2YkS4SAXBhLStgw=="
+ },
+ "Microsoft.Bcl.AsyncInterfaces": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg=="
+ },
+ "Microsoft.DiaSymReader": {
+ "type": "Transitive",
+ "resolved": "2.2.5",
+ "contentHash": "Cq0DLpL8oQmXX3EUCClAYWDBy7Nf3Km6kmUw/eYWlYcTeC3g3Nekd/Z/ldsiy+Oi3xboanlQV9oaVCkgdLEhOQ=="
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "wZbGh7J8R1vXN525O6d8dlcDTxhRTnd5MyW4LdfP5S0tSnTwTCseYSrq6g0Mxh7W9xn8P/2xPuf0D/m6k2dy2w==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "t56nEgvECcyLPojZIUFWJknQQDAbgfTf9J+QMYJE1YYvVgz69vN6B/AKL8Grvj3Lcnp8kTpNqwmwFhb3YLJmtQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Binder": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "8bS1qIaRivny+WX+49pmeJ6iAylbtX8C0DLEcCQWZjdxQvLqaMssXiGD9P/6pYElrHbK5/nAHmjbQ8STqdMYeg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "TWto3imA+mJMLZI+5sbgLiFFoOFNFkizQYNaC5jTuiHKn3diwm1RN7mWDOEZN9kG2bixw7IvgpvtUG5/teSRzA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.7",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "91F/o3emPV/+xY/ip3s2LqDNF14kjttlVtq0BXgg6p4MnCzeSZxnUJm+t6WRrtD3JdGo88/oX+z7OwK4y8PZuw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "Z6mfFEaFcwCfSboxJwOLfu7/31npCY9q70WUamHW/vRQhDvBKOT4Vf9YkZj5J6hLvJpb0oDEYfHunQZj0xxvKw=="
+ },
+ "Microsoft.Extensions.DependencyModel": {
+ "type": "Transitive",
+ "resolved": "8.0.2",
+ "contentHash": "mUBDZZRgZrSyFOsJ2qJJ9fXfqd/kXJwf3AiDoqLD9m6TjY5OO/vLNOb9fb4juC0487eq4hcGN/M2Rh/CKS7QYw=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "00SHUGTh2jSMvIr6x9Xwd2nE+B5/qFCO/9hDwUDhJsjYRDlADmaBZ7tqehXzBDsfjHSXJzuRHJzPYPPjphBQ7Q==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Options.ConfigurationExtensions": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "IT7f+EMXZtkjatEcF+o6aOw/7OE4etRrMiDGEWH/iiTu2R3uhC4NEQJCfHiibtX45U3sIQ5Fh6tbb1qaOz3YAg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Configuration.Binder": "10.0.7",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.7",
+ "Microsoft.Extensions.Options": "10.0.7",
+ "Microsoft.Extensions.Primitives": "10.0.7"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "D5M0Jr551iTgwkZMN9rm0pSkgNLj5quUWQUmQPMZh7k/bnvZTnXRGfE2KuvXf1EEjt/ofD9yw9IumpgdP9QCnw=="
+ },
+ "Microsoft.Testing.Extensions.Telemetry": {
+ "type": "Transitive",
+ "resolved": "2.2.1",
+ "contentHash": "7zB8BjffOyvqfHF26rFVPuK0w1fCf5+j1tLuhHIr76CqxXkGb+fMJtq6YNOV+m6qPytExHMXxluk3RgJ+dSIqw==",
+ "dependencies": {
+ "Microsoft.ApplicationInsights": "2.23.0",
+ "Microsoft.Testing.Platform": "2.2.1"
+ }
+ },
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.1",
+ "contentHash": "RD6D1Jx6cKDA5IHd1H2q8ylIuQG3PD+gdULI0JC8CvsRtaypFzTFpB5xDPuQi8o6kAkcM04cBhAiJPxZboNH2Q==",
+ "dependencies": {
+ "Microsoft.Testing.Platform": "2.2.1"
+ }
+ },
+ "Microsoft.Testing.Platform": {
+ "type": "Transitive",
+ "resolved": "2.2.1",
+ "contentHash": "9bbPuls/b6/vUFzxbSjJLZlJHyKBfOZE5kjIY+ITI2ASqlFPJhR83BdLydJeQOCLEZhEbrEcz5xtt1B69nwSVg=="
+ },
+ "Microsoft.Testing.Platform.MSBuild": {
+ "type": "Transitive",
+ "resolved": "2.2.1",
+ "contentHash": "CSJOcZHfKlTyPbS0CTJk6iEnU4gJC+eUA5z72UBnMDRdgVHYOmB8k9Y7jT233gZjnCOQiYFg3acQHRfu2H62nw==",
+ "dependencies": {
+ "Microsoft.Testing.Platform": "2.2.1"
+ }
+ },
+ "Microsoft.Win32.Registry": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg=="
+ },
+ "System.Reflection.MetadataLoadContext": {
+ "type": "Transitive",
+ "resolved": "10.0.7",
+ "contentHash": "XDkKntYPUaANhLVdo7AHbrJ+QbUAY5u/T7lG5rHSx5kLxeHceoc3JcIMVAc/vZT+3rbwFYlrdnikxdi6G+2nvA=="
+ },
+ "System.Security.AccessControl": {
+ "type": "Transitive",
+ "resolved": "6.0.1",
+ "contentHash": "IQ4NXP/B3Ayzvw0rDQzVTYsCKyy0Jp9KI6aYcK7UnGVlR9+Awz++TIPCQtPYfLJfOpm8ajowMR09V7quD3sEHw=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "2.0.0-pre.40",
+ "contentHash": "TCfW5P8EnzDta+ETuKil1R6pCv2mW/kYqdUTjRagdhEnFKeBHqLwHF+xLmsl5TeBAlx/VdGJR7/26YUZMf72aA=="
+ },
+ "xunit.v3.assert": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "vhke3b55zpgL9BwqlK3TmXMAPyVqD1MwHYu2jO35Jvb96Wrts0zL9pXWbrJrS1rny0pgoIeagAsguUGXjJpAag=="
+ },
+ "xunit.v3.common": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "9d6oYJqTNLG0/a2n2sR7i5ChJx9xV9DH287u1SqiFZ8imx+Cua7bMuObNANOlvEd5EpTXQjCOC+p9JoULdzF1w==",
+ "dependencies": {
+ "Microsoft.Bcl.AsyncInterfaces": "6.0.0"
+ }
+ },
+ "xunit.v3.core.mtp-v2": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "vm5t24zX+N+cKGLA2pJVxHclVxhtXLXyhBWrZqjK8N8oo1WFDkPAcF2Toxc/VfF0r4DV4U8trZpl8WPNd8viZA==",
+ "dependencies": {
+ "Microsoft.Testing.Extensions.Telemetry": "2.2.1",
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.2.1",
+ "Microsoft.Testing.Platform": "2.2.1",
+ "Microsoft.Testing.Platform.MSBuild": "2.2.1",
+ "xunit.v3.extensibility.core": "[4.0.0-pre.103]",
+ "xunit.v3.runner.inproc.console": "[4.0.0-pre.103]"
+ }
+ },
+ "xunit.v3.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "WVO4mpv2HErpqe5yqYXUXeVZz+Hx7E3JYrVdOMtVuirrXk3ls3i1zRoyGrhQY+thzY5K3beww/8h8B9Qis0S/Q==",
+ "dependencies": {
+ "xunit.v3.common": "[4.0.0-pre.103]"
+ }
+ },
+ "xunit.v3.runner.common": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "eHOnqLu5g16Kbgi3m7cXzGbwEAtVbDCF0pla4u6xtQOuLXs129IazvDjnxoLZnKPt7uMZkfhIQIMojlI/kjrKA==",
+ "dependencies": {
+ "Microsoft.Win32.Registry": "[5.0.0]",
+ "System.Security.AccessControl": "[6.0.1]",
+ "xunit.v3.common": "[4.0.0-pre.103]"
+ }
+ },
+ "xunit.v3.runner.inproc.console": {
+ "type": "Transitive",
+ "resolved": "4.0.0-pre.103",
+ "contentHash": "2M3cPwh5VXrnRDkhAbxCIhrDpZN44wxAuFg0Vl3gupORdUeZ4ya62sN7pzM99IRwABZ3lKp17UlFu11e04wfFw==",
+ "dependencies": {
+ "xunit.v3.extensibility.core": "[4.0.0-pre.103]",
+ "xunit.v3.runner.common": "[4.0.0-pre.103]"
+ }
+ },
+ "feff.testfixtures": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.abstractions": {
+ "type": "Project",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.engine": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures.Abstractions": "[0.0.1, )",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "[10.0.7, )",
+ "Microsoft.Extensions.DependencyInjection": "[10.0.7, )",
+ "Microsoft.Extensions.Options": "[10.0.7, )",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "[10.0.7, )",
+ "System.Reflection.MetadataLoadContext": "[10.0.7, )"
+ }
+ },
+ "feff.testfixtures.xunitv4": {
+ "type": "Project",
+ "dependencies": {
+ "FEFF.TestFixtures": "[0.0.1, )",
+ "FEFF.TestFixtures.Engine": "[0.0.1, )",
+ "xunit.v3.extensibility.core": "[4.0.0-pre.103, )"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file