using System.Collections; using System.Reflection; namespace ScadaLink.Commons.Tests.Entities; public class EntityConventionTests { private static readonly Assembly CommonsAssembly = typeof(ScadaLink.Commons.Types.RetryPolicy).Assembly; private static IEnumerable GetEntityTypes() => CommonsAssembly.GetTypes() .Where(t => t.IsClass && !t.IsAbstract && t.Namespace != null && t.Namespace.Contains(".Entities.")); [Fact] public void AllEntities_ShouldHaveNoEfAttributes() { var efAttributeNames = new HashSet { "KeyAttribute", "ForeignKeyAttribute", "TableAttribute", "ColumnAttribute", "RequiredAttribute", "MaxLengthAttribute", "StringLengthAttribute", "DatabaseGeneratedAttribute", "NotMappedAttribute", "IndexAttribute", "InversePropertyAttribute" }; foreach (var entityType in GetEntityTypes()) { // Check class-level attributes var classAttrs = entityType.GetCustomAttributes(true); foreach (var attr in classAttrs) { Assert.DoesNotContain(attr.GetType().Name, efAttributeNames); } // Check property-level attributes foreach (var prop in entityType.GetProperties()) { var propAttrs = prop.GetCustomAttributes(true); foreach (var attr in propAttrs) { Assert.False(efAttributeNames.Contains(attr.GetType().Name), $"Entity {entityType.Name}.{prop.Name} has EF attribute {attr.GetType().Name}"); } } } } [Fact] public void AllTimestampProperties_ShouldBeDateTimeOffset() { var timestampNames = new HashSet(StringComparer.OrdinalIgnoreCase) { "Timestamp", "DeployedAt", "CompletedAt", "GeneratedAt", "ReportTimestamp", "SnapshotTimestamp" }; foreach (var entityType in GetEntityTypes()) { foreach (var prop in entityType.GetProperties()) { if (timestampNames.Contains(prop.Name)) { var underlyingType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; Assert.True(underlyingType == typeof(DateTimeOffset), $"{entityType.Name}.{prop.Name} should be DateTimeOffset but is {prop.PropertyType.Name}"); } } } } [Fact] public void NavigationProperties_ShouldBeICollection() { foreach (var entityType in GetEntityTypes()) { foreach (var prop in entityType.GetProperties()) { if (prop.PropertyType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(prop.PropertyType) && prop.PropertyType != typeof(string)) { Assert.True( prop.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>), $"{entityType.Name}.{prop.Name} should be ICollection but is {prop.PropertyType.Name}"); } } } } }