diff --git a/ZySharp.Validation.Tests/Test.Basic.cs b/ZySharp.Validation.Tests/Test.Basic.cs index 5f3f46f..83ed2c3 100644 --- a/ZySharp.Validation.Tests/Test.Basic.cs +++ b/ZySharp.Validation.Tests/Test.Basic.cs @@ -143,4 +143,56 @@ public void NotNullOrEmptyVal(ValTestCase test) } #endregion NotNullOrEmpty + + #region MutuallyExclusive + + public static IEnumerable DataMutuallyExclusiveRef => new List + { + new object[] { new RefTestCaseWithParam(null , null , false) }, + new object[] { new RefTestCaseWithParam(TestConstants.Obj.A, TestConstants.Obj.A , true ) }, + new object[] { new RefTestCaseWithParam(TestConstants.Obj.A, TestConstants.Obj.B , true ) }, + new object[] { new RefTestCaseWithParam(TestConstants.Obj.A, null , false) }, + new object[] { new RefTestCaseWithParam(null , TestConstants.Obj.B , false) }, + new object[] { new RefTestCaseWithParam("A" , "A" , true ) }, + new object[] { new RefTestCaseWithParam("A" , "B" , true ) }, + new object[] { new RefTestCaseWithParam("A" , null , false) }, + new object[] { new RefTestCaseWithParam(null , "B" , false) } + }; + + [Theory] + [MemberData(nameof(DataMutuallyExclusiveRef))] + public void MutuallyExclusiveRef(RefTestCaseWithParam test) + where T : class + { + TestExtensions.TestValidation(test, v => v.MutuallyExclusive(ArgumentReference.For(test.Parameter, "param"))); + } + + public static IEnumerable DataMutuallyExclusiveVal => new List + { + new object[] { new ValTestCaseWithValParam(null , null , false) }, + new object[] { new ValTestCaseWithValParam(0 , 0 , true ) }, + new object[] { new ValTestCaseWithValParam(0 , 1 , true ) }, + new object[] { new ValTestCaseWithValParam(0 , null , false) }, + new object[] { new ValTestCaseWithValParam(null , 1 , false) }, + new object[] { new ValTestCaseWithValParam(null , null , false) }, + new object[] { new ValTestCaseWithValParam(TestConstants.GuidA , TestConstants.GuidA , true ) }, + new object[] { new ValTestCaseWithValParam(TestConstants.GuidA , TestConstants.GuidB , true ) }, + new object[] { new ValTestCaseWithValParam(TestConstants.GuidA , null , false) }, + new object[] { new ValTestCaseWithValParam(null , TestConstants.GuidB , false) }, + new object[] { new ValTestCaseWithValParam(null , null , false) }, + new object[] { new ValTestCaseWithValParam(TestConstants.TimeSpanA, TestConstants.TimeSpanA, true ) }, + new object[] { new ValTestCaseWithValParam(TestConstants.TimeSpanA, TestConstants.TimeSpanB, true ) }, + new object[] { new ValTestCaseWithValParam(TestConstants.TimeSpanA, null , false) }, + new object[] { new ValTestCaseWithValParam(null , TestConstants.TimeSpanB, false) } + }; + + [Theory] + [MemberData(nameof(DataMutuallyExclusiveVal))] + public void MutuallyExclusiveVal(ValTestCaseWithValParam test) + where T : struct + { + TestExtensions.TestValidation(test, v => v.MutuallyExclusive(ArgumentReference.For(test.Parameter, "param"))); + } + + #endregion MutuallyExclusive } diff --git a/ZySharp.Validation.Tests/TestExtensions.cs b/ZySharp.Validation.Tests/TestExtensions.cs index 768700c..90f951e 100644 --- a/ZySharp.Validation.Tests/TestExtensions.cs +++ b/ZySharp.Validation.Tests/TestExtensions.cs @@ -155,3 +155,18 @@ public ValTestCaseWithParam(TValue? value, TParam? parameter, bool expectThrow, Parameter = parameter; } } + +[ExcludeFromCodeCoverage] +public class ValTestCaseWithValParam : + ValTestCase + where TValue : struct + where TParam : struct +{ + public TParam? Parameter { get; } + + public ValTestCaseWithValParam(TValue? value, TParam? parameter, bool expectThrow, Type? exceptionType = null) : + base(value, expectThrow, exceptionType) + { + Parameter = parameter; + } +} diff --git a/ZySharp.Validation/Properties/Resources.Designer.cs b/ZySharp.Validation/Properties/Resources.Designer.cs index 4001409..c8e3957 100644 --- a/ZySharp.Validation/Properties/Resources.Designer.cs +++ b/ZySharp.Validation/Properties/Resources.Designer.cs @@ -168,6 +168,15 @@ internal static string ArgumentMustBeLessThanReference { } } + /// + /// Looks up a localized string similar to The argument '{0}' must be used mutually exclusive to the argument '{1}'.. + /// + internal static string ArgumentMustBeMutuallyExclusive { + get { + return ResourceManager.GetString("ArgumentMustBeMutuallyExclusive", resourceCulture); + } + } + /// /// Looks up a localized string similar to The type of argument '{0}' must be '{1}'.. /// diff --git a/ZySharp.Validation/Properties/Resources.resx b/ZySharp.Validation/Properties/Resources.resx index 261da53..c18f90c 100644 --- a/ZySharp.Validation/Properties/Resources.resx +++ b/ZySharp.Validation/Properties/Resources.resx @@ -153,6 +153,9 @@ The value of argument '{0}' must be less than the value of argument `{1}`. Values: '{0}' = '{2}', '{1}' = '{3}' + + The argument '{0}' must be used mutually exclusive to the argument '{1}'. + The type of argument '{0}' must be '{1}'. diff --git a/ZySharp.Validation/ValidateArgument.Basic.cs b/ZySharp.Validation/ValidateArgument.Basic.cs index 6a421f7..02d8ca8 100644 --- a/ZySharp.Validation/ValidateArgument.Basic.cs +++ b/ZySharp.Validation/ValidateArgument.Basic.cs @@ -179,4 +179,32 @@ public static IValidatorContext NotEmpty(this IValidatorContext validat } #endregion NotNullOrEmpty + + #region MutuallyExclusive + + /// + /// Throws if both, the current value and the value is not null. + /// + /// The type of the current value. + /// The current validator context. + /// A reference to the other value. + /// The unmodified validator context. + public static IValidatorContext MutuallyExclusive(this IValidatorContext validator, + IArgumentReference reference) + { + ValidationInternals.ValidateNotNull(reference, nameof(reference)); + + return validator.Perform(() => + { + if ((validator.Value is not null) && (reference.Value is not null)) + { + validator.SetArgumentException( + string.Format(CultureInfo.InvariantCulture, Resources.ArgumentMustBeMutuallyExclusive, + ValidationInternals.FormatName(validator.Path, null), + ValidationInternals.FormatName(reference.Path, null))); + } + }, false); + } + + #endregion } diff --git a/ZySharp.Validation/ValidateArgument.cs b/ZySharp.Validation/ValidateArgument.cs index 560235a..73a08e5 100644 --- a/ZySharp.Validation/ValidateArgument.cs +++ b/ZySharp.Validation/ValidateArgument.cs @@ -23,7 +23,7 @@ public static partial class ValidateArgument /// The name of the argument to validate. /// The action to perform for the selected parameter. /// The value of the validated argument. - [return: NotNullIfNotNull("value")] + [return: NotNullIfNotNull(nameof(value))] public static T? For([ValidatedNotNull][NoEnumeration] T? value, string name, Action> action) { ValidationInternals.ValidateNotNull(name, nameof(name));