Dalibor Votruba 3 éve
szülő
commit
db6fee943f
28 módosított fájl, 541 hozzáadás és 105 törlés
  1. 3 2
      Common/qdr.app.qlbrc.common/Configuration/Settings.cs
  2. 1 1
      Common/qdr.app.qlbrc.common/Dtos/QlbrcDtoTrackedWithId.cs
  3. 1 1
      Common/qdr.app.qlbrc.common/Dtos/QlbrcDtoTrackedWithoutId.cs
  4. 1 1
      Common/qdr.app.qlbrc.common/Entities/Base/ITracked.cs
  5. 12 12
      Common/qdr.app.qlbrc.common/Entities/Base/QlbrcEntityTrackedWithoutId.cs
  6. 0 1
      Common/qdr.fnd.core.data/Entity/Entity.cs
  7. 6 0
      Common/qdr.fnd.core.test/BaseTest.cs
  8. 92 0
      Common/qdr.fnd.core.test/DaoTest.cs
  9. 6 0
      Common/qdr.fnd.core.test/DbContextTest.cs
  10. 12 0
      Common/qdr.fnd.core.test/DtoTest.cs
  11. 6 0
      Common/qdr.fnd.core.test/ServiceDbContextTest.cs
  12. 6 0
      Common/qdr.fnd.core.test/ServiceTest.cs
  13. 1 0
      Common/qdr.fnd.core.test/Usings.cs
  14. 95 0
      Common/qdr.fnd.core.test/Utils/ReflectionUtils.cs
  15. 24 0
      Common/qdr.fnd.core.test/qdr.fnd.core.test.csproj
  16. 9 0
      Common/qdr.fnd.core/Reflection/Extensions/TypeExt.cs
  17. 2 2
      Modules/qdr.app.qlbrc.base/Dtos/TenantDto.cs
  18. 1 1
      Modules/qdr.app.qlbrc.base/Dtos/UserDto.cs
  19. 72 71
      Modules/qdr.app.qlbrc.base/Entities/Setting.cs
  20. 5 3
      Modules/qdr.app.qlbrc.base/Entities/Tenant.cs
  21. 1 1
      Modules/qdr.app.qlbrc.base/Entities/User.cs
  22. 3 3
      Modules/qdr.app.qlbrc.base/QlbrcDbContext.cs
  23. 61 0
      Tests/qdr.app.qlbrc.base.Tests/Entities/Base/BaseDaoTest.cs
  24. 27 5
      Tests/qdr.app.qlbrc.base.Tests/Entities/SettingTest.cs
  25. 41 0
      Tests/qdr.app.qlbrc.base.Tests/Entities/TenantTest.cs
  26. 39 0
      Tests/qdr.app.qlbrc.base.Tests/Entities/UserTest.cs
  27. 6 0
      Tests/qdr.app.qlbrc.base.Tests/qdr.app.qlbrc.base.Tests.csproj
  28. 8 1
      qdr.app.qlbrc.sln

+ 3 - 2
Common/qdr.app.qlbrc.common/Configuration/Settings.cs

@@ -18,8 +18,9 @@ namespace Quadarax.Application.QLiberace.Common.Configuration
     public class ModuleConfiguration
     {
         [JsonPropertyName("code")]
-        public string Code { get; set; }
+        public string Code { get; set; } = null!;
+
         [JsonPropertyName("connection-string")]
-        public string ConnectionString { get; set; }
+        public string ConnectionString { get; set; } = null!;
     }
 }

+ 1 - 1
Common/qdr.app.qlbrc.common/Dtos/QlbrcDtoTrackedWithId.cs

@@ -6,6 +6,6 @@ namespace Quadarax.Application.QLiberace.Common.Dtos
     {
         public DateTime Created { get; }
         public DateTime? Modified { get; }
-        public string Modifier { get; }
+        public string Modifier { get; } = null!;
     }
 }

+ 1 - 1
Common/qdr.app.qlbrc.common/Dtos/QlbrcDtoTrackedWithoutId.cs

@@ -6,6 +6,6 @@ namespace Quadarax.Application.QLiberace.Common.Dtos
     {
         public DateTime Created { get; }
         public DateTime? Modified { get; }
-        public string Modifier { get; }
+        public string Modifier { get; } = null!;
     }
 }

+ 1 - 1
Common/qdr.app.qlbrc.common/Entities/Base/ITracked.cs

@@ -4,6 +4,6 @@
     {
         public DateTime Created { get; }
         public DateTime? Modified { get;}
-        public string Modifier { get; }
+        public string? Modifier { get; }
     }
 }

+ 12 - 12
Common/qdr.app.qlbrc.common/Entities/Base/QlbrcEntityTrackedWithoutId.cs

@@ -1,15 +1,15 @@
 using System.ComponentModel.DataAnnotations.Schema;
 using System.ComponentModel.DataAnnotations;
 
-namespace Quadarax.Application.QLiberace.Common.Entities.Base
-{
-    public abstract class QlbrcEntityTrackedWithoutId: QlbrcEntityWithId, ITracked
-    {
-        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
-        [Required]
-        public DateTime Created { get; protected set; }
-        public DateTime? Modified { get; protected set;}
-        [MaxLength(100)]
-        public string? Modifier { get; protected set;}
-    }
-}
+namespace Quadarax.Application.QLiberace.Common.Entities.Base
+{
+    public abstract class QlbrcEntityTrackedWithoutId: QlbrcEntityWithId, ITracked
+    {
+        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
+        [Required]
+        public DateTime Created { get; protected set; }
+        public DateTime? Modified { get; protected set;}
+        [MaxLength(100)]
+        public string? Modifier { get; protected set;}
+    }
+}

+ 0 - 1
Common/qdr.fnd.core.data/Entity/Entity.cs

@@ -1,6 +1,5 @@
 using System;
 using System.ComponentModel.DataAnnotations;
-using System.ComponentModel.DataAnnotations.Schema;
 using System.Text;
 using Quadarax.Foundation.Core.Data.Interface.Entity;
 

+ 6 - 0
Common/qdr.fnd.core.test/BaseTest.cs

@@ -0,0 +1,6 @@
+namespace qdr.fnd.core.test
+{
+    public abstract class BaseTest
+    {
+    }
+}

+ 92 - 0
Common/qdr.fnd.core.test/DaoTest.cs

@@ -0,0 +1,92 @@
+using System.ComponentModel;
+using Quadarax.Foundation.Core.Data.Entity;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using qdr.fnd.core.test.Utils;
+
+namespace qdr.fnd.core.test
+{
+    public abstract class DaoTest<TDao,TKey> : BaseTest where TDao : Entity<TKey> 
+                                                        where TKey : IEquatable<TKey>
+    {
+        protected void CheckHasPK(string customMessage)
+        {
+            if (string.IsNullOrEmpty(customMessage))
+                customMessage = "Has no PK flag";
+            Assert.IsTrue(ReflectionUtils.HasPropertyAttribute<KeyAttribute>(typeof(TDao),"Id"), customMessage);
+        }
+
+        public void CheckColumnMappings(string propertyName, string columnName, bool? isRequired = null, int? maxSize = null, object? defaultValue = null)
+        {
+            var pinfo = ReflectionUtils.GetProperty(typeof(TDao), propertyName, false);
+            Assert.IsNotNull(pinfo, $"type '{typeof(TDao).Name}' has no public property '{propertyName}'");
+            Assert.IsTrue(pinfo.CanRead, $"type '{typeof(TDao).Name}' has no public getter on property '{propertyName}'");
+            Assert.IsTrue(pinfo.CanWrite, $"type '{typeof(TDao).Name}' has no public getter on property '{propertyName}'");
+
+            if (!string.IsNullOrEmpty(columnName))
+            {
+                //check column mapping
+                var attrCol = ReflectionUtils.GetPropertyAttribute<ColumnAttribute>(typeof(TDao), propertyName, true);
+                Assert.IsNotNull(attrCol, $"type '{typeof(TDao).Name}' property '{propertyName}' has no Column attribute therefore expected");
+                Assert.That(attrCol.Name, Is.EqualTo(columnName));
+            }
+
+            if (isRequired!=null)
+            {
+                //check requiref attribute
+                var attrCol = ReflectionUtils.GetPropertyAttribute<RequiredAttribute>(typeof(TDao), propertyName, true);
+                if (isRequired.GetValueOrDefault())
+                    Assert.IsNotNull(attrCol, $"type '{typeof(TDao).Name}' property '{propertyName}' has no Require attribute therefore expected");
+                else
+                    Assert.IsNull(attrCol, $"type '{typeof(TDao).Name}' property '{propertyName}' has Require attribute therefore not allowed");
+            }
+
+            if (maxSize!=null)
+            {
+                //check max size attribute
+                var attrCol = ReflectionUtils.GetPropertyAttribute<MaxLengthAttribute>(typeof(TDao), propertyName, true);
+                Assert.IsNotNull(attrCol, $"type '{typeof(TDao).Name}' property '{propertyName}' has no MaxLength attribute therefore expected");
+                Assert.That(attrCol.Length, Is.EqualTo(maxSize));
+            }
+
+            if (defaultValue!=null)
+            {
+                //check max size attribute
+                var attrCol = ReflectionUtils.GetPropertyAttribute<DefaultValueAttribute>(typeof(TDao), propertyName, true);
+                Assert.IsNotNull(attrCol, $"type '{typeof(TDao).Name}' property '{propertyName}' has no DefaultValue attribute therefore expected");
+                Assert.That(attrCol.Value, Is.EqualTo(defaultValue));
+            }
+        }
+
+        public void CheckColumnFKMappings(string propertyName, string columnName, string fkName, bool? isRequired = null)
+        {
+            var pinfo = ReflectionUtils.GetProperty(typeof(TDao), propertyName, false);
+            Assert.IsNotNull(pinfo, $"type '{typeof(TDao).Name}' has no public property '{propertyName}'");
+            Assert.IsTrue(pinfo.CanRead, $"type '{typeof(TDao).Name}' has no public getter on property '{propertyName}'");
+            Assert.IsTrue(pinfo.CanWrite, $"type '{typeof(TDao).Name}' has no public getter on property '{propertyName}'");
+
+            if (!string.IsNullOrEmpty(columnName))
+            {
+                //check column mapping
+                var attrCol = ReflectionUtils.GetPropertyAttribute<ColumnAttribute>(typeof(TDao), propertyName, true);
+                Assert.IsNotNull(attrCol, $"type '{typeof(TDao).Name}' property '{propertyName}' has no Column attribute therefore expected");
+                Assert.That(attrCol.Name, Is.EqualTo(columnName));
+            }
+
+            var attrFk = ReflectionUtils.GetPropertyAttribute<ForeignKeyAttribute>(typeof(TDao), propertyName, true);
+            Assert.IsNotNull(attrFk, $"type '{typeof(TDao).Name}' property '{propertyName}' has no ForeignKey attribute therefore expected");
+            Assert.That(attrFk.Name, Is.EqualTo(fkName));
+
+            if (isRequired!=null)
+            {
+                //check requiref attribute
+                var attrCol = ReflectionUtils.GetPropertyAttribute<RequiredAttribute>(typeof(TDao), propertyName, true);
+                if (isRequired.GetValueOrDefault())
+                    Assert.IsNotNull(attrCol, $"type '{typeof(TDao).Name}' property '{propertyName}' has no Require attribute therefore expected");
+                else
+                    Assert.IsNull(attrCol, $"type '{typeof(TDao).Name}' property '{propertyName}' has Require attribute therefore not allowed");
+            }
+
+        }
+    }
+}

+ 6 - 0
Common/qdr.fnd.core.test/DbContextTest.cs

@@ -0,0 +1,6 @@
+namespace qdr.fnd.core.test
+{
+    public abstract class DbContextTest : BaseTest
+    {
+    }
+}

+ 12 - 0
Common/qdr.fnd.core.test/DtoTest.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace qdr.fnd.core.test
+{
+    public abstract class DtoTest
+    {
+    }
+}

+ 6 - 0
Common/qdr.fnd.core.test/ServiceDbContextTest.cs

@@ -0,0 +1,6 @@
+namespace qdr.fnd.core.test
+{
+    public abstract class ServiceDbContextTest : ServiceTest
+    {
+    }
+}

+ 6 - 0
Common/qdr.fnd.core.test/ServiceTest.cs

@@ -0,0 +1,6 @@
+namespace qdr.fnd.core.test
+{
+    public abstract class ServiceTest : BaseTest
+    {
+    }
+}

+ 1 - 0
Common/qdr.fnd.core.test/Usings.cs

@@ -0,0 +1 @@
+global using NUnit.Framework;

+ 95 - 0
Common/qdr.fnd.core.test/Utils/ReflectionUtils.cs

@@ -0,0 +1,95 @@
+using System.Reflection;
+using Quadarax.Foundation.Core.Reflection;
+
+namespace qdr.fnd.core.test.Utils
+{
+    public static class ReflectionUtils
+    {
+        #region *** Properties operations ***
+        public static bool HasProperty(Type type, string propertyName, bool includeInternals = false)
+        {
+            return GetProperty(type, propertyName, includeInternals)!=null;
+        }
+
+        public static bool HasPropertySetter(Type type, string propertyName, bool includeInternals = false)
+        {
+            var pinfo = GetProperty(type, propertyName, includeInternals);
+            if (pinfo != null)
+            {
+                return pinfo.CanWrite;
+            }
+
+            throw new InvalidOperationException($"Cannot find property '{propertyName}' in type '{type.Name}'.");
+        }
+
+        public static bool HasPropertyGetter(Type type, string propertyName, bool includeInternals = false)
+        {
+            var pinfo = GetProperty(type, propertyName, includeInternals);
+            if (pinfo != null)
+            {
+                return pinfo.CanRead;
+            }
+
+            throw new InvalidOperationException($"Cannot find property '{propertyName}' in type '{type.Name}'.");
+
+        }
+
+        public static PropertyInfo? GetProperty(Type type, string propertyName, bool includeInternals = false)
+        {
+            if (type == null) throw new ArgumentNullException(nameof(type));
+            if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException(nameof(propertyName));
+
+            var bindings = includeInternals ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic : BindingFlags.Instance | BindingFlags.Public;
+            return type.GetProperties(bindings).FirstOrDefault(x=>string.Equals(x.Name, propertyName, StringComparison.InvariantCulture));
+        }
+
+        public static TAttribute? GetPropertyAttribute<TAttribute>(Type type, string propertyName, bool includeInherited = false) where TAttribute : Attribute
+        {
+            var pinfo = GetProperty(type, propertyName, true);
+            if (pinfo != null)
+            {
+                return AttributeQuery<TAttribute>.Find(pinfo, includeInherited);
+            }
+            throw new InvalidOperationException($"Cannot find property '{propertyName}' in type '{type.Name}'.");
+        }
+
+        public static bool HasPropertyAttribute<TAttribute>(Type type, string propertyName, bool includeInherited = false) where TAttribute : Attribute
+        {
+            return GetPropertyAttribute<TAttribute>(type, propertyName, includeInherited)!=null;
+        }
+        #endregion
+
+
+        #region *** Class operations ***
+        public static bool HasInterface(Type type, Type interfaceType)
+        {
+            if (type == null) throw new ArgumentNullException(nameof(type));
+            if (interfaceType == null) throw new ArgumentNullException(nameof(interfaceType));
+
+            return type.IsAssignableFrom(interfaceType);
+
+        }
+        public static bool HasInterfaceAll(Type type, params Type[] interfaceTypes)
+        {
+            var result = true;
+            foreach (var interfaceType in interfaceTypes)
+            {
+                result = result && HasInterface(type, interfaceType);
+            }
+
+            return result;
+        }
+
+        public static bool HasInterfaceAny(Type type, params Type[] interfaceTypes)
+        {
+            var result = false;
+            foreach (var interfaceType in interfaceTypes)
+            {
+                result = result || HasInterface(type, interfaceType);
+            }
+
+            return result;
+        }
+        #endregion
+    }
+}

+ 24 - 0
Common/qdr.fnd.core.test/qdr.fnd.core.test.csproj

@@ -0,0 +1,24 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+
+    <IsPackable>false</IsPackable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
+    <PackageReference Include="NUnit" Version="3.13.3" />
+    <PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
+    <PackageReference Include="NUnit.Analyzers" Version="3.3.0" />
+    <PackageReference Include="coverlet.collector" Version="3.1.2" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\qdr.fnd.core.data\qdr.fnd.core.data.csproj" />
+    <ProjectReference Include="..\qdr.fnd.core\qdr.fnd.core.csproj" />
+  </ItemGroup>
+
+</Project>

+ 9 - 0
Common/qdr.fnd.core/Reflection/Extensions/TypeExt.cs

@@ -33,5 +33,14 @@ namespace Quadarax.Foundation.Core.Reflection.Extensions
             return propList;
         }
 
+        public static PropertyInfo GetProperty(this Type type, string propertyName)
+        {
+            if (type == null)
+                return null;
+
+            return GetAllProperties(type)
+                .FirstOrDefault(x => string.Equals(x.Name, propertyName, StringComparison.InvariantCulture));
+        }
+
     }
 }

+ 2 - 2
Modules/qdr.app.qlbrc.base/Dtos/TenantDto.cs

@@ -4,8 +4,8 @@ namespace Quadarax.Application.QLiberace.Base.Dtos
 {
     public class TenantDto : IStructTenant
     {
-        public string Code { get; set; }
-        public string Name { get; set; }
+        public string Code { get; set; } = null!;
+        public string Name { get; set; } = null!;
         public DateTime? LastAccess { get; set; }
         public bool IsLocked { get; set; }
     }

+ 1 - 1
Modules/qdr.app.qlbrc.base/Dtos/UserDto.cs

@@ -5,7 +5,7 @@ namespace Quadarax.Application.QLiberace.Base.Dtos
 {
     public class UserDto : QlbrcDtoTrackedWithId, IStructUser
     {
-        public string LoginName { get; set; }
+        public string LoginName { get; set; } = null!;
         public bool IsLocked { get; set; }
     }
 }

+ 72 - 71
Modules/qdr.app.qlbrc.base/Entities/Setting.cs

@@ -1,72 +1,73 @@
-using System.ComponentModel;
-using System.ComponentModel.DataAnnotations;
-using Quadarax.Application.QLiberace.Base.Entities.Interfaces;
-using Quadarax.Application.QLiberace.Common.Entities.Base;
-using System.ComponentModel.DataAnnotations.Schema;
-using Microsoft.EntityFrameworkCore;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
+using Quadarax.Application.QLiberace.Base.Entities.Interfaces;
+using Quadarax.Application.QLiberace.Common.Entities.Base;
+using System.ComponentModel.DataAnnotations.Schema;
+using Microsoft.EntityFrameworkCore;
 using Quadarax.Foundation.Core.Reflection;
-namespace Quadarax.Application.QLiberace.Base.Entities;
-
-[Table(Constants.Modules.Base.TblSetting,Schema = Constants.Modules.Base.Schema)]
-[Index("ModuleCode","Code", Name="IDX_CODE_MODULECODE", IsUnique = true )]
-public class Setting : QlbrcEntityTrackedWithoutId, IStructSetting
-{
-    #region *** Properties ***
-    [ForeignKey("FK_Setting_Parent_Id")]
-    public long? ParentId { get; set; }
-    [Required]
-    [DefaultValue(0)]
-    public int SequenceNo { get; set; }
-    [MaxLength(10)]
-    [Required(AllowEmptyStrings = false)]
-    public string ModuleCode { get; set; }
-    [MaxLength(100)]
-    [Required(AllowEmptyStrings = false)]
-    public string Code { get; set; }
-
-    [MaxLength(500)]
-    public string? Description { get; set; }
-
-    [MaxLength(500)]
-    [Required(AllowEmptyStrings = false)]
-    public string ValueTypeQualified { get; set; }
-    [MaxLength(5000)]
-    [Required]
-    public string? Value { get; set; }
-    [Required]
-    [DefaultValue(false)]
-    public bool IsEnabled { get; set; }
-    #endregion
-
-    #region *** Private fields ***
-
-    #endregion
-
-
-    public TValue? GetTypedValue<TValue>()
-    {
-        return (TValue?)GetTypedValue();
-    }
-
-    public object? GetTypedValue()
-    {
-
-        if (string.IsNullOrEmpty(ValueTypeQualified))
-            throw new InvalidDataException(
-                $"Cannot get typed value of setting '{Code}' (module '{ModuleCode}') because ValueTypeQualified is not set.");
-
-
-        if (string.IsNullOrEmpty(Value))
-            return null;
-
-        var type = TypeUtils.GetRemoteType(ValueTypeQualified);
-        var converter = TypeDescriptor.GetConverter(type);
-        if (converter.CanConvertFrom(typeof(string)))
-        {
-            return converter.ConvertFrom(Value);
-        }
-
-        throw new InvalidCastException($"Cannot convert value of setting '{Code}' (module '{ModuleCode}') from type '{typeof(string).Name}' to '{ValueTypeQualified}'.");
-    }
-
-}
+namespace Quadarax.Application.QLiberace.Base.Entities;
+
+[Table(Constants.Modules.Base.TblSetting,Schema = Constants.Modules.Base.Schema)]
+[Index("ModuleCode","Code", Name="IDX_CODE_MODULECODE", IsUnique = true )]
+public class Setting : QlbrcEntityTrackedWithoutId, IStructSetting
+{
+    #region *** Properties ***
+    [ForeignKey("FK_Setting_Parent_Id")]
+    public long? ParentId { get; set; }
+    [Required]
+    [DefaultValue(0)]
+    public int SequenceNo { get; set; }
+    [MaxLength(10)]
+    [Required(AllowEmptyStrings = false)]
+    public string ModuleCode { get; set; } = null!;
+
+    [MaxLength(100)]
+    [Required(AllowEmptyStrings = false)]
+    public string Code { get; set; } = null!;
+
+    [MaxLength(500)]
+    public string? Description { get; set; }
+
+    [MaxLength(500)]
+    [Required(AllowEmptyStrings = false)]
+    public string ValueTypeQualified { get; set; } = null!;
+    [MaxLength(5000)]
+    [Required]
+    public string? Value { get; set; }
+    [Required]
+    [DefaultValue(false)]
+    public bool IsEnabled { get; set; }
+    #endregion
+
+    #region *** Private fields ***
+
+    #endregion
+
+
+    public TValue? GetTypedValue<TValue>()
+    {
+        return (TValue?)GetTypedValue();
+    }
+
+    public object? GetTypedValue()
+    {
+
+        if (string.IsNullOrEmpty(ValueTypeQualified))
+            throw new InvalidDataException(
+                $"Cannot get typed value of setting '{Code}' (module '{ModuleCode}') because ValueTypeQualified is not set.");
+
+
+        if (string.IsNullOrEmpty(Value))
+            return null;
+
+        var type = TypeUtils.GetRemoteType(ValueTypeQualified);
+        var converter = TypeDescriptor.GetConverter(type);
+        if (converter.CanConvertFrom(typeof(string)))
+        {
+            return converter.ConvertFrom(Value);
+        }
+
+        throw new InvalidCastException($"Cannot convert value of setting '{Code}' (module '{ModuleCode}') from type '{typeof(string).Name}' to '{ValueTypeQualified}'.");
+    }
+
+}

+ 5 - 3
Modules/qdr.app.qlbrc.base/Entities/Tenant.cs

@@ -12,10 +12,12 @@ namespace Quadarax.Application.QLiberace.Base.Entities
     {
         [MaxLength(20)]
         [Required(AllowEmptyStrings =false)]
-        public string Code { get; set; }
-        [MaxLength(100)]
+        public string Code { get; set; } = null!;
+
+        [MaxLength(200)]
         [Required(AllowEmptyStrings =false)]
-        public string Name { get; set; }
+        public string Name { get; set; } = null!;
+
         public DateTime? LastAccess { get; set; }
         [Required]
         public bool IsLocked { get; set; }

+ 1 - 1
Modules/qdr.app.qlbrc.base/Entities/User.cs

@@ -13,7 +13,7 @@ namespace Quadarax.Application.QLiberace.Base.Entities
     {
         [MaxLength(100)]
         [Required(AllowEmptyStrings = false)]
-        public string LoginName { get; set; }
+        public string LoginName { get; set; } = null!;
 
         [Required]
         [DefaultValue(false)]

+ 3 - 3
Modules/qdr.app.qlbrc.base/QlbrcDbContext.cs

@@ -11,9 +11,9 @@ namespace Quadarax.Application.QLiberace.Base
     {
 
         #region *** Mapped entities ***
-        public DbSet<User> Users { get; set; }
-        public DbSet<Tenant> Tenants { get; set; }
-        public DbSet<Setting> Settings { get; set; }
+        public DbSet<User> Users { get; set; } = null!;
+        public DbSet<Tenant> Tenants { get; set; } = null!;
+        public DbSet<Setting> Settings { get; set; } = null!;
 
         #endregion
         

+ 61 - 0
Tests/qdr.app.qlbrc.base.Tests/Entities/Base/BaseDaoTest.cs

@@ -0,0 +1,61 @@
+using System.ComponentModel.DataAnnotations.Schema;
+using qdr.fnd.core.test;
+using Quadarax.Application.QLiberace.Base.Entities;
+using Quadarax.Application.QLiberace.Common.Entities.Base;
+using Quadarax.Foundation.Core.Reflection;
+
+namespace Quadarax.Application.QLiberace.Base.Tests.Entities.Base
+{ 
+    public abstract class BaseDaoTest<TDao> : DaoTest<TDao, long> where TDao : QlbrcEntityWithId
+    {
+        protected void CheckHasTracked(string customMessage)
+        {
+            if (string.IsNullOrEmpty(customMessage))
+                customMessage = "Has no ITracked implemented";
+            Assert.IsTrue(typeof(TDao).IsAssignableTo(typeof(ITracked)), customMessage);
+        }
+
+        protected void CheckClassTable(string customMessage)
+        {
+            if (string.IsNullOrEmpty(customMessage))
+                customMessage = "Has no Table attribute";
+            Assert.IsTrue(AttributeQuery<TableAttribute>.Has(typeof(TDao)), customMessage);
+
+            var attr = AttributeQuery<TableAttribute>.Get(typeof(TDao));
+            Assert.IsFalse(string.IsNullOrEmpty(attr.Schema), "Attribute Table has no Schema set");
+        }
+
+
+        protected void CheckColumnCode(int? alternativeLength)
+        {
+            if (alternativeLength == null)
+                alternativeLength = 100;
+            CheckColumnMappings("Code", string.Empty,true, alternativeLength);
+        }
+        protected void CheckColumnName(int? alternativeLength)
+        {
+            if (alternativeLength == null)
+                alternativeLength = 200;
+            CheckColumnMappings("Name", string.Empty,true, alternativeLength);
+        }
+
+        protected void CheckColumnDescription(int? alternativeLength)
+        {
+            if (alternativeLength == null)
+                alternativeLength = 500;
+            CheckColumnMappings("Description", string.Empty,false, alternativeLength);
+        }
+
+        protected void CheckColumnModuleCode(int? alternativeLength)
+        {
+            if (alternativeLength == null)
+                alternativeLength = 10;
+            CheckColumnMappings("ModuleCode", string.Empty,true, alternativeLength);
+        }
+
+        protected void CheckColumnEnabled(bool isRequired, bool defaultValue)
+        {
+            CheckColumnMappings("IsEnabled", string.Empty,isRequired,null, defaultValue);
+        }
+    }
+}

+ 27 - 5
Tests/qdr.app.qlbrc.base.Tests/Entities/SettingTest.cs

@@ -1,7 +1,11 @@
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
+using Quadarax.Application.QLiberace.Base.Entities;
+using Quadarax.Application.QLiberace.Base.Tests.Entities.Base;
+
 namespace Quadarax.Application.QLiberace.Base.Tests.Entities
 {
     [TestFixture(Category = "Dao")]
-    public class SettingTest
+    public class SettingTest : BaseDaoTest<Setting>
     {
         [SetUp]
         public void Setup()
@@ -9,15 +13,33 @@ namespace Quadarax.Application.QLiberace.Base.Tests.Entities
         }
 
         [Test]
-        public void HasPKOK()
+        public void HasClassPKOK()
+        {
+            CheckHasPK(string.Empty);
+        }
+
+        [Test]
+        public void HasClassTrackedOK()
+        {
+            CheckHasTracked(string.Empty);
+        }
+
+        [Test]
+        public void HasClassTableOK()
         {
-            Assert.Pass();
+            CheckClassTable(string.Empty);
         }
 
         [Test]
-        public void HasTrackedOK()
+        public void ColumnMappingsOK()
         {
-            Assert.Pass();
+            CheckColumnFKMappings(nameof(Setting.ParentId), string.Empty,"FK_Setting_Parent_Id", false);
+            CheckColumnMappings(nameof(Setting.Value), string.Empty,true, 5000);
+            CheckColumnCode(null);
+            CheckColumnDescription(null);
+            CheckColumnModuleCode(null);
+            CheckColumnEnabled(true,false);
+            CheckColumnMappings(nameof(Setting.SequenceNo), string.Empty,true, null,0);
         }
     }
 }

+ 41 - 0
Tests/qdr.app.qlbrc.base.Tests/Entities/TenantTest.cs

@@ -0,0 +1,41 @@
+using qdr.fnd.core.test.Utils;
+using Quadarax.Application.QLiberace.Base.Entities;
+using Quadarax.Application.QLiberace.Base.Tests.Entities.Base;
+
+namespace Quadarax.Application.QLiberace.Base.Tests.Entities
+{
+    [TestFixture(Category = "Dao")]
+    public class TenantTest : BaseDaoTest<Tenant>
+    {
+        [SetUp]
+        public void Setup()
+        {
+        }
+
+        [Test]
+        public void HasClassPKOK()
+        {
+            CheckHasPK(string.Empty);
+        }
+
+        [Test]
+        public void HasClassTrackedOK()
+        {
+            CheckHasTracked(string.Empty);
+        }
+
+        [Test]
+        public void HasClassTableOK()
+        {
+            CheckClassTable(string.Empty);
+        }
+
+        [Test]
+        public void ColumnMappingsOK()
+        {
+            CheckColumnName(null);
+            CheckColumnMappings(nameof(Tenant.IsLocked), string.Empty,true, null,null);
+            Assert.IsTrue(ReflectionUtils.HasPropertyGetter(typeof(Tenant), nameof(Tenant.LastAccess), false));
+        }
+    }
+}

+ 39 - 0
Tests/qdr.app.qlbrc.base.Tests/Entities/UserTest.cs

@@ -0,0 +1,39 @@
+using Quadarax.Application.QLiberace.Base.Entities;
+using Quadarax.Application.QLiberace.Base.Tests.Entities.Base;
+
+namespace Quadarax.Application.QLiberace.Base.Tests.Entities
+{
+    [TestFixture(Category = "Dao")]
+    public class UserTest : BaseDaoTest<User>
+    {
+        [SetUp]
+        public void Setup()
+        {
+        }
+
+        [Test]
+        public void HasClassPKOK()
+        {
+            CheckHasPK(string.Empty);
+        }
+
+        [Test]
+        public void HasClassTrackedOK()
+        {
+            CheckHasTracked(string.Empty);
+        }
+
+        [Test]
+        public void HasClassTableOK()
+        {
+            CheckClassTable(string.Empty);
+        }
+
+        [Test]
+        public void ColumnMappingsOK()
+        {
+            CheckColumnMappings(nameof(User.LoginName), string.Empty, true, 100, null);
+            CheckColumnMappings(nameof(Tenant.IsLocked), string.Empty, true, null, false);
+        }
+    }
+}

+ 6 - 0
Tests/qdr.app.qlbrc.base.Tests/qdr.app.qlbrc.base.Tests.csproj

@@ -22,4 +22,10 @@
     <Folder Include="Repositories\" />
   </ItemGroup>
 
+  <ItemGroup>
+    <ProjectReference Include="..\..\Common\qdr.fnd.core.test\qdr.fnd.core.test.csproj" />
+    <ProjectReference Include="..\..\Common\qdr.fnd.core\qdr.fnd.core.csproj" />
+    <ProjectReference Include="..\..\Modules\qdr.app.qlbrc.base\qdr.app.qlbrc.base.csproj" />
+  </ItemGroup>
+
 </Project>

+ 8 - 1
qdr.app.qlbrc.sln

@@ -35,7 +35,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D8C71782
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "qdr.app.qlbrc.common.Tests", "Tests\qdr.app.qlbrc.common.Tests\qdr.app.qlbrc.common.Tests.csproj", "{653F7A49-07B8-4AE5-80FC-E559F38718CF}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "qdr.app.qlbrc.base.Tests", "Tests\qdr.app.qlbrc.base.Tests\qdr.app.qlbrc.base.Tests.csproj", "{3F99AB71-EB24-47D4-BBB6-755ED785D0FE}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "qdr.app.qlbrc.base.Tests", "Tests\qdr.app.qlbrc.base.Tests\qdr.app.qlbrc.base.Tests.csproj", "{3F99AB71-EB24-47D4-BBB6-755ED785D0FE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "qdr.fnd.core.test", "Common\qdr.fnd.core.test\qdr.fnd.core.test.csproj", "{0D88D15B-DC73-43F2-8661-ECAAF8EEB173}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -91,6 +93,10 @@ Global
 		{3F99AB71-EB24-47D4-BBB6-755ED785D0FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{3F99AB71-EB24-47D4-BBB6-755ED785D0FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{3F99AB71-EB24-47D4-BBB6-755ED785D0FE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0D88D15B-DC73-43F2-8661-ECAAF8EEB173}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0D88D15B-DC73-43F2-8661-ECAAF8EEB173}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0D88D15B-DC73-43F2-8661-ECAAF8EEB173}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0D88D15B-DC73-43F2-8661-ECAAF8EEB173}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -110,6 +116,7 @@ Global
 		{D8C71782-99B7-49FA-BF63-F40D8232B8DE} = {52B118CE-E47C-475C-8177-FC49F0FC8FE8}
 		{653F7A49-07B8-4AE5-80FC-E559F38718CF} = {D8C71782-99B7-49FA-BF63-F40D8232B8DE}
 		{3F99AB71-EB24-47D4-BBB6-755ED785D0FE} = {D8C71782-99B7-49FA-BF63-F40D8232B8DE}
+		{0D88D15B-DC73-43F2-8661-ECAAF8EEB173} = {F528683A-B908-440C-9D94-F4675A3F760E}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {AB5693A0-BE22-4D85-997A-EC8F74FE9B10}