Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

Represents the **NuGet** versions.

## v5.6.3
- *Fixed:* `TestSetUp` fixed to load _all_ assemblies on start up (versus selective) to ensure all `OneOffTestSetUpAttribute` implementations are executed prior to any test executions.
- *Fixed:* Added `IJsonSerializer.Clone()` and `JsonElementComparerOptions.Clone` to ensure cross test contamination does not occur.

## v5.6.2
- *Fixed:* Republish packages with a new version; last publish was incomplete.

Expand Down
2 changes: 1 addition & 1 deletion Common.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>5.6.2</Version>
<Version>5.6.3</Version>
<LangVersion>preview</LangVersion>
<Authors>Avanade</Authors>
<Company>Avanade</Company>
Expand Down
3 changes: 0 additions & 3 deletions src/UnitTestEx/Abstractions/OneOffTestSetUpAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ namespace UnitTestEx.Abstractions
[AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
public class OneOffTestSetUpAttribute(Type type) : Attribute
{
private static readonly object _oneOffSetUpLock = new();
private static readonly HashSet<Type> _oneOffSetUpTypes = [];

/// <summary>
/// Performs the set up for the specified <paramref name="assembly"/> where configured using the <see cref="OneOffTestSetUpAttribute"/>.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/UnitTestEx/Abstractions/TesterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public abstract class TesterBase
/// </summary>
static TesterBase()
{
TestSetUp.Force();

try
{
var fi = new FileInfo(Path.Combine(Environment.CurrentDirectory, "appsettings.unittest.json"));
Expand Down
6 changes: 6 additions & 0 deletions src/UnitTestEx/Json/IJsonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,11 @@ public interface IJsonSerializer
/// <param name="json">The JSON <see cref="string"/>.</param>
/// <returns>The corresponding typed value.</returns>
T? Deserialize<T>(string json);

/// <summary>
/// Clones the <see cref="IJsonSerializer"/>.
/// </summary>
/// <returns>The cloned <see cref="IJsonSerializer"/>.</returns>
IJsonSerializer Clone();
}
}
2 changes: 1 addition & 1 deletion src/UnitTestEx/Json/JsonElementComparerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public static JsonElementComparerOptions Default
MaxDifferences = MaxDifferences,
ValueComparison = ValueComparison,
NullComparison = NullComparison,
JsonSerializer = JsonSerializer
JsonSerializer = JsonSerializer?.Clone()
};
}
}
3 changes: 3 additions & 0 deletions src/UnitTestEx/Json/JsonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,8 @@ public JsonSerializer(Stj.JsonSerializerOptions? options = null)

/// <inheritdoc/>
public string Serialize<T>(T value, JsonWriteFormat? format = null) => Stj.JsonSerializer.Serialize(value, format == null || format.Value == JsonWriteFormat.None ? Options : IndentedOptions);

/// <inheritdoc/>
public IJsonSerializer Clone() => new JsonSerializer(new Stj.JsonSerializerOptions(Options));
}
}
16 changes: 10 additions & 6 deletions src/UnitTestEx/TestSetUp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class TestSetUp : ICloneable
{
private static readonly SemaphoreSlim _semaphore = new(1, 1);
private static readonly ConcurrentQueue<string> _autoSetUpOutputs = new();
private static readonly ConcurrentDictionary<string, object?> _registeredAssemblies = new();

private TestSetUp? _clonedFrom;
private bool _setUpSet = false;
Expand All @@ -40,13 +41,16 @@ public class TestSetUp : ICloneable
/// <remarks>Wires up the <see cref="OneOffTestSetUpAttribute.SetUp()"/> invocation whenever an <see cref="Assembly"/> is <see cref="AppDomain.AssemblyLoad">loaded.</see></remarks>
static TestSetUp()
{
// Load dependent UnitTestEx assemblies as they may not have been loaded yet!
foreach (var fi in new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).EnumerateFiles("*.dll").Where(f => f.Name.StartsWith("UnitTestEx.")))
// Load all dependent assemblies to ensure all one off test set up(s) execute before any test exection is perfomed.
foreach (var fi in new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).EnumerateFiles("*.dll"))
Assembly.LoadFrom(fi.FullName);

// Wire up for any assemblies already loaded.
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
OneOffTestSetUpAttribute.SetUp(assembly);
{
if (_registeredAssemblies.TryAdd(assembly.FullName!, null))
OneOffTestSetUpAttribute.SetUp(assembly);
}

// Wire up for any future assembly loading.
AppDomain.CurrentDomain.AssemblyLoad += (_, e) => OneOffTestSetUpAttribute.SetUp(e.LoadedAssembly);
Expand Down Expand Up @@ -199,8 +203,8 @@ public static void LogAutoSetUpOutputs(TestFrameworkImplementor implementor)
/// <remarks>The <see cref="RegisterSetUp"/> and <see cref="RegisterAutoSetUp"/> will reference the originating unless explicitly registered (overridden) for the cloned instance.</remarks>
public TestSetUp Clone() => new()
{
JsonSerializer = JsonSerializer,
JsonComparerOptions = JsonComparerOptions,
JsonSerializer = JsonSerializer.Clone(),
JsonComparerOptions = JsonComparerOptions.Clone(),
Properties = new Dictionary<string, object?>(Properties),
DefaultUserName = DefaultUserName,
UserNameConverter = UserNameConverter,
Expand Down Expand Up @@ -255,7 +259,7 @@ public void RegisterAutoSetUp(Func<int, object?, CancellationToken, Task<(bool,
public async Task<bool> SetUpAsync(object? data = null, CancellationToken cancellationToken = default)
{
if (SetUpFunc == null && AutoSetUpFunc == null)
throw new InvalidOperationException("Set up can not be invoked as no set up function has been registered; please use RegisterSetUp() ot AutoRegisterSetUp() to enable.");
throw new InvalidOperationException("Set up can not be invoked as no set up function has been registered; please use RegisterSetUp() or AutoRegisterSetUp() to enable.");

await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
Expand Down
7 changes: 5 additions & 2 deletions tests/UnitTestEx.MSTest.Test/NewtonsoftJsonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class NewtonsoftJsonSerializer : IJsonSerializer
/// <summary>
/// Copies the settings.
/// </summary>
private Nsj.JsonSerializerSettings CopySettings(JsonWriteFormat format)
private Nsj.JsonSerializerSettings CopySettings(JsonWriteFormat? format)
{
var s = new Nsj.JsonSerializerSettings
{
Expand All @@ -89,7 +89,7 @@ private Nsj.JsonSerializerSettings CopySettings(JsonWriteFormat format)
Context = Settings.Context,
DateFormatString = Settings.DateFormatString,
MaxDepth = Settings.MaxDepth,
Formatting = format == JsonWriteFormat.None ? Nsj.Formatting.None : Nsj.Formatting.Indented,
Formatting = format is null ? Settings.Formatting : format == JsonWriteFormat.None ? Nsj.Formatting.None : Nsj.Formatting.Indented,
DateFormatHandling = Settings.DateFormatHandling,
DateTimeZoneHandling = Settings.DateTimeZoneHandling,
DateParseHandling = Settings.DateParseHandling,
Expand All @@ -105,6 +105,9 @@ private Nsj.JsonSerializerSettings CopySettings(JsonWriteFormat format)

return s;
}

/// <inheritdoc/>
public IJsonSerializer Clone() => new NewtonsoftJsonSerializer(CopySettings(null));
}
}

Expand Down
Loading