diff --git a/src/Xunit.Combinatorial/CombinatorialDataAttribute.cs b/src/Xunit.Combinatorial/CombinatorialDataAttribute.cs
index b67fdf0..6c10c6a 100644
--- a/src/Xunit.Combinatorial/CombinatorialDataAttribute.cs
+++ b/src/Xunit.Combinatorial/CombinatorialDataAttribute.cs
@@ -4,82 +4,81 @@
using System.Reflection;
using Xunit.Sdk;
-namespace Xunit
+namespace Xunit;
+
+///
+/// Provides a test method decorated with a
+/// with arguments to run every possible combination of values for the
+/// parameters taken by the test method.
+///
+[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
+public class CombinatorialDataAttribute : DataAttribute
{
///
- /// Provides a test method decorated with a
- /// with arguments to run every possible combination of values for the
- /// parameters taken by the test method.
+ /// Initializes a new instance of the class.
///
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
- public class CombinatorialDataAttribute : DataAttribute
+ public CombinatorialDataAttribute()
+ {
+ }
+
+ ///
+ public override IEnumerable GetData(MethodInfo testMethod)
{
- ///
- /// Initializes a new instance of the class.
- ///
- public CombinatorialDataAttribute()
+ Requires.NotNull(testMethod, nameof(testMethod));
+
+ ParameterInfo[]? parameters = testMethod.GetParameters();
+ if (parameters.Length == 0)
{
+ return Enumerable.Empty();
}
- ///
- public override IEnumerable GetData(MethodInfo testMethod)
+ var values = new List[parameters.Length];
+ for (int i = 0; i < parameters.Length; i++)
{
- Requires.NotNull(testMethod, nameof(testMethod));
-
- ParameterInfo[]? parameters = testMethod.GetParameters();
- if (parameters.Length == 0)
- {
- return Enumerable.Empty();
- }
+ values[i] = ValuesUtilities.GetValuesFor(parameters[i]).ToList();
+ }
- var values = new List[parameters.Length];
- for (int i = 0; i < parameters.Length; i++)
- {
- values[i] = ValuesUtilities.GetValuesFor(parameters[i]).ToList();
- }
+ object[]? currentValues = new object[parameters.Length];
+ return this.FillCombinations(parameters, values, currentValues, 0);
+ }
- object[]? currentValues = new object[parameters.Length];
- return this.FillCombinations(parameters, values, currentValues, 0);
- }
+ ///
+ /// Produces a sequence of argument arrays that capture every possible
+ /// combination of values.
+ ///
+ /// The parameters taken by the test method.
+ /// An array of each argument's list of possible values.
+ /// An array that is being recursively initialized with a set of arguments to pass to the test method.
+ /// The index into that this particular invocation should rotate through for.
+ /// A sequence of all combinations of arguments from , starting at .
+ private IEnumerable FillCombinations(ParameterInfo[] parameters, List[] candidateValues, object?[] currentValues, int index)
+ {
+ Requires.NotNull(parameters, nameof(parameters));
+ Requires.NotNull(candidateValues, nameof(candidateValues));
+ Requires.NotNull(currentValues, nameof(currentValues));
+ Requires.Argument(parameters.Length == candidateValues.Length, nameof(candidateValues), $"Expected to have same array length as {nameof(parameters)}");
+ Requires.Argument(parameters.Length == currentValues.Length, nameof(currentValues), $"Expected to have same array length as {nameof(parameters)}");
+ Requires.Range(index >= 0 && index < parameters.Length, nameof(index));
- ///
- /// Produces a sequence of argument arrays that capture every possible
- /// combination of values.
- ///
- /// The parameters taken by the test method.
- /// An array of each argument's list of possible values.
- /// An array that is being recursively initialized with a set of arguments to pass to the test method.
- /// The index into that this particular invocation should rotate through for.
- /// A sequence of all combinations of arguments from , starting at .
- private IEnumerable FillCombinations(ParameterInfo[] parameters, List[] candidateValues, object?[] currentValues, int index)
+ foreach (object? value in candidateValues[index])
{
- Requires.NotNull(parameters, nameof(parameters));
- Requires.NotNull(candidateValues, nameof(candidateValues));
- Requires.NotNull(currentValues, nameof(currentValues));
- Requires.Argument(parameters.Length == candidateValues.Length, nameof(candidateValues), $"Expected to have same array length as {nameof(parameters)}");
- Requires.Argument(parameters.Length == currentValues.Length, nameof(currentValues), $"Expected to have same array length as {nameof(parameters)}");
- Requires.Range(index >= 0 && index < parameters.Length, nameof(index));
+ currentValues[index] = value;
- foreach (object? value in candidateValues[index])
+ if (index + 1 < parameters.Length)
{
- currentValues[index] = value;
-
- if (index + 1 < parameters.Length)
- {
- foreach (object?[] result in this.FillCombinations(parameters, candidateValues, currentValues, index + 1))
- {
- yield return result;
- }
- }
- else
+ foreach (object?[] result in this.FillCombinations(parameters, candidateValues, currentValues, index + 1))
{
- // We're the tail end, so just produce the value.
- // Copy the array before returning since we're about to mutate currentValues
- object[] finalSet = new object[currentValues.Length];
- Array.Copy(currentValues, finalSet, currentValues.Length);
- yield return finalSet;
+ yield return result;
}
}
+ else
+ {
+ // We're the tail end, so just produce the value.
+ // Copy the array before returning since we're about to mutate currentValues
+ object[] finalSet = new object[currentValues.Length];
+ Array.Copy(currentValues, finalSet, currentValues.Length);
+ yield return finalSet;
+ }
}
}
}
diff --git a/src/Xunit.Combinatorial/CombinatorialMemberDataAttribute.cs b/src/Xunit.Combinatorial/CombinatorialMemberDataAttribute.cs
index 8731d9f..c3058e1 100644
--- a/src/Xunit.Combinatorial/CombinatorialMemberDataAttribute.cs
+++ b/src/Xunit.Combinatorial/CombinatorialMemberDataAttribute.cs
@@ -4,231 +4,226 @@
using System.Collections;
using System.Reflection;
-namespace Xunit
+namespace Xunit;
+
+///
+/// Specifies which member should provide data for this parameter used for running the test method.
+///
+[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)]
+public class CombinatorialMemberDataAttribute : Attribute
{
///
- /// Specifies which member should provide data for this parameter used for running the test method.
+ /// Initializes a new instance of the class.
///
- [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)]
- public class CombinatorialMemberDataAttribute : Attribute
+ /// The name of the public static member on the test class that will provide the test data.
+ /// The arguments for the member (only supported for methods; ignored for everything else).
+ public CombinatorialMemberDataAttribute(string memberName, params object?[]? arguments)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The name of the public static member on the test class that will provide the test data.
- /// The arguments for the member (only supported for methods; ignored for everything else).
- public CombinatorialMemberDataAttribute(string memberName, params object?[]? arguments)
- {
- this.MemberName = memberName ?? throw new ArgumentNullException(nameof(memberName));
- this.Arguments = arguments;
- }
+ this.MemberName = memberName ?? throw new ArgumentNullException(nameof(memberName));
+ this.Arguments = arguments;
+ }
- ///
- /// Gets the member name.
- ///
- public string MemberName { get; }
+ ///
+ /// Gets the member name.
+ ///
+ public string MemberName { get; }
- ///
- /// Gets or sets the type to retrieve the member from. If not set, then the property will be
- /// retrieved from the unit test class.
- ///
- public Type? MemberType { get; set; }
+ ///
+ /// Gets or sets the type to retrieve the member from. If not set, then the property will be
+ /// retrieved from the unit test class.
+ ///
+ public Type? MemberType { get; set; }
- ///
- /// Gets the arguments passed to the member. Only supported for static methods.
- ///
- public object?[]? Arguments { get; }
+ ///
+ /// Gets the arguments passed to the member. Only supported for static methods.
+ ///
+ public object?[]? Arguments { get; }
- ///
- /// Gets the values that should be passed to this parameter on the test method.
- ///
- /// The parameter for which the data should be provided.
- /// An array of values.
- public object?[] GetValues(ParameterInfo parameterInfo)
- {
- Requires.NotNull(parameterInfo, nameof(parameterInfo));
+ ///
+ /// Gets the values that should be passed to this parameter on the test method.
+ ///
+ /// The parameter for which the data should be provided.
+ /// An array of values.
+ public object?[] GetValues(ParameterInfo parameterInfo)
+ {
+ Requires.NotNull(parameterInfo, nameof(parameterInfo));
- MemberInfo? testMethod = parameterInfo.Member;
+ MemberInfo? testMethod = parameterInfo.Member;
- Type? type = this.MemberType ?? testMethod?.DeclaringType;
+ Type? type = this.MemberType ?? testMethod?.DeclaringType;
- if (type is null)
- {
-#if NETSTANDARD
- return Array.Empty();
-#else
- return new object[0];
-#endif
- }
+ if (type is null)
+ {
+ return Array.Empty();
+ }
- Func? accessor = this.GetPropertyAccessor(type, parameterInfo) ?? this.GetMethodAccessor(type, parameterInfo) ?? this.GetFieldAccessor(type, parameterInfo);
- if (accessor is null)
- {
- string? parameterText = this.Arguments?.Length > 0 ? $" with parameter types: {string.Join(", ", this.Arguments.Select(p => p?.GetType().FullName ?? "(null)"))}" : string.Empty;
- throw new ArgumentException($"Could not find public static member (property, field, or method) named '{this.MemberName}' on {type.FullName}{parameterText}.");
- }
+ Func? accessor = this.GetPropertyAccessor(type, parameterInfo) ?? this.GetMethodAccessor(type, parameterInfo) ?? this.GetFieldAccessor(type, parameterInfo);
+ if (accessor is null)
+ {
+ string? parameterText = this.Arguments?.Length > 0 ? $" with parameter types: {string.Join(", ", this.Arguments.Select(p => p?.GetType().FullName ?? "(null)"))}" : string.Empty;
+ throw new ArgumentException($"Could not find public static member (property, field, or method) named '{this.MemberName}' on {type.FullName}{parameterText}.");
+ }
- var obj = (IEnumerable)accessor();
- return obj.Cast().ToArray();
+ var obj = (IEnumerable)accessor();
+ return obj.Cast().ToArray();
+ }
+
+ ///
+ /// Gets the type of the value enumerated by a given type that is or implements .
+ ///
+ /// An type or a type that implements .
+ /// The generic type argument for (one of) the interface)s) implemented by the .
+ private static TypeInfo? GetEnumeratedType(Type enumerableType)
+ {
+ if (enumerableType.IsGenericType && enumerableType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ {
+ Type[] enumerableGenericTypeArgs = enumerableType.GetTypeInfo().GetGenericArguments();
+ return enumerableGenericTypeArgs[0].GetTypeInfo();
}
- ///
- /// Gets the type of the value enumerated by a given type that is or implements .
- ///
- /// An type or a type that implements .
- /// The generic type argument for (one of) the interface)s) implemented by the .
- private static TypeInfo? GetEnumeratedType(Type enumerableType)
+ foreach (Type implementedInterface in enumerableType.GetTypeInfo().ImplementedInterfaces)
{
- if (enumerableType.IsGenericType && enumerableType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ TypeInfo interfaceTypeInfo = implementedInterface.GetTypeInfo();
+ if (interfaceTypeInfo.IsGenericType && interfaceTypeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
- Type[] enumerableGenericTypeArgs = enumerableType.GetTypeInfo().GetGenericArguments();
- return enumerableGenericTypeArgs[0].GetTypeInfo();
+ return interfaceTypeInfo.GetGenericArguments()[0].GetTypeInfo();
}
+ }
- foreach (Type implementedInterface in enumerableType.GetTypeInfo().ImplementedInterfaces)
+ return null;
+ }
+
+ private Func? GetPropertyAccessor(Type type, ParameterInfo parameterInfo)
+ {
+ PropertyInfo? propInfo = null;
+ for (Type? reflectionType = type; reflectionType is not null; reflectionType = reflectionType.GetTypeInfo().BaseType)
+ {
+ propInfo = reflectionType.GetRuntimeProperty(this.MemberName);
+ if (propInfo is not null)
{
- TypeInfo interfaceTypeInfo = implementedInterface.GetTypeInfo();
- if (interfaceTypeInfo.IsGenericType && interfaceTypeInfo.GetGenericTypeDefinition() == typeof(IEnumerable<>))
- {
- return interfaceTypeInfo.GetGenericArguments()[0].GetTypeInfo();
- }
+ break;
}
+ }
+ if (propInfo?.GetMethod is null || !propInfo.GetMethod.IsStatic)
+ {
return null;
}
- private Func? GetPropertyAccessor(Type type, ParameterInfo parameterInfo)
+ this.EnsureValidMemberDataType(propInfo.PropertyType, propInfo.DeclaringType, parameterInfo);
+
+ return () => propInfo.GetValue(null, null);
+ }
+
+ private Func? GetMethodAccessor(Type type, ParameterInfo parameterInfo)
+ {
+ MethodInfo? methodInfo = null;
+ for (Type? reflectionType = type; reflectionType is not null; reflectionType = reflectionType.GetTypeInfo().BaseType)
{
- PropertyInfo? propInfo = null;
- for (Type? reflectionType = type; reflectionType is not null; reflectionType = reflectionType.GetTypeInfo().BaseType)
+ methodInfo = reflectionType.GetRuntimeMethods().FirstOrDefault(m => m.Name == this.MemberName && this.ParameterTypesCompatible(m.GetParameters(), this.Arguments));
+ if (methodInfo is not null)
{
- propInfo = reflectionType.GetRuntimeProperty(this.MemberName);
- if (propInfo is not null)
- {
- break;
- }
+ break;
}
+ }
- if (propInfo?.GetMethod is null || !propInfo.GetMethod.IsStatic)
- {
- return null;
- }
+ if (methodInfo is null || !methodInfo.IsStatic)
+ {
+ return null;
+ }
- this.EnsureValidMemberDataType(propInfo.PropertyType, propInfo.DeclaringType, parameterInfo);
+ this.EnsureValidMemberDataType(methodInfo.ReturnType, methodInfo.DeclaringType, parameterInfo);
- return () => propInfo.GetValue(null, null);
+ return () => methodInfo.Invoke(null, this.Arguments);
+ }
+
+ private bool ParameterTypesCompatible(ParameterInfo[] parameters, object?[]? arguments)
+ {
+ if (arguments is null)
+ {
+ return parameters.Length == 0;
+ }
+ else if (parameters.Length != arguments.Length)
+ {
+ return false;
}
- private Func? GetMethodAccessor(Type type, ParameterInfo parameterInfo)
+ for (int i = 0; i < parameters.Length; i++)
{
- MethodInfo? methodInfo = null;
- for (Type? reflectionType = type; reflectionType is not null; reflectionType = reflectionType.GetTypeInfo().BaseType)
+ if (arguments[i] is object arg)
{
- methodInfo = reflectionType.GetRuntimeMethods().FirstOrDefault(m => m.Name == this.MemberName && this.ParameterTypesCompatible(m.GetParameters(), this.Arguments));
- if (methodInfo is not null)
+ if (!parameters[i].ParameterType.GetTypeInfo().IsAssignableFrom(arg.GetType().GetTypeInfo()))
{
- break;
+ return false;
}
}
-
- if (methodInfo is null || !methodInfo.IsStatic)
+ else
{
- return null;
+ if (parameters[i].ParameterType.IsValueType)
+ {
+ // Cannot assign null to a value type parameter.
+ return false;
+ }
}
-
- this.EnsureValidMemberDataType(methodInfo.ReturnType, methodInfo.DeclaringType, parameterInfo);
-
- return () => methodInfo.Invoke(null, this.Arguments);
}
- private bool ParameterTypesCompatible(ParameterInfo[] parameters, object?[]? arguments)
+ return true;
+ }
+
+ private Func? GetFieldAccessor(Type type, ParameterInfo parameterInfo)
+ {
+ FieldInfo? fieldInfo = null;
+ for (Type? reflectionType = type; reflectionType is not null; reflectionType = reflectionType.GetTypeInfo().BaseType)
{
- if (arguments is null)
- {
- return parameters.Length == 0;
- }
- else if (parameters.Length != arguments.Length)
- {
- return false;
- }
+ fieldInfo = reflectionType.GetRuntimeField(this.MemberName);
- for (int i = 0; i < parameters.Length; i++)
+ if (fieldInfo is not null)
{
- if (arguments[i] is object arg)
- {
- if (!parameters[i].ParameterType.GetTypeInfo().IsAssignableFrom(arg.GetType().GetTypeInfo()))
- {
- return false;
- }
- }
- else
- {
- if (parameters[i].ParameterType.IsValueType)
- {
- // Cannot assign null to a value type parameter.
- return false;
- }
- }
+ break;
}
-
- return true;
}
- private Func? GetFieldAccessor(Type type, ParameterInfo parameterInfo)
+ if (fieldInfo is null || !fieldInfo.IsStatic)
{
- FieldInfo? fieldInfo = null;
- for (Type? reflectionType = type; reflectionType is not null; reflectionType = reflectionType.GetTypeInfo().BaseType)
- {
- fieldInfo = reflectionType.GetRuntimeField(this.MemberName);
-
- if (fieldInfo is not null)
- {
- break;
- }
- }
+ return null;
+ }
- if (fieldInfo is null || !fieldInfo.IsStatic)
- {
- return null;
- }
+ this.EnsureValidMemberDataType(fieldInfo.FieldType, fieldInfo.DeclaringType, parameterInfo);
- this.EnsureValidMemberDataType(fieldInfo.FieldType, fieldInfo.DeclaringType, parameterInfo);
+ return () => fieldInfo.GetValue(null);
+ }
- return () => fieldInfo.GetValue(null);
+ ///
+ /// Throws if a given type will not generate values that are compatible with a given parameter.
+ ///
+ /// The type of value stored by the field or property.
+ /// The type on which the member is declared.
+ /// The parameter that must receive the values generated by .
+ /// Throw when does not conform to requirements or does not produce values assignable to .
+ private void EnsureValidMemberDataType(Type enumerableType, Type declaringType, ParameterInfo parameterInfo)
+ {
+ TypeInfo? enumeratedType = GetEnumeratedType(enumerableType);
+ if (enumeratedType is null)
+ {
+ throw new ArgumentException($"Member {this.MemberName} on {declaringType.FullName} must return a type that implements IEnumerable.");
}
- ///
- /// Throws if a given type will not generate values that are compatible with a given parameter.
- ///
- /// The type of value stored by the field or property.
- /// The type on which the member is declared.
- /// The parameter that must receive the values generated by .
- /// Throw when does not conform to requirements or does not produce values assignable to .
- private void EnsureValidMemberDataType(Type enumerableType, Type declaringType, ParameterInfo parameterInfo)
+ if (enumeratedType.IsArray)
{
- TypeInfo? enumeratedType = GetEnumeratedType(enumerableType);
- if (enumeratedType is null)
- {
- throw new ArgumentException($"Member {this.MemberName} on {declaringType.FullName} must return a type that implements IEnumerable.");
- }
-
- if (enumeratedType.IsArray)
- {
- throw new ArgumentException(
- $"Member {this.MemberName} on {declaringType.FullName} returned an IEnumerable<{enumeratedType.Name}>, which is not supported.");
- }
+ throw new ArgumentException(
+ $"Member {this.MemberName} on {declaringType.FullName} returned an IEnumerable<{enumeratedType.Name}>, which is not supported.");
+ }
- if (enumeratedType.IsGenericType && enumeratedType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
- {
- throw new ArgumentException(
- $"Member {this.MemberName} on {declaringType.FullName} returned an IEnumerable>, which is not supported.");
- }
+ if (enumeratedType.IsGenericType && enumeratedType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
+ {
+ throw new ArgumentException(
+ $"Member {this.MemberName} on {declaringType.FullName} returned an IEnumerable>, which is not supported.");
+ }
- if (!enumeratedType.IsAssignableFrom(parameterInfo.ParameterType.GetTypeInfo()))
- {
- throw new ArgumentException(
- $"Parameter type {parameterInfo.ParameterType.FullName} is not compatible with returned member type {enumeratedType.FullName}.");
- }
+ if (!enumeratedType.IsAssignableFrom(parameterInfo.ParameterType.GetTypeInfo()))
+ {
+ throw new ArgumentException(
+ $"Parameter type {parameterInfo.ParameterType.FullName} is not compatible with returned member type {enumeratedType.FullName}.");
}
}
}
diff --git a/src/Xunit.Combinatorial/CombinatorialRandomDataAttribute.cs b/src/Xunit.Combinatorial/CombinatorialRandomDataAttribute.cs
index b88e965..a5d7c0b 100644
--- a/src/Xunit.Combinatorial/CombinatorialRandomDataAttribute.cs
+++ b/src/Xunit.Combinatorial/CombinatorialRandomDataAttribute.cs
@@ -3,96 +3,95 @@
using System.Globalization;
-namespace Xunit
+namespace Xunit;
+
+///
+/// Specifies which range of values for this parameter should be used for running the test method.
+///
+[AttributeUsage(AttributeTargets.Parameter)]
+public class CombinatorialRandomDataAttribute : Attribute
{
///
- /// Specifies which range of values for this parameter should be used for running the test method.
+ /// Special seed value to create System.Random class without seed.
+ ///
+ public const int NoSeed = 0;
+
+ private object[]? values;
+
+ ///
+ /// Gets or sets the number of values to generate. Must be positive.
+ ///
+ /// The default value is 5.
+ public int Count { get; set; } = 5;
+
+ ///
+ /// Gets or sets the minimum value (inclusive) that may be randomly generated.
+ ///
+ /// The default value is 0.
+ public int Minimum { get; set; }
+
+ ///
+ /// Gets or sets the maximum value (inclusive) that may be randomly generated.
+ ///
+ /// The default value is - 1 , which is the maximum allowable value.
+ public int Maximum { get; set; } = int.MaxValue - 1;
+
+ ///
+ /// Gets or sets the seed to use for random number generation.
+ ///
+ /// The default value of allows for a new seed to be used each time.
+ public int Seed { get; set; } = NoSeed;
+
+ ///
+ /// Gets the values that should be passed to this parameter on the test method.
///
- [AttributeUsage(AttributeTargets.Parameter)]
- public class CombinatorialRandomDataAttribute : Attribute
+ /// An array of values.
+ public object[] Values => this.values ??= this.GenerateValues();
+
+ private object[] GenerateValues()
{
- ///
- /// Special seed value to create System.Random class without seed.
- ///
- public const int NoSeed = 0;
-
- private object[]? values;
-
- ///
- /// Gets or sets the number of values to generate. Must be positive.
- ///
- /// The default value is 5.
- public int Count { get; set; } = 5;
-
- ///
- /// Gets or sets the minimum value (inclusive) that may be randomly generated.
- ///
- /// The default value is 0.
- public int Minimum { get; set; }
-
- ///
- /// Gets or sets the maximum value (inclusive) that may be randomly generated.
- ///
- /// The default value is - 1 , which is the maximum allowable value.
- public int Maximum { get; set; } = int.MaxValue - 1;
-
- ///
- /// Gets or sets the seed to use for random number generation.
- ///
- /// The default value of allows for a new seed to be used each time.
- public int Seed { get; set; } = NoSeed;
-
- ///
- /// Gets the values that should be passed to this parameter on the test method.
- ///
- /// An array of values.
- public object[] Values => this.values ??= this.GenerateValues();
-
- private object[] GenerateValues()
+ if (this.Count < 1)
{
- if (this.Count < 1)
- {
- throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ValueMustBePositive, nameof(this.Count)));
- }
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ValueMustBePositive, nameof(this.Count)));
+ }
+
+ if (this.Minimum > this.Maximum)
+ {
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.XMustNotBeGreaterThanY, nameof(this.Minimum), nameof(this.Maximum)));
+ }
+
+ int maxPossibleValues = this.Maximum - this.Minimum + 1;
+ if (this.Count > maxPossibleValues)
+ {
+ throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.MoreRandomValuesRequestedThanPossibleOnes, nameof(this.Count), nameof(this.Minimum), nameof(this.Maximum)));
+ }
- if (this.Minimum > this.Maximum)
+ Random random = this.Seed != NoSeed ? new Random(this.Seed) : new Random();
+
+ HashSet collisionChecker = new HashSet();
+ object[] values = new object[this.Count];
+ int collisionCount = 0;
+ int i = 0;
+ while (collisionChecker.Count < this.Count)
+ {
+ int value = random.Next(this.Minimum, this.Maximum + 1);
+ if (collisionChecker.Add(value))
{
- throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.XMustNotBeGreaterThanY, nameof(this.Minimum), nameof(this.Maximum)));
+ values[i++] = value;
}
-
- int maxPossibleValues = this.Maximum - this.Minimum + 1;
- if (this.Count > maxPossibleValues)
+ else
{
- throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.MoreRandomValuesRequestedThanPossibleOnes, nameof(this.Count), nameof(this.Minimum), nameof(this.Maximum)));
+ collisionCount++;
}
- Random random = this.Seed != NoSeed ? new Random(this.Seed) : new Random();
-
- HashSet collisionChecker = new HashSet();
- object[] values = new object[this.Count];
- int collisionCount = 0;
- int i = 0;
- while (collisionChecker.Count < this.Count)
+ if (collisionCount > collisionChecker.Count * 5)
{
- int value = random.Next(this.Minimum, this.Maximum + 1);
- if (collisionChecker.Add(value))
- {
- values[i++] = value;
- }
- else
- {
- collisionCount++;
- }
-
- if (collisionCount > collisionChecker.Count * 5)
- {
- // We have collided in random values far more than we have successfully generated values.
- // Rather than spin in this loop, throw.
- throw new InvalidOperationException(Strings.TooManyRandomCollisions);
- }
+ // We have collided in random values far more than we have successfully generated values.
+ // Rather than spin in this loop, throw.
+ throw new InvalidOperationException(Strings.TooManyRandomCollisions);
}
-
- return values;
}
+
+ return values;
}
}
diff --git a/src/Xunit.Combinatorial/CombinatorialRangeAttribute.cs b/src/Xunit.Combinatorial/CombinatorialRangeAttribute.cs
index b21295f..c2e6ea5 100644
--- a/src/Xunit.Combinatorial/CombinatorialRangeAttribute.cs
+++ b/src/Xunit.Combinatorial/CombinatorialRangeAttribute.cs
@@ -1,152 +1,151 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE file in the project root for full license information.
-namespace Xunit
+namespace Xunit;
+
+///
+/// Specifies which range of values for this parameter should be used for running the test method.
+///
+[AttributeUsage(AttributeTargets.Parameter)]
+public class CombinatorialRangeAttribute : Attribute
{
///
- /// Specifies which range of values for this parameter should be used for running the test method.
+ /// Initializes a new instance of the class.
///
- [AttributeUsage(AttributeTargets.Parameter)]
- public class CombinatorialRangeAttribute : Attribute
+ /// The value at the beginning of the range.
+ ///
+ /// The quantity of consecutive integer values to include.
+ /// Cannot be less than 1, which would conceptually result in zero test cases.
+ ///
+ public CombinatorialRangeAttribute(int from, int count)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The value at the beginning of the range.
- ///
- /// The quantity of consecutive integer values to include.
- /// Cannot be less than 1, which would conceptually result in zero test cases.
- ///
- public CombinatorialRangeAttribute(int from, int count)
+ if (count < 1)
{
- if (count < 1)
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
-
- object[] values = new object[count];
- for (int i = 0; i < count; i++)
- {
- values[i] = from + i;
- }
+ throw new ArgumentOutOfRangeException(nameof(count));
+ }
- this.Values = values;
+ object[] values = new object[count];
+ for (int i = 0; i < count; i++)
+ {
+ values[i] = from + i;
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The value at the beginning of the range.
- ///
- /// The value at the end of the range.
- /// Cannot be less than "from" parameter.
- /// When "to" and "from" are equal, CombinatorialValues is more appropriate.
- ///
- ///
- /// The number of integers to step for each value in result.
- /// Cannot be less than one. Stepping zero or backwards is not useful.
- /// Stepping over "to" does not add another value to the range.
- ///
- public CombinatorialRangeAttribute(int from, int to, int step)
+ this.Values = values;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value at the beginning of the range.
+ ///
+ /// The value at the end of the range.
+ /// Cannot be less than "from" parameter.
+ /// When "to" and "from" are equal, CombinatorialValues is more appropriate.
+ ///
+ ///
+ /// The number of integers to step for each value in result.
+ /// Cannot be less than one. Stepping zero or backwards is not useful.
+ /// Stepping over "to" does not add another value to the range.
+ ///
+ public CombinatorialRangeAttribute(int from, int to, int step)
+ {
+ if (step > 0)
{
- if (step > 0)
+ if (to < from)
{
- if (to < from)
- {
- throw new ArgumentOutOfRangeException(nameof(to));
- }
+ throw new ArgumentOutOfRangeException(nameof(to));
}
- else if (step < 0)
- {
- if (to > from)
- {
- throw new ArgumentOutOfRangeException(nameof(to));
- }
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(step));
- }
-
- int count = ((to - from) / step) + 1;
- object[] values = new object[count];
- for (int i = 0; i < count; i++)
+ }
+ else if (step < 0)
+ {
+ if (to > from)
{
- values[i] = from + (i * step);
+ throw new ArgumentOutOfRangeException(nameof(to));
}
-
- this.Values = values;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(nameof(step));
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The value at the beginning of the range.
- ///
- /// The quantity of consecutive integer values to include.
- /// Cannot be less than 1, which would conceptually result in zero test cases.
- ///
- public CombinatorialRangeAttribute(uint from, uint count)
+ int count = ((to - from) / step) + 1;
+ object[] values = new object[count];
+ for (int i = 0; i < count; i++)
{
- if (count < 1)
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
+ values[i] = from + (i * step);
+ }
- object[] values = new object[count];
- for (uint i = 0; i < count; i++)
- {
- values[i] = from + i;
- }
+ this.Values = values;
+ }
- this.Values = values;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value at the beginning of the range.
+ ///
+ /// The quantity of consecutive integer values to include.
+ /// Cannot be less than 1, which would conceptually result in zero test cases.
+ ///
+ public CombinatorialRangeAttribute(uint from, uint count)
+ {
+ if (count < 1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(count));
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The value at the beginning of the range.
- ///
- /// The value at the end of the range.
- /// Cannot be less than "from" parameter.
- /// When "to" and "from" are equal, CombinatorialValues is more appropriate.
- ///
- ///
- /// The number of unsigned integers to step for each value in result.
- /// Cannot be less than one. Stepping zero is not useful.
- /// Stepping over "to" does not add another value to the range.
- ///
- public CombinatorialRangeAttribute(uint from, uint to, uint step)
+ object[] values = new object[count];
+ for (uint i = 0; i < count; i++)
{
- if (step == 0)
- {
- throw new ArgumentOutOfRangeException(nameof(step));
- }
+ values[i] = from + i;
+ }
- var values = new List();
+ this.Values = values;
+ }
- if (from < to)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value at the beginning of the range.
+ ///
+ /// The value at the end of the range.
+ /// Cannot be less than "from" parameter.
+ /// When "to" and "from" are equal, CombinatorialValues is more appropriate.
+ ///
+ ///
+ /// The number of unsigned integers to step for each value in result.
+ /// Cannot be less than one. Stepping zero is not useful.
+ /// Stepping over "to" does not add another value to the range.
+ ///
+ public CombinatorialRangeAttribute(uint from, uint to, uint step)
+ {
+ if (step == 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(step));
+ }
+
+ var values = new List();
+
+ if (from < to)
+ {
+ for (uint i = from; i <= to; i += step)
{
- for (uint i = from; i <= to; i += step)
- {
- values.Add(i);
- }
+ values.Add(i);
}
- else
+ }
+ else
+ {
+ for (uint i = from; i >= to && i <= from; i -= step)
{
- for (uint i = from; i >= to && i <= from; i -= step)
- {
- values.Add(i);
- }
+ values.Add(i);
}
-
- this.Values = values.Cast().ToArray();
}
- ///
- /// Gets the values that should be passed to this parameter on the test method.
- ///
- /// An array of values.
- public object[] Values { get; }
+ this.Values = values.Cast().ToArray();
}
+
+ ///
+ /// Gets the values that should be passed to this parameter on the test method.
+ ///
+ /// An array of values.
+ public object[] Values { get; }
}
diff --git a/src/Xunit.Combinatorial/CombinatorialValuesAttribute.cs b/src/Xunit.Combinatorial/CombinatorialValuesAttribute.cs
index 1367ef9..889067a 100644
--- a/src/Xunit.Combinatorial/CombinatorialValuesAttribute.cs
+++ b/src/Xunit.Combinatorial/CombinatorialValuesAttribute.cs
@@ -1,29 +1,28 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE file in the project root for full license information.
-namespace Xunit
+namespace Xunit;
+
+///
+/// Specifies which values for this parameter should be used for running the test method.
+///
+[AttributeUsage(AttributeTargets.Parameter)]
+public class CombinatorialValuesAttribute : Attribute
{
///
- /// Specifies which values for this parameter should be used for running the test method.
+ /// Initializes a new instance of the class.
///
- [AttributeUsage(AttributeTargets.Parameter)]
- public class CombinatorialValuesAttribute : Attribute
+ /// The values to pass to this parameter.
+ public CombinatorialValuesAttribute(params object?[]? values)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The values to pass to this parameter.
- public CombinatorialValuesAttribute(params object?[]? values)
- {
- // When values is `null`, it's because the user passed in `null` as the only value and C# interpreted it as a null array.
- // Re-interpret that.
- this.Values = values ?? new object?[] { null };
- }
-
- ///
- /// Gets the values that should be passed to this parameter on the test method.
- ///
- /// An array of values.
- public object?[] Values { get; }
+ // When values is `null`, it's because the user passed in `null` as the only value and C# interpreted it as a null array.
+ // Re-interpret that.
+ this.Values = values ?? new object?[] { null };
}
+
+ ///
+ /// Gets the values that should be passed to this parameter on the test method.
+ ///
+ /// An array of values.
+ public object?[] Values { get; }
}
diff --git a/src/Xunit.Combinatorial/PairwiseDataAttribute.cs b/src/Xunit.Combinatorial/PairwiseDataAttribute.cs
index 1ae126f..f7b47bf 100644
--- a/src/Xunit.Combinatorial/PairwiseDataAttribute.cs
+++ b/src/Xunit.Combinatorial/PairwiseDataAttribute.cs
@@ -4,35 +4,34 @@
using System.Reflection;
using Xunit.Sdk;
-namespace Xunit
+namespace Xunit;
+
+///
+/// Provides a test method decorated with a
+/// with arguments to run various combination of values for the
+/// parameters taken by the test method using a pairwise strategy.
+///
+public class PairwiseDataAttribute : DataAttribute
{
- ///
- /// Provides a test method decorated with a
- /// with arguments to run various combination of values for the
- /// parameters taken by the test method using a pairwise strategy.
- ///
- public class PairwiseDataAttribute : DataAttribute
+ ///
+ public override IEnumerable GetData(MethodInfo testMethod)
{
- ///
- public override IEnumerable GetData(MethodInfo testMethod)
- {
- Requires.NotNull(testMethod, nameof(testMethod));
+ Requires.NotNull(testMethod, nameof(testMethod));
- ParameterInfo[]? parameters = testMethod.GetParameters();
- if (parameters.Length == 0)
- {
- return Enumerable.Empty();
- }
-
- var values = new List[parameters.Length];
- for (int i = 0; i < parameters.Length; i++)
- {
- values[i] = ValuesUtilities.GetValuesFor(parameters[i]).ToList();
- }
+ ParameterInfo[]? parameters = testMethod.GetParameters();
+ if (parameters.Length == 0)
+ {
+ return Enumerable.Empty();
+ }
- List? testCaseInfo = PairwiseStrategy.GetTestCases(values.Select(v => v.Count).ToArray());
- return from testCase in testCaseInfo
- select testCase.Select((j, i) => values[i][j]).ToArray();
+ var values = new List[parameters.Length];
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ values[i] = ValuesUtilities.GetValuesFor(parameters[i]).ToList();
}
+
+ List? testCaseInfo = PairwiseStrategy.GetTestCases(values.Select(v => v.Count).ToArray());
+ return from testCase in testCaseInfo
+ select testCase.Select((j, i) => values[i][j]).ToArray();
}
}
diff --git a/src/Xunit.Combinatorial/PairwiseStrategy.cs b/src/Xunit.Combinatorial/PairwiseStrategy.cs
index 8e118d7..1625516 100644
--- a/src/Xunit.Combinatorial/PairwiseStrategy.cs
+++ b/src/Xunit.Combinatorial/PairwiseStrategy.cs
@@ -24,566 +24,565 @@
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ***********************************************************************
-namespace Xunit
+namespace Xunit;
+
+///
+/// PairwiseStrategy creates test cases by combining the parameter
+/// data so that all possible pairs of data items are used.
+///
+///
+///
+/// The number of test cases that cover all possible pairs of test function
+/// parameters values is significantly less than the number of test cases
+/// that cover all possible combination of test function parameters values.
+/// And because different studies show that most of software failures are
+/// caused by combination of no more than two parameters, pairwise testing
+/// can be an effective ways to test the system when it's impossible to test
+/// all combinations of parameters.
+///
+///
+/// The PairwiseStrategy code is based on "jenny" tool by Bob Jenkins:
+/// .
+///
+///
+internal static class PairwiseStrategy
{
+ // NOTE: Terminology in this class is based on the literature
+ // relating to strategies for combining variable features when
+ // creating tests. This terminology is more closely related to
+ // higher level testing than it is to unit tests. See
+ // comments in the code for further explanations.
+
///
- /// PairwiseStrategy creates test cases by combining the parameter
- /// data so that all possible pairs of data items are used.
+ /// Creates a set of test cases for specified dimensions.
///
- ///
- ///
- /// The number of test cases that cover all possible pairs of test function
- /// parameters values is significantly less than the number of test cases
- /// that cover all possible combination of test function parameters values.
- /// And because different studies show that most of software failures are
- /// caused by combination of no more than two parameters, pairwise testing
- /// can be an effective ways to test the system when it's impossible to test
- /// all combinations of parameters.
- ///
- ///
- /// The PairwiseStrategy code is based on "jenny" tool by Bob Jenkins:
- /// .
- ///
- ///
- internal static class PairwiseStrategy
+ ///
+ /// An array which contains information about dimensions. Each element of
+ /// this array represents a number of features in the specific dimension.
+ ///
+ ///
+ /// A set of test cases.
+ ///
+ public static List GetTestCases(int[] dimensions)
{
- // NOTE: Terminology in this class is based on the literature
- // relating to strategies for combining variable features when
- // creating tests. This terminology is more closely related to
- // higher level testing than it is to unit tests. See
- // comments in the code for further explanations.
-
- ///
- /// Creates a set of test cases for specified dimensions.
- ///
- ///
- /// An array which contains information about dimensions. Each element of
- /// this array represents a number of features in the specific dimension.
- ///
- ///
- /// A set of test cases.
- ///
- public static List GetTestCases(int[] dimensions)
- {
- return (from testCase in new PairwiseTestCaseGenerator().GetTestCases(dimensions)
- select testCase.Features).ToList();
- }
+ return (from testCase in new PairwiseTestCaseGenerator().GetTestCases(dimensions)
+ select testCase.Features).ToList();
+ }
- private static bool IsTupleCovered(this TestCaseInfo testCaseInfo, FeatureTuple tuple)
+ private static bool IsTupleCovered(this TestCaseInfo testCaseInfo, FeatureTuple tuple)
+ {
+ for (int i = 0; i < tuple.Length; i++)
{
- for (int i = 0; i < tuple.Length; i++)
+ if (testCaseInfo.Features[tuple[i].Dimension] != tuple[i].Feature)
{
- if (testCaseInfo.Features[tuple[i].Dimension] != tuple[i].Feature)
- {
- return false;
- }
+ return false;
}
-
- return true;
}
+ return true;
+ }
+
+ ///
+ /// FleaRand is a pseudo-random number generator developed by Bob Jenkins:
+ /// .
+ ///
+ private class FleaRand
+ {
+ private uint b;
+ private uint c;
+ private uint d;
+ private uint z;
+ private uint[] m;
+ private uint[] r;
+ private uint q;
+
///
- /// FleaRand is a pseudo-random number generator developed by Bob Jenkins:
- /// .
+ /// Initializes a new instance of the class.
///
- private class FleaRand
+ /// The seed.
+ public FleaRand(uint seed)
{
- private uint b;
- private uint c;
- private uint d;
- private uint z;
- private uint[] m;
- private uint[] r;
- private uint q;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The seed.
- public FleaRand(uint seed)
+ this.b = seed;
+ this.c = seed;
+ this.d = seed;
+ this.z = seed;
+ this.m = new uint[256];
+ this.r = new uint[256];
+
+ for (int i = 0; i < this.m.Length; i++)
{
- this.b = seed;
- this.c = seed;
- this.d = seed;
- this.z = seed;
- this.m = new uint[256];
- this.r = new uint[256];
-
- for (int i = 0; i < this.m.Length; i++)
- {
- this.m[i] = seed;
- }
-
- for (int i = 0; i < 10; i++)
- {
- this.Batch();
- }
-
- this.q = 0;
+ this.m[i] = seed;
}
- public uint Next()
+ for (int i = 0; i < 10; i++)
{
- if (this.q == 0)
- {
- this.Batch();
- this.q = (uint)this.r.Length - 1;
- }
- else
- {
- this.q--;
- }
-
- return this.r[this.q];
+ this.Batch();
}
- private void Batch()
+ this.q = 0;
+ }
+
+ public uint Next()
+ {
+ if (this.q == 0)
{
- uint a;
- uint b = this.b;
- uint c = this.c + (++this.z);
- uint d = this.d;
+ this.Batch();
+ this.q = (uint)this.r.Length - 1;
+ }
+ else
+ {
+ this.q--;
+ }
- for (int i = 0; i < this.r.Length; i++)
- {
- a = this.m[b % this.m.Length];
- this.m[b % this.m.Length] = d;
- d = (c << 19) + (c >> 13) + b;
- c = b ^ this.m[i];
- b = a + d;
- this.r[i] = c;
- }
+ return this.r[this.q];
+ }
+
+ private void Batch()
+ {
+ uint a;
+ uint b = this.b;
+ uint c = this.c + (++this.z);
+ uint d = this.d;
- this.b = b;
- this.c = c;
- this.d = d;
+ for (int i = 0; i < this.r.Length; i++)
+ {
+ a = this.m[b % this.m.Length];
+ this.m[b % this.m.Length] = d;
+ d = (c << 19) + (c >> 13) + b;
+ c = b ^ this.m[i];
+ b = a + d;
+ this.r[i] = c;
}
+
+ this.b = b;
+ this.c = c;
+ this.d = d;
}
+ }
+ ///
+ /// FeatureInfo represents coverage of a single value of test function
+ /// parameter, represented as a pair of indices, Dimension and Feature. In
+ /// terms of unit testing, Dimension is the index of the test parameter and
+ /// Feature is the index of the supplied value in that parameter's list of
+ /// sources.
+ ///
+ private class FeatureInfo
+ {
///
- /// FeatureInfo represents coverage of a single value of test function
- /// parameter, represented as a pair of indices, Dimension and Feature. In
- /// terms of unit testing, Dimension is the index of the test parameter and
- /// Feature is the index of the supplied value in that parameter's list of
- /// sources.
+ /// Initializes a new instance of the class.
///
- private class FeatureInfo
+ /// Index of a dimension.
+ /// Index of a feature.
+ public FeatureInfo(int dimension, int feature)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// Index of a dimension.
- /// Index of a feature.
- public FeatureInfo(int dimension, int feature)
- {
- this.Dimension = dimension;
- this.Feature = feature;
- }
+ this.Dimension = dimension;
+ this.Feature = feature;
+ }
- public int Dimension { get; }
+ public int Dimension { get; }
- public int Feature { get; }
- }
+ public int Feature { get; }
+ }
+
+ ///
+ /// A FeatureTuple represents a combination of features, one per test
+ /// parameter, which should be covered by a test case. In the
+ /// PairwiseStrategy, we are only trying to cover pairs of features, so the
+ /// tuples actually may contain only single feature or pair of features, but
+ /// the algorithm itself works with triplets, quadruples and so on.
+ ///
+ private class FeatureTuple
+ {
+ private readonly FeatureInfo[] features;
///
- /// A FeatureTuple represents a combination of features, one per test
- /// parameter, which should be covered by a test case. In the
- /// PairwiseStrategy, we are only trying to cover pairs of features, so the
- /// tuples actually may contain only single feature or pair of features, but
- /// the algorithm itself works with triplets, quadruples and so on.
+ /// Initializes a new instance of the class
+ /// for a single feature.
///
- private class FeatureTuple
+ /// Single feature.
+ public FeatureTuple(FeatureInfo feature1)
{
- private readonly FeatureInfo[] features;
-
- ///
- /// Initializes a new instance of the class
- /// for a single feature.
- ///
- /// Single feature.
- public FeatureTuple(FeatureInfo feature1)
- {
- this.features = new FeatureInfo[] { feature1 };
- }
+ this.features = new FeatureInfo[] { feature1 };
+ }
- ///
- /// Initializes a new instance of the class
- /// for a pair of features.
- ///
- /// First feature.
- /// Second feature.
- public FeatureTuple(FeatureInfo feature1, FeatureInfo feature2)
- {
- this.features = new FeatureInfo[] { feature1, feature2 };
- }
+ ///
+ /// Initializes a new instance of the class
+ /// for a pair of features.
+ ///
+ /// First feature.
+ /// Second feature.
+ public FeatureTuple(FeatureInfo feature1, FeatureInfo feature2)
+ {
+ this.features = new FeatureInfo[] { feature1, feature2 };
+ }
- public int Length
+ public int Length
+ {
+ get
{
- get
- {
- return this.features.Length;
- }
+ return this.features.Length;
}
+ }
- public FeatureInfo this[int index]
+ public FeatureInfo this[int index]
+ {
+ get
{
- get
- {
- return this.features[index];
- }
+ return this.features[index];
}
}
+ }
+ ///
+ /// TestCase represents a single test case covering a list of features.
+ ///
+ private class TestCaseInfo
+ {
///
- /// TestCase represents a single test case covering a list of features.
+ /// Initializes a new instance of the class.
///
- private class TestCaseInfo
+ /// A number of features in the test case.
+ public TestCaseInfo(int length)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// A number of features in the test case.
- public TestCaseInfo(int length)
- {
- this.Features = new int[length];
- }
-
- public int[] Features { get; }
+ this.Features = new int[length];
}
+ public int[] Features { get; }
+ }
+
+ ///
+ /// PairwiseTestCaseGenerator class implements an algorithm which generates
+ /// a set of test cases which covers all pairs of possible values of test
+ /// function.
+ ///
+ ///
+ ///
+ /// The algorithm starts with creating a set of all feature tuples which we
+ /// will try to cover (see method). This set
+ /// includes every single feature and all possible pairs of features. We
+ /// store feature tuples in the 3-D collection (where axes are "dimension",
+ /// "feature", and "all combinations which includes this feature"), and for
+ /// every two feature (e.g. "A" and "B") we generate both ("A", "B") and
+ /// ("B", "A") pairs. This data structure extremely reduces the amount of
+ /// time needed to calculate coverage for a single test case (this
+ /// calculation is the most time-consuming part of the algorithm).
+ ///
+ ///
+ /// Then the algorithm picks one tuple from the uncovered tuple, creates a
+ /// test case that covers this tuple, and then removes this tuple and all
+ /// other tuples covered by this test case from the collection of uncovered
+ /// tuples.
+ ///
+ ///
+ /// Picking a tuple to cover.
+ ///
+ ///
+ /// There are no any special rules defined for picking tuples to cover. We
+ /// just pick them one by one, in the order they were generated.
+ ///
+ ///
+ /// Test generation.
+ ///
+ ///
+ /// Test generation starts from creating a completely random test case which
+ /// covers, nevertheless, previously selected tuple. Then the algorithm
+ /// tries to maximize number of tuples which this test covers.
+ ///
+ ///
+ /// Test generation and maximization process repeats seven times for every
+ /// selected tuple and then the algorithm picks the best test case ("seven"
+ /// is a magic number which provides good results in acceptable time).
+ ///
+ /// Maximizing test coverage.
+ ///
+ /// To maximize tests coverage, the algorithm walks thru the list of mutable
+ /// dimensions (mutable dimension is a dimension that are not included in
+ /// the previously selected tuple). Then for every dimension, the algorithm
+ /// walks thru the list of features and checks if this feature provides
+ /// better coverage than randomly selected feature, and if yes keeps this
+ /// feature.
+ ///
+ ///
+ /// This process repeats while it shows progress. If the last iteration
+ /// doesn't improve coverage, the process ends.
+ ///
+ ///
+ /// In addition, for better results, before start every iteration, the
+ /// algorithm "scrambles" dimensions - so for every iteration dimension
+ /// probes in a different order.
+ ///
+ ///
+ private class PairwiseTestCaseGenerator
+ {
+ private FleaRand? prng;
+
+ private int[]? dimensions;
+
+ private List[][]? uncoveredTuples;
+
///
- /// PairwiseTestCaseGenerator class implements an algorithm which generates
- /// a set of test cases which covers all pairs of possible values of test
- /// function.
+ /// Creates a set of test cases for specified dimensions.
///
- ///
- ///
- /// The algorithm starts with creating a set of all feature tuples which we
- /// will try to cover (see method). This set
- /// includes every single feature and all possible pairs of features. We
- /// store feature tuples in the 3-D collection (where axes are "dimension",
- /// "feature", and "all combinations which includes this feature"), and for
- /// every two feature (e.g. "A" and "B") we generate both ("A", "B") and
- /// ("B", "A") pairs. This data structure extremely reduces the amount of
- /// time needed to calculate coverage for a single test case (this
- /// calculation is the most time-consuming part of the algorithm).
- ///
- ///
- /// Then the algorithm picks one tuple from the uncovered tuple, creates a
- /// test case that covers this tuple, and then removes this tuple and all
- /// other tuples covered by this test case from the collection of uncovered
- /// tuples.
- ///
- ///
- /// Picking a tuple to cover.
- ///
- ///
- /// There are no any special rules defined for picking tuples to cover. We
- /// just pick them one by one, in the order they were generated.
- ///
- ///
- /// Test generation.
- ///
- ///
- /// Test generation starts from creating a completely random test case which
- /// covers, nevertheless, previously selected tuple. Then the algorithm
- /// tries to maximize number of tuples which this test covers.
- ///
- ///
- /// Test generation and maximization process repeats seven times for every
- /// selected tuple and then the algorithm picks the best test case ("seven"
- /// is a magic number which provides good results in acceptable time).
- ///
- /// Maximizing test coverage.
- ///
- /// To maximize tests coverage, the algorithm walks thru the list of mutable
- /// dimensions (mutable dimension is a dimension that are not included in
- /// the previously selected tuple). Then for every dimension, the algorithm
- /// walks thru the list of features and checks if this feature provides
- /// better coverage than randomly selected feature, and if yes keeps this
- /// feature.
- ///
- ///
- /// This process repeats while it shows progress. If the last iteration
- /// doesn't improve coverage, the process ends.
- ///
- ///
- /// In addition, for better results, before start every iteration, the
- /// algorithm "scrambles" dimensions - so for every iteration dimension
- /// probes in a different order.
- ///
- ///
- private class PairwiseTestCaseGenerator
+ ///
+ /// An array which contains information about dimensions. Each element of
+ /// this array represents a number of features in the specific dimension.
+ ///
+ ///
+ /// A set of test cases.
+ ///
+ public List GetTestCases(int[] dimensions)
{
- private FleaRand? prng;
-
- private int[]? dimensions;
-
- private List[][]? uncoveredTuples;
-
- ///
- /// Creates a set of test cases for specified dimensions.
- ///
- ///
- /// An array which contains information about dimensions. Each element of
- /// this array represents a number of features in the specific dimension.
- ///
- ///
- /// A set of test cases.
- ///
- public List GetTestCases(int[] dimensions)
- {
- this.prng = new FleaRand(15485863);
- this.dimensions = dimensions;
+ this.prng = new FleaRand(15485863);
+ this.dimensions = dimensions;
- this.CreateAllTuples();
+ this.CreateAllTuples();
- List testCases = new List();
+ List testCases = new List();
+
+ while (true)
+ {
+ FeatureTuple? tuple = this.GetNextTuple();
- while (true)
+ if (tuple is null)
{
- FeatureTuple? tuple = this.GetNextTuple();
+ break;
+ }
- if (tuple is null)
- {
- break;
- }
+ TestCaseInfo? testCase = this.CreateTestCase(tuple);
- TestCaseInfo? testCase = this.CreateTestCase(tuple);
+ this.RemoveTuplesCoveredByTest(testCase);
- this.RemoveTuplesCoveredByTest(testCase);
+ testCases.Add(testCase);
+ }
- testCases.Add(testCase);
- }
+ return testCases;
+ }
- return testCases;
- }
+ private int GetNextRandomNumber()
+ {
+ return (int)(this.prng!.Next() >> 1);
+ }
- private int GetNextRandomNumber()
- {
- return (int)(this.prng!.Next() >> 1);
- }
+ private void CreateAllTuples()
+ {
+ this.uncoveredTuples = new List[this.dimensions!.Length][];
- private void CreateAllTuples()
+ for (int d = 0; d < this.dimensions.Length; d++)
{
- this.uncoveredTuples = new List[this.dimensions!.Length][];
+ this.uncoveredTuples[d] = new List[this.dimensions[d]];
- for (int d = 0; d < this.dimensions.Length; d++)
+ for (int f = 0; f < this.dimensions[d]; f++)
{
- this.uncoveredTuples[d] = new List[this.dimensions[d]];
-
- for (int f = 0; f < this.dimensions[d]; f++)
- {
- this.uncoveredTuples[d][f] = this.CreateTuples(d, f);
- }
+ this.uncoveredTuples[d][f] = this.CreateTuples(d, f);
}
}
+ }
- private List CreateTuples(int dimension, int feature)
- {
- List result = new List();
-
- result.Add(new FeatureTuple(new FeatureInfo(dimension, feature)));
-
- for (int d = 0; d < this.dimensions!.Length; d++)
- {
- if (d != dimension)
- {
- for (int f = 0; f < this.dimensions[d]; f++)
- {
- result.Add(new FeatureTuple(new FeatureInfo(dimension, feature), new FeatureInfo(d, f)));
- }
- }
- }
+ private List CreateTuples(int dimension, int feature)
+ {
+ List result = new List();
- return result;
- }
+ result.Add(new FeatureTuple(new FeatureInfo(dimension, feature)));
- private FeatureTuple? GetNextTuple()
+ for (int d = 0; d < this.dimensions!.Length; d++)
{
- for (int d = 0; d < this.uncoveredTuples!.Length; d++)
+ if (d != dimension)
{
- for (int f = 0; f < this.uncoveredTuples[d].Length; f++)
+ for (int f = 0; f < this.dimensions[d]; f++)
{
- List tuples = this.uncoveredTuples[d][f];
-
- if (tuples.Count > 0)
- {
- FeatureTuple tuple = tuples[0];
- tuples.RemoveAt(0);
- return tuple;
- }
+ result.Add(new FeatureTuple(new FeatureInfo(dimension, feature), new FeatureInfo(d, f)));
}
}
-
- return null;
}
- private TestCaseInfo CreateTestCase(FeatureTuple tuple)
- {
- TestCaseInfo? bestTestCase = null;
- int bestCoverage = -1;
+ return result;
+ }
- for (int i = 0; i < 7; i++)
+ private FeatureTuple? GetNextTuple()
+ {
+ for (int d = 0; d < this.uncoveredTuples!.Length; d++)
+ {
+ for (int f = 0; f < this.uncoveredTuples[d].Length; f++)
{
- TestCaseInfo testCase = this.CreateRandomTestCase(tuple);
-
- int coverage = this.MaximizeCoverage(testCase, tuple);
+ List tuples = this.uncoveredTuples[d][f];
- if (coverage > bestCoverage)
+ if (tuples.Count > 0)
{
- bestTestCase = testCase;
- bestCoverage = coverage;
+ FeatureTuple tuple = tuples[0];
+ tuples.RemoveAt(0);
+ return tuple;
}
}
-
- return bestTestCase!;
}
- private TestCaseInfo CreateRandomTestCase(FeatureTuple tuple)
+ return null;
+ }
+
+ private TestCaseInfo CreateTestCase(FeatureTuple tuple)
+ {
+ TestCaseInfo? bestTestCase = null;
+ int bestCoverage = -1;
+
+ for (int i = 0; i < 7; i++)
{
- TestCaseInfo result = new TestCaseInfo(this.dimensions!.Length);
+ TestCaseInfo testCase = this.CreateRandomTestCase(tuple);
- for (int d = 0; d < this.dimensions.Length; d++)
- {
- result.Features[d] = this.GetNextRandomNumber() % this.dimensions[d];
- }
+ int coverage = this.MaximizeCoverage(testCase, tuple);
- for (int i = 0; i < tuple.Length; i++)
+ if (coverage > bestCoverage)
{
- result.Features[tuple[i].Dimension] = tuple[i].Feature;
+ bestTestCase = testCase;
+ bestCoverage = coverage;
}
+ }
- return result;
+ return bestTestCase!;
+ }
+
+ private TestCaseInfo CreateRandomTestCase(FeatureTuple tuple)
+ {
+ TestCaseInfo result = new TestCaseInfo(this.dimensions!.Length);
+
+ for (int d = 0; d < this.dimensions.Length; d++)
+ {
+ result.Features[d] = this.GetNextRandomNumber() % this.dimensions[d];
}
- private int MaximizeCoverage(TestCaseInfo testCase, FeatureTuple tuple)
+ for (int i = 0; i < tuple.Length; i++)
{
- // It starts with one because we always have one tuple which is covered by the test.
- int totalCoverage = 1;
- int[] mutableDimensions = this.GetMutableDimensions(tuple);
+ result.Features[tuple[i].Dimension] = tuple[i].Feature;
+ }
- while (true)
- {
- bool progress = false;
+ return result;
+ }
- this.ScrambleDimensions(mutableDimensions);
+ private int MaximizeCoverage(TestCaseInfo testCase, FeatureTuple tuple)
+ {
+ // It starts with one because we always have one tuple which is covered by the test.
+ int totalCoverage = 1;
+ int[] mutableDimensions = this.GetMutableDimensions(tuple);
- for (int i = 0; i < mutableDimensions.Length; i++)
- {
- int d = mutableDimensions[i];
+ while (true)
+ {
+ bool progress = false;
- int bestCoverage = this.CountTuplesCoveredByTest(testCase, d, testCase.Features[d]);
+ this.ScrambleDimensions(mutableDimensions);
- int newCoverage = this.MaximizeCoverageForDimension(testCase, d, bestCoverage);
+ for (int i = 0; i < mutableDimensions.Length; i++)
+ {
+ int d = mutableDimensions[i];
- totalCoverage += newCoverage;
+ int bestCoverage = this.CountTuplesCoveredByTest(testCase, d, testCase.Features[d]);
- if (newCoverage > bestCoverage)
- {
- progress = true;
- }
- }
+ int newCoverage = this.MaximizeCoverageForDimension(testCase, d, bestCoverage);
- if (!progress)
+ totalCoverage += newCoverage;
+
+ if (newCoverage > bestCoverage)
{
- return totalCoverage;
+ progress = true;
}
}
- }
-
- private int[] GetMutableDimensions(FeatureTuple tuple)
- {
- List result = new List();
- bool[] immutableDimensions = new bool[this.dimensions!.Length];
-
- for (int i = 0; i < tuple.Length; i++)
+ if (!progress)
{
- immutableDimensions[tuple[i].Dimension] = true;
+ return totalCoverage;
}
+ }
+ }
- for (int d = 0; d < this.dimensions.Length; d++)
- {
- if (!immutableDimensions[d])
- {
- result.Add(d);
- }
- }
+ private int[] GetMutableDimensions(FeatureTuple tuple)
+ {
+ List result = new List();
- return result.ToArray();
+ bool[] immutableDimensions = new bool[this.dimensions!.Length];
+
+ for (int i = 0; i < tuple.Length; i++)
+ {
+ immutableDimensions[tuple[i].Dimension] = true;
}
- private void ScrambleDimensions(int[] dimensions)
+ for (int d = 0; d < this.dimensions.Length; d++)
{
- for (int i = 0; i < dimensions.Length; i++)
+ if (!immutableDimensions[d])
{
- int j = this.GetNextRandomNumber() % dimensions.Length;
- int t = dimensions[i];
- dimensions[i] = dimensions[j];
- dimensions[j] = t;
+ result.Add(d);
}
}
- private int MaximizeCoverageForDimension(TestCaseInfo testCase, int dimension, int bestCoverage)
+ return result.ToArray();
+ }
+
+ private void ScrambleDimensions(int[] dimensions)
+ {
+ for (int i = 0; i < dimensions.Length; i++)
{
- List bestFeatures = new List(this.dimensions![dimension]);
+ int j = this.GetNextRandomNumber() % dimensions.Length;
+ int t = dimensions[i];
+ dimensions[i] = dimensions[j];
+ dimensions[j] = t;
+ }
+ }
- for (int f = 0; f < this.dimensions[dimension]; f++)
- {
- testCase.Features[dimension] = f;
+ private int MaximizeCoverageForDimension(TestCaseInfo testCase, int dimension, int bestCoverage)
+ {
+ List bestFeatures = new List(this.dimensions![dimension]);
- int coverage = this.CountTuplesCoveredByTest(testCase, dimension, f);
+ for (int f = 0; f < this.dimensions[dimension]; f++)
+ {
+ testCase.Features[dimension] = f;
- if (coverage >= bestCoverage)
- {
- if (coverage > bestCoverage)
- {
- bestCoverage = coverage;
- bestFeatures.Clear();
- }
+ int coverage = this.CountTuplesCoveredByTest(testCase, dimension, f);
- bestFeatures.Add(f);
+ if (coverage >= bestCoverage)
+ {
+ if (coverage > bestCoverage)
+ {
+ bestCoverage = coverage;
+ bestFeatures.Clear();
}
+
+ bestFeatures.Add(f);
}
+ }
- testCase.Features[dimension] = bestFeatures[this.GetNextRandomNumber() % bestFeatures.Count];
+ testCase.Features[dimension] = bestFeatures[this.GetNextRandomNumber() % bestFeatures.Count];
- return bestCoverage;
- }
+ return bestCoverage;
+ }
- private int CountTuplesCoveredByTest(TestCaseInfo testCase, int dimension, int feature)
- {
- int result = 0;
+ private int CountTuplesCoveredByTest(TestCaseInfo testCase, int dimension, int feature)
+ {
+ int result = 0;
- List tuples = this.uncoveredTuples![dimension][feature];
+ List tuples = this.uncoveredTuples![dimension][feature];
- for (int i = 0; i < tuples.Count; i++)
+ for (int i = 0; i < tuples.Count; i++)
+ {
+ if (testCase.IsTupleCovered(tuples[i]))
{
- if (testCase.IsTupleCovered(tuples[i]))
- {
- result++;
- }
+ result++;
}
-
- return result;
}
- private void RemoveTuplesCoveredByTest(TestCaseInfo testCase)
+ return result;
+ }
+
+ private void RemoveTuplesCoveredByTest(TestCaseInfo testCase)
+ {
+ for (int d = 0; d < this.uncoveredTuples!.Length; d++)
{
- for (int d = 0; d < this.uncoveredTuples!.Length; d++)
+ for (int f = 0; f < this.uncoveredTuples[d].Length; f++)
{
- for (int f = 0; f < this.uncoveredTuples[d].Length; f++)
- {
- List tuples = this.uncoveredTuples[d][f];
+ List tuples = this.uncoveredTuples[d][f];
- for (int i = tuples.Count - 1; i >= 0; i--)
+ for (int i = tuples.Count - 1; i >= 0; i--)
+ {
+ if (testCase.IsTupleCovered(tuples[i]))
{
- if (testCase.IsTupleCovered(tuples[i]))
- {
- tuples.RemoveAt(i);
- }
+ tuples.RemoveAt(i);
}
}
}
diff --git a/src/Xunit.Combinatorial/PrivateErrorHelpers.cs b/src/Xunit.Combinatorial/PrivateErrorHelpers.cs
index 26698b9..d894014 100644
--- a/src/Xunit.Combinatorial/PrivateErrorHelpers.cs
+++ b/src/Xunit.Combinatorial/PrivateErrorHelpers.cs
@@ -4,43 +4,42 @@
using System.Globalization;
using System.Reflection;
-namespace Xunit
+namespace Xunit;
+
+///
+/// Common utility methods used by the various error detection and reporting classes.
+///
+internal static class PrivateErrorHelpers
{
///
- /// Common utility methods used by the various error detection and reporting classes.
+ /// Trims away a given surrounding type, returning just the generic type argument,
+ /// if the given type is in fact a generic type with just one type argument and
+ /// the generic type matches a given wrapper type. Otherwise, it returns the original type.
///
- internal static class PrivateErrorHelpers
+ /// The type to trim, or return unmodified.
+ /// The SomeType<> generic type definition to trim away from if it is present.
+ /// , if it is not a generic type instance of ; otherwise the type argument.
+ internal static Type TrimGenericWrapper(Type type, Type wrapper)
{
- ///
- /// Trims away a given surrounding type, returning just the generic type argument,
- /// if the given type is in fact a generic type with just one type argument and
- /// the generic type matches a given wrapper type. Otherwise, it returns the original type.
- ///
- /// The type to trim, or return unmodified.
- /// The SomeType<> generic type definition to trim away from if it is present.
- /// , if it is not a generic type instance of ; otherwise the type argument.
- internal static Type TrimGenericWrapper(Type type, Type wrapper)
+ Type[] typeArgs;
+ if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == wrapper && (typeArgs = type.GetTypeInfo().GetGenericArguments()).Length == 1)
{
- Type[] typeArgs;
- if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == wrapper && (typeArgs = type.GetTypeInfo().GetGenericArguments()).Length == 1)
- {
- return typeArgs[0];
- }
- else
- {
- return type;
- }
+ return typeArgs[0];
}
-
- ///
- /// Helper method that formats string arguments.
- ///
- /// The unformatted string.
- /// The formatting arguments.
- /// The formatted string.
- internal static string Format(string format, params object[] arguments)
+ else
{
- return string.Format(CultureInfo.CurrentCulture, format, arguments);
+ return type;
}
}
+
+ ///
+ /// Helper method that formats string arguments.
+ ///
+ /// The unformatted string.
+ /// The formatting arguments.
+ /// The formatted string.
+ internal static string Format(string format, params object[] arguments)
+ {
+ return string.Format(CultureInfo.CurrentCulture, format, arguments);
+ }
}
diff --git a/src/Xunit.Combinatorial/Requires.cs b/src/Xunit.Combinatorial/Requires.cs
index 36bbeea..15d0e40 100644
--- a/src/Xunit.Combinatorial/Requires.cs
+++ b/src/Xunit.Combinatorial/Requires.cs
@@ -7,409 +7,404 @@
#pragma warning disable SA1611 // Element parameters must be documented
-namespace Xunit
+namespace Xunit;
+
+///
+/// Common runtime checks that throw ArgumentExceptions upon failure.
+///
+internal static class Requires
{
///
- /// Common runtime checks that throw ArgumentExceptions upon failure.
+ /// Throws an exception if the specified parameter's value is null.
///
- internal static class Requires
+ /// The type of the parameter.
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// The value of the parameter.
+ /// Thrown if is .
+ [DebuggerStepThrough]
+ public static T NotNull(T value, string parameterName)
+ where T : class // ensures value-types aren't passed to a null checking method
{
- ///
- /// Throws an exception if the specified parameter's value is null.
- ///
- /// The type of the parameter.
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// The value of the parameter.
- /// Thrown if is .
- [DebuggerStepThrough]
- public static T NotNull(T value, string parameterName)
- where T : class // ensures value-types aren't passed to a null checking method
+ if (value is null)
{
- if (value is null)
- {
- throw new ArgumentNullException(parameterName);
- }
+ throw new ArgumentNullException(parameterName);
+ }
- return value;
+ return value;
+ }
+
+ ///
+ /// Throws an exception if the specified parameter's value is IntPtr.Zero.
+ ///
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// The value of the parameter.
+ /// Thrown if is IntPtr.Zero.
+ [DebuggerStepThrough]
+ public static IntPtr NotNull(IntPtr value, string parameterName)
+ {
+ if (value == IntPtr.Zero)
+ {
+ throw new ArgumentNullException(parameterName);
}
- ///
- /// Throws an exception if the specified parameter's value is IntPtr.Zero.
- ///
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// The value of the parameter.
- /// Thrown if is IntPtr.Zero.
- [DebuggerStepThrough]
- public static IntPtr NotNull(IntPtr value, string parameterName)
+ return value;
+ }
+
+ ///
+ /// Throws an exception if the specified parameter's value is null.
+ ///
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// Thrown if is .
+ ///
+ /// This method allows async methods to use Requires.NotNull without having to assign the result
+ /// to local variables to avoid C# warnings.
+ ///
+ [DebuggerStepThrough]
+ public static void NotNull(System.Threading.Tasks.Task value, string parameterName)
+ {
+ if (value is null)
{
- if (value == IntPtr.Zero)
- {
- throw new ArgumentNullException(parameterName);
- }
+ throw new ArgumentNullException(parameterName);
+ }
+ }
- return value;
+ ///
+ /// Throws an exception if the specified parameter's value is null.
+ ///
+ /// The type of the return value of the task.
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// Thrown if is .
+ ///
+ /// This method allows async methods to use Requires.NotNull without having to assign the result
+ /// to local variables to avoid C# warnings.
+ ///
+ [DebuggerStepThrough]
+ public static void NotNull(System.Threading.Tasks.Task value, string parameterName)
+ {
+ if (value is null)
+ {
+ throw new ArgumentNullException(parameterName);
}
+ }
-#if !NET35
- ///
- /// Throws an exception if the specified parameter's value is null.
- ///
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// Thrown if is .
- ///
- /// This method allows async methods to use Requires.NotNull without having to assign the result
- /// to local variables to avoid C# warnings.
- ///
- [DebuggerStepThrough]
- public static void NotNull(System.Threading.Tasks.Task value, string parameterName)
+ ///
+ /// Throws an exception if the specified parameter's value is null.
+ ///
+ /// The type of the parameter.
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// The value of the parameter.
+ /// Thrown if is .
+ ///
+ /// This method exists for callers who themselves only know the type as a generic parameter which
+ /// may or may not be a class, but certainly cannot be null.
+ ///
+ [DebuggerStepThrough]
+ public static T NotNullAllowStructs(T value, string parameterName)
+ {
+ if (value is null)
{
- if (value is null)
- {
- throw new ArgumentNullException(parameterName);
- }
+ throw new ArgumentNullException(parameterName);
}
- ///
- /// Throws an exception if the specified parameter's value is null.
- ///
- /// The type of the return value of the task.
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// Thrown if is .
- ///
- /// This method allows async methods to use Requires.NotNull without having to assign the result
- /// to local variables to avoid C# warnings.
- ///
- [DebuggerStepThrough]
- public static void NotNull(System.Threading.Tasks.Task value, string parameterName)
+ return value;
+ }
+
+ ///
+ /// Throws an exception if the specified parameter's value is null or empty.
+ ///
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// Thrown if is or empty.
+ [DebuggerStepThrough]
+ public static void NotNullOrEmpty(string value, string parameterName)
+ {
+ // To the guy that is doing random code cleaning:
+ // Consider the perfomance when changing the code to delegate to NotNull.
+ // In general do not chain call to another function, check first and return as earlier as possible.
+ if (value is null)
{
- if (value is null)
- {
- throw new ArgumentNullException(parameterName);
- }
+ throw new ArgumentNullException(parameterName);
}
-#endif
-
- ///
- /// Throws an exception if the specified parameter's value is null.
- ///
- /// The type of the parameter.
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// The value of the parameter.
- /// Thrown if is .
- ///
- /// This method exists for callers who themselves only know the type as a generic parameter which
- /// may or may not be a class, but certainly cannot be null.
- ///
- [DebuggerStepThrough]
- public static T NotNullAllowStructs(T value, string parameterName)
+
+ if (value.Length == 0 || value[0] == '\0')
{
- if (value is null)
- {
- throw new ArgumentNullException(parameterName);
- }
+ throw new ArgumentException(Format(Strings.Argument_EmptyString, parameterName), parameterName);
+ }
+ }
- return value;
+ ///
+ /// Throws an exception if the specified parameter's value is null, empty, or whitespace.
+ ///
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// Thrown if is or empty.
+ [DebuggerStepThrough]
+ public static void NotNullOrWhiteSpace(string value, string parameterName)
+ {
+ // To the guy that is doing random code cleaning:
+ // Consider the perfomance when changing the code to delegate to NotNull.
+ // In general do not chain call to another function, check first and return as earlier as possible.
+ if (value is null)
+ {
+ throw new ArgumentNullException(parameterName);
}
- ///
- /// Throws an exception if the specified parameter's value is null or empty.
- ///
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// Thrown if is or empty.
- [DebuggerStepThrough]
- public static void NotNullOrEmpty(string value, string parameterName)
+ if (value.Length == 0 || value[0] == '\0')
{
- // To the guy that is doing random code cleaning:
- // Consider the perfomance when changing the code to delegate to NotNull.
- // In general do not chain call to another function, check first and return as earlier as possible.
- if (value is null)
- {
- throw new ArgumentNullException(parameterName);
- }
+ throw new ArgumentException(Format(Strings.Argument_EmptyString, parameterName), parameterName);
+ }
- if (value.Length == 0 || value[0] == '\0')
- {
- throw new ArgumentException(Format(Strings.Argument_EmptyString, parameterName), parameterName);
- }
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ throw new ArgumentException(Format(Strings.Argument_Whitespace, parameterName));
}
+ }
-#if !NET35
- ///
- /// Throws an exception if the specified parameter's value is null, empty, or whitespace.
- ///
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// Thrown if is or empty.
- [DebuggerStepThrough]
- public static void NotNullOrWhiteSpace(string value, string parameterName)
+ ///
+ /// Throws an exception if the specified parameter's value is null,
+ /// has no elements or has an element with a null value.
+ ///
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// Thrown if the tested condition is false.
+ [DebuggerStepThrough]
+ public static void NotNullOrEmpty(System.Collections.IEnumerable values, string parameterName)
+ {
+ // To the guy that is doing random code cleaning:
+ // Consider the perfomance when changing the code to delegate to NotNull.
+ // In general do not chain call to another function, check first and return as earlier as possible.
+ if (values is null)
{
- // To the guy that is doing random code cleaning:
- // Consider the perfomance when changing the code to delegate to NotNull.
- // In general do not chain call to another function, check first and return as earlier as possible.
- if (value is null)
- {
- throw new ArgumentNullException(parameterName);
- }
+ throw new ArgumentNullException(parameterName);
+ }
- if (value.Length == 0 || value[0] == '\0')
- {
- throw new ArgumentException(Format(Strings.Argument_EmptyString, parameterName), parameterName);
- }
+ ICollection? collection = values as ICollection;
- if (string.IsNullOrWhiteSpace(value))
+ if (collection is not null)
+ {
+ if (collection.Count > 0)
{
- throw new ArgumentException(Format(Strings.Argument_Whitespace, parameterName));
+ return;
}
+
+ throw new ArgumentException(Format(Strings.Argument_EmptyArray, parameterName), parameterName);
}
-#endif
-
- ///
- /// Throws an exception if the specified parameter's value is null,
- /// has no elements or has an element with a null value.
- ///
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// Thrown if the tested condition is false.
- [DebuggerStepThrough]
- public static void NotNullOrEmpty(System.Collections.IEnumerable values, string parameterName)
+
+ IEnumerator enumerator = values.GetEnumerator();
+
+ using (enumerator as IDisposable)
{
- // To the guy that is doing random code cleaning:
- // Consider the perfomance when changing the code to delegate to NotNull.
- // In general do not chain call to another function, check first and return as earlier as possible.
- if (values is null)
+ if (enumerator.MoveNext())
{
- throw new ArgumentNullException(parameterName);
+ return;
}
+ }
- ICollection? collection = values as ICollection;
-
- if (collection is not null)
- {
- if (collection.Count > 0)
- {
- return;
- }
+ throw new ArgumentException(Format(Strings.Argument_EmptyArray, parameterName), parameterName);
+ }
- throw new ArgumentException(Format(Strings.Argument_EmptyArray, parameterName), parameterName);
- }
+ ///
+ /// Throws an exception if the specified parameter's value is null,
+ /// has no elements or has an element with a null value.
+ ///
+ /// The type of the elements in the sequence.
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// Thrown if the tested condition is false.
+ [DebuggerStepThrough]
+ public static void NotNullEmptyOrNullElements(IEnumerable values, string parameterName)
+ where T : class // ensures value-types aren't passed to a null checking method
+ {
+ NotNull(values, parameterName);
- IEnumerator enumerator = values.GetEnumerator();
+ bool hasElements = false;
+ foreach (T value in values)
+ {
+ hasElements = true;
- using (enumerator as IDisposable)
+ if (value is null)
{
- if (enumerator.MoveNext())
- {
- return;
- }
+ throw new ArgumentException(Format(Strings.Argument_NullElement, parameterName), parameterName);
}
+ }
+ if (!hasElements)
+ {
throw new ArgumentException(Format(Strings.Argument_EmptyArray, parameterName), parameterName);
}
+ }
- ///
- /// Throws an exception if the specified parameter's value is null,
- /// has no elements or has an element with a null value.
- ///
- /// The type of the elements in the sequence.
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// Thrown if the tested condition is false.
- [DebuggerStepThrough]
- public static void NotNullEmptyOrNullElements(IEnumerable values, string parameterName)
- where T : class // ensures value-types aren't passed to a null checking method
+ ///
+ /// Throws an exception if the specified parameter's value is not null
+ /// and has an element with a null value.
+ ///
+ /// The type of the elements in the sequence.
+ /// The value of the argument.
+ /// The name of the parameter to include in any thrown exception.
+ /// Thrown if the tested condition is false.
+ [DebuggerStepThrough]
+ public static void NullOrNotNullElements(IEnumerable values, string parameterName)
+ {
+ if (values is not null)
{
- NotNull(values, parameterName);
-
- bool hasElements = false;
foreach (T value in values)
{
- hasElements = true;
-
if (value is null)
{
throw new ArgumentException(Format(Strings.Argument_NullElement, parameterName), parameterName);
}
}
-
- if (!hasElements)
- {
- throw new ArgumentException(Format(Strings.Argument_EmptyArray, parameterName), parameterName);
- }
}
+ }
- ///
- /// Throws an exception if the specified parameter's value is not null
- /// and has an element with a null value.
- ///
- /// The type of the elements in the sequence.
- /// The value of the argument.
- /// The name of the parameter to include in any thrown exception.
- /// Thrown if the tested condition is false.
- [DebuggerStepThrough]
- public static void NullOrNotNullElements(IEnumerable values, string parameterName)
+ ///
+ /// Throws an if a condition does not evaluate to true.
+ ///
+ [DebuggerStepThrough]
+ public static void Range(bool condition, string parameterName, string? message = null)
+ {
+ if (!condition)
{
- if (values is not null)
- {
- foreach (T value in values)
- {
- if (value is null)
- {
- throw new ArgumentException(Format(Strings.Argument_NullElement, parameterName), parameterName);
- }
- }
- }
+ FailRange(parameterName, message);
}
+ }
- ///
- /// Throws an if a condition does not evaluate to true.
- ///
- [DebuggerStepThrough]
- public static void Range(bool condition, string parameterName, string? message = null)
+ ///
+ /// Throws an if a condition does not evaluate to true.
+ ///
+ /// Nothing. This method always throws.
+ [DebuggerStepThrough]
+ public static Exception FailRange(string parameterName, string? message = null)
+ {
+ if (string.IsNullOrEmpty(message))
{
- if (!condition)
- {
- FailRange(parameterName, message);
- }
+ throw new ArgumentOutOfRangeException(parameterName);
}
-
- ///
- /// Throws an if a condition does not evaluate to true.
- ///
- /// Nothing. This method always throws.
- [DebuggerStepThrough]
- public static Exception FailRange(string parameterName, string? message = null)
+ else
{
- if (string.IsNullOrEmpty(message))
- {
- throw new ArgumentOutOfRangeException(parameterName);
- }
- else
- {
- throw new ArgumentOutOfRangeException(parameterName, message);
- }
+ throw new ArgumentOutOfRangeException(parameterName, message);
}
+ }
- ///
- /// Throws an ArgumentException if a condition does not evaluate to true.
- ///
- [DebuggerStepThrough]
- public static void Argument(bool condition, string parameterName, string message)
+ ///
+ /// Throws an ArgumentException if a condition does not evaluate to true.
+ ///
+ [DebuggerStepThrough]
+ public static void Argument(bool condition, string parameterName, string message)
+ {
+ if (!condition)
{
- if (!condition)
- {
- throw new ArgumentException(message, parameterName);
- }
+ throw new ArgumentException(message, parameterName);
}
+ }
- ///
- /// Throws an ArgumentException if a condition does not evaluate to true.
- ///
- [DebuggerStepThrough]
- public static void Argument(bool condition, string parameterName, string message, object arg1)
+ ///
+ /// Throws an ArgumentException if a condition does not evaluate to true.
+ ///
+ [DebuggerStepThrough]
+ public static void Argument(bool condition, string parameterName, string message, object arg1)
+ {
+ if (!condition)
{
- if (!condition)
- {
- throw new ArgumentException(Format(message, arg1), parameterName);
- }
+ throw new ArgumentException(Format(message, arg1), parameterName);
}
+ }
- ///
- /// Throws an ArgumentException if a condition does not evaluate to true.
- ///
- [DebuggerStepThrough]
- public static void Argument(bool condition, string parameterName, string message, object arg1, object arg2)
+ ///
+ /// Throws an ArgumentException if a condition does not evaluate to true.
+ ///
+ [DebuggerStepThrough]
+ public static void Argument(bool condition, string parameterName, string message, object arg1, object arg2)
+ {
+ if (!condition)
{
- if (!condition)
- {
- throw new ArgumentException(Format(message, arg1, arg2), parameterName);
- }
+ throw new ArgumentException(Format(message, arg1, arg2), parameterName);
}
+ }
- ///
- /// Throws an ArgumentException if a condition does not evaluate to true.
- ///
- [DebuggerStepThrough]
- public static void Argument(bool condition, string parameterName, string message, params object[] args)
+ ///
+ /// Throws an ArgumentException if a condition does not evaluate to true.
+ ///
+ [DebuggerStepThrough]
+ public static void Argument(bool condition, string parameterName, string message, params object[] args)
+ {
+ if (!condition)
{
- if (!condition)
- {
- throw new ArgumentException(Format(message, args), parameterName);
- }
+ throw new ArgumentException(Format(message, args), parameterName);
}
+ }
- ///
- /// Validates some expression describing the acceptable condition for an argument evaluates to true.
- ///
- /// The expression that must evaluate to true to avoid an .
- /// Name of the parameter.
- /// The unformatted message.
- /// Formatting arguments.
- [DebuggerStepThrough]
- public static void That(bool condition, string parameterName, string unformattedMessage, params object[] args)
+ ///
+ /// Validates some expression describing the acceptable condition for an argument evaluates to true.
+ ///
+ /// The expression that must evaluate to true to avoid an .
+ /// Name of the parameter.
+ /// The unformatted message.
+ /// Formatting arguments.
+ [DebuggerStepThrough]
+ public static void That(bool condition, string parameterName, string unformattedMessage, params object[] args)
+ {
+ if (!condition)
{
- if (!condition)
- {
- throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, unformattedMessage, args), parameterName);
- }
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, unformattedMessage, args), parameterName);
}
+ }
- ///
- /// Validates some expression describing the acceptable condition for an argument evaluates to true.
- ///
- /// The expression that must evaluate to true to avoid an .
- /// The message to include with the exception.
- [DebuggerStepThrough]
- public static void ValidState(bool condition, string message)
+ ///
+ /// Validates some expression describing the acceptable condition for an argument evaluates to true.
+ ///
+ /// The expression that must evaluate to true to avoid an .
+ /// The message to include with the exception.
+ [DebuggerStepThrough]
+ public static void ValidState(bool condition, string message)
+ {
+ if (!condition)
{
- if (!condition)
- {
- throw new InvalidOperationException(message);
- }
+ throw new InvalidOperationException(message);
}
+ }
- ///
- /// Throws an ArgumentException.
- ///
- /// Nothing. It always throws.
- [DebuggerStepThrough]
- public static Exception Fail(string message)
- {
- throw new ArgumentException(message);
- }
+ ///
+ /// Throws an ArgumentException.
+ ///
+ /// Nothing. It always throws.
+ [DebuggerStepThrough]
+ public static Exception Fail(string message)
+ {
+ throw new ArgumentException(message);
+ }
- ///
- /// Throws an ArgumentException.
- ///
- /// Nothing. It always throws.
- [DebuggerStepThrough]
- public static Exception Fail(string unformattedMessage, params object[] args)
- {
- throw Fail(Format(unformattedMessage, args));
- }
+ ///
+ /// Throws an ArgumentException.
+ ///
+ /// Nothing. It always throws.
+ [DebuggerStepThrough]
+ public static Exception Fail(string unformattedMessage, params object[] args)
+ {
+ throw Fail(Format(unformattedMessage, args));
+ }
- ///
- /// Throws an ArgumentException.
- ///
- /// Nothing. This method always throws. But the signature allows calling code to "throw" this method for C# syntax reasons.
- [DebuggerStepThrough]
- public static Exception Fail(Exception innerException, string unformattedMessage, params object[] args)
- {
- throw new ArgumentException(Format(unformattedMessage, args), innerException);
- }
+ ///
+ /// Throws an ArgumentException.
+ ///
+ /// Nothing. This method always throws. But the signature allows calling code to "throw" this method for C# syntax reasons.
+ [DebuggerStepThrough]
+ public static Exception Fail(Exception innerException, string unformattedMessage, params object[] args)
+ {
+ throw new ArgumentException(Format(unformattedMessage, args), innerException);
+ }
- ///
- /// Helper method that formats string arguments.
- ///
- /// The formatted string.
- private static string Format(string format, params object[] arguments)
- {
- return PrivateErrorHelpers.Format(format, arguments);
- }
+ ///
+ /// Helper method that formats string arguments.
+ ///
+ /// The formatted string.
+ private static string Format(string format, params object[] arguments)
+ {
+ return PrivateErrorHelpers.Format(format, arguments);
}
}
diff --git a/src/Xunit.Combinatorial/Strings.Designer.cs b/src/Xunit.Combinatorial/Strings.Designer.cs
index 0f72dbd..c2009b4 100644
--- a/src/Xunit.Combinatorial/Strings.Designer.cs
+++ b/src/Xunit.Combinatorial/Strings.Designer.cs
@@ -8,147 +8,146 @@
//
//------------------------------------------------------------------------------
-namespace Xunit {
- using System;
- using System.Reflection;
+namespace Xunit;
+using System;
+using System.Reflection;
+
+
+///
+/// A strongly-typed resource class, for looking up localized strings, etc.
+///
+// This class was auto-generated by the StronglyTypedResourceBuilder
+// class via a tool like ResGen or Visual Studio.
+// To add or remove a member, edit your .ResX file then rerun ResGen
+// with the /str option, or rebuild your VS project.
+[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+internal class Strings {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Strings() {
+ }
///
- /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// Returns the cached ResourceManager instance used by this class.
///
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class Strings {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal Strings() {
- }
-
- ///
- /// Returns the cached ResourceManager instance used by this class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xunit.Strings", typeof(Strings).GetTypeInfo().Assembly);
- resourceMan = temp;
- }
- return resourceMan;
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xunit.Strings", typeof(Strings).GetTypeInfo().Assembly);
+ resourceMan = temp;
}
+ return resourceMan;
}
-
- ///
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
}
-
- ///
- /// Looks up a localized string similar to '{0}' must contain at least one element..
- ///
- internal static string Argument_EmptyArray {
- get {
- return ResourceManager.GetString("Argument_EmptyArray", resourceCulture);
- }
+ set {
+ resourceCulture = value;
}
-
- ///
- /// Looks up a localized string similar to '{0}' cannot be an empty string ("") or start with the null character..
- ///
- internal static string Argument_EmptyString {
- get {
- return ResourceManager.GetString("Argument_EmptyString", resourceCulture);
- }
+ }
+
+ ///
+ /// Looks up a localized string similar to '{0}' must contain at least one element..
+ ///
+ internal static string Argument_EmptyArray {
+ get {
+ return ResourceManager.GetString("Argument_EmptyArray", resourceCulture);
}
-
- ///
- /// Looks up a localized string similar to '{0}' cannot contain a null (Nothing in Visual Basic) element..
- ///
- internal static string Argument_NullElement {
- get {
- return ResourceManager.GetString("Argument_NullElement", resourceCulture);
- }
+ }
+
+ ///
+ /// Looks up a localized string similar to '{0}' cannot be an empty string ("") or start with the null character..
+ ///
+ internal static string Argument_EmptyString {
+ get {
+ return ResourceManager.GetString("Argument_EmptyString", resourceCulture);
}
-
- ///
- /// Looks up a localized string similar to The parameter "{0}" cannot consist entirely of white space characters..
- ///
- internal static string Argument_Whitespace {
- get {
- return ResourceManager.GetString("Argument_Whitespace", resourceCulture);
- }
+ }
+
+ ///
+ /// Looks up a localized string similar to '{0}' cannot contain a null (Nothing in Visual Basic) element..
+ ///
+ internal static string Argument_NullElement {
+ get {
+ return ResourceManager.GetString("Argument_NullElement", resourceCulture);
}
-
- ///
- /// Looks up a localized string similar to An internal error occurred. Please contact customer support..
- ///
- internal static string InternalExceptionMessage {
- get {
- return ResourceManager.GetString("InternalExceptionMessage", resourceCulture);
- }
+ }
+
+ ///
+ /// Looks up a localized string similar to The parameter "{0}" cannot consist entirely of white space characters..
+ ///
+ internal static string Argument_Whitespace {
+ get {
+ return ResourceManager.GetString("Argument_Whitespace", resourceCulture);
}
-
- ///
- /// Looks up a localized string similar to {0} must not exceed the length of the range from {1} to {2}..
- ///
- internal static string MoreRandomValuesRequestedThanPossibleOnes {
- get {
- return ResourceManager.GetString("MoreRandomValuesRequestedThanPossibleOnes", resourceCulture);
- }
+ }
+
+ ///
+ /// Looks up a localized string similar to An internal error occurred. Please contact customer support..
+ ///
+ internal static string InternalExceptionMessage {
+ get {
+ return ResourceManager.GetString("InternalExceptionMessage", resourceCulture);
}
-
- ///
- /// Looks up a localized string similar to Cannot find an instance of the {0} service..
- ///
- internal static string ServiceMissing {
- get {
- return ResourceManager.GetString("ServiceMissing", resourceCulture);
- }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0} must not exceed the length of the range from {1} to {2}..
+ ///
+ internal static string MoreRandomValuesRequestedThanPossibleOnes {
+ get {
+ return ResourceManager.GetString("MoreRandomValuesRequestedThanPossibleOnes", resourceCulture);
}
-
- ///
- /// Looks up a localized string similar to We are unable to generate the desired number of unique random values because too many non-unique random numbers are coming from the random number generator. Try reducing your target count or expanding your allowed range..
- ///
- internal static string TooManyRandomCollisions {
- get {
- return ResourceManager.GetString("TooManyRandomCollisions", resourceCulture);
- }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot find an instance of the {0} service..
+ ///
+ internal static string ServiceMissing {
+ get {
+ return ResourceManager.GetString("ServiceMissing", resourceCulture);
}
-
- ///
- /// Looks up a localized string similar to The value for {0} must be positive..
- ///
- internal static string ValueMustBePositive {
- get {
- return ResourceManager.GetString("ValueMustBePositive", resourceCulture);
- }
+ }
+
+ ///
+ /// Looks up a localized string similar to We are unable to generate the desired number of unique random values because too many non-unique random numbers are coming from the random number generator. Try reducing your target count or expanding your allowed range..
+ ///
+ internal static string TooManyRandomCollisions {
+ get {
+ return ResourceManager.GetString("TooManyRandomCollisions", resourceCulture);
}
-
- ///
- /// Looks up a localized string similar to The value of {0} must not be greater than the value of {1}..
- ///
- internal static string XMustNotBeGreaterThanY {
- get {
- return ResourceManager.GetString("XMustNotBeGreaterThanY", resourceCulture);
- }
+ }
+
+ ///
+ /// Looks up a localized string similar to The value for {0} must be positive..
+ ///
+ internal static string ValueMustBePositive {
+ get {
+ return ResourceManager.GetString("ValueMustBePositive", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The value of {0} must not be greater than the value of {1}..
+ ///
+ internal static string XMustNotBeGreaterThanY {
+ get {
+ return ResourceManager.GetString("XMustNotBeGreaterThanY", resourceCulture);
}
}
}
diff --git a/src/Xunit.Combinatorial/TypeInfoExtensions.cs b/src/Xunit.Combinatorial/TypeInfoExtensions.cs
index 7c04268..431fa5f 100644
--- a/src/Xunit.Combinatorial/TypeInfoExtensions.cs
+++ b/src/Xunit.Combinatorial/TypeInfoExtensions.cs
@@ -3,22 +3,21 @@
using System.Reflection;
-namespace Xunit
+namespace Xunit;
+
+///
+/// Extension methods for the class to emulate older reflection APIs.
+///
+internal static class TypeInfoExtensions
{
///
- /// Extension methods for the class to emulate older reflection APIs.
+ /// Returns the generic type arguments of specified type.
///
- internal static class TypeInfoExtensions
- {
- ///
- /// Returns the generic type arguments of specified type.
- ///
- /// The type whose generic type arguments should be returned.
- /// An array of types.
- ///
- /// This silly method allows the same code to compile against the newer
- /// as well as older Reflection APIs.
- ///
- internal static Type[] GetGenericArguments(this TypeInfo type) => type.GenericTypeArguments;
- }
+ /// The type whose generic type arguments should be returned.
+ /// An array of types.
+ ///
+ /// This silly method allows the same code to compile against the newer
+ /// as well as older Reflection APIs.
+ ///
+ internal static Type[] GetGenericArguments(this TypeInfo type) => type.GenericTypeArguments;
}
diff --git a/src/Xunit.Combinatorial/ValuesUtilities.cs b/src/Xunit.Combinatorial/ValuesUtilities.cs
index bda970a..293c69d 100644
--- a/src/Xunit.Combinatorial/ValuesUtilities.cs
+++ b/src/Xunit.Combinatorial/ValuesUtilities.cs
@@ -4,128 +4,127 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
-namespace Xunit
+namespace Xunit;
+
+///
+/// Utility methods for generating values for test parameters.
+///
+internal static class ValuesUtilities
{
///
- /// Utility methods for generating values for test parameters.
+ /// Gets a sequence of values that should be tested for the specified parameter.
///
- internal static class ValuesUtilities
+ /// The parameter to get possible values for.
+ /// A sequence of values for the parameter.
+ internal static IEnumerable GetValuesFor(ParameterInfo parameter)
{
- ///
- /// Gets a sequence of values that should be tested for the specified parameter.
- ///
- /// The parameter to get possible values for.
- /// A sequence of values for the parameter.
- internal static IEnumerable GetValuesFor(ParameterInfo parameter)
+ Requires.NotNull(parameter, nameof(parameter));
{
- Requires.NotNull(parameter, nameof(parameter));
+ CombinatorialValuesAttribute? attribute = parameter.GetCustomAttribute();
+ if (attribute is not null)
{
- CombinatorialValuesAttribute? attribute = parameter.GetCustomAttribute();
- if (attribute is not null)
- {
- return attribute.Values;
- }
+ return attribute.Values;
}
+ }
+ {
+ CombinatorialRangeAttribute? attribute = parameter.GetCustomAttribute();
+ if (attribute is not null)
{
- CombinatorialRangeAttribute? attribute = parameter.GetCustomAttribute();
- if (attribute is not null)
- {
- return attribute.Values;
- }
+ return attribute.Values;
}
+ }
+ {
+ CombinatorialRandomDataAttribute? attribute = parameter.GetCustomAttribute();
+ if (attribute is not null)
{
- CombinatorialRandomDataAttribute? attribute = parameter.GetCustomAttribute();
- if (attribute is not null)
- {
- return attribute.Values;
- }
+ return attribute.Values;
}
+ }
+ {
+ CombinatorialMemberDataAttribute? attribute = parameter.GetCustomAttribute();
+ if (attribute is not null)
{
- CombinatorialMemberDataAttribute? attribute = parameter.GetCustomAttribute();
- if (attribute is not null)
- {
- return attribute.GetValues(parameter);
- }
+ return attribute.GetValues(parameter);
}
-
- return GetValuesFor(parameter.ParameterType);
}
- ///
- /// Gets a sequence of values that should be tested for the specified type.
- ///
- /// The type to get possible values for.
- /// A sequence of values for the .
- internal static IEnumerable GetValuesFor(Type dataType)
- {
- Requires.NotNull(dataType, nameof(dataType));
+ return GetValuesFor(parameter.ParameterType);
+ }
- if (dataType == typeof(bool))
- {
- yield return true;
- yield return false;
- }
- else if (dataType == typeof(int))
- {
- yield return 0;
- yield return 1;
- }
- else if (dataType.GetTypeInfo().IsEnum)
- {
- foreach (string name in Enum.GetNames(dataType))
- {
- yield return Enum.Parse(dataType, name);
- }
- }
- else if (IsNullable(dataType, out Type? innerDataType))
+ ///
+ /// Gets a sequence of values that should be tested for the specified type.
+ ///
+ /// The type to get possible values for.
+ /// A sequence of values for the .
+ internal static IEnumerable GetValuesFor(Type dataType)
+ {
+ Requires.NotNull(dataType, nameof(dataType));
+
+ if (dataType == typeof(bool))
+ {
+ yield return true;
+ yield return false;
+ }
+ else if (dataType == typeof(int))
+ {
+ yield return 0;
+ yield return 1;
+ }
+ else if (dataType.GetTypeInfo().IsEnum)
+ {
+ foreach (string name in Enum.GetNames(dataType))
{
- yield return null;
- foreach (object? value in GetValuesFor(innerDataType))
- {
- yield return value;
- }
+ yield return Enum.Parse(dataType, name);
}
- else
+ }
+ else if (IsNullable(dataType, out Type? innerDataType))
+ {
+ yield return null;
+ foreach (object? value in GetValuesFor(innerDataType))
{
- throw new NotSupportedException();
+ yield return value;
}
}
-
- ///
- /// Determines whether is
- /// and extracts the inner type, if any.
- ///
- ///
- /// The type to test whether it is .
- ///
- ///
- /// When this method returns, contains the inner type of the Nullable, if the
- /// type is Nullable is found; otherwise, null.
- ///
- ///
- /// if the type is a Nullable type; otherwise .
- ///
- private static bool IsNullable(Type dataType, [NotNullWhen(true)] out Type? innerDataType)
+ else
{
- innerDataType = null;
+ throw new NotSupportedException();
+ }
+ }
- TypeInfo? ti = dataType.GetTypeInfo();
+ ///
+ /// Determines whether is
+ /// and extracts the inner type, if any.
+ ///
+ ///
+ /// The type to test whether it is .
+ ///
+ ///
+ /// When this method returns, contains the inner type of the Nullable, if the
+ /// type is Nullable is found; otherwise, null.
+ ///
+ ///
+ /// if the type is a Nullable type; otherwise .
+ ///
+ private static bool IsNullable(Type dataType, [NotNullWhen(true)] out Type? innerDataType)
+ {
+ innerDataType = null;
- if (!ti.IsGenericType)
- {
- return false;
- }
+ TypeInfo? ti = dataType.GetTypeInfo();
- if (ti.GetGenericTypeDefinition() != typeof(Nullable<>))
- {
- return false;
- }
+ if (!ti.IsGenericType)
+ {
+ return false;
+ }
- innerDataType = ti.GenericTypeArguments[0];
- return true;
+ if (ti.GetGenericTypeDefinition() != typeof(Nullable<>))
+ {
+ return false;
}
+
+ innerDataType = ti.GenericTypeArguments[0];
+ return true;
}
}
diff --git a/test/Xunit.Combinatorial.Tests/CombinatorialDataAttributeTests.cs b/test/Xunit.Combinatorial.Tests/CombinatorialDataAttributeTests.cs
index 7bf6390..565efdc 100644
--- a/test/Xunit.Combinatorial.Tests/CombinatorialDataAttributeTests.cs
+++ b/test/Xunit.Combinatorial.Tests/CombinatorialDataAttributeTests.cs
@@ -12,105 +12,103 @@ public class CombinatorialDataAttributeTests
[Fact]
public void GetData_NoArguments()
{
- AssertData(new object[][]
- {
- });
+ AssertData([]);
}
[Fact]
public void GetData_Bool()
{
- AssertData(new object[][]
- {
- new object[] { true },
- new object[] { false },
- });
+ AssertData(
+ [
+ [true],
+ [false],
+ ]);
}
[Fact]
public void GetData_BoolBool()
{
- AssertData(new object[][]
- {
- new object[] { true, true },
- new object[] { true, false },
- new object[] { false, true },
- new object[] { false, false },
- });
+ AssertData(
+ [
+ [true, true],
+ [true, false],
+ [false, true],
+ [false, false],
+ ]);
}
[Fact]
public void GetData_Int()
{
- AssertData(new object[][]
- {
- new object[] { 0 },
- new object[] { 1 },
- });
+ AssertData(
+ [
+ [0],
+ [1],
+ ]);
}
[Fact]
public void GetData_NullableInt()
{
- AssertData(new object?[][]
- {
- new object?[] { null },
- new object?[] { 0 },
- new object?[] { 1 },
- });
+ AssertData(
+ [
+ [null],
+ [0],
+ [1],
+ ]);
}
[Fact]
public void GetData_Int_35()
{
- AssertData(new object[][]
- {
- new object[] { 3 },
- new object[] { 5 },
- });
+ AssertData(
+ [
+ [3],
+ [5],
+ ]);
}
[Fact]
public void GetData_string_int_bool_Values()
{
- AssertData(new object[][]
- {
- new object[] { "a", 2, true },
- new object[] { "a", 2, false },
- new object[] { "a", 4, true },
- new object[] { "a", 4, false },
- new object[] { "a", 6, true },
- new object[] { "a", 6, false },
- new object[] { "b", 2, true },
- new object[] { "b", 2, false },
- new object[] { "b", 4, true },
- new object[] { "b", 4, false },
- new object[] { "b", 6, true },
- new object[] { "b", 6, false },
- });
+ AssertData(
+ [
+ ["a", 2, true],
+ ["a", 2, false],
+ ["a", 4, true],
+ ["a", 4, false],
+ ["a", 6, true],
+ ["a", 6, false],
+ ["b", 2, true],
+ ["b", 2, false],
+ ["b", 4, true],
+ ["b", 4, false],
+ ["b", 6, true],
+ ["b", 6, false],
+ ]);
}
[Fact]
public void GetData_DateTimeKind()
{
- AssertData(new object[][]
- {
- new object[] { DateTimeKind.Unspecified },
- new object[] { DateTimeKind.Utc },
- new object[] { DateTimeKind.Local },
- });
+ AssertData(
+ [
+ [DateTimeKind.Unspecified],
+ [DateTimeKind.Utc],
+ [DateTimeKind.Local],
+ ]);
}
[Fact]
public void GetData_NullableDateTimeKind()
{
- AssertData(new object?[][]
- {
- new object?[] { null },
- new object?[] { DateTimeKind.Unspecified },
- new object?[] { DateTimeKind.Utc },
- new object?[] { DateTimeKind.Local },
- });
+ AssertData(
+ [
+ [null],
+ [DateTimeKind.Unspecified],
+ [DateTimeKind.Utc],
+ [DateTimeKind.Local],
+ ]);
}
[Fact]
@@ -134,12 +132,11 @@ public void GetData_CustomDataFromDerivedAttriute()
MethodInfo testhelperMethodInfo = this.GetType().GetMethod(nameof(this.SomeTestWithCustomValues), BindingFlags.Instance | BindingFlags.NonPublic)!;
IEnumerable actual = att.GetData(testhelperMethodInfo);
Assert.Equal(
- new[]
- {
- new object[] { 5 },
- new object[] { 10 },
- new object[] { 15 },
- },
+ [
+ [5],
+ [10],
+ [15],
+ ],
actual);
}
@@ -260,7 +257,7 @@ private void SomeTestWithCustomValues([CustomValues] int a)
private class CustomValuesAttribute : CombinatorialValuesAttribute
{
public CustomValuesAttribute()
- : base(new object[] { 5, 10, 15 })
+ : base([5, 10, 15])
{
}
}
diff --git a/test/Xunit.Combinatorial.Tests/CombinatorialMemberDataAttributeTests.cs b/test/Xunit.Combinatorial.Tests/CombinatorialMemberDataAttributeTests.cs
index ba8aec0..932666a 100644
--- a/test/Xunit.Combinatorial.Tests/CombinatorialMemberDataAttributeTests.cs
+++ b/test/Xunit.Combinatorial.Tests/CombinatorialMemberDataAttributeTests.cs
@@ -17,7 +17,7 @@ public void EnumerableOfIntReturnsValues()
var attribute = new CombinatorialMemberDataAttribute(nameof(GetValuesAsEnumerableOfInt));
ParameterInfo parameter = StubIntMethodInfo.GetParameters()[0];
object?[]? values = attribute.GetValues(parameter);
- Assert.Equal(new object[] { 1, 2, 3, 4 }, values);
+ Assert.Equal([1, 2, 3, 4], values);
}
[Fact]
@@ -26,7 +26,7 @@ public void ConcreteClassImplementingEnumerableOfIntReturnsValues()
var attribute = new CombinatorialMemberDataAttribute(nameof(GetValuesAsConcreteClassImplementingEnumerableOfInt));
ParameterInfo parameter = StubIntMethodInfo.GetParameters()[0];
object?[]? values = attribute.GetValues(parameter);
- Assert.Equal(new object[] { 1, 2, 3, 4 }, values);
+ Assert.Equal([1, 2, 3, 4], values);
}
[Fact]
@@ -35,7 +35,7 @@ public void ConcreteNonGenericClassImplementingEnumerableOfIntReturnsValues()
var attribute = new CombinatorialMemberDataAttribute(nameof(GetValuesAsConcreteNonGenericClassImplementingEnumerableOfInt));
ParameterInfo parameter = StubIntMethodInfo.GetParameters()[0];
object?[]? values = attribute.GetValues(parameter);
- Assert.Equal(new object[] { 1, 2, 3, 4 }, values);
+ Assert.Equal([1, 2, 3, 4], values);
}
[Fact]
diff --git a/test/Xunit.Combinatorial.Tests/CombinatorialValuesAttributeTests.cs b/test/Xunit.Combinatorial.Tests/CombinatorialValuesAttributeTests.cs
index f56a90b..bc0b7e5 100644
--- a/test/Xunit.Combinatorial.Tests/CombinatorialValuesAttributeTests.cs
+++ b/test/Xunit.Combinatorial.Tests/CombinatorialValuesAttributeTests.cs
@@ -17,13 +17,13 @@ public void Ctor_SetsProperty()
public void NullArg()
{
var attribute = new CombinatorialValuesAttribute(null);
- Assert.Equal(new object?[] { null }, attribute.Values);
+ Assert.Equal([null], attribute.Values);
}
[Fact]
public void NullArgInArray()
{
- var attribute = new CombinatorialValuesAttribute(new object?[] { null });
- Assert.Equal(new object?[] { null }, attribute.Values);
+ var attribute = new CombinatorialValuesAttribute([null]);
+ Assert.Equal([null], attribute.Values);
}
}
diff --git a/test/Xunit.Combinatorial.Tests/SampleUses.cs b/test/Xunit.Combinatorial.Tests/SampleUses.cs
index 524d88e..4eb7524 100644
--- a/test/Xunit.Combinatorial.Tests/SampleUses.cs
+++ b/test/Xunit.Combinatorial.Tests/SampleUses.cs
@@ -98,7 +98,7 @@ public void CombinatorialRandomValuesCountMinMaxValuesSeed([CombinatorialRandomD
private class CustomValuesAttribute : CombinatorialValuesAttribute
{
public CustomValuesAttribute()
- : base(new object[] { 5, 10, 15 })
+ : base([5, 10, 15])
{
}
}