using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; using e_suite.Database.Audit.Attributes; using Microsoft.EntityFrameworkCore; using NUnit.Framework; namespace e_suite.Database.Core.UnitTests; [TestFixture] public class TableDefinitionUnitTests { protected List Tables { get; set; } = []; private static CustomAttributeData? FindAttribute(Type type, Type attributeType) { return type.CustomAttributes.FirstOrDefault(customAttribute => attributeType.IsAssignableFrom(customAttribute.AttributeType)); } private static CustomAttributeData? FindAttribute(PropertyInfo propertyInfo, Type type) { return propertyInfo.CustomAttributes.FirstOrDefault(customAttribute => type.IsAssignableFrom(customAttribute.AttributeType)); } private static List CompileAcceptableTableNames(string tableName) { var result = new List(); var lastCharactor = tableName[^1..]; var lastTwoCharactors = tableName[^2..]; if (lastTwoCharactors.Equals("ey", StringComparison.InvariantCultureIgnoreCase)) { result.Add(tableName + "s"); } else if (lastCharactor.Equals("y", StringComparison.InvariantCultureIgnoreCase)) { result.Add(string.Concat(tableName.AsSpan(0, tableName.Length - 1), "ies")); } else if (lastCharactor.Equals("s", StringComparison.InvariantCultureIgnoreCase)) { result.Add(tableName); } else { result.Add(tableName + "s"); } return result; } [SetUp] public void Setup() { Tables.Clear(); var databaseContextClass = typeof(EsuiteDatabaseDbContext); var properties = databaseContextClass.GetProperties(); foreach (var property in properties) { if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)) { Tables.Add(property.PropertyType.GenericTypeArguments[0]); } } } [Test] public void Table_PropertyHasAuditParentAttribute_AlsoHasForeignKey() { //Arrange //Act foreach (var table in Tables) { //Need to check all the properties of the table to see if it contains the AuditParent Custom property var properties = table.GetProperties(); foreach (var property in properties) { if (FindAttribute(property, typeof(AuditParentAttribute)) != null) { //Assert if (FindAttribute(property, typeof(ForeignKeyAttribute)) != null) Assert.Pass($"Property {property.Name} Has both AuditParentAttribute And ForeignKey attribute"); else Assert.Fail($"Property {property.Name} Has AuditParentAttribute but is missing the ForeignKey attribute"); } } } } [Test] public void Table_TableName_IsSetConsistently() { //Arrange //Act foreach (var table in Tables) { //Need to check all the properties of the table to see if it contains the AuditParent Custom property var tableAttribute = FindAttribute(table, typeof(TableAttribute)); //Assert if (tableAttribute == null) Assert.Fail($"Table \"{table.Name}\" Missing the TableNameAttribute"); var acceptableTableNames = CompileAcceptableTableNames(table.Name); var tableName = tableAttribute?.ConstructorArguments[0].Value?.ToString() ?? string.Empty; if (!acceptableTableNames.Contains(tableName)) Assert.Fail($"Table name \"{tableName}\" for class \"{table.Name}\" does not conform to the naming standards"); var schemaName = tableAttribute!.NamedArguments.Single( x=> x.MemberName == "Schema"); var tableNamespace = table.Namespace?.Split("."); if (tableNamespace != null && tableNamespace.Last() != schemaName.TypedValue.Value?.ToString()) Assert.Fail($"Schema name for \"{table.Name}\" set incorrectly is currently \"{schemaName.TypedValue.Value}\" but should be \"{tableNamespace}\""); } } [Test] public void Table_AuditedTables_HasLastUpdated() { //Arrange //Act foreach (var table in Tables) { //Assert var tableAttribute = FindAttribute(table, typeof(TableAttribute)); if (tableAttribute == null) continue; //Need to check all the properties of the table to see if it contains the AuditParent Custom property var noAuditAttribute = FindAttribute(table, typeof(NoAuditAttribute)); if (noAuditAttribute != null) continue; var foundLastUpdated = false; var properties = table.GetProperties(); foreach (var property in properties) { if (FindAttribute(property, typeof(AuditLastUpdatedAttribute)) != null) { foundLastUpdated = true; break; } } if (!foundLastUpdated) Assert.Fail($"Table {table.Name} Missing {nameof(AuditLastUpdatedAttribute)}"); } } [Test] public void Table_ForeignKeysAreVirtual() { //Arrange //Act foreach (var table in Tables) { var properties = table.GetProperties(); foreach (var property in properties) { if (FindAttribute(property, typeof(ForeignKeyAttribute)) != null) { //Assert if (!property.GetAccessors().Any( x=> x.IsVirtual)) Assert.Fail($"Table {table.Name}.{property.Name} is not virtual"); } } } } }