Backend/e-suite.Database.Core/e-suite.Database.Core.UnitTests/TableDefinitionUnitTests.cs
2026-01-20 21:50:10 +00:00

172 lines
6.1 KiB
C#

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<Type> 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<string> CompileAcceptableTableNames(string tableName)
{
var result = new List<string>();
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");
}
}
}
}
}