New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ArgumentOutOfRangeException in FluentAssertions.Equivalency.Tracing.StringBuilderTraceWriter.ToString() #2619
Comments
I assume you're using |
This reproduces the exception using FluentAssertions;
using FluentAssertions.Execution;
AssertionOptions.AssertEquivalencyUsing(e => e.WithTracing());
Parallel.For(1, 10_000, (_, _) =>
{
try
{
new { A = "a" }.Should().BeEquivalentTo(new { A = "b" });
}
catch (AssertionFailedException) { }
}); The problem is setting a single |
@jnyrup thanks for the quick reply. Yes, I have a If this uses a shared Should().BeEquivalentTo(foo, options => options.WithTracing(new StringBuilderTraceWriter())); |
Setting The two workarounds I can currently think of are:
I have not dug further into what we could do in FA to make this (more) thread-safe. |
With the current So use at your own risk, setting up AssertionOptions.AssertEquivalencyUsing(e => e.WithTracing(new StringBuilderTraceWriterPool()));
Parallel.For(1, 1_000, (_, _) =>
{
new { A = "a" }.Should().BeEquivalentTo(new { A = "a" });
}); public sealed class StringBuilderTraceWriterPool : ITraceWriter
{
private readonly AsyncLocal<StringBuilderTraceWriter> builders = new();
private StringBuilderTraceWriter Builder => builders.Value ??= new();
public void AddSingle(string trace) => Builder.AddSingle(trace);
public IDisposable AddBlock(string trace) => Builder.AddBlock(trace);
public override string ToString()
{
var result = Builder.ToString();
builders.Value = null;
return result;
}
} The underlying problem is that we reuse the same fluentassertions/Src/FluentAssertions/Equivalency/SelfReferenceEquivalencyOptions.cs Lines 95 to 102 in 7632b78
|
Although it's a bug, tracing is meant for individual diagnostic situations. Why are you enabling it globally? |
Thanks @jnyrup, for now I've disabled tracing globally. If I need to enable it globally again I'll try that version, but for now I'll turn it on only as needed. @dennisdoomen it's useful to have as much information as possible for test failures during automated test runs (e.g., build pipelines), especially in cases where test failures are not consistently reproducible (like this one, ironically). Since trace output only happens during test failures, it seems like it makes sense to always have it on so that traces are available when a test fails during an automated test run. |
Description
I'm getting random
ArgumentOutOfRangeException
from an internalStringBuilder.ToString()
call when using object equivalency (Should().BeEquivalentTo
) with large object graphs during concurrent test runs with xUnit:This only seems to occur sometimes when multiple tests are running concurrently. When run individually or sequentially, this error does not occur.
Is there any static or shared StringBuilder internally that might be used in overlapping test runs?
Reproduction Steps
This is difficult to reproduce in a controlled environment, since it only happens occasionally during concurrent test runs. It seems more likely to happen when evaluating large object graphs (depth > 15 or so) and only during concurrent test runs (xUnit concurrency settings
"parallelizeAssembly": false
)Expected behavior
Not expecting an exception from StringBuilder.ToString()
Actual behavior
ArgumentOutOfRangeException
Regression?
No response
Known Workarounds
No response
Configuration
.NET 7
Fluent Assertions 6.12.0
xUnit 2.4.1
Other information
No response
Are you willing to help with a pull-request?
No
The text was updated successfully, but these errors were encountered: