Parcourir la source

fix qdr.fnd.core.Tests, add MoshPit, Enumeration, cleanup code

Dalibor Votruba il y a 2 ans
Parent
commit
2b66d179d4

+ 1 - 1
qdr.fnd.core.test/Exceptions/CodeExceptionTest.cs

@@ -40,7 +40,7 @@ namespace qdr.fnd.core.test.Exceptions
             Assert.That(ex.Code, Is.EqualTo(CS_CODE));
             Assert.That(ex.Message, Is.EqualTo(CS_MESSAGE));
             Assert.That(ex.InnerException, Is.Not.Null);
-            Assert.That(ex.InnerException.Message, Is.EqualTo(ex.InnerException.Message));
+            Assert.That(ex.InnerException!.Message, Is.EqualTo(ex.InnerException.Message));
         }
 
         [Test(TestOf = typeof(CodeException))]

+ 22 - 11
qdr.fnd.core.test/StringPatternComparerTest.cs

@@ -18,14 +18,16 @@ namespace qdr.fnd.core.test
         {
             var pattern = "*Dalibor*";
             var result = _comparer?.Equals(_testSource, pattern);
-            Assert.IsTrue(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.True);
         }
         [Test(TestOf = typeof(StringPatternComparer))]
         public void EqualsAnySpaceTextAny()
         {
             var pattern = "*_Dalibor*";
             var result = _comparer?.Equals(_testSource, pattern);
-            Assert.IsTrue(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.True);
         }
 
         [Test(TestOf = typeof(StringPatternComparer))]
@@ -33,42 +35,48 @@ namespace qdr.fnd.core.test
         {
             var pattern = "/* Dalibor*";
             var result = _comparer?.Equals(_testSource, pattern);
-            Assert.IsTrue(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.True);
         }
         [Test(TestOf = typeof(StringPatternComparer))]
         public void EqualsEscTextSpaceAlphaNumNumAny()
         {
             var pattern = "/* Dalibor_?#*";
             var result = _comparer?.Equals(_testSource, pattern);
-            Assert.IsTrue(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.True);
         }
         [Test(TestOf = typeof(StringPatternComparer))]
         public void EqualsAnySpaceEscText()
         {
             var pattern = "*_/*";
             var result = _comparer?.Equals(_testSource, pattern);
-            Assert.IsTrue(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.True);
         }
         [Test(TestOf = typeof(StringPatternComparer))]
         public void EqualsAnyNumericAny()
         {
             var pattern = "*#*";
             var result = _comparer?.Equals(_testSource, pattern);
-            Assert.IsTrue(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.True);
         }
         [Test(TestOf = typeof(StringPatternComparer))]
         public void NotEqualsEmptyPattern()
         {
             var pattern = string.Empty;
             var result = _comparer?.Equals(_testSource, pattern);
-            Assert.IsFalse(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.False);
         }
         [Test(TestOf = typeof(StringPatternComparer))]
         public void NotEqualsOccurences()
         {
             var pattern = "*Da#*V*";
             var result = _comparer?.Equals(_testSource, pattern);
-            Assert.IsFalse(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.False);
         }
         [Test(TestOf = typeof(StringPatternComparer))]
         public void EqualsEmptySource()
@@ -76,7 +84,8 @@ namespace qdr.fnd.core.test
             var pattern = string.Empty;
             var source = string.Empty;
             var result = _comparer?.Equals(source, pattern);
-            Assert.IsTrue(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.True);
         }
         [Test(TestOf = typeof(StringPatternComparer))]
         public void EqualsNullSourceNullPattern()
@@ -84,7 +93,8 @@ namespace qdr.fnd.core.test
             string? pattern = null;
             string? source = null;
             var result = _comparer?.Equals(source, pattern);
-            Assert.IsTrue(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.True);
         }
         [Test(TestOf = typeof(StringPatternComparer))]
         public void EqualsSourceShorterThanPattern()
@@ -92,7 +102,8 @@ namespace qdr.fnd.core.test
             var pattern = "*A";
             var source = "A";
             var result = _comparer?.Equals(source, pattern);
-            Assert.IsTrue(result);
+            Assert.That(result, Is.Not.Null);
+            Assert.That(result, Is.True);
         }
     }
 }

+ 7 - 7
qdr.fnd.core.test/Value/Generators/TinyHashTest.cs

@@ -7,7 +7,7 @@ namespace qdr.fnd.core.test.Value.Generators
         [Test(TestOf = typeof(TinyHash))]
         public void ImplementsInterface()
         {
-            Assert.IsInstanceOf<IIdGenerator<string>>(new TinyHash());
+            Assert.That(new TinyHash(), Is.InstanceOf<IIdGenerator<string>>());
         }
 
         [Test(TestOf = typeof(TinyHash))]
@@ -34,8 +34,8 @@ namespace qdr.fnd.core.test.Value.Generators
             var result1 = generator.NewId();
             var result2 = generator.NewId();
 
-            Assert.IsNotNull(result1);
-            Assert.IsNotNull(result2);
+            Assert.That(result1, Is.Not.Null);
+            Assert.That(result2, Is.Not.Null);
             Assert.That(result2, Is.Not.EqualTo(result1));
             Assert.That(result1.Length, Is.EqualTo(TinyHash.DefaultLength));
             Assert.That(result2.Length, Is.EqualTo(TinyHash.DefaultLength));
@@ -51,8 +51,8 @@ namespace qdr.fnd.core.test.Value.Generators
             var result1 = generator.NewId();
             var result2 = generator.NewId();
 
-            Assert.IsNotNull(result1);
-            Assert.IsNotNull(result2);
+            Assert.That(result1, Is.Not.Null);
+            Assert.That(result2, Is.Not.Null);
             Assert.That(result2, Is.Not.EqualTo(result1));
             Assert.That(result1.Length, Is.EqualTo(length));
             Assert.That(result2.Length, Is.EqualTo(length));
@@ -67,8 +67,8 @@ namespace qdr.fnd.core.test.Value.Generators
             var result1 = generator.NewId();
             var result2 = generator.NewId();
 
-            Assert.IsNotNull(result1);
-            Assert.IsNotNull(result2);
+            Assert.That(result1, Is.Not.Null);
+            Assert.That(result2, Is.Not.Null);
             Assert.That(result2, Is.Not.EqualTo(result1));
             Assert.That(result1.Length, Is.EqualTo(TinyHash.DefaultLength));
             Assert.That(result2.Length, Is.EqualTo(TinyHash.DefaultLength));

+ 11 - 5
qdr.fnd.core.test/qdr.fnd.core.test.csproj

@@ -10,11 +10,17 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1" />
-    <PackageReference Include="NUnit" Version="3.13.3" />
-    <PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
-    <PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
-    <PackageReference Include="coverlet.collector" Version="3.2.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0-preview-24080-01" />
+    <PackageReference Include="NUnit" Version="4.1.0" />
+    <PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
+    <PackageReference Include="NUnit.Analyzers" Version="4.1.0">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="coverlet.collector" Version="6.0.2">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
   </ItemGroup>
 
   <ItemGroup>

+ 1 - 1
qdr.fnd.core.web/qdr.fnd.core.web.csproj

@@ -30,7 +30,7 @@
 
   <ItemGroup>
     <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
-    <PackageReference Include="NLog" Version="5.2.4" />
+    <PackageReference Include="NLog" Version="5.2.8" />
     <PackageReference Include="qdr.fnd.core" Version="0.0.1-alpha" />
     <PackageReference Include="qdr.fnd.core.business" Version="0.0.1-alpha" />
   </ItemGroup>

+ 101 - 101
qdr.fnd.core/Exceptions/CodeException.cs

@@ -1,108 +1,108 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Quadarax.Foundation.Core.Attributes;
-using Quadarax.Foundation.Core.Value.Extensions;
-
-namespace Quadarax.Foundation.Core.Exceptions
-{
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Quadarax.Foundation.Core.Attributes;
+using Quadarax.Foundation.Core.Value.Extensions;
+
+namespace Quadarax.Foundation.Core.Exceptions
+{
     /// <summary>
     /// Provides a base class for exceptions that include a code.
-    /// </summary>
-    [Serializable]
-    public class CodeException : Exception
-    {
-        public int Code => this.GetCode();
-        public CodeException(int code, string message, Exception innerException) : base(message, innerException)
-        {
-            this.SetCode(code);
-        }
-
-        public CodeException(int code, string message) : base(message)
-        {
-            this.SetCode(code);
-        }
-       
-        public CodeException(int code, string message, params object[] messageArguments) : base(string.Format(message, messageArguments))
-        {
-            this.SetCode(code);
-        }
-        public CodeException(int code, string message, Exception innerException, params object[] messageArguments) : base(string.Format(message, messageArguments), innerException)
-        {
-            this.SetCode(code);
-        }
-
-    }
-
+    /// </summary>
+    [Serializable]
+    public class CodeException : Exception
+    {
+        public int Code => this.GetCode();
+        public CodeException(int code, string message, Exception innerException) : base(message, innerException)
+        {
+            this.SetCode(code);
+        }
+
+        public CodeException(int code, string message) : base(message)
+        {
+            this.SetCode(code);
+        }
+       
+        public CodeException(int code, string message, params object[] messageArguments) : base(string.Format(message, messageArguments))
+        {
+            this.SetCode(code);
+        }
+        public CodeException(int code, string message, Exception innerException, params object[] messageArguments) : base(string.Format(message, messageArguments), innerException)
+        {
+            this.SetCode(code);
+        }
+
+    }
+
     /// <summary>
-    /// Provides a base class for exceptions that include a code in enumeration form.
+    /// Provides a base class for exceptions that include a code in enumeration form.
     /// Exception message is resolved from the <see cref="ErrorMessageAttribute"/> of the enumeration.
     /// </summary>
-    /// <typeparam name="TCodeEnum">Enumeration that defines error codes end its message defined by <see cref="ErrorMessageAttribute"/>.</typeparam>
-    public class CodeException<TCodeEnum> : CodeException where TCodeEnum : struct, Enum
-    {
-
-        public new TCodeEnum Code => (TCodeEnum)Enum.ToObject(typeof(TCodeEnum), this.GetCode());
-
+    /// <typeparam name="TCodeEnum">Enumeration that defines error codes end its message defined by <see cref="ErrorMessageAttribute"/>.</typeparam>
+    public class CodeException<TCodeEnum> : CodeException where TCodeEnum : struct, Enum
+    {
+
+        public new TCodeEnum Code => (TCodeEnum)Enum.ToObject(typeof(TCodeEnum), this.GetCode());
+
         /// <summary>
         /// Static cache for error messages.
-        /// </summary>
-        private static readonly IDictionary<int, string> _messageCache = new Dictionary<int, string>();
-
-        public CodeException(TCodeEnum code, Exception innerException) : base(Convert.ToInt32(code),
-            ResolveMessage(code), innerException)
-        {
-        }
-
-        public CodeException(TCodeEnum code) : base(Convert.ToInt32(code), ResolveMessage(code))
-        {
-        }
-
-        public CodeException(TCodeEnum code, params object[] messageArguments) : base(
-            Convert.ToInt32(code), ResolveMessage(code, messageArguments))
-        {
-        }
-
-        public CodeException(TCodeEnum code, Exception innerException, params object[] messageArguments)
-            : base(Convert.ToInt32(code),ResolveMessage(code,messageArguments), innerException)
-        {
-        }
-
-        private static string ResolveMessage(TCodeEnum code, params object[] messageArguments)
-        {
-            var codeValue = Convert.ToInt32(code);
-            // check if cache is initialized
-            if (_messageCache.Count == 0)
-            {
-                // initialize cache
-                var fields = typeof(TCodeEnum).GetFields();
-                var names = Enum.GetNames(typeof(TCodeEnum)).ToArray();
-                var values = Enum.GetValues(typeof(TCodeEnum));
-                // iterate through all fields of the enumeration
-                foreach (var field in fields)
-                {
-                    var attr = field.GetCustomAttributes(typeof(ErrorMessageAttribute), false);
-                    var index = Array.IndexOf(names, field.Name);
-                    if (index<0) continue;
-                    var fieldVal = (int) (values.GetValue(index) ?? -1);
-                    // if value has attribute ErrorMessageAttribute, add it to the cache
-                    if (attr.Length == 1)
-                    {
-                        var message = ((ErrorMessageAttribute)attr[0]).ErrorMessage;
-                        _messageCache.Add(fieldVal, message);
-                    }
-                    else
-                    {
-                        // message not found, log warning and add default message to the cache
-                        System.Diagnostics.Debug.WriteLine($"Error message in enumeration '{typeof(TCodeEnum).Name}' not found for code '{codeValue}'", "WARN");
-                        _messageCache.Add(fieldVal, $"Error message code: {code} [{fieldVal}]");
-                    }
-                }
-            }
-            // return message from cache
-            return string.Format(_messageCache[codeValue], messageArguments);
-        }
-
-    }
-     
-}
+        /// </summary>
+        private static readonly IDictionary<int, string> _messageCache = new Dictionary<int, string>();
+
+        public CodeException(TCodeEnum code, Exception innerException) : base(Convert.ToInt32(code),
+            ResolveMessage(code), innerException)
+        {
+        }
+
+        public CodeException(TCodeEnum code) : base(Convert.ToInt32(code), ResolveMessage(code))
+        {
+        }
+
+        public CodeException(TCodeEnum code, params object[] messageArguments) : base(
+            Convert.ToInt32(code), ResolveMessage(code, messageArguments))
+        {
+        }
+
+        public CodeException(TCodeEnum code, Exception innerException, params object[] messageArguments)
+            : base(Convert.ToInt32(code),ResolveMessage(code,messageArguments), innerException)
+        {
+        }
+
+        private static string ResolveMessage(TCodeEnum code, params object[] messageArguments)
+        {
+            var codeValue = Convert.ToInt32(code);
+            // check if cache is initialized
+            if (_messageCache.Count == 0)
+            {
+                // initialize cache
+                var fields = typeof(TCodeEnum).GetFields();
+                var names = Enum.GetNames(typeof(TCodeEnum)).ToArray();
+                var values = Enum.GetValues(typeof(TCodeEnum));
+                // iterate through all fields of the enumeration
+                foreach (var field in fields)
+                {
+                    var attr = field.GetCustomAttributes(typeof(ErrorMessageAttribute), false);
+                    var index = Array.IndexOf(names, field.Name);
+                    if (index<0) continue;
+                    var fieldVal = (int) (values.GetValue(index) ?? -1);
+                    // if value has attribute ErrorMessageAttribute, add it to the cache
+                    if (attr.Length == 1)
+                    {
+                        var message = ((ErrorMessageAttribute)attr[0]).ErrorMessage;
+                        _messageCache.Add(fieldVal, message);
+                    }
+                    else
+                    {
+                        // message not found, log warning and add default message to the cache
+                        System.Diagnostics.Debug.WriteLine($"Error message in enumeration '{typeof(TCodeEnum).Name}' not found for code '{codeValue}'", "WARN");
+                        _messageCache.Add(fieldVal, $"Error message code: {code} [{fieldVal}]");
+                    }
+                }
+            }
+            // return message from cache
+            return string.Format(_messageCache[codeValue], messageArguments);
+        }
+
+    }
+     
+}

+ 2 - 2
qdr.fnd.core/IO/FileUtils.cs

@@ -95,7 +95,7 @@ namespace Quadarax.Foundation.Core.IO
         }
         public static string GetConfigPath(IFileSystem fileSystemAbstraction)
         {
-            return EnsurePathNotEndsWithDirSeparator(fileSystemAbstraction, (GetConfigBasePath(fileSystemAbstraction) + fileSystemAbstraction.Path.DirectorySeparatorChar + Assembly.GetEntryAssembly().GetName().Name));
+            return EnsurePathNotEndsWithDirSeparator(fileSystemAbstraction, (GetConfigBasePath(fileSystemAbstraction) + fileSystemAbstraction.Path.DirectorySeparatorChar + Assembly.GetEntryAssembly()?.GetName().Name));
         }
 
         public static string GetLogsPath(IFileSystem fileSystemAbstraction)
@@ -104,7 +104,7 @@ namespace Quadarax.Foundation.Core.IO
         }
 
 
-        public static string GetLogBasePath(IFileSystem fileSystemAbstraction)
+        public static string? GetLogBasePath(IFileSystem fileSystemAbstraction)
         {
 #if LINUX
             return $"{fileSystemAbstraction.Path.DirectorySeparatorChar}var{fileSystemAbstraction.Path.DirectorySeparatorChar}logs";

+ 26 - 12
qdr.fnd.core/Json/Binder.cs

@@ -87,14 +87,20 @@ namespace Quadarax.Foundation.Core.Json
                     if (property.GetType().IsClass && property.PropertyType.Assembly.FullName == targetType.Assembly.FullName)
                     {
                         var mapMethod = typeof(Binder).GetMethod("LoadTo");
-                        var genericMethod = mapMethod?.MakeGenericMethod(property.GetValue(shadow).GetType());
-                        var obj2 = genericMethod.Invoke(null, new object[] { property.GetValue(shadow), JsonSerializer.Serialize(property.GetValue(shadow)) });
+                        var shadowValue = property.GetValue(shadow);
+                        var shadowType = property.GetValue(shadow)?.GetType() ?? property.PropertyType;
+                        var genericMethod = mapMethod?.MakeGenericMethod(shadowType);
+                        var obj2 = genericMethod?.Invoke(null, new object?[] { shadowValue, JsonSerializer.Serialize(property.GetValue(shadow)) });
 
-                        foreach (var property2 in obj2.GetType().GetProperties())
+                        if (obj2 != null)
                         {
-                            if (property2.GetValue(obj2) != null)
+                            foreach (var property2 in obj2.GetType().GetProperties())
                             {
-                                property.GetValue(target).GetType().GetProperty(property2.Name).SetValue(property.GetValue(target), property2.GetValue(obj2));
+                                if (property2.GetValue(obj2) != null)
+                                {
+                                    (property.GetValue(target)?.GetType() ?? property.PropertyType).GetProperty(
+                                        property2.Name)!.SetValue(property.GetValue(target), property2.GetValue(obj2));
+                                }
                             }
                         }
                     }
@@ -115,7 +121,8 @@ namespace Quadarax.Foundation.Core.Json
             if (target == null)
                 throw new ArgumentNullException(nameof(target));
             var shadow = LoadFromString(jsonString, targetType);
-            
+            if(shadow == null) throw new InvalidOperationException($"Cannot load object ({targetType.FullName}) from json string.");
+
             foreach (var property in shadow.GetType().GetProperties())
             {
                 if (target.GetType().GetProperties().Any(x => x.Name == property.Name && property.GetValue(shadow) != null))
@@ -123,14 +130,18 @@ namespace Quadarax.Foundation.Core.Json
                     if (property.GetType().IsClass && property.PropertyType.Assembly.FullName == targetType.Assembly.FullName)
                     {
                         var mapMethod = typeof(Binder).GetMethod("LoadFromStringTo");
-                        var genericMethod = mapMethod.MakeGenericMethod(property.GetValue(shadow).GetType());
-                        var obj2 = genericMethod.Invoke(null, new object[] { property.GetValue(shadow), JsonSerializer.Serialize(property.GetValue(shadow)) });
-
-                        foreach (var property2 in obj2.GetType().GetProperties())
+                        var shadowType = property.GetValue(shadow)?.GetType() ?? property.PropertyType;
+                        var genericMethod = mapMethod?.MakeGenericMethod(shadowType);
+                        var obj2 = genericMethod?.Invoke(null, new object?[] { property.GetValue(shadow), JsonSerializer.Serialize(property.GetValue(shadow)) });
+                        if (obj2 != null)
                         {
-                            if (property2.GetValue(obj2) != null)
+                            foreach (var property2 in obj2.GetType().GetProperties())
                             {
-                                property.GetValue(target).GetType().GetProperty(property2.Name).SetValue(property.GetValue(target), property2.GetValue(obj2));
+                                if (property2.GetValue(obj2) != null)
+                                {
+                                    property?.GetValue(target)?.GetType()?.GetProperty(property2.Name)?
+                                        .SetValue(property.GetValue(target), property2.GetValue(obj2));
+                                }
                             }
                         }
                     }
@@ -145,6 +156,9 @@ namespace Quadarax.Foundation.Core.Json
 
         public void LoadTo<TObject>(string fileName, TObject target)
         {
+            if (target == null)
+                throw new ArgumentNullException(nameof(target));
+
             LoadTo(fileName, target, typeof(TObject));
         }
 

+ 2 - 2
qdr.fnd.core/Json/IListConverterFactory.cs

@@ -25,9 +25,9 @@ namespace Quadarax.Foundation.Core.Json
             return false;
         }
 
-        public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+        public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
         {
-            return (JsonConverter)Activator.CreateInstance(
+            return (JsonConverter?)Activator.CreateInstance(
                 typeof(ListConverter<>).MakeGenericType(this.InterfaceType));
         }
     }

+ 1 - 1
qdr.fnd.core/Json/InterfaceConverter.cs

@@ -6,7 +6,7 @@ namespace Quadarax.Foundation.Core.Json
 {
     public class InterfaceConverter<M, I> : JsonConverter<I> where M : class, I
     {
-        public override I Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        public override I? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
         {
             return JsonSerializer.Deserialize<M>(ref reader, options);
         }

+ 1 - 1
qdr.fnd.core/Json/InterfaceConverterFactory.cs

@@ -24,7 +24,7 @@ namespace Quadarax.Foundation.Core.Json
         {
             var converterType = typeof(InterfaceConverter<,>).MakeGenericType(this.ConcreteType, this.InterfaceType);
 
-            return (JsonConverter)Activator.CreateInstance(converterType);
+            return (JsonConverter)Activator.CreateInstance(converterType)!;
         }
     }
 }

+ 1 - 1
qdr.fnd.core/Json/ListConverter.cs

@@ -7,7 +7,7 @@ namespace Quadarax.Foundation.Core.Json
 {
     public class ListConverter<M> : JsonConverter<IList<M>>
     {
-        public override IList<M> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+        public override IList<M>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
         {
             return JsonSerializer.Deserialize<List<M>>(ref reader, options);
         }

+ 16 - 19
qdr.fnd.core/Mapper/Loom.cs

@@ -30,8 +30,7 @@ namespace Quadarax.Foundation.Core.Mapper
         /// <param name="map">The mapping function.</param>
         public void Define<TFrom, TTo>(Action<TFrom, TTo> map)
         {
-            Dictionary<Type, Delegate> inner;
-            if (!_maps.TryGetValue(typeof(TFrom), out inner))
+            if (!_maps.TryGetValue(typeof(TFrom), out Dictionary<Type, Delegate>? inner))
             {
                 inner = new Dictionary<Type, Delegate>();
                 _maps[typeof(TFrom)] = inner;
@@ -45,12 +44,10 @@ namespace Quadarax.Foundation.Core.Mapper
         /// <typeparam name="TFrom">The source type.</typeparam>
         /// <typeparam name="TTo">The destination type.</typeparam>
         /// <returns>The mapping function for the given combination of types or a null reference when not defined.</returns>
-        public Action<TFrom, TTo> Find<TFrom, TTo>()
+        public Action<TFrom, TTo>? Find<TFrom, TTo>()
         {
-            Dictionary<Type, Delegate> inner;
-            if (!_maps.TryGetValue(typeof(TFrom), out inner)) return null;
-            Delegate map;
-            if (!inner.TryGetValue(typeof(TTo), out map)) return null;
+            if (!_maps.TryGetValue(typeof(TFrom), out Dictionary<Type, Delegate>? inner)) return null;
+            if (!inner.TryGetValue(typeof(TTo), out var map)) return null;
             return (Action<TFrom, TTo>) map;
         }
 
@@ -65,9 +62,9 @@ namespace Quadarax.Foundation.Core.Mapper
             where TFrom : class
             where TTo : class
         {
-            if (from == null) throw new ArgumentNullException("from");
-            if (to == null) throw new ArgumentNullException("to");
-            Find<TFrom, TTo>()(from, to);
+            if (from == null) throw new ArgumentNullException(nameof(from));
+            if (to == null) throw new ArgumentNullException(nameof(to));
+            Find<TFrom, TTo>()?.Invoke(from, to);
         }
 
         /// <summary>
@@ -77,13 +74,13 @@ namespace Quadarax.Foundation.Core.Mapper
         /// <typeparam name="TTo">The destination type.</typeparam>
         /// <param name="from">The source object.</param>
         /// <returns>The destination object or a null reference in case <paramref name="from"/> is a null reference, too.</returns>
-        public TTo Map<TFrom, TTo>(TFrom from)
+        public TTo? Map<TFrom, TTo>(TFrom? from)
             where TFrom : class
             where TTo : class, new()
         {
             if (from == null) return null;
             var to = new TTo();
-            Find<TFrom, TTo>()(from, to);
+            Find<TFrom, TTo>()?.Invoke(from, to);
             return to;
         }
 
@@ -94,7 +91,7 @@ namespace Quadarax.Foundation.Core.Mapper
         /// <typeparam name="TTo">The destination type.</typeparam>
         /// <param name="from">The source objects.</param>
         /// <returns>The destination objects.</returns>
-        public List<TTo> Map<TFrom, TTo>(IEnumerable<TFrom> from)
+        public List<TTo>? Map<TFrom, TTo>(IEnumerable<TFrom>? from)
             where TFrom : class
             where TTo : class, new()
         {
@@ -102,7 +99,7 @@ namespace Quadarax.Foundation.Core.Mapper
             var map = Find<TFrom, TTo>();
             return new List<TTo>(from.Select(f => { 
                 var to = new TTo();
-                map(f, to);
+                map?.Invoke(f, to);
                 return to;
             }));
         }
@@ -114,7 +111,7 @@ namespace Quadarax.Foundation.Core.Mapper
         /// <typeparam name="TTo">The destination type.</typeparam>
         /// <param name="from">The source objects.</param>
         /// <returns>The destination objects.</returns>
-        public List<TTo> MapList<TFrom, TTo>(IEnumerable<TFrom> from)
+        public List<TTo>? MapList<TFrom, TTo>(IEnumerable<TFrom>? from)
             where TFrom : class
             where TTo : class, new()
         {
@@ -131,7 +128,7 @@ namespace Quadarax.Foundation.Core.Mapper
         /// <typeparam name="TTo">The destination type.</typeparam>
         /// <param name="from">The source objects.</param>
         /// <returns>The destination objects.</returns>
-        public List<TTo> MapList<TFrom, TTo>(IQueryable<TFrom> from)
+        public List<TTo>? MapList<TFrom, TTo>(IQueryable<TFrom>? from)
             where TFrom : class
             where TTo : class, new()
         {
@@ -142,19 +139,19 @@ namespace Quadarax.Foundation.Core.Mapper
 
         #region ------ Internals ------------------------------------------------------------------
 
-        private TTo New<TFrom, TTo>(Action<TFrom, TTo> map, TFrom f)
+        private TTo New<TFrom, TTo>(Action<TFrom, TTo>? map, TFrom f)
             where TFrom : class
             where TTo : class, new()
         {
             var to = new TTo();
-            map(f, to);
+            map?.Invoke(f, to);
             return to;
         }
 
         /// <summary>
         /// Repository of all known mapping functions.
         /// </summary>
-        private readonly Dictionary<Type, Dictionary<Type, Delegate>> _maps = new Dictionary<Type, Dictionary<Type, Delegate>>();
+        private readonly Dictionary<Type, Dictionary<Type, Delegate>> _maps = new();
 
         #endregion
     }

+ 3 - 3
qdr.fnd.core/Mapper/LoomBuilder.cs

@@ -56,7 +56,7 @@ namespace Quadarax.Foundation.Core.Mapper
 
             protected override Expression VisitParameter(ParameterExpression node)
             {
-                return node.Name.Equals(oldParam.Name) ? newParam : node;
+                return node.Name != null && node.Name.Equals(oldParam.Name) ? newParam : node;
             }
         }
 
@@ -90,7 +90,7 @@ namespace Quadarax.Foundation.Core.Mapper
                     else
                     {
                         // source may be Nullable<T>
-                        Type sourceNullabeType = Nullable.GetUnderlyingType(sourceProp.PropertyType);
+                        Type? sourceNullabeType = Nullable.GetUnderlyingType(sourceProp.PropertyType);
                         if (sourceNullabeType != null && destProp.PropertyType.IsAssignableFrom(sourceNullabeType))
                         {
                             rules.Add(Expression.IfThen(
@@ -104,7 +104,7 @@ namespace Quadarax.Foundation.Core.Mapper
             return this;
         }
 
-        public Func<TFrom, TTo> Compile()
+        public Func<TFrom, TTo?> Compile()
         {
             var parameters = new[] {sourceObj, destObj};
             var body = Expression.Block(rules);

+ 1 - 1
qdr.fnd.core/Object/Extensions/ObjectExt.cs

@@ -6,7 +6,7 @@ namespace Quadarax.Foundation.Core.Object.Extensions
 {
     public static class ObjectExt
     {
-        public static IDictionary<string, object> GetAllPropertyValues(this object? obj,string? indentPrefix = null)
+        public static IDictionary<string, object?> GetAllPropertyValues(this object? obj,string? indentPrefix = null)
         {
             var props = new Dictionary<string, object?>();
             if (obj == null)

+ 4 - 3
qdr.fnd.core/Thread/ContiguousWorker.cs

@@ -14,12 +14,13 @@ namespace Quadarax.Foundation.Core.Thread
         #endregion
 
         #region *** Constructors ***
-        public ContiguousWorker(Func<Task> body = null) : base()
+        public ContiguousWorker(Func<Task> body) : base()
         {
             _body = body;
         }
-        public ContiguousWorker(string workerName, ILogger logger = null) : base(workerName,null, logger)
+        public ContiguousWorker(string workerName, ILogger? logger = null) : base(workerName,null, logger)
         {
+            _body = () => Task.CompletedTask;
         }
         #endregion
 
@@ -27,7 +28,7 @@ namespace Quadarax.Foundation.Core.Thread
         #endregion
 
         #region *** Virtuals and protected ***
-        protected override async Task Do(IWorkerContext context)
+        protected override async Task Do(IWorkerContext? context)
         {
             await _body.Invoke();
         }

+ 67 - 0
qdr.fnd.core/Thread/MoshPit.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Quadarax.Foundation.Core.Thread
+{
+    public class MoshPit<TContext> where TContext : class
+    {
+        private readonly List<Action<TContext>> _actions;
+        private Timer? _timer;
+        private readonly Random _random;
+
+
+        public TContext Context { get; set; }
+
+        public long Iterations { get; private set; }
+        public TimeSpan AvgIterationDuration { get; private set; }
+        public TimeSpan TotalDuration { get; private set; }
+        public decimal AvgIterationPerSecond { get; private set; }
+        public MoshPit(TContext context)
+        {
+            Context = context;
+            _actions = new List<Action<TContext>>();
+            _random = new Random();
+        }
+
+        public void AddAction(Action<TContext> action)
+        {
+            _actions.Add(action);
+        }
+
+        public void Start(int iterationInterval, int totalDuration)
+        {
+            _timer = new Timer(ExecuteRandomAction, Context, 0, iterationInterval);
+
+            // Stop the _timer after the specified duration
+            _ = new Timer((e) => _timer.Dispose(), null, totalDuration, Timeout.Infinite);
+
+            System.Threading.Thread.Sleep(totalDuration);
+        }
+
+        private void ExecuteRandomAction(object? state)
+        {
+            if (state == null)
+                throw new ArgumentNullException(nameof(state));
+
+            var context = (TContext)state;
+
+            if (_actions.Count > 0)
+            {
+                Iterations++;
+                var index = _random.Next(_actions.Count);
+                var startIteration = DateTime.Now;
+
+                _actions[index](context);
+                
+                var durationIteration = DateTime.Now - startIteration;
+                TotalDuration = TotalDuration.Add(durationIteration);
+                AvgIterationDuration = TimeSpan.FromTicks(TotalDuration.Ticks / Iterations);
+                if (AvgIterationDuration==TimeSpan.Zero)
+                    AvgIterationPerSecond = 0;
+                else
+                    AvgIterationPerSecond = TimeSpan.FromSeconds(1).Ticks / (decimal)AvgIterationDuration.Ticks;
+            }
+        }
+    }
+}

+ 18 - 0
qdr.fnd.core/Value/Enumeration.cs

@@ -0,0 +1,18 @@
+using System;
+
+namespace Quadarax.Foundation.Core.Value
+{
+    public static  class Enumeration
+    {
+        private static readonly Random _random = new Random();
+        public static TEnumValue GetRandom<TEnumValue>() where TEnumValue : Enum
+        {
+            var values = Enum.GetValues(typeof(TEnumValue));
+            var result = values.GetValue(_random.Next(values.Length));
+            if (result is null)
+                return default!;
+            return (TEnumValue)result;
+
+        }
+    }
+}

+ 24 - 24
qdr.fnd.core/Value/Result.cs

@@ -1,24 +1,24 @@
-using System;
-
-namespace Quadarax.Foundation.Core.Value
-{
-    
-    public class Result
-    {        
-    
-        public bool IsSuccess { get; }
-        public Exception ThrownException { get; }
-
-
-        public Result(Exception e)
-        {
-            ThrownException = e;
-            IsSuccess = false;
-        }
-        
-        public Result()
-        {
-            IsSuccess = true;
-        }
-    }
-}
+using System;
+
+namespace Quadarax.Foundation.Core.Value
+{
+    
+    public class Result
+    {        
+    
+        public bool IsSuccess { get; }
+        public Exception? ThrownException { get; }
+
+
+        public Result(Exception e)
+        {
+            ThrownException = e;
+            IsSuccess = false;
+        }
+
+        public Result()
+        {
+            IsSuccess = true;
+        }
+    }
+}

+ 4 - 4
qdr.fnd.core/Value/Validator.cs

@@ -35,12 +35,12 @@ namespace Quadarax.Foundation.Core.Value
             Results.Clear();
         }
 
-        public AggregateException ToAggregateException(bool includeWarning = false, bool inclueInfo = false)
+        public AggregateException? ToAggregateException(bool includeWarning = false, bool inclueInfo = false)
         {
             return ToAggregateException(Results, includeWarning, inclueInfo);
         }
 
-        public static AggregateException ToAggregateException(IEnumerable<ValidationResult> results, bool includeWarning = false, bool inclueInfo = false)
+        public static AggregateException? ToAggregateException(IEnumerable<ValidationResult> results, bool includeWarning = false, bool inclueInfo = false)
         {
             var errors = new List<Exception>();
             foreach (var result in results)
@@ -74,7 +74,7 @@ namespace Quadarax.Foundation.Core.Value
             return true;
         }
 
-        protected bool CheckIfNull(string name,object value, ValidationResult.ValidationSeverityEnum severity, string description = "")
+        protected bool CheckIfNull(string name,object? value, ValidationResult.ValidationSeverityEnum severity, string description = "")
         {
             if (value!=null) 
                 return false;
@@ -85,7 +85,7 @@ namespace Quadarax.Foundation.Core.Value
             return true;
         }
 
-        protected bool CheckIfCollectionEmpty(string name,IEnumerable<object> value, ValidationResult.ValidationSeverityEnum severity, string description = "")
+        protected bool CheckIfCollectionEmpty(string name,IEnumerable<object>? value, ValidationResult.ValidationSeverityEnum severity, string description = "")
         {
             if (value!=null && value.Any())  
                 return false;

+ 9 - 9
qdr.fnd.core/Value/ValidatorContext.cs

@@ -4,23 +4,23 @@ namespace Quadarax.Foundation.Core.Value
 {
     public class ValidatorContext
     {
-        private readonly IDictionary<string, object> _context = new Dictionary<string, object>();
+        private readonly IDictionary<string, object?> _context = new Dictionary<string, object?>();
 
         public ValidatorContext()
         {
         }
-        public ValidatorContext(IEnumerable<KeyValuePair<string,object>> initialContext)
+
+        public ValidatorContext(IEnumerable<KeyValuePair<string, object?>> initialContext)
         {
-            if (initialContext != null)
-                foreach (var item in initialContext)
-                {
-                    _context.Add(item);    
-                }
+            foreach (var item in initialContext)
+            {
+                _context.Add(item);
+            }
         }
 
-        public TValue GetValue<TValue>(string key)
+        public TValue? GetValue<TValue>(string key)
         {
-            return (TValue) _context[key];
+            return (TValue?) _context[key];
         }
 
         public void SetValue<TValue>(string key, TValue value)

+ 4 - 2
qdr.fnd.core/qdr.fnd.core.csproj

@@ -18,7 +18,9 @@
     <AssemblyVersion>0.0.4.0</AssemblyVersion>
     <FileVersion>0.0.4.0</FileVersion>
     <Version>0.0.4.0-alpha</Version>
-    <PackageReleaseNotes>Date:22.3.2024
+    <PackageReleaseNotes>Date:24.3.2024
+      - add Value/Enumeration class with method GetRandom
+      - add Thread/MoshPit class to process random operations
       - extends Data/IError add Timestamp property, Error implementation modified
       - extends Data/TypedArgument to use null value and valuyeType at once, add Value setter
       - add constructor to Exceptions/CodeException to support parameter message
@@ -49,7 +51,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="System.IO.Abstractions" Version="20.0.28" />
+    <PackageReference Include="System.IO.Abstractions" Version="21.0.2" />
   </ItemGroup>
 
   <ItemGroup>

+ 3 - 1
qdr.fnd.core/releasenotes.md

@@ -2,7 +2,9 @@
 Ordered by version descending
 
 ## 0.0.4.0
-Date:__22.3.2024__
+Date:__24.3.2024__
+- add Value/Enumeration class with method GetRandom
+- add Thread/MoshPit class to process random operations
 - extends Data/IError add Timestamp property, Error implementation modified
 - extends Data/TypedArgument to use null value and valuyeType at once, add Value setter
 - add constructor to Exceptions/CodeException to support parameter message

+ 2 - 0
qdr.fnd.sln.DotSettings

@@ -0,0 +1,2 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:Boolean x:Key="/Default/UserDictionary/Words/=Quadarax/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>