Skip to content

Update SharedInfrastructure for Xunit V3#2854

Open
stefannikolei wants to merge 9 commits into
SixLabors:mainfrom
stefannikolei:sn/upd/xunit
Open

Update SharedInfrastructure for Xunit V3#2854
stefannikolei wants to merge 9 commits into
SixLabors:mainfrom
stefannikolei:sn/upd/xunit

Conversation

@stefannikolei

Copy link
Copy Markdown
Contributor

Submodule points to my fork for iterating faster. When this works, I will create a mr in the SharedInfrastructure project

@stefannikolei

Copy link
Copy Markdown
Contributor Author

I started looking into it.

Gonna take longer. This is not a small change.

# Conflicts:
#	shared-infrastructure
@JimBobSquarePants

Copy link
Copy Markdown
Member

You’re a brave man! XUnit versioning is a shambles.

@stefannikolei

stefannikolei commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@JimBobSquarePants Just small changes then it should work.

But those changes are 🤮

Will have to clean it up. I just saw that there are some unrelated changes.

Breaking changes addressed:
- Update xunit.v3 to 3.2.2 and xunit.runner.visualstudio to 3.1.5
- Remove Microsoft.DotNet.XUnitExtensions (conflicts with xunit.v3 via xunit.core v2)
- Replace ConditionalFact/ConditionalTheory with Fact/Theory SkipUnless/SkipWhen/SkipType
- Remove 'using Xunit.Abstractions' (ITestOutputHelper now in Xunit namespace globally)
- Fix TestFrameworkAttribute: string args → typeof(T) form
- Fix XunitTestFramework ctor: no longer takes IMessageSink
- Fix BeforeAfterTestAttribute Before/After: added IXunitTest parameter, use Xunit.v3 ns
- Fix DataAttribute: new GetData signature (DisposalTracker), add SupportsDiscoveryEnumeration()
- Fix IXunitSerializable/IXunitSerializationInfo: add 'using Xunit.Sdk' to all consumers
- Fix BasicSerializer: implement new IXunitSerializationInfo.GetValue(string) returning object?
  Store type info in dump format (key:TypeAQN:value) to enable typed reconstruction
- Fix TheoryData<T> CS0121 ambiguity on C# 12/net8.0: add explicit casts (T)value
  Affects ExifValuesTests, PixelOperationsTests, QuantizerTests, DitherTests,
  TestImageProviderTests, RotateTests, L8Tests, La16Tests
- Fix PngEncoderTests: TheoryData<T> now yields TheoryDataRow<T>, not object[]
when used in nameof it is not allowed to be a filed it must be a property
@stefannikolei

Copy link
Copy Markdown
Contributor Author

@JimBobSquarePants so i finale succeeded. If you want you can have a look

@stefannikolei stefannikolei marked this pull request as ready for review May 21, 2026 19:25

// TODO: Figure out cancellation failures on Linux
[ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsWindows))]
[Theory(Skip = "Skipped on non-Windows platforms", SkipType = typeof(TestEnvironment), SkipUnless = nameof(TestEnvironment.IsWindows))]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ConditionalTheory] comes from Arcade doesn't it. Can we write our own version? Seems less verbose.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can look into it. Arcade is strange. You use a package which is not findable on Nuget

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it’s from a runtime feed we add via the submodule. Has RemoteExecutor also.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can add it. Where would you want me to put it? TestUtilities.XUnit.Attributes ?

Comment thread tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedMemoryPoolTests.Trim.cs Outdated
Comment thread tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs Outdated
{
string[] kv = s.Split(Separator);
this.map[kv[0]] = kv[1];
// Format: key:TypeAQN:value (3 parts max to preserve ':' inside value)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll need you to explain all this I'm afraid.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old interface did pass the type in the Get. That's why it was saved internally as key:value.

With XunitV3 we do not get that info with the get method that's why we now save it in the dictionary. So we now have 3 parts and not 3 parts like before

GCMemoryInfo memInfo = GC.GetGCMemoryInfo();
int highLoadThreshold = (int)(memInfo.HighMemoryLoadThresholdBytes / oneMb);
highLoadThreshold = (int)(trimSettings.HighPressureThresholdRate * highLoadThreshold);
highLoadThreshold = (int)(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting like this is weird. Can you please look in the diff for other odd changes like this and revert. I've spotted a few.

{
public static readonly TheoryData<byte> LuminanceData
= new() { 0, 1, 2, 3, 5, 13, 31, 71, 73, 79, 83, 109, 127, 128, 131, 199, 250, 251, 254, 255 };
= new() { (byte)0, (byte)1, (byte)2, (byte)3, (byte)5, (byte)13, (byte)31, (byte)71, (byte)73, (byte)79, (byte)83, (byte)109, (byte)127, (byte)128, (byte)131, (byte)199, (byte)250, (byte)251, (byte)254, (byte)255 };

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we definitely need this new casting?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Do you see another way?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image better than this

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does casting the first entry work? (byte)0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this?
image
nope ...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤮

Oh XUnit!

new WebSafePaletteQuantizer(OrderedDitherOptions),
new WernerPaletteQuantizer(OrderedDitherOptions),
new WuQuantizer(OrderedDitherOptions)
(IQuantizer)KnownQuantizers.Hexadecatree,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Lots of new casting

{
addedRows = memberItems.Select(x => new[] { x });
}
if (x is ITheoryDataRow row) return row.GetData();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

braces

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be an editorconfig setting for this.

Another thing is formatting.

Should we work onto an ci check and tooling that formats the code? Or do you want it handcrafted.

I made good experience with csharpier. It's opinionated. At first a bit strange but after getting used to it 👌 and no more formatting discussions or problems

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we work onto an ci check and tooling that formats the code? Or do you want it handcrafted.

No. I do not want to ever rely on automation for code formatting. I want people to be aware of the styles and standards.

There should be an editorconfig setting for this.

csharp_prefer_braces is already present as a warning. We just don't have them as errors in the tests.

[Fact]
public void SolutionDirectoryFullPath()
=> this.CheckPath(TestEnvironment.SolutionDirectoryFullPath);
public void SolutionDirectoryFullPath() =>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Odd formatting changes

public void GetReferenceOutputFileName()
{
string actual = Path.Combine(TestEnvironment.ActualOutputDirectoryFullPath, @"foo\bar\lol.jpeg");
string actual = Path.Combine(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to wrap here.

[InlineData("lol/Baz.gif", typeof(GifDecoder))]
[InlineData("lol/foobar.webp", typeof(WebpDecoder))]
public void GetReferenceDecoder_ReturnsCorrectDecoders_Windows(string fileName, Type expectedDecoderType)
public void GetReferenceDecoder_ReturnsCorrectDecoders_Windows(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No here etc.

CalleeType = calleeType;
ConditionMemberNames = conditionMemberNames;
string skipReason = ConditionalTestDiscoverer.EvaluateSkipConditions(calleeType, conditionMemberNames);
if (skipReason != null)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

braces

Skip = skipReason;
}

[Obsolete(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

odd wrapping

List<string> falseConditions = new(conditionMemberNames.Length);
foreach (string entry in conditionMemberNames)
{
if (string.IsNullOrWhiteSpace(entry))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

braces

conditionMemberNames
);
if (skipReason != null)
Skip = skipReason;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

braces

Skip = skipReason;
}

[Obsolete(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

odd wrapping

public DynamicallyAccessedMemberTypes MemberTypes { get; }
}

internal enum DynamicallyAccessedMemberTypes

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (directory == null)
{
throw new DirectoryNotFoundException($"Unable to find ImageSharp solution directory from {TestAssemblyFile}!");
throw new DirectoryNotFoundException(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary wrapping

$"Unable to find ImageSharp solution directory from {TestAssemblyFile} because of {ex.GetType().Name}!",
ex);
ex
);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've seen this change in a few places now and it violates StyleCop

internal static bool IsMono => Type.GetType("Mono.Runtime") != null; // https://stackoverflow.com/a/721194

internal static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this public and no others?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was needed for using plain fact. This can probably switched back to internal


string remoteExecutorConfigPath =
Path.Combine(TestAssemblyFile.DirectoryName, "Microsoft.DotNet.RemoteExecutor.exe.config");
string remoteExecutorConfigPath = Path.Combine(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More new wrapping

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants