Skip to content

Instantly share code, notes, and snippets.

@LSTANCZYK
Last active September 25, 2017 01:52
Show Gist options
  • Select an option

  • Save LSTANCZYK/4f6f5cffc225d545630604f4cd2c7223 to your computer and use it in GitHub Desktop.

Select an option

Save LSTANCZYK/4f6f5cffc225d545630604f4cd2c7223 to your computer and use it in GitHub Desktop.
Validates that at least one of the given properties has value (in case of strings also checks for empty strings)
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace DataValidation
{
/// <summary>
/// Validates that at least one of the given properties has value (in case of strings also checks for empty strings)
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class OneOfIsRequired : ValidationAttribute
{
private readonly string[] _propertyNames;
public OneOfIsRequired(params string[] propertyNames)
{
_propertyNames = propertyNames;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (_propertyNames.Length < 2)
{
return new ValidationResult($"At least two property names have to be specified in '{GetType().Name}' Validation Attribute for '{validationContext.ObjectType.Name}' class");
}
var conditionsMetCounter = 0;
var propertyValues = new List<object>();
foreach (var propertyName in _propertyNames)
{
var property = validationContext.ObjectType.GetProperty(propertyName);
var propertyValue = property.GetValue(validationContext.ObjectInstance, null);
if (propertyValue is string && !string.IsNullOrWhiteSpace((string) propertyValue))
{
conditionsMetCounter++;
}
else if (propertyValue != null)
{
conditionsMetCounter++;
}
}
if (conditionsMetCounter > 0)
{
return ValidationResult.Success;
}
return new ValidationResult($"'{validationContext.ObjectType.Name} requires that one of '{string.Join("', '", _propertyNames)}' properties has value'");
}
}
}
using System.CodeDom;
using System.ComponentModel.DataAnnotations;
using System.Web.Http;
using DataValidation;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Tests.Validation
{
[TestClass]
public class OneOfIsRequiredTests
{
private class TestClass
{
public string StringProperty1 { get; set; }
public string StringProperty2 { get; set; }
public string StringProperty3 { get; set; }
public object ObjectProperty1 { get; set; }
public object ObjectProperty2 { get; set; }
public int IntProperty3 { get; set; }
}
[TestMethod]
public void When_All_2_Properties_Have_Value_Should_Return_True()
{
//arrange
var classInstance = new TestClass()
{
StringProperty1 = "abc",
StringProperty2 = "xyz"
};
var sut = new OneOfIsRequired("Property1", "Property2");
//act
bool valid = sut.IsValid(classInstance);
//assert
Assert.IsTrue(valid);
}
[TestMethod]
public void When_All_3_Properties_Have_Value_Should_Return_True()
{
//arrange
var classInstance = new TestClass()
{
StringProperty1 = "abc",
StringProperty2 = "xyz",
ObjectProperty1 = new {Test=true,Text="Test Object"}
};
var sut = new OneOfIsRequired("StringProperty1", "StringProperty2","ObjectProperty1");
//act
bool valid = sut.IsValid(classInstance);
//assert
Assert.IsTrue(valid);
}
[TestMethod]
public void When_One_3_Properties_Has_Value_Should_Return_True()
{
//arrange
var classInstance = new TestClass()
{
ObjectProperty1 = new { Test = true, Text = "Test Object" }
};
var sut = new OneOfIsRequired("StringProperty1", "StringProperty2", "ObjectProperty1");
//act
bool valid = sut.IsValid(classInstance);
//assert
Assert.IsTrue(valid);
}
[TestMethod]
public void When_Properties_Are_Empty_or_whitespace_Strings_Should_Return_False()
{
//arrange
var classInstance = new TestClass()
{
StringProperty1 = string.Empty,
StringProperty2 = " ",
ObjectProperty1 = new { Test = true, Text = "Test Object" },
IntProperty3 = 5,
};
var sut = new OneOfIsRequired("StringProperty1", "StringProperty2");
//act
bool valid = sut.IsValid(classInstance);
//assert
Assert.IsFalse(valid);
}
[TestMethod]
public void When_Property_Does_Not_Exist_Should_Return_False()
{
//arrange
var classInstance = new TestClass()
{
StringProperty1 = string.Empty,
StringProperty2 = " ",
ObjectProperty1 = new { Test = true, Text = "Test Object" },
IntProperty3 = 5,
};
var sut = new OneOfIsRequired("MadeUpProperty1", "StringProperty1");
//act
bool valid = sut.IsValid(classInstance);
//assert
Assert.IsFalse(valid);
}
[TestMethod]
public void When_Properties_Are_Mixed_Type_Should_Return_True()
{
//arrange
var classInstance = new TestClass()
{
ObjectProperty1 = new { Test = true, Text = "Test Object" }
};
var sut = new OneOfIsRequired("StringProperty1", "ObjectProperty1","IntProperty1");
//act
bool valid = sut.IsValid(classInstance);
//assert
Assert.IsTrue(valid);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment