using System; using System.Reflection; using System.Linq; using System.Collections.Generic; using Xunit; using Landmark.OLA.Tests.TestData; using Landmark.OLA.Models.Loan; using Landmark.OLA.Models; namespace Landmark.OLA.Tests { public class ModelValidatorTest { [Theory] [MemberData(nameof(TestIndividuals.GetValidTestIndividuals), MemberType = typeof(TestIndividuals))] [MemberData(nameof(TestAddresses.GetValidTestAddresses), MemberType = typeof(TestAddresses))] [MemberData(nameof(TestEmployers.GetValidTestEmployers), MemberType = typeof(TestEmployers))] public void ExpectValidModelsTest(object testData) { ModelValidator.Validate(testData); } [Theory] [MemberData(nameof(TestIndividuals.GetInvalidTestIndividuals), MemberType = typeof(TestIndividuals))] [MemberData(nameof(TestAddresses.GetInvalidTestAddresses), MemberType = typeof(TestAddresses))] [MemberData(nameof(TestEmployers.GetInvalidTestEmployers), MemberType = typeof(TestEmployers))] public void ExpectInvalidModelsTest(object testData) { Assert.Throws(() => ModelValidator.Validate(testData)); } [Fact] public void VerifyDataAnnotations() { string nspace = "Landmark.OLA.Models"; //LoanApplication is in the namespace we want to look into Assembly modelAssembly = typeof(LoanApplication).GetTypeInfo().Assembly; var models = modelAssembly.GetTypes() .Where(t => t.IsClass == true && string.Equals(t.Namespace, nspace, StringComparison.Ordinal)) .ToArray(); var missingValidation = new List(); foreach(var model in models) { var fields = model.GetProperties() .Where(x => !x.PropertyType.Namespace.StartsWith("Landmark") && x.PropertyType != typeof(bool) && x.PropertyType != typeof(Guid) && x.PropertyType != typeof(Enum)); foreach (var field in fields) { var hasSizeValidation = false; var fieldType = field.PropertyType; if (fieldType.IsGenericType) { if (fieldType.GetGenericTypeDefinition() == typeof(Nullable<>)) { fieldType = Nullable.GetUnderlyingType(fieldType); } else { fieldType = fieldType.GetGenericArguments()[0]; } } if (fieldType.BaseType == typeof(Enum) || fieldType == typeof(bool) || fieldType == typeof(Guid) || fieldType == typeof(DateTime) || fieldType.IsClass) { //enum, bool, guid are restricted to specific sizes or values //DateTime seems safe? //Landmark classes will already have their validation checked hasSizeValidation = true; } if(field.SetMethod?.IsPrivate ?? false) { //If inbound data ins't accepted we won't require validation hasSizeValidation = true; } if (!hasSizeValidation) { foreach (var attribute in field.GetCustomAttributes() .Where(x => x.TypeId.ToString().StartsWith("System.ComponentModel.DataAnnotations"))) { var sizeValidationAttributeTypes = new List { typeof(System.ComponentModel.DataAnnotations.MaxLengthAttribute), typeof(System.ComponentModel.DataAnnotations.RangeAttribute), typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute), }; if (sizeValidationAttributeTypes.Contains(attribute.GetType())) { hasSizeValidation = true; } } } if(!hasSizeValidation) { missingValidation.Add($"{model.Name} : {field.Name}"); } } } Assert.Empty(missingValidation); } private T GetAttributeFrom(object instance, string propertyName) where T : Attribute { var attrType = typeof(T); var property = instance.GetType().GetProperty(propertyName); return (T)property.GetCustomAttributes(attrType, false).First(); } } }