Stefan Nikolei 2 months ago
parent
commit
3a434f7a8b
  1. 2
      tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs
  2. 2
      tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedMemoryPoolTests.Trim.cs
  3. 2
      tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedMemoryPoolTests.cs
  4. 2
      tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs
  5. 32
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs
  6. 13
      tests/ImageSharp.Tests/TestUtilities/XUnit/ConditionalDiscovererException.cs
  7. 38
      tests/ImageSharp.Tests/TestUtilities/XUnit/ConditionalFact.cs
  8. 146
      tests/ImageSharp.Tests/TestUtilities/XUnit/ConditionalTestDiscoverer.cs
  9. 42
      tests/ImageSharp.Tests/TestUtilities/XUnit/ConditionalTheory.cs
  10. 64
      tests/ImageSharp.Tests/TestUtilities/XUnit/StaticReflectionConstants.cs

2
tests/ImageSharp.Tests/Image/ImageTests.Decode_Cancellation.cs

@ -58,7 +58,7 @@ public partial class ImageTests
public static TheoryData<bool, string, double> LoadData { get; } = CreateLoadData();
// TODO: Figure out cancellation failures on Linux
[Theory(Skip = "Skipped on non-Windows platforms", SkipType = typeof(TestEnvironment), SkipUnless = nameof(TestEnvironment.IsWindows))]
[ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsWindows))]
[MemberData(nameof(LoadData))]
public async Task LoadAsync_IsCancellable(bool useMemoryStream, string file, double percentageOfStreamReadToCancel)
{

2
tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedMemoryPoolTests.Trim.cs

@ -57,7 +57,7 @@ public partial class UniformUnmanagedMemoryPoolTests
// TODO: Investigate failures on macOS. All handles are released after GC.
// (It seems to happen more consistently on .NET 6.)
[Fact(Skip = "Skipped on macOS", SkipUnless = nameof(IsNotMacOS))]
[ConditionalFact(nameof(IsNotMacOS))]
public void MultiplePoolInstances_TrimPeriodElapsed_AllAreTrimmed()
{
if (!TestEnvironment.RunsOnCI)

2
tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedMemoryPoolTests.cs

@ -251,7 +251,7 @@ public partial class UniformUnmanagedMemoryPoolTests
public static bool IsNotMacOS => !TestEnvironment.IsMacOS;
// TODO: Investigate macOS failures
[Theory(Skip = "Skipped on macOS", SkipUnless = nameof(IsNotMacOS))]
[ConditionalTheory(nameof(IsNotMacOS))]
[InlineData(false)]
[InlineData(true)]
public void RentReturnRelease_SubsequentRentReturnsDifferentHandles(bool multiple)

2
tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs

@ -584,7 +584,7 @@ public class UniformUnmanagedPoolMemoryAllocatorTests
}
}
[Fact(Skip = "Requires 64-bit process", SkipType = typeof(Environment), SkipUnless = nameof(Environment.Is64BitProcess))]
[ConditionalFact(typeof(Environment), nameof(Environment.Is64BitProcess))]
public void MemoryAllocator_Create_SetHighLimit()
{
RemoteExecutor.Invoke(RunTest).Dispose();

32
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs

@ -312,38 +312,6 @@ public abstract class PixelOperationsTests<TPixel> : MeasureFixture
(s, d) => this.Operations.ToVector4(this.Configuration, s, d.GetSpan()));
}
public static readonly TheoryData<object> Generic_To_Data = new()
{
(object)new TestPixel<A8>(),
(object)new TestPixel<Abgr32>(),
(object)new TestPixel<Argb32>(),
(object)new TestPixel<Bgr24>(),
(object)new TestPixel<Bgr565>(),
(object)new TestPixel<Bgra32>(),
(object)new TestPixel<Bgra4444>(),
(object)new TestPixel<Bgra5551>(),
(object)new TestPixel<Byte4>(),
(object)new TestPixel<HalfSingle>(),
(object)new TestPixel<HalfVector2>(),
(object)new TestPixel<HalfVector4>(),
(object)new TestPixel<L16>(),
(object)new TestPixel<L8>(),
(object)new TestPixel<La16>(),
(object)new TestPixel<La32>(),
(object)new TestPixel<NormalizedByte2>(),
(object)new TestPixel<NormalizedByte4>(),
(object)new TestPixel<NormalizedShort2>(),
(object)new TestPixel<NormalizedShort4>(),
(object)new TestPixel<Rg32>(),
(object)new TestPixel<Rgb24>(),
(object)new TestPixel<Rgb48>(),
(object)new TestPixel<Rgba1010102>(),
(object)new TestPixel<Rgba32>(),
(object)new TestPixel<Rgba64>(),
(object)new TestPixel<RgbaVector>(),
(object)new TestPixel<Short2>(),
(object)new TestPixel<Short4>(),
};
public static readonly TheoryData<object> Generic_To_Data = new(
new object[]
{

13
tests/ImageSharp.Tests/TestUtilities/XUnit/ConditionalDiscovererException.cs

@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
namespace Microsoft.DotNet.XUnitExtensions
{
internal class ConditionalDiscovererException : Exception
{
public ConditionalDiscovererException(string message)
: base(message) { }
}
}

38
tests/ImageSharp.Tests/TestUtilities/XUnit/ConditionalFact.cs

@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.DotNet.XUnitExtensions;
using Xunit.Sdk;
namespace Xunit
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class ConditionalFactAttribute : FactAttribute
{
[DynamicallyAccessedMembers(StaticReflectionConstants.ConditionalMemberKinds)]
public Type CalleeType { get; private set; }
public string[] ConditionMemberNames { get; private set; }
public ConditionalFactAttribute(
[DynamicallyAccessedMembers(StaticReflectionConstants.ConditionalMemberKinds)]
Type calleeType,
params string[] conditionMemberNames)
{
CalleeType = calleeType;
ConditionMemberNames = conditionMemberNames;
string skipReason = ConditionalTestDiscoverer.EvaluateSkipConditions(calleeType, conditionMemberNames);
if (skipReason != null)
Skip = skipReason;
}
[Obsolete(
"Use the overload that takes a Type parameter: ConditionalFact(typeof(MyClass), nameof(MyCondition)).")]
public ConditionalFactAttribute(params string[] conditionMemberNames)
{
ConditionMemberNames = conditionMemberNames;
}
}
}

146
tests/ImageSharp.Tests/TestUtilities/XUnit/ConditionalTestDiscoverer.cs

@ -0,0 +1,146 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using Xunit.Sdk;
namespace Microsoft.DotNet.XUnitExtensions
{
// Internal helper class for code common to conditional test discovery through
// [ConditionalFact] and [ConditionalTheory]
internal static class ConditionalTestDiscoverer
{
/// <summary>
/// Evaluates skip conditions given an explicit callee type and condition member names.
/// Used by attribute constructors in xunit v3 where discoverers are not needed.
/// </summary>
internal static string EvaluateSkipConditions(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type calleeType,
string[] conditionMemberNames
)
{
if (
calleeType == null
|| conditionMemberNames == null
|| conditionMemberNames.Length == 0
)
return null;
List<string> falseConditions = new(conditionMemberNames.Length);
foreach (string entry in conditionMemberNames)
{
if (string.IsNullOrWhiteSpace(entry))
continue;
Func<bool> conditionFunc = LookupConditionalMember(calleeType, entry);
if (conditionFunc == null)
throw new ConditionalDiscovererException(
GetFailedLookupString(entry, calleeType)
);
try
{
if (!conditionFunc())
falseConditions.Add(entry);
}
catch (Exception exc)
{
falseConditions.Add($"{entry} ({exc.GetType().Name})");
}
}
return falseConditions.Count > 0
? string.Format(
"Condition(s) not met: \"{0}\"",
string.Join("\", \"", falseConditions)
)
: null;
}
internal static string GetFailedLookupString(string name, Type type)
{
return $"An appropriate member '{name}' could not be found. "
+ $"The conditional method needs to be a static method, property, or field on the type {type} or any ancestor, "
+ "of any visibility, accepting zero arguments, and having a return type of Boolean.";
}
internal static Func<bool> LookupConditionalMember(Type t, string name)
{
if (t == null || name == null)
return null;
TypeInfo ti = t.GetTypeInfo();
MethodInfo mi = ti.GetDeclaredMethod(name);
if (
mi != null
&& mi.IsStatic
&& mi.GetParameters().Length == 0
&& mi.ReturnType == typeof(bool)
)
return () => (bool)mi.Invoke(null, null);
PropertyInfo pi = ti.GetDeclaredProperty(name);
if (
pi != null
&& pi.PropertyType == typeof(bool)
&& pi.GetMethod != null
&& pi.GetMethod.IsStatic
&& pi.GetMethod.GetParameters().Length == 0
)
return () => (bool)pi.GetValue(null);
FieldInfo fi = ti.GetDeclaredField(name);
if (fi != null && fi.FieldType == typeof(bool) && fi.IsStatic)
return () => (bool)fi.GetValue(null);
return LookupConditionalMember(ti.BaseType, name);
}
internal static bool CheckInputToSkipExecution(
object[] conditionArguments,
ref Type calleeType,
ref string[] conditionMemberNames,
object testMethod = null
)
{
// A null or empty list of conditionArguments is treated as "no conditions".
// and the test cases will be executed.
// Example: [ConditionalClass()]
if (conditionArguments == null || conditionArguments.Length == 0)
return true;
calleeType = conditionArguments[0] as Type;
if (calleeType != null)
{
if (conditionArguments.Length < 2)
{
// [ConditionalFact(typeof(x))] no provided methods.
return true;
}
// [ConditionalFact(typeof(x), "MethodName")]
conditionMemberNames = conditionArguments[1] as string[];
}
else
{
// For [ConditionalClass], unable to get the Type info. All test cases will be executed.
if (testMethod == null)
return true;
// [ConditionalFact("MethodName")]
conditionMemberNames = conditionArguments[0] as string[];
}
// [ConditionalFact((string[]) null)]
if (conditionMemberNames == null || conditionMemberNames.Count() == 0)
return true;
return false;
}
}
}

42
tests/ImageSharp.Tests/TestUtilities/XUnit/ConditionalTheory.cs

@ -0,0 +1,42 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.DotNet.XUnitExtensions;
using Xunit.Sdk;
namespace Xunit
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class ConditionalTheoryAttribute : TheoryAttribute
{
[DynamicallyAccessedMembers(StaticReflectionConstants.ConditionalMemberKinds)]
public Type CalleeType { get; private set; }
public string[] ConditionMemberNames { get; private set; }
public ConditionalTheoryAttribute(
[DynamicallyAccessedMembers(StaticReflectionConstants.ConditionalMemberKinds)]
Type calleeType,
params string[] conditionMemberNames
)
{
CalleeType = calleeType;
ConditionMemberNames = conditionMemberNames;
string skipReason = ConditionalTestDiscoverer.EvaluateSkipConditions(
calleeType,
conditionMemberNames
);
if (skipReason != null)
Skip = skipReason;
}
[Obsolete(
"Use the overload that takes a Type parameter: ConditionalTheory(typeof(MyClass), nameof(MyCondition))."
)]
public ConditionalTheoryAttribute(params string[] conditionMemberNames)
{
ConditionMemberNames = conditionMemberNames;
}
}
}

64
tests/ImageSharp.Tests/TestUtilities/XUnit/StaticReflectionConstants.cs

@ -0,0 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
namespace Xunit
{
internal static class StaticReflectionConstants
{
// ConditionalTestDiscoverer looks at all fields/methods/properties, recursively.
internal const DynamicallyAccessedMemberTypes ConditionalMemberKinds =
DynamicallyAccessedMemberTypes.AllMethods
| DynamicallyAccessedMemberTypes.AllFields
| DynamicallyAccessedMemberTypes.AllProperties;
}
}
namespace System.Diagnostics.CodeAnalysis
{
// This is a copy of the attribute from CoreLib. The attribute shipped in .NET 5.
// The tooling looks for the attribute by name, so we can define a local copy.
// This copy can be deleted once we stop supporting anything below .NET 5.
internal sealed class DynamicallyAccessedMembersAttribute : Attribute
{
public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) =>
MemberTypes = memberTypes;
public DynamicallyAccessedMemberTypes MemberTypes { get; }
}
internal enum DynamicallyAccessedMemberTypes
{
None = 0,
PublicParameterlessConstructor = 0x0001,
PublicConstructors = 0x0002 | PublicParameterlessConstructor,
NonPublicConstructors = 0x0004,
PublicMethods = 0x0008,
NonPublicMethods = 0x0010,
PublicFields = 0x0020,
NonPublicFields = 0x0040,
PublicNestedTypes = 0x0080,
NonPublicNestedTypes = 0x0100,
PublicProperties = 0x0200,
NonPublicProperties = 0x0400,
PublicEvents = 0x0800,
NonPublicEvents = 0x1000,
Interfaces = 0x2000,
NonPublicConstructorsWithInherited = NonPublicConstructors | 0x4000,
NonPublicMethodsWithInherited = NonPublicMethods | 0x8000,
NonPublicFieldsWithInherited = NonPublicFields | 0x10000,
NonPublicNestedTypesWithInherited = NonPublicNestedTypes | 0x20000,
NonPublicPropertiesWithInherited = NonPublicProperties | 0x40000,
NonPublicEventsWithInherited = NonPublicEvents | 0x80000,
PublicConstructorsWithInherited = PublicConstructors | 0x100000,
PublicNestedTypesWithInherited = PublicNestedTypes | 0x200000,
AllConstructors = PublicConstructorsWithInherited | NonPublicConstructorsWithInherited,
AllMethods = PublicMethods | NonPublicMethodsWithInherited,
AllFields = PublicFields | NonPublicFieldsWithInherited,
AllNestedTypes = PublicNestedTypesWithInherited | NonPublicNestedTypesWithInherited,
AllProperties = PublicProperties | NonPublicPropertiesWithInherited,
AllEvents = PublicEvents | NonPublicEventsWithInherited,
All = ~None,
}
}
Loading…
Cancel
Save