From 04c8d57f221be47e3f4f1534c59d0ce735f75042 Mon Sep 17 00:00:00 2001 From: Gregor Mohorko Date: Thu, 8 Feb 2024 20:35:57 +0100 Subject: [PATCH 1/6] feat: Additional debug logging of ThrottlerPerTime --- src/GM.Utility/GM.Utility/GM.Utility.csproj | 3 ++- .../GM.Utility/Throttling/ThrottlerPerTime.cs | 21 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/GM.Utility/GM.Utility/GM.Utility.csproj b/src/GM.Utility/GM.Utility/GM.Utility.csproj index e4a56bb..5fbdeff 100644 --- a/src/GM.Utility/GM.Utility/GM.Utility.csproj +++ b/src/GM.Utility/GM.Utility/GM.Utility.csproj @@ -28,7 +28,8 @@ - + + diff --git a/src/GM.Utility/GM.Utility/Throttling/ThrottlerPerTime.cs b/src/GM.Utility/GM.Utility/Throttling/ThrottlerPerTime.cs index 6941aeb..9aa5560 100644 --- a/src/GM.Utility/GM.Utility/Throttling/ThrottlerPerTime.cs +++ b/src/GM.Utility/GM.Utility/Throttling/ThrottlerPerTime.cs @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2023 Gregor Mohorko +Copyright (c) 2024 Gregor Mohorko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -29,6 +29,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; namespace GM.Utility.Throttling; /// @@ -49,17 +50,33 @@ public class ThrottlerPerTime private volatile int _executionLogPosition; private readonly DateTime[] _executionLog; + private readonly ILogger _logger; + /// /// Creates a new instance of . /// /// The time frame. /// The max number of executions that are allowed in the specified time frame. Zero means no limit. + /// Thrown when max executions is not non-negative. public ThrottlerPerTime(TimeSpan time, int maxExecutions) + : this(time, maxExecutions, null) + { } + + /// + /// Creates a new instance of . + /// + /// The time frame. + /// The max number of executions that are allowed in the specified time frame. Zero means no limit. + /// Logger. + /// Thrown when max executions is not non-negative. + public ThrottlerPerTime(TimeSpan time, int maxExecutions, ILogger logger) { if(maxExecutions < 0) { throw new ArgumentOutOfRangeException(nameof(maxExecutions), maxExecutions, "Should be non-negative."); } + _logger = logger; + Time = time; MaxExecutions = maxExecutions; @@ -86,6 +103,7 @@ public async Task WaitExecutionLimit(CancellationToken ct) nextAvailableExecutionAt = _executionLog[_executionLogPosition].Add(Time); if(utcNow >= nextAvailableExecutionAt) { // can execute now + _logger?.LogDebug("Position: {current}/{total}. Can execute now, since NextAvailableExecutionAt={nextAvailableExecutionAt} <= UtcNow={utcNow}.", _executionLogPosition, _executionLog.Length, nextAvailableExecutionAt, utcNow); // log new execution _executionLog[_executionLogPosition] = DateTime.UtcNow; @@ -99,6 +117,7 @@ public async Task WaitExecutionLimit(CancellationToken ct) // wait and try again at next available execution var sleepTime = nextAvailableExecutionAt - utcNow; + _logger?.LogDebug("Position: {current}/{total}. Cannot execute now, since NextAvailableExecutionAt={nextAvailableExecutionAt} > UtcNow={utcNow}. Sleeping for {sleepTime}.", _executionLogPosition, _executionLog.Length, nextAvailableExecutionAt, utcNow, sleepTime); await Task.Delay(sleepTime, ct); } } From 88d58fd8fa62c347749a2abf37279483cb2ba338 Mon Sep 17 00:00:00 2001 From: Gregor Mohorko Date: Wed, 22 May 2024 13:12:19 +0200 Subject: [PATCH 2/6] feat: Add TimeSpanUtility --- src/GM.Utility/GM.Utility/TimeSpanUtility.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/GM.Utility/GM.Utility/TimeSpanUtility.cs diff --git a/src/GM.Utility/GM.Utility/TimeSpanUtility.cs b/src/GM.Utility/GM.Utility/TimeSpanUtility.cs new file mode 100644 index 0000000..70dc9b7 --- /dev/null +++ b/src/GM.Utility/GM.Utility/TimeSpanUtility.cs @@ -0,0 +1,18 @@ +using System; + +namespace GM.Utility; +/// +/// Utilities for . +/// +public static class TimeSpanUtility +{ + /// + /// Returns the maximum value of the two provided values. + /// + /// The first value. + /// The second value. + public static TimeSpan Max(TimeSpan val1, TimeSpan val2) + { + return val1 > val2 ? val1 : val2; + } +} From 8b28eaa59a73d00b461467c112b7b63336838156 Mon Sep 17 00:00:00 2001 From: Gregor Mohorko Date: Wed, 31 Jul 2024 02:11:42 +0200 Subject: [PATCH 3/6] tests: Update tests --- src/.gitignore => .gitignore | 0 .../GM.Utility.sln => GM.Utility.sln | 15 +- .../{GM.Utility => }/ArrayUtility.cs | 0 .../{GM.Utility => }/BigIntegerUtility.cs | 0 .../{GM.Utility => }/BoolUtility.cs | 0 .../Collections/ReloadableCollection.cs | 0 .../Collections/SortableBindingList.cs | 0 .../{GM.Utility => }/ColorUtility.cs | 0 .../{GM.Utility => }/CryptographyUtility.cs | 0 src/GM.Utility/{GM.Utility => }/CsvUtility.cs | 0 .../{GM.Utility => }/DateTimeUtility.cs | 0 .../{GM.Utility => }/DayOfWeekUtility.cs | 0 .../{GM.Utility => }/DecimalUtility.cs | 0 .../{GM.Utility => }/DefaultedObject.cs | 0 .../{GM.Utility => }/DefensiveUtility.cs | 0 .../{GM.Utility => }/DictionaryUtility.cs | 0 .../{GM.Utility => }/DoubleUtility.cs | 0 .../{GM.Utility => }/EmailUtility.cs | 0 .../{GM.Utility => }/EnumUtility.cs | 0 .../{GM.Utility => }/EnvironmentUtility.cs | 0 .../ReferenceEqualityComparer.cs | 0 .../{GM.Utility => }/EqualityUtility.cs | 0 .../{GM.Utility => }/ExcelUtility.cs | 0 .../{GM.Utility => }/ExceptionUtility.cs | 0 .../{GM.Utility => }/Framework/Enumeration.cs | 0 .../GM.Utility.Test/DateTimeUtilityTest.cs | 123 --------------- .../GM.Utility.Test/DecimalUtilityTest.cs | 94 ----------- .../GM.Utility.Test/DefaultedObjectTest.cs | 95 ------------ .../GM.Utility.Test/DoubleUtilityTest.cs | 90 ----------- .../GM.Utility.Test/GM.Utility.Test.csproj | 87 ----------- .../GM.Utility.Test/IEnumerableUtilityTest.cs | 111 ------------- .../GM.Utility.Test/ReflectionUtilityTest.cs | 146 ------------------ .../GM.Utility.Test/StringUtilityTest.cs | 54 ------- src/GM.Utility/GM.Utility.Test/UtilTest.cs | 55 ------- .../GM.Utility.Test/WildcardUtilityTest.cs | 71 --------- .../GM.Utility.Test/packages.config | 5 - .../{GM.Utility => }/GM.Utility.csproj | 2 +- .../{GM.Utility => }/GM.Utility.licenseheader | 0 src/GM.Utility/GM.Utility/TimeSpanUtility.cs | 18 --- .../{GM.Utility => }/GlobalizationUtility.cs | 0 .../{GM.Utility => }/HashCodeUtility.cs | 0 .../{GM.Utility => }/IEnumerableUtility.cs | 0 src/GM.Utility/{GM.Utility => }/IOUtility.cs | 0 src/GM.Utility/{GM.Utility => }/IntUtility.cs | 0 src/GM.Utility/{GM.Utility => }/KeyCodes.cs | 0 .../{GM.Utility => }/ListUtility.cs | 0 .../{GM.Utility => }/LongUtility.cs | 0 .../{GM.Utility => }/Net/GMHttpClient.cs | 0 .../{GM.Utility => }/NetworkUtility.cs | 0 .../{GM.Utility => }/ObjectUtility.cs | 0 .../{GM.Utility => }/ParseUtility.cs | 0 .../{GM.Utility => }/PathUtility.cs | 0 .../{GM.Utility => }/Patterns/Singleton.cs | 0 .../Patterns/UndoRedo/GMUndoRedo.cs | 0 .../Patterns/UndoRedo/UndoRedoAction.cs | 0 .../{GM.Utility => }/RandomUtility.cs | 0 .../{GM.Utility => }/ReflectionUtility.cs | 0 .../{GM.Utility => }/SecureStringUtility.cs | 0 .../{GM.Utility => }/StatisticUtility.cs | 0 .../{GM.Utility => }/StringUtility.cs | 0 .../{GM.Utility => }/TaskUtility.cs | 0 .../Throttling/ThrottlerPerTime.cs | 74 +++++++-- .../UriUtilityTest.cs => TimeSpanUtility.cs} | 31 ++-- .../{GM.Utility => }/ToStringUtility.cs | 0 .../{GM.Utility => }/TypeUtility.cs | 0 src/GM.Utility/{GM.Utility => }/UriUtility.cs | 0 src/GM.Utility/{GM.Utility => }/Util.cs | 0 .../{GM.Utility => }/ValueTypeUtility.cs | 0 .../{GM.Utility => }/WildcardUtility.cs | 0 src/GM.Utility/{GM.Utility => }/XMLUtility.cs | 0 src/GM.Utility/{GM.Utility => }/icon.png | Bin .../ArrayUtilityTests.cs | 57 ++++--- .../DateTimeUtilityTests.cs | 117 ++++++++++++++ .../DecimalUtilityTests.cs | 85 ++++++++++ .../DefaultedObjectTests.cs | 90 +++++++++++ .../DoubleUtilityTests.cs | 85 ++++++++++ .../EmailUtilityTests.cs | 33 ++-- .../EnumUtilityTests.cs | 28 ++-- .../GM.Utility.Testing.Unit.csproj | 27 ++++ .../GM.Utility.Testing.Unit.licenseheader | 2 +- .../IEnumerableUtilityTests.cs | 104 +++++++++++++ .../ReflectionUtilityTests.cs | 137 ++++++++++++++++ .../StringUtilityTests.cs | 51 +++--- .../UriUtilityTests.cs | 38 +++++ testing/GM.Utility.Testing.Unit/UtilTests.cs | 46 ++++++ .../WildcardUtilityTests.cs | 63 ++++++++ 86 files changed, 950 insertions(+), 1084 deletions(-) rename src/.gitignore => .gitignore (100%) rename src/GM.Utility/GM.Utility.sln => GM.Utility.sln (67%) rename src/GM.Utility/{GM.Utility => }/ArrayUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/BigIntegerUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/BoolUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/Collections/ReloadableCollection.cs (100%) rename src/GM.Utility/{GM.Utility => }/Collections/SortableBindingList.cs (100%) rename src/GM.Utility/{GM.Utility => }/ColorUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/CryptographyUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/CsvUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/DateTimeUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/DayOfWeekUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/DecimalUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/DefaultedObject.cs (100%) rename src/GM.Utility/{GM.Utility => }/DefensiveUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/DictionaryUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/DoubleUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/EmailUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/EnumUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/EnvironmentUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/EqualityComparers/ReferenceEqualityComparer.cs (100%) rename src/GM.Utility/{GM.Utility => }/EqualityUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/ExcelUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/ExceptionUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/Framework/Enumeration.cs (100%) delete mode 100644 src/GM.Utility/GM.Utility.Test/DateTimeUtilityTest.cs delete mode 100644 src/GM.Utility/GM.Utility.Test/DecimalUtilityTest.cs delete mode 100644 src/GM.Utility/GM.Utility.Test/DefaultedObjectTest.cs delete mode 100644 src/GM.Utility/GM.Utility.Test/DoubleUtilityTest.cs delete mode 100644 src/GM.Utility/GM.Utility.Test/GM.Utility.Test.csproj delete mode 100644 src/GM.Utility/GM.Utility.Test/IEnumerableUtilityTest.cs delete mode 100644 src/GM.Utility/GM.Utility.Test/ReflectionUtilityTest.cs delete mode 100644 src/GM.Utility/GM.Utility.Test/StringUtilityTest.cs delete mode 100644 src/GM.Utility/GM.Utility.Test/UtilTest.cs delete mode 100644 src/GM.Utility/GM.Utility.Test/WildcardUtilityTest.cs delete mode 100644 src/GM.Utility/GM.Utility.Test/packages.config rename src/GM.Utility/{GM.Utility => }/GM.Utility.csproj (98%) rename src/GM.Utility/{GM.Utility => }/GM.Utility.licenseheader (100%) delete mode 100644 src/GM.Utility/GM.Utility/TimeSpanUtility.cs rename src/GM.Utility/{GM.Utility => }/GlobalizationUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/HashCodeUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/IEnumerableUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/IOUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/IntUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/KeyCodes.cs (100%) rename src/GM.Utility/{GM.Utility => }/ListUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/LongUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/Net/GMHttpClient.cs (100%) rename src/GM.Utility/{GM.Utility => }/NetworkUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/ObjectUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/ParseUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/PathUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/Patterns/Singleton.cs (100%) rename src/GM.Utility/{GM.Utility => }/Patterns/UndoRedo/GMUndoRedo.cs (100%) rename src/GM.Utility/{GM.Utility => }/Patterns/UndoRedo/UndoRedoAction.cs (100%) rename src/GM.Utility/{GM.Utility => }/RandomUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/ReflectionUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/SecureStringUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/StatisticUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/StringUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/TaskUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/Throttling/ThrottlerPerTime.cs (54%) rename src/GM.Utility/{GM.Utility.Test/UriUtilityTest.cs => TimeSpanUtility.cs} (68%) rename src/GM.Utility/{GM.Utility => }/ToStringUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/TypeUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/UriUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/Util.cs (100%) rename src/GM.Utility/{GM.Utility => }/ValueTypeUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/WildcardUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/XMLUtility.cs (100%) rename src/GM.Utility/{GM.Utility => }/icon.png (100%) rename src/GM.Utility/GM.Utility.Test/Properties/AssemblyInfo.cs => testing/GM.Utility.Testing.Unit/ArrayUtilityTests.cs (58%) create mode 100644 testing/GM.Utility.Testing.Unit/DateTimeUtilityTests.cs create mode 100644 testing/GM.Utility.Testing.Unit/DecimalUtilityTests.cs create mode 100644 testing/GM.Utility.Testing.Unit/DefaultedObjectTests.cs create mode 100644 testing/GM.Utility.Testing.Unit/DoubleUtilityTests.cs rename src/GM.Utility/GM.Utility.Test/EmailUtilityTest.cs => testing/GM.Utility.Testing.Unit/EmailUtilityTests.cs (60%) rename src/GM.Utility/GM.Utility.Test/EnumUtilityTest.cs => testing/GM.Utility.Testing.Unit/EnumUtilityTests.cs (67%) create mode 100644 testing/GM.Utility.Testing.Unit/GM.Utility.Testing.Unit.csproj rename src/GM.Utility/GM.Utility.Test/GM.Utility.Test.licenseheader => testing/GM.Utility.Testing.Unit/GM.Utility.Testing.Unit.licenseheader (96%) create mode 100644 testing/GM.Utility.Testing.Unit/IEnumerableUtilityTests.cs create mode 100644 testing/GM.Utility.Testing.Unit/ReflectionUtilityTests.cs rename src/GM.Utility/GM.Utility.Test/ArrayUtilityTest.cs => testing/GM.Utility.Testing.Unit/StringUtilityTests.cs (51%) create mode 100644 testing/GM.Utility.Testing.Unit/UriUtilityTests.cs create mode 100644 testing/GM.Utility.Testing.Unit/UtilTests.cs create mode 100644 testing/GM.Utility.Testing.Unit/WildcardUtilityTests.cs diff --git a/src/.gitignore b/.gitignore similarity index 100% rename from src/.gitignore rename to .gitignore diff --git a/src/GM.Utility/GM.Utility.sln b/GM.Utility.sln similarity index 67% rename from src/GM.Utility/GM.Utility.sln rename to GM.Utility.sln index c94700a..0e8c3c8 100644 --- a/src/GM.Utility/GM.Utility.sln +++ b/GM.Utility.sln @@ -3,12 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.3.32929.385 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GM.Utility", "GM.Utility\GM.Utility.csproj", "{0689FB8B-C7DE-4F4A-A422-05EA5E5938B4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GM.Utility", "src\GM.Utility\GM.Utility.csproj", "{0689FB8B-C7DE-4F4A-A422-05EA5E5938B4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GM.Utility.Test", "GM.Utility.Test\GM.Utility.Test.csproj", "{DBE09199-2DF5-40BF-9920-A313D674E6EB}" - ProjectSection(ProjectDependencies) = postProject - {0689FB8B-C7DE-4F4A-A422-05EA5E5938B4} = {0689FB8B-C7DE-4F4A-A422-05EA5E5938B4} - EndProjectSection +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GM.Utility.Testing.Unit", "testing\GM.Utility.Testing.Unit\GM.Utility.Testing.Unit.csproj", "{410047B8-B3EE-42B6-818A-698DB8B44219}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -20,10 +17,10 @@ Global {0689FB8B-C7DE-4F4A-A422-05EA5E5938B4}.Debug|Any CPU.Build.0 = Debug|Any CPU {0689FB8B-C7DE-4F4A-A422-05EA5E5938B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {0689FB8B-C7DE-4F4A-A422-05EA5E5938B4}.Release|Any CPU.Build.0 = Release|Any CPU - {DBE09199-2DF5-40BF-9920-A313D674E6EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DBE09199-2DF5-40BF-9920-A313D674E6EB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DBE09199-2DF5-40BF-9920-A313D674E6EB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DBE09199-2DF5-40BF-9920-A313D674E6EB}.Release|Any CPU.Build.0 = Release|Any CPU + {410047B8-B3EE-42B6-818A-698DB8B44219}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {410047B8-B3EE-42B6-818A-698DB8B44219}.Debug|Any CPU.Build.0 = Debug|Any CPU + {410047B8-B3EE-42B6-818A-698DB8B44219}.Release|Any CPU.ActiveCfg = Release|Any CPU + {410047B8-B3EE-42B6-818A-698DB8B44219}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/GM.Utility/GM.Utility/ArrayUtility.cs b/src/GM.Utility/ArrayUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ArrayUtility.cs rename to src/GM.Utility/ArrayUtility.cs diff --git a/src/GM.Utility/GM.Utility/BigIntegerUtility.cs b/src/GM.Utility/BigIntegerUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/BigIntegerUtility.cs rename to src/GM.Utility/BigIntegerUtility.cs diff --git a/src/GM.Utility/GM.Utility/BoolUtility.cs b/src/GM.Utility/BoolUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/BoolUtility.cs rename to src/GM.Utility/BoolUtility.cs diff --git a/src/GM.Utility/GM.Utility/Collections/ReloadableCollection.cs b/src/GM.Utility/Collections/ReloadableCollection.cs similarity index 100% rename from src/GM.Utility/GM.Utility/Collections/ReloadableCollection.cs rename to src/GM.Utility/Collections/ReloadableCollection.cs diff --git a/src/GM.Utility/GM.Utility/Collections/SortableBindingList.cs b/src/GM.Utility/Collections/SortableBindingList.cs similarity index 100% rename from src/GM.Utility/GM.Utility/Collections/SortableBindingList.cs rename to src/GM.Utility/Collections/SortableBindingList.cs diff --git a/src/GM.Utility/GM.Utility/ColorUtility.cs b/src/GM.Utility/ColorUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ColorUtility.cs rename to src/GM.Utility/ColorUtility.cs diff --git a/src/GM.Utility/GM.Utility/CryptographyUtility.cs b/src/GM.Utility/CryptographyUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/CryptographyUtility.cs rename to src/GM.Utility/CryptographyUtility.cs diff --git a/src/GM.Utility/GM.Utility/CsvUtility.cs b/src/GM.Utility/CsvUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/CsvUtility.cs rename to src/GM.Utility/CsvUtility.cs diff --git a/src/GM.Utility/GM.Utility/DateTimeUtility.cs b/src/GM.Utility/DateTimeUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/DateTimeUtility.cs rename to src/GM.Utility/DateTimeUtility.cs diff --git a/src/GM.Utility/GM.Utility/DayOfWeekUtility.cs b/src/GM.Utility/DayOfWeekUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/DayOfWeekUtility.cs rename to src/GM.Utility/DayOfWeekUtility.cs diff --git a/src/GM.Utility/GM.Utility/DecimalUtility.cs b/src/GM.Utility/DecimalUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/DecimalUtility.cs rename to src/GM.Utility/DecimalUtility.cs diff --git a/src/GM.Utility/GM.Utility/DefaultedObject.cs b/src/GM.Utility/DefaultedObject.cs similarity index 100% rename from src/GM.Utility/GM.Utility/DefaultedObject.cs rename to src/GM.Utility/DefaultedObject.cs diff --git a/src/GM.Utility/GM.Utility/DefensiveUtility.cs b/src/GM.Utility/DefensiveUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/DefensiveUtility.cs rename to src/GM.Utility/DefensiveUtility.cs diff --git a/src/GM.Utility/GM.Utility/DictionaryUtility.cs b/src/GM.Utility/DictionaryUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/DictionaryUtility.cs rename to src/GM.Utility/DictionaryUtility.cs diff --git a/src/GM.Utility/GM.Utility/DoubleUtility.cs b/src/GM.Utility/DoubleUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/DoubleUtility.cs rename to src/GM.Utility/DoubleUtility.cs diff --git a/src/GM.Utility/GM.Utility/EmailUtility.cs b/src/GM.Utility/EmailUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/EmailUtility.cs rename to src/GM.Utility/EmailUtility.cs diff --git a/src/GM.Utility/GM.Utility/EnumUtility.cs b/src/GM.Utility/EnumUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/EnumUtility.cs rename to src/GM.Utility/EnumUtility.cs diff --git a/src/GM.Utility/GM.Utility/EnvironmentUtility.cs b/src/GM.Utility/EnvironmentUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/EnvironmentUtility.cs rename to src/GM.Utility/EnvironmentUtility.cs diff --git a/src/GM.Utility/GM.Utility/EqualityComparers/ReferenceEqualityComparer.cs b/src/GM.Utility/EqualityComparers/ReferenceEqualityComparer.cs similarity index 100% rename from src/GM.Utility/GM.Utility/EqualityComparers/ReferenceEqualityComparer.cs rename to src/GM.Utility/EqualityComparers/ReferenceEqualityComparer.cs diff --git a/src/GM.Utility/GM.Utility/EqualityUtility.cs b/src/GM.Utility/EqualityUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/EqualityUtility.cs rename to src/GM.Utility/EqualityUtility.cs diff --git a/src/GM.Utility/GM.Utility/ExcelUtility.cs b/src/GM.Utility/ExcelUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ExcelUtility.cs rename to src/GM.Utility/ExcelUtility.cs diff --git a/src/GM.Utility/GM.Utility/ExceptionUtility.cs b/src/GM.Utility/ExceptionUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ExceptionUtility.cs rename to src/GM.Utility/ExceptionUtility.cs diff --git a/src/GM.Utility/GM.Utility/Framework/Enumeration.cs b/src/GM.Utility/Framework/Enumeration.cs similarity index 100% rename from src/GM.Utility/GM.Utility/Framework/Enumeration.cs rename to src/GM.Utility/Framework/Enumeration.cs diff --git a/src/GM.Utility/GM.Utility.Test/DateTimeUtilityTest.cs b/src/GM.Utility/GM.Utility.Test/DateTimeUtilityTest.cs deleted file mode 100644 index 26a31f5..0000000 --- a/src/GM.Utility/GM.Utility.Test/DateTimeUtilityTest.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* -MIT License - -Copyright (c) 2021 Gregor Mohorko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Project: GM.Utility.Test -Created: 2018-9-12 -Author: Gregor Mohorko -*/ - -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace GM.Utility.Test -{ - [TestClass] - public class DateTimeUtilityTest - { - [TestMethod] - public void DurationBetween() - { - const int MS_IN_ONE_DAY = 24 * 60 * 60 * 1000; - - DateTime date1; - DateTime date2; - TimeSpan durationBetween; - - // ascending order - date1 = new DateTime(2021, 12, 17); - date2 = new DateTime(2021, 12, 18); - durationBetween = DateTimeUtility.DurationBetween(date1, date2); - Assert.AreEqual(1, durationBetween.Days); - Assert.AreEqual(MS_IN_ONE_DAY, durationBetween.TotalMilliseconds); - - // descending order - date1 = new DateTime(2021, 12, 18); - date2 = new DateTime(2021, 12, 17); - durationBetween = DateTimeUtility.DurationBetween(date1, date2); - Assert.AreEqual(1, durationBetween.Days); - Assert.AreEqual(MS_IN_ONE_DAY, durationBetween.TotalMilliseconds); - - } - - [TestMethod] - public void EndOfMonth() - { - DateTime date; - DateTime endOfMonth; - - // normal 30 day month - date = new DateTime(2018, 9, 15); - endOfMonth = date.EndOfMonth(); - Assert.AreEqual(new DateTime(2018, 9, 15), date); // make sure that the original DateTime is not modified - Assert.AreEqual(new DateTime(2018,9,30), endOfMonth); - - // normal 31 day month - date = new DateTime(2018, 12, 20); - endOfMonth = date.EndOfMonth(); - Assert.AreEqual(new DateTime(2018, 12, 31), endOfMonth); - - // february 28 - date = new DateTime(2018, 2, 10); - endOfMonth = date.EndOfMonth(); - Assert.AreEqual(new DateTime(2018, 2, 28), endOfMonth); - - // february 29 - date = new DateTime(2016, 2, 1); - endOfMonth = date.EndOfMonth(); - Assert.AreEqual(new DateTime(2016, 2, 29), endOfMonth); - - // already last day - date = new DateTime(1993, 1, 31); - endOfMonth = date.EndOfMonth(); - Assert.AreEqual(new DateTime(1993, 1, 31), endOfMonth); - - // current end of month - date = DateTime.Today.EndOfMonth(); - endOfMonth = DateTimeUtility.EndOfMonth(); - Assert.AreEqual(date, endOfMonth); - } - - [TestMethod] - public void StartOfMonth() - { - DateTime date; - DateTime startOfMonth; - - // normal month - date = new DateTime(2018, 9, 15); - startOfMonth = date.StartOfMonth(); - Assert.AreEqual(new DateTime(2018, 9, 15), date); // make sure that the original DateTime is not modified - Assert.AreEqual(new DateTime(2018, 9, 1), startOfMonth); - - // already first day - date = new DateTime(2000, 6, 1); - startOfMonth = date.StartOfMonth(); - Assert.AreEqual(new DateTime(2000, 6, 1), startOfMonth); - - // current start of month - date = DateTime.Today.StartOfMonth(); - startOfMonth = DateTimeUtility.StartOfMonth(); - Assert.AreEqual(date, startOfMonth); - } - } -} diff --git a/src/GM.Utility/GM.Utility.Test/DecimalUtilityTest.cs b/src/GM.Utility/GM.Utility.Test/DecimalUtilityTest.cs deleted file mode 100644 index e8b3887..0000000 --- a/src/GM.Utility/GM.Utility.Test/DecimalUtilityTest.cs +++ /dev/null @@ -1,94 +0,0 @@ -/* -MIT License - -Copyright (c) 2018 Grega Mohorko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Project: GM.Utility.Test -Created: 2018-3-18 -Author: GregaMohorko -*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace GM.Utility.Test -{ - [TestClass] - public class DecimalUtilityTest - { - [TestMethod] - public void GetDecimals() - { - Assert.AreEqual(0.123456789m, 42.123456789m.GetDecimals()); - Assert.AreEqual(-0.123456789m, -42.123456789m.GetDecimals()); - Assert.AreEqual(0.123456789m, 0.123456789m.GetDecimals()); - Assert.AreEqual(0.987654321m, 1.987654321m.GetDecimals()); - Assert.AreEqual(0m, 123m.GetDecimals()); - } - - [TestMethod] - public void GetDecimals_WithRounding() - { - Assert.AreEqual(0.123m, 42.123456789m.GetDecimals(3)); - Assert.AreEqual(-0.1235m, -42.123456789m.GetDecimals(4)); - Assert.AreEqual(0.12346m, 0.123456789m.GetDecimals(5)); - Assert.AreEqual(0.987654m, 1.987654321m.GetDecimals(6)); - Assert.AreEqual(0m, 123m.GetDecimals(7)); - } - - [TestMethod] - public void GetDecimalPart() - { - Assert.AreEqual(1, 42.123m.GetDecimalPart(1, false)); - Assert.AreEqual(1, 42.123m.GetDecimalPart(1, true)); - Assert.AreEqual(7, 42.789m.GetDecimalPart(1, false)); - Assert.AreEqual(8, 42.789m.GetDecimalPart(1, true)); - Assert.AreEqual(12, 42.123m.GetDecimalPart(2, false)); - Assert.AreEqual(12, 42.123m.GetDecimalPart(2, true)); - Assert.AreEqual(123, 42.123m.GetDecimalPart(3, false)); - Assert.AreEqual(123, 42.123m.GetDecimalPart(3, true)); - Assert.AreEqual(123456789, 42.123456789m.GetDecimalPart(9, false)); - Assert.AreEqual(123456789, 42.123456789m.GetDecimalPart(9, true)); - Assert.AreEqual(1234567, 42.123456789m.GetDecimalPart(7, false)); - Assert.AreEqual(1234568, 42.123456789m.GetDecimalPart(7, true)); - Assert.AreEqual(-98, -42.987m.GetDecimalPart(2, false)); - Assert.AreEqual(-99, -42.987m.GetDecimalPart(2, true)); - Assert.AreEqual(0, 42m.GetDecimalPart(1, false)); - Assert.AreEqual(0, 42m.GetDecimalPart(1, true)); - Assert.AreEqual(0, 1.23m.GetDecimalPart(0, false)); - Assert.AreEqual(0, 1.23m.GetDecimalPart(0, true)); - } - - [TestMethod] - public void GetDecimalPart_Whole() - { - Assert.AreEqual(1, 42.1m.GetDecimalPart()); - Assert.AreEqual(12, 0.12m.GetDecimalPart()); - Assert.AreEqual(-123, -456.123m.GetDecimalPart()); - Assert.AreEqual(123456789, 42.123456789m.GetDecimalPart()); - Assert.AreEqual(0, 123m.GetDecimalPart()); - } - } -} diff --git a/src/GM.Utility/GM.Utility.Test/DefaultedObjectTest.cs b/src/GM.Utility/GM.Utility.Test/DefaultedObjectTest.cs deleted file mode 100644 index b92e0e8..0000000 --- a/src/GM.Utility/GM.Utility.Test/DefaultedObjectTest.cs +++ /dev/null @@ -1,95 +0,0 @@ -/* -MIT License - -Copyright (c) 2018 Grega Mohorko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Project: GM.Utility.Test -Created: 2018-3-29 -Author: GregaMohorko -*/ - -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace GM.Utility.Test -{ - [TestClass] - public class DefaultedObjectTest - { - private class MyClass:DefaultedObject - { - internal const string DEFAULT = "DEFAULT TEXT"; - protected override string Default => DEFAULT; - -#pragma warning disable 0649 - public int IntField; - public int IntProperty { get; set; } - - public static string StaticPublicStringField; - internal static string staticInternalStringField; - protected static string StaticProtectedStringField; - public static string GetStaticProtectedStringField => StaticProtectedStringField; - private static string staticPrivateStringField; - public static string GetStaticPrivateStringField => staticPrivateStringField; - - public string PublicStringField; - internal string InternalStringField; - protected string ProtectedStringField; - public string GetProtectedStringField => ProtectedStringField; - private string PrivateStringField; - public string GetPrivateStringField => PrivateStringField; -#pragma warning restore 0649 - - public string PublicStringProperty { get; set; } - public string PublicStringPropertyWithInternalSetter { get; internal set; } - public string PublicStringPropertyWithProtectedSetter { get; protected set; } - public string PublicStringPropertyWithPrivateSetter { get; private set; } - internal string InternalStringProperty { get; set; } - protected string ProtectedStringProperty { get; set; } - public string GetProtectedStringProperty => ProtectedStringProperty; - private string PrivateStringProperty { get; set; } - public string GetPrivateStringProperty => PrivateStringProperty; - } - - [TestMethod] - public void Test() - { - var @object = new MyClass(); - Assert.AreEqual(default(int), @object.IntField); - Assert.AreEqual(default(int), @object.IntProperty); - Assert.AreEqual(MyClass.DEFAULT, @object.PublicStringField); - Assert.AreEqual(MyClass.DEFAULT, @object.InternalStringField); - Assert.AreEqual(MyClass.DEFAULT, @object.GetProtectedStringField); - Assert.AreEqual(MyClass.DEFAULT, @object.GetPrivateStringField); - Assert.AreEqual(MyClass.DEFAULT, @object.PublicStringProperty); - Assert.AreEqual(MyClass.DEFAULT, @object.PublicStringPropertyWithInternalSetter); - Assert.AreEqual(MyClass.DEFAULT, @object.PublicStringPropertyWithProtectedSetter); - Assert.AreEqual(MyClass.DEFAULT, @object.PublicStringPropertyWithPrivateSetter); - Assert.AreEqual(MyClass.DEFAULT, @object.InternalStringProperty); - Assert.AreEqual(MyClass.DEFAULT, @object.GetProtectedStringProperty); - Assert.AreEqual(MyClass.DEFAULT, @object.GetPrivateStringProperty); - Assert.AreEqual(null, MyClass.StaticPublicStringField); - Assert.AreEqual(null, MyClass.staticInternalStringField); - Assert.AreEqual(null, MyClass.GetStaticProtectedStringField); - Assert.AreEqual(null, MyClass.GetStaticPrivateStringField); - } - } -} diff --git a/src/GM.Utility/GM.Utility.Test/DoubleUtilityTest.cs b/src/GM.Utility/GM.Utility.Test/DoubleUtilityTest.cs deleted file mode 100644 index f6395a1..0000000 --- a/src/GM.Utility/GM.Utility.Test/DoubleUtilityTest.cs +++ /dev/null @@ -1,90 +0,0 @@ -/* -MIT License - -Copyright (c) 2018 Grega Mohorko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Project: GM.Utility.Test -Created: 2018-3-18 -Author: GregaMohorko -*/ - -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace GM.Utility.Test -{ - [TestClass] - public class DoubleUtilityTest - { - [TestMethod] - public void GetDecimals() - { - Assert.AreEqual(0.123456789, 42.123456789.GetDecimals()); - Assert.AreEqual(-0.123456789, -42.123456789.GetDecimals()); - Assert.AreEqual(0.123456789, 0.123456789.GetDecimals()); - Assert.AreEqual(0.987654321, 1.987654321.GetDecimals()); - Assert.AreEqual(0d, 123d.GetDecimals()); - } - - [TestMethod] - public void GetDecimals_WithRounding() - { - Assert.AreEqual(0.123, 42.123456789.GetDecimals(3)); - Assert.AreEqual(-0.1235, -42.123456789.GetDecimals(4)); - Assert.AreEqual(0.12346, 0.123456789.GetDecimals(5)); - Assert.AreEqual(0.987654, 1.987654321.GetDecimals(6)); - Assert.AreEqual(0d, 123d.GetDecimals(7)); - } - - [TestMethod] - public void GetDecimalPart() - { - Assert.AreEqual(1, 42.123.GetDecimalPart(1, false)); - Assert.AreEqual(1, 42.123.GetDecimalPart(1, true)); - Assert.AreEqual(7, 42.789.GetDecimalPart(1, false)); - Assert.AreEqual(8, 42.789.GetDecimalPart(1, true)); - Assert.AreEqual(12, 42.123.GetDecimalPart(2, false)); - Assert.AreEqual(12, 42.123.GetDecimalPart(2, true)); - Assert.AreEqual(123, 42.123.GetDecimalPart(3, false)); - Assert.AreEqual(123, 42.123.GetDecimalPart(3, true)); - Assert.AreEqual(123456789, 42.123456789.GetDecimalPart(9, false)); - Assert.AreEqual(123456789, 42.123456789.GetDecimalPart(9, true)); - Assert.AreEqual(1234567, 42.123456789.GetDecimalPart(7, false)); - Assert.AreEqual(1234568, 42.123456789.GetDecimalPart(7, true)); - Assert.AreEqual(-98, -42.987.GetDecimalPart(2, false)); - Assert.AreEqual(-99, -42.987.GetDecimalPart(2, true)); - Assert.AreEqual(0, 42d.GetDecimalPart(1, false)); - Assert.AreEqual(0, 42d.GetDecimalPart(1, true)); - Assert.AreEqual(0, 1.23.GetDecimalPart(0, false)); - Assert.AreEqual(0, 1.23.GetDecimalPart(0, true)); - } - - [TestMethod] - public void GetDecimalPart_Whole() - { - Assert.AreEqual(1, 42.1.GetDecimalPart()); - Assert.AreEqual(12, 0.12.GetDecimalPart()); - Assert.AreEqual(-123, -456.123.GetDecimalPart()); - Assert.AreEqual(123456789, 42.123456789.GetDecimalPart()); - Assert.AreEqual(0, 123d.GetDecimalPart()); - } - } -} diff --git a/src/GM.Utility/GM.Utility.Test/GM.Utility.Test.csproj b/src/GM.Utility/GM.Utility.Test/GM.Utility.Test.csproj deleted file mode 100644 index 308485c..0000000 --- a/src/GM.Utility/GM.Utility.Test/GM.Utility.Test.csproj +++ /dev/null @@ -1,87 +0,0 @@ - - - - - Debug - AnyCPU - {DBE09199-2DF5-40BF-9920-A313D674E6EB} - Library - Properties - GM.Utility.Test - GM.Utility.Test - v4.8 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 15.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\MSTest.TestFramework.2.2.8\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll - - - ..\packages\MSTest.TestFramework.2.2.8\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - {0689fb8b-c7de-4f4a-a422-05ea5e5938b4} - GM.Utility - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - \ No newline at end of file diff --git a/src/GM.Utility/GM.Utility.Test/IEnumerableUtilityTest.cs b/src/GM.Utility/GM.Utility.Test/IEnumerableUtilityTest.cs deleted file mode 100644 index 4afdde5..0000000 --- a/src/GM.Utility/GM.Utility.Test/IEnumerableUtilityTest.cs +++ /dev/null @@ -1,111 +0,0 @@ -/* -MIT License - -Copyright (c) 2018 Grega Mohorko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Project: GM.Utility.Test -Created: 2018-3-28 -Author: GregaMohorko -*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace GM.Utility.Test -{ - [TestClass] - public class IEnumerableUtilityTest - { - [TestMethod] - public void AllSame1() - { - char valueSelector1(string s) => s[0]; - char valueSelector3(string s) => s[2]; - var example = new List { "abc", "aac", "bac" }; - - Assert.ThrowsException(delegate - { - IEnumerableUtility.AllSame(null, valueSelector1); - }); - Assert.ThrowsException(delegate - { - IEnumerableUtility.AllSame(example, null); - }); - - // all strings have the same character in the third position - Assert.IsTrue(example.AllSame(valueSelector3)); - // not all strings have the same character in the first position - Assert.IsFalse(example.AllSame(valueSelector1)); - - // empty collections should return true, the same as LINQ All method - Assert.IsTrue(new List().AllSame(valueSelector1)); - } - - [TestMethod] - public void AllSame2() - { - char valueSelector1(string s) => s[0]; - char valueSelector2(string s) => s[1]; - char valueSelector3(string s) => s[2]; - char valueSelector4(string s) => s[3]; - var example = new List { "abcd", "aacd", "bacd" }; - - Assert.ThrowsException(delegate - { - IEnumerableUtility.AllSame(null, valueSelector1, valueSelector1); - }); - Assert.ThrowsException(delegate - { - IEnumerableUtility.AllSame(example, null, valueSelector1); - }); - Assert.ThrowsException(delegate - { - IEnumerableUtility.AllSame(example, valueSelector1, null); - }); - - // all strings have the same character in the third and forth position - Assert.IsTrue(example.AllSame(valueSelector3,valueSelector4)); - // not all strings have the same character in the first and third position - Assert.IsFalse(example.AllSame(valueSelector1, valueSelector3)); - // not all strings have the same character in the third and first position - Assert.IsFalse(example.AllSame(valueSelector3, valueSelector1)); - // not all strings have the same character in the first and second position - Assert.IsFalse(example.AllSame(valueSelector1, valueSelector2)); - - // empty collections should return true, the same as LINQ All method - Assert.IsTrue(new List().AllSame(valueSelector1, valueSelector2)); - } - - [TestMethod] - public void Rotate() - { - var example = new List { 1, 2, 3, 4 }; - List rotated = example.Rotate(1).ToList(); - CollectionAssert.AreEqual(new List { 4, 1, 2, 3 }, rotated); - - example = new List { 1, 2, 3, 4, 5 }; - rotated = example.Rotate(-2).ToList(); - CollectionAssert.AreEqual(new List { 3, 4, 5, 1, 2 }, rotated); - } - } -} diff --git a/src/GM.Utility/GM.Utility.Test/ReflectionUtilityTest.cs b/src/GM.Utility/GM.Utility.Test/ReflectionUtilityTest.cs deleted file mode 100644 index 5f87372..0000000 --- a/src/GM.Utility/GM.Utility.Test/ReflectionUtilityTest.cs +++ /dev/null @@ -1,146 +0,0 @@ -/* -MIT License - -Copyright (c) 2020 Gregor Mohorko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Project: GM.Utility.Test -Created: 2018-12-10 -Author: Gregor Mohorko -*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace GM.Utility.Test -{ - [TestClass] - public class ReflectionUtilityTest - { - private class ReflectionExampleClass - { -#pragma warning disable IDE0032 // Use auto property -#pragma warning disable IDE0044 // Add readonly modifier -#pragma warning disable 0649 // never assigned to -#pragma warning disable IDE0051 // Remove unused private members - public string PublicField; - internal string InternalField; - protected internal string ProtectedInternalField; - protected string ProtectedField; - public string GetProtectedField => ProtectedField; - private string privateField; - public string GetPrivateField => privateField; - private readonly string privateReadonlyField; - public string GetPrivateReadonlyField => privateReadonlyField; - - public string PublicProperty { get; set; } - public string PublicReadonlyProperty { get; } = "Public Readonly Property Value"; - internal string InternalProperty { get; set; } - protected string ProtectedProperty { get; set; } - private string PrivateProperty { get; set; } -#pragma warning restore IDE0051 // Remove unused private members -#pragma warning disable 0649 // never assigned to -#pragma warning restore IDE0044 // Add readonly modifier -#pragma warning restore IDE0032 // Use auto property - } - - [TestMethod] - public void AreAllPropertiesEqual() - { - _ = Assert.ThrowsException(() => ReflectionUtility.AreAllPropertiesEqual(null)); - // at least two objects must be provided - _ = Assert.ThrowsException(() => ReflectionUtility.AreAllPropertiesEqual(new object[0])); - _ = Assert.ThrowsException(() => ReflectionUtility.AreAllPropertiesEqual(new object[1])); - // null objects are not allowed - _ = Assert.ThrowsException(() => ReflectionUtility.AreAllPropertiesEqual(new object[2])); - _ = Assert.ThrowsException(() => ReflectionUtility.AreAllPropertiesEqual(new ReflectionExampleClass[1024])); - // all objects must be of the same type - _ = Assert.ThrowsException(() => ReflectionUtility.AreAllPropertiesEqual(new object[2] { "string", 42 })); - // primitive types are not allowed - _ = Assert.ThrowsException(() => ReflectionUtility.AreAllPropertiesEqual(new object[2] { "string", "string" })); - - var objects = new ReflectionExampleClass[2] - { - new ReflectionExampleClass - { - // different field values and internal properties - PublicField = "Public field 0", - InternalField = "Internal field 0", - InternalProperty = "Internal property 0" - }, - new ReflectionExampleClass - { - // different field values and internal properties - PublicField = "Public field 1", - InternalField = "Internal field 1", - InternalProperty = "Internal property 1" - } - }; - - // set different values to private and protected properties - for(int i = 0; i < objects.Length; ++i) { - objects[i].SetProperty("PrivateProperty", $"Private property {i}"); - objects[i].SetProperty("ProtectedProperty", $"Protected property {i}"); - } - - // all public properties are null (have not been set) - Assert.IsTrue(ReflectionUtility.AreAllPropertiesEqual(objects)); - - objects.ForEach(obj => obj.PublicProperty = "some value"); - Assert.IsTrue(ReflectionUtility.AreAllPropertiesEqual(objects)); - - // set different public readonly properties - for(int i = 0; i < objects.Length; ++i) { - objects[i].SetField("privateField", $"Public readonly property {i}"); - } - Assert.IsFalse(ReflectionUtility.AreAllPropertiesEqual(objects)); - - // reset public readonly properties - objects.ForEach(obj => obj.SetField("privateField", "same readonly value")); - Assert.IsTrue(ReflectionUtility.AreAllPropertiesEqual(objects)); - - objects[0].PublicProperty = "different value"; - Assert.IsFalse(ReflectionUtility.AreAllPropertiesEqual(objects)); - } - - [TestMethod] - public void SetField() - { - var obj = new ReflectionExampleClass(); - - ReflectionUtility.SetField(obj, nameof(ReflectionExampleClass.PublicField), "publicValue"); - Assert.AreEqual("publicValue", obj.PublicField); - obj.SetField(nameof(ReflectionExampleClass.InternalField), "internalValue"); - Assert.AreEqual("internalValue", obj.InternalField); - obj.SetField(nameof(ReflectionExampleClass.ProtectedInternalField), "protectedInternalValue"); - Assert.AreEqual("protectedInternalValue", obj.ProtectedInternalField); - obj.SetField("ProtectedField", "protectedValue"); - Assert.AreEqual("protectedValue", obj.GetProtectedField); - obj.SetField("privateField", "privateValue"); - Assert.AreEqual("privateValue", obj.GetPrivateField); - obj.SetField("privateReadonlyField", "privateReadonlyValue"); - Assert.AreEqual("privateReadonlyValue", obj.GetPrivateReadonlyField); - } - } -} diff --git a/src/GM.Utility/GM.Utility.Test/StringUtilityTest.cs b/src/GM.Utility/GM.Utility.Test/StringUtilityTest.cs deleted file mode 100644 index 9a0cde5..0000000 --- a/src/GM.Utility/GM.Utility.Test/StringUtilityTest.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* -MIT License - -Copyright (c) 2018 Grega Mohorko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Project: GM.Utility.Test -Created: 2018-11-23 -Author: GregaMohorko -*/ - -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace GM.Utility.Test -{ - [TestClass] - public class StringUtilityTest - { - [TestMethod] - public void ShortenWith3Dots() - { - Assert.ThrowsException(() => StringUtility.ShortenWith3Dots(null, -42)); - Assert.ThrowsException(() => StringUtility.ShortenWith3Dots("", -1)); - Assert.ThrowsException(() => StringUtility.ShortenWith3Dots("", -100)); - Assert.ThrowsException(() => StringUtility.ShortenWith3Dots("", int.MinValue)); - Assert.ThrowsException(() => StringUtility.ShortenWith3Dots("", 0)); - - string text = "Blues for the Red Sun"; - Assert.AreEqual(text, text.ShortenWith3Dots(int.MaxValue)); - Assert.AreEqual(text, text.ShortenWith3Dots(text.Length)); - Assert.AreEqual("B...", text.ShortenWith3Dots(1)); - Assert.AreEqual("Blues...", text.ShortenWith3Dots(5)); - Assert.AreEqual("Blues for the Red Su...", text.ShortenWith3Dots(20)); - } - } -} diff --git a/src/GM.Utility/GM.Utility.Test/UtilTest.cs b/src/GM.Utility/GM.Utility.Test/UtilTest.cs deleted file mode 100644 index 028896b..0000000 --- a/src/GM.Utility/GM.Utility.Test/UtilTest.cs +++ /dev/null @@ -1,55 +0,0 @@ -/* -MIT License - -Copyright (c) 2021 Gregor Mohorko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Project: GM.Utility -Created: 2021-01-11 -Author: Gregor Mohorko -*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace GM.Utility.Test -{ - [TestClass] - public class UtilTest - { - [TestMethod] - public void CombineWithParams() - { - // should throw exceptions - _ = Assert.ThrowsException(() => Util.CombineWithParams(default(string), null)); - _ = Assert.ThrowsException(() => Util.CombineWithParams(default(EventArgs), null)); - - // should not throw an exception - Util.CombineWithParams(default(int), null); - Util.CombineWithParams(default(TimeSpan), null); - Util.CombineWithParams(default(DateTime), null); - Util.CombineWithParams(default(DayOfWeek), null); - } - } -} diff --git a/src/GM.Utility/GM.Utility.Test/WildcardUtilityTest.cs b/src/GM.Utility/GM.Utility.Test/WildcardUtilityTest.cs deleted file mode 100644 index f6718d1..0000000 --- a/src/GM.Utility/GM.Utility.Test/WildcardUtilityTest.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* -MIT License - -Copyright (c) 2021 Gregor Mohorko - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -Project: GM.Utility.Test -Created: 2021-01-10 -Author: Gregor Mohorko -*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace GM.Utility.Test -{ - [TestClass] - public class WildcardUtilityTest - { - [TestMethod] - public void Insert() - { - string wildcard = "*/some/example/*/wildcard/*"; - string result = WildcardUtility.Insert(wildcard, new string[] { "first", "second", "last" }); - Assert.AreEqual("first/some/example/second/wildcard/last", result); - } - - [TestMethod] - public void WildcardToRegex() - { - string[] wildcards = - { - "*/some/example/*/wildcard/*", - "^*/some/example/*/wildcard/*", - "*/some/example/*/wildcard/*$", - "^*/some/example/*/wildcard/*$" - }; - foreach(string wildcard in wildcards) { - string regexPattern = WildcardUtility.WildcardToRegex(wildcard); - var regex = new Regex(regexPattern); - - Assert.IsTrue(regex.IsMatch("test/some/example/test/wildcard/test")); - Assert.IsFalse(regex.IsMatch("some/example/test/wildcard/test")); - Assert.IsFalse(regex.IsMatch("test/some/example/wildcard/test")); - Assert.IsFalse(regex.IsMatch("test/some/example/test/wildcard")); - } - } - } -} diff --git a/src/GM.Utility/GM.Utility.Test/packages.config b/src/GM.Utility/GM.Utility.Test/packages.config deleted file mode 100644 index 1c8e18d..0000000 --- a/src/GM.Utility/GM.Utility.Test/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/GM.Utility/GM.Utility/GM.Utility.csproj b/src/GM.Utility/GM.Utility.csproj similarity index 98% rename from src/GM.Utility/GM.Utility/GM.Utility.csproj rename to src/GM.Utility/GM.Utility.csproj index 8f502ef..ec41a4b 100644 --- a/src/GM.Utility/GM.Utility/GM.Utility.csproj +++ b/src/GM.Utility/GM.Utility.csproj @@ -44,7 +44,7 @@ - + True diff --git a/src/GM.Utility/GM.Utility/GM.Utility.licenseheader b/src/GM.Utility/GM.Utility.licenseheader similarity index 100% rename from src/GM.Utility/GM.Utility/GM.Utility.licenseheader rename to src/GM.Utility/GM.Utility.licenseheader diff --git a/src/GM.Utility/GM.Utility/TimeSpanUtility.cs b/src/GM.Utility/GM.Utility/TimeSpanUtility.cs deleted file mode 100644 index 70dc9b7..0000000 --- a/src/GM.Utility/GM.Utility/TimeSpanUtility.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace GM.Utility; -/// -/// Utilities for . -/// -public static class TimeSpanUtility -{ - /// - /// Returns the maximum value of the two provided values. - /// - /// The first value. - /// The second value. - public static TimeSpan Max(TimeSpan val1, TimeSpan val2) - { - return val1 > val2 ? val1 : val2; - } -} diff --git a/src/GM.Utility/GM.Utility/GlobalizationUtility.cs b/src/GM.Utility/GlobalizationUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/GlobalizationUtility.cs rename to src/GM.Utility/GlobalizationUtility.cs diff --git a/src/GM.Utility/GM.Utility/HashCodeUtility.cs b/src/GM.Utility/HashCodeUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/HashCodeUtility.cs rename to src/GM.Utility/HashCodeUtility.cs diff --git a/src/GM.Utility/GM.Utility/IEnumerableUtility.cs b/src/GM.Utility/IEnumerableUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/IEnumerableUtility.cs rename to src/GM.Utility/IEnumerableUtility.cs diff --git a/src/GM.Utility/GM.Utility/IOUtility.cs b/src/GM.Utility/IOUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/IOUtility.cs rename to src/GM.Utility/IOUtility.cs diff --git a/src/GM.Utility/GM.Utility/IntUtility.cs b/src/GM.Utility/IntUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/IntUtility.cs rename to src/GM.Utility/IntUtility.cs diff --git a/src/GM.Utility/GM.Utility/KeyCodes.cs b/src/GM.Utility/KeyCodes.cs similarity index 100% rename from src/GM.Utility/GM.Utility/KeyCodes.cs rename to src/GM.Utility/KeyCodes.cs diff --git a/src/GM.Utility/GM.Utility/ListUtility.cs b/src/GM.Utility/ListUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ListUtility.cs rename to src/GM.Utility/ListUtility.cs diff --git a/src/GM.Utility/GM.Utility/LongUtility.cs b/src/GM.Utility/LongUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/LongUtility.cs rename to src/GM.Utility/LongUtility.cs diff --git a/src/GM.Utility/GM.Utility/Net/GMHttpClient.cs b/src/GM.Utility/Net/GMHttpClient.cs similarity index 100% rename from src/GM.Utility/GM.Utility/Net/GMHttpClient.cs rename to src/GM.Utility/Net/GMHttpClient.cs diff --git a/src/GM.Utility/GM.Utility/NetworkUtility.cs b/src/GM.Utility/NetworkUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/NetworkUtility.cs rename to src/GM.Utility/NetworkUtility.cs diff --git a/src/GM.Utility/GM.Utility/ObjectUtility.cs b/src/GM.Utility/ObjectUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ObjectUtility.cs rename to src/GM.Utility/ObjectUtility.cs diff --git a/src/GM.Utility/GM.Utility/ParseUtility.cs b/src/GM.Utility/ParseUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ParseUtility.cs rename to src/GM.Utility/ParseUtility.cs diff --git a/src/GM.Utility/GM.Utility/PathUtility.cs b/src/GM.Utility/PathUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/PathUtility.cs rename to src/GM.Utility/PathUtility.cs diff --git a/src/GM.Utility/GM.Utility/Patterns/Singleton.cs b/src/GM.Utility/Patterns/Singleton.cs similarity index 100% rename from src/GM.Utility/GM.Utility/Patterns/Singleton.cs rename to src/GM.Utility/Patterns/Singleton.cs diff --git a/src/GM.Utility/GM.Utility/Patterns/UndoRedo/GMUndoRedo.cs b/src/GM.Utility/Patterns/UndoRedo/GMUndoRedo.cs similarity index 100% rename from src/GM.Utility/GM.Utility/Patterns/UndoRedo/GMUndoRedo.cs rename to src/GM.Utility/Patterns/UndoRedo/GMUndoRedo.cs diff --git a/src/GM.Utility/GM.Utility/Patterns/UndoRedo/UndoRedoAction.cs b/src/GM.Utility/Patterns/UndoRedo/UndoRedoAction.cs similarity index 100% rename from src/GM.Utility/GM.Utility/Patterns/UndoRedo/UndoRedoAction.cs rename to src/GM.Utility/Patterns/UndoRedo/UndoRedoAction.cs diff --git a/src/GM.Utility/GM.Utility/RandomUtility.cs b/src/GM.Utility/RandomUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/RandomUtility.cs rename to src/GM.Utility/RandomUtility.cs diff --git a/src/GM.Utility/GM.Utility/ReflectionUtility.cs b/src/GM.Utility/ReflectionUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ReflectionUtility.cs rename to src/GM.Utility/ReflectionUtility.cs diff --git a/src/GM.Utility/GM.Utility/SecureStringUtility.cs b/src/GM.Utility/SecureStringUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/SecureStringUtility.cs rename to src/GM.Utility/SecureStringUtility.cs diff --git a/src/GM.Utility/GM.Utility/StatisticUtility.cs b/src/GM.Utility/StatisticUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/StatisticUtility.cs rename to src/GM.Utility/StatisticUtility.cs diff --git a/src/GM.Utility/GM.Utility/StringUtility.cs b/src/GM.Utility/StringUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/StringUtility.cs rename to src/GM.Utility/StringUtility.cs diff --git a/src/GM.Utility/GM.Utility/TaskUtility.cs b/src/GM.Utility/TaskUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/TaskUtility.cs rename to src/GM.Utility/TaskUtility.cs diff --git a/src/GM.Utility/GM.Utility/Throttling/ThrottlerPerTime.cs b/src/GM.Utility/Throttling/ThrottlerPerTime.cs similarity index 54% rename from src/GM.Utility/GM.Utility/Throttling/ThrottlerPerTime.cs rename to src/GM.Utility/Throttling/ThrottlerPerTime.cs index 9aa5560..f50f900 100644 --- a/src/GM.Utility/GM.Utility/Throttling/ThrottlerPerTime.cs +++ b/src/GM.Utility/Throttling/ThrottlerPerTime.cs @@ -27,6 +27,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ using System; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -39,13 +40,9 @@ namespace GM.Utility.Throttling; public class ThrottlerPerTime { /// - /// The time frame of this throttler. + /// A collection of common limits of this throttler. The Time is the time frame of the specific limit. The MaxExecutions is the max number of executions that are allowed in the time frame (zero means no limit). /// - public TimeSpan Time { get; } - /// - /// The max number of executions that are allowed in the time frame set in . Zero means no limit. - /// - public int MaxExecutions { get; } + public (TimeSpan Time, int MaxExecutions)[] Limits { get; } private volatile int _executionLogPosition; private readonly DateTime[] _executionLog; @@ -57,7 +54,9 @@ public class ThrottlerPerTime /// /// The time frame. /// The max number of executions that are allowed in the specified time frame. Zero means no limit. - /// Thrown when max executions is not non-negative. + /// + /// + /// Thrown when max executions is not non-negative. public ThrottlerPerTime(TimeSpan time, int maxExecutions) : this(time, maxExecutions, null) { } @@ -68,18 +67,50 @@ public ThrottlerPerTime(TimeSpan time, int maxExecutions) /// The time frame. /// The max number of executions that are allowed in the specified time frame. Zero means no limit. /// Logger. - /// Thrown when max executions is not non-negative. + /// + /// + /// Thrown when max executions is not non-negative. public ThrottlerPerTime(TimeSpan time, int maxExecutions, ILogger logger) + : this(new[] { (time, maxExecutions) }, logger) + { } + + /// + /// Creates a new instance of . + /// + /// A collection of limits for this throttler. A single limit consists of the time frame and the max number of executions that are allowed in this time frame. Zero means no limit. + /// + /// + /// Thrown when a max executions of any limit is not non-negative. + public ThrottlerPerTime((TimeSpan Time, int MaxExecutions)[] limits) + : this(limits, null) + { } + + /// + /// Creates a new instance of . + /// + /// A collection of limits for this throttler. A single limit consists of the time frame and the max number of executions that are allowed in this time frame. Zero means no limit. + /// Logger. + /// + /// + /// Thrown when a max executions of any limit is not non-negative. + public ThrottlerPerTime((TimeSpan Time, int MaxExecutions)[] limits, ILogger logger) { - if(maxExecutions < 0) { - throw new ArgumentOutOfRangeException(nameof(maxExecutions), maxExecutions, "Should be non-negative."); + if(limits == null) { + throw new ArgumentNullException(nameof(limits)); + } + if(limits.Length == 0) { + throw new ArgumentOutOfRangeException(nameof(limits), "Empty."); + } + if(limits.Any(l => l.MaxExecutions < 0)) { + var (_, MaxExecutions) = limits[0]; + throw new ArgumentException($"{nameof(MaxExecutions)} should be non-negative.", nameof(limits)); } _logger = logger; - Time = time; - MaxExecutions = maxExecutions; + Limits = limits; + int maxExecutions = limits.Max(l => l.MaxExecutions); _executionLog = new DateTime[maxExecutions]; _executionLogPosition = 0; } @@ -90,17 +121,28 @@ public ThrottlerPerTime(TimeSpan time, int maxExecutions, ILogger logger) /// public async Task WaitExecutionLimit(CancellationToken ct) { - if(MaxExecutions == 0) { + if(Limits.All(l => l.MaxExecutions == 0)) { // no limit return; } while(true) { DateTime utcNow = DateTime.UtcNow; - DateTime nextAvailableExecutionAt; + DateTime nextAvailableExecutionAt = DateTime.MaxValue; lock(_executionLog) { - nextAvailableExecutionAt = _executionLog[_executionLogPosition].Add(Time); + DateTime hm = _executionLog[_executionLogPosition]; + foreach(var (Time, MaxExecutions) in Limits) { + int previousRelevantLogPosition = (_executionLogPosition - MaxExecutions + _executionLog.Length) % _executionLog.Length; + DateTime previousExecutionTime = _executionLog[previousRelevantLogPosition]; + DateTime limitsNextAvailableExecutionAt = previousExecutionTime.Add(Time); + if(utcNow >= limitsNextAvailableExecutionAt + && limitsNextAvailableExecutionAt < nextAvailableExecutionAt + ) { + nextAvailableExecutionAt = limitsNextAvailableExecutionAt; + } + } + if(utcNow >= nextAvailableExecutionAt) { // can execute now _logger?.LogDebug("Position: {current}/{total}. Can execute now, since NextAvailableExecutionAt={nextAvailableExecutionAt} <= UtcNow={utcNow}.", _executionLogPosition, _executionLog.Length, nextAvailableExecutionAt, utcNow); @@ -116,7 +158,7 @@ public async Task WaitExecutionLimit(CancellationToken ct) } // wait and try again at next available execution - var sleepTime = nextAvailableExecutionAt - utcNow; + TimeSpan sleepTime = nextAvailableExecutionAt - utcNow; _logger?.LogDebug("Position: {current}/{total}. Cannot execute now, since NextAvailableExecutionAt={nextAvailableExecutionAt} > UtcNow={utcNow}. Sleeping for {sleepTime}.", _executionLogPosition, _executionLog.Length, nextAvailableExecutionAt, utcNow, sleepTime); await Task.Delay(sleepTime, ct); } diff --git a/src/GM.Utility/GM.Utility.Test/UriUtilityTest.cs b/src/GM.Utility/TimeSpanUtility.cs similarity index 68% rename from src/GM.Utility/GM.Utility.Test/UriUtilityTest.cs rename to src/GM.Utility/TimeSpanUtility.cs index 250de54..a5615cd 100644 --- a/src/GM.Utility/GM.Utility.Test/UriUtilityTest.cs +++ b/src/GM.Utility/TimeSpanUtility.cs @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2022 Gregor Mohorko +Copyright (c) 2024 Gregor Mohorko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -22,26 +22,25 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Project: GM.Utility -Created: 2022-03-09 -Author: Gregor Mohorko +Created: 2024-7-30 +Author: grega */ -using Microsoft.VisualStudio.TestTools.UnitTesting; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace GM.Utility.Test +namespace GM.Utility; +/// +/// Utilities for . +/// +public static class TimeSpanUtility { - [TestClass] - public class UriUtilityTest + /// + /// Returns the maximum value of the two provided values. + /// + /// The first value. + /// The second value. + public static TimeSpan Max(TimeSpan val1, TimeSpan val2) { - [TestMethod] - public void Combine() - { - Assert.AreEqual("http://www.google.com/additional/paths/test", UriUtility.Combine("http://www.google.com/", "/additional/paths", "test").ToString()); - } + return val1 > val2 ? val1 : val2; } } diff --git a/src/GM.Utility/GM.Utility/ToStringUtility.cs b/src/GM.Utility/ToStringUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ToStringUtility.cs rename to src/GM.Utility/ToStringUtility.cs diff --git a/src/GM.Utility/GM.Utility/TypeUtility.cs b/src/GM.Utility/TypeUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/TypeUtility.cs rename to src/GM.Utility/TypeUtility.cs diff --git a/src/GM.Utility/GM.Utility/UriUtility.cs b/src/GM.Utility/UriUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/UriUtility.cs rename to src/GM.Utility/UriUtility.cs diff --git a/src/GM.Utility/GM.Utility/Util.cs b/src/GM.Utility/Util.cs similarity index 100% rename from src/GM.Utility/GM.Utility/Util.cs rename to src/GM.Utility/Util.cs diff --git a/src/GM.Utility/GM.Utility/ValueTypeUtility.cs b/src/GM.Utility/ValueTypeUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/ValueTypeUtility.cs rename to src/GM.Utility/ValueTypeUtility.cs diff --git a/src/GM.Utility/GM.Utility/WildcardUtility.cs b/src/GM.Utility/WildcardUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/WildcardUtility.cs rename to src/GM.Utility/WildcardUtility.cs diff --git a/src/GM.Utility/GM.Utility/XMLUtility.cs b/src/GM.Utility/XMLUtility.cs similarity index 100% rename from src/GM.Utility/GM.Utility/XMLUtility.cs rename to src/GM.Utility/XMLUtility.cs diff --git a/src/GM.Utility/GM.Utility/icon.png b/src/GM.Utility/icon.png similarity index 100% rename from src/GM.Utility/GM.Utility/icon.png rename to src/GM.Utility/icon.png diff --git a/src/GM.Utility/GM.Utility.Test/Properties/AssemblyInfo.cs b/testing/GM.Utility.Testing.Unit/ArrayUtilityTests.cs similarity index 58% rename from src/GM.Utility/GM.Utility.Test/Properties/AssemblyInfo.cs rename to testing/GM.Utility.Testing.Unit/ArrayUtilityTests.cs index 8c9f82c..2842d17 100644 --- a/src/GM.Utility/GM.Utility.Test/Properties/AssemblyInfo.cs +++ b/testing/GM.Utility.Testing.Unit/ArrayUtilityTests.cs @@ -1,7 +1,7 @@ -/* +/* MIT License -Copyright (c) 2018 Grega Mohorko +Copyright (c) 2024 Gregor Mohorko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -21,28 +21,35 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Project: GM.Utility.Test -Created: 2018-3-18 -Author: GregaMohorko +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega */ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("GM.Utility.Test")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Grega Mohorko")] -[assembly: AssemblyProduct("GM.Utility.Test")] -[assembly: AssemblyCopyright("Copyright © Grega Mohorko 2018")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("dbe09199-2df5-40bf-9920-a313d674e6eb")] - -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +namespace GM.Utility.Testing.Unit; + +public class ArrayUtilityTests +{ + [Fact] + public void Reset() + { + Assert.Throws(delegate + { + ArrayUtility.Reset(null); + }); + Assert.Throws(delegate + { + ArrayUtility.Reset(null,""); + }); + + var array1 = new int[] { 1,2,3,4,5,6,7,8,9,10 }; + array1.Reset(); + var expected1 = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + array1.Should().Equal(expected1); + + var array2 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + array2.Reset(42); + var expected2 = new int[] { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 }; + array2.Should().Equal(expected2); + } +} diff --git a/testing/GM.Utility.Testing.Unit/DateTimeUtilityTests.cs b/testing/GM.Utility.Testing.Unit/DateTimeUtilityTests.cs new file mode 100644 index 0000000..ee7de14 --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/DateTimeUtilityTests.cs @@ -0,0 +1,117 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +namespace GM.Utility.Testing.Unit; + +public class DateTimeUtilityTests +{ + [Fact] + public void DurationBetween() + { + const int MS_IN_ONE_DAY = 24 * 60 * 60 * 1000; + + DateTime date1; + DateTime date2; + TimeSpan durationBetween; + + // ascending order + date1 = new DateTime(2021, 12, 17); + date2 = new DateTime(2021, 12, 18); + durationBetween = DateTimeUtility.DurationBetween(date1, date2); + durationBetween.Days.Should().Be(1); + durationBetween.TotalMilliseconds.Should().Be(MS_IN_ONE_DAY); + + // descending order + date1 = new DateTime(2021, 12, 18); + date2 = new DateTime(2021, 12, 17); + durationBetween = DateTimeUtility.DurationBetween(date1, date2); + durationBetween.Days.Should().Be(1); + durationBetween.TotalMilliseconds.Should().Be(MS_IN_ONE_DAY); + } + + [Fact] + public void EndOfMonth() + { + DateTime date; + DateTime endOfMonth; + + // normal 30 day month + date = new DateTime(2018, 9, 15); + endOfMonth = date.EndOfMonth(); + date.Should().Be(new DateTime(2018, 9, 15)); // make sure that the original DateTime is not modified + endOfMonth.Should().Be(new DateTime(2018, 9, 30)); + + // normal 31 day month + date = new DateTime(2018, 12, 20); + endOfMonth = date.EndOfMonth(); + endOfMonth.Should().Be(new DateTime(2018, 12, 31)); + + // february 28 + date = new DateTime(2018, 2, 10); + endOfMonth = date.EndOfMonth(); + endOfMonth.Should().Be(new DateTime(2018, 2, 28)); + + // february 29 + date = new DateTime(2016, 2, 1); + endOfMonth = date.EndOfMonth(); + endOfMonth.Should().Be(new DateTime(2016, 2, 29)); + + // already last day + date = new DateTime(1993, 1, 31); + endOfMonth = date.EndOfMonth(); + endOfMonth.Should().Be(new DateTime(1993, 1, 31)); + + // current end of month + date = DateTime.Today.EndOfMonth(); + endOfMonth = DateTimeUtility.EndOfMonth(); + endOfMonth.Should().Be(date); + } + + [Fact] + public void StartOfMonth() + { + DateTime date; + DateTime startOfMonth; + + // normal month + date = new DateTime(2018, 9, 15); + startOfMonth = date.StartOfMonth(); + date.Should().Be(new DateTime(2018, 9, 15)); // make sure that the original DateTime is not modified + startOfMonth.Should().Be(new DateTime(2018, 9, 1)); + + // already first day + date = new DateTime(2000, 6, 1); + startOfMonth = date.StartOfMonth(); + startOfMonth.Should().Be(new DateTime(2000, 6, 1)); + + // current start of month + date = DateTime.Today.StartOfMonth(); + startOfMonth = DateTimeUtility.StartOfMonth(); + startOfMonth.Should().Be(date); + } +} diff --git a/testing/GM.Utility.Testing.Unit/DecimalUtilityTests.cs b/testing/GM.Utility.Testing.Unit/DecimalUtilityTests.cs new file mode 100644 index 0000000..c1d472b --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/DecimalUtilityTests.cs @@ -0,0 +1,85 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +namespace GM.Utility.Testing.Unit; + +public class DecimalUtilityTests +{ + [Fact] + public void GetDecimals() + { + 42.123456789m.GetDecimals().Should().Be(0.123456789m); + (-42.123456789m).GetDecimals().Should().Be(-0.123456789m); + 0.123456789m.GetDecimals().Should().Be(0.123456789m); + 1.987654321m.GetDecimals().Should().Be(0.987654321m); + 123m.GetDecimals().Should().Be(0m); + } + + [Fact] + public void GetDecimals_WithRounding() + { + 42.123456789m.GetDecimals(3).Should().Be(0.123m); + (-42.123456789m).GetDecimals(4).Should().Be(-0.1235m); + 0.123456789m.GetDecimals(5).Should().Be(0.12346m); + 1.987654321m.GetDecimals(6).Should().Be(0.987654m); + 123m.GetDecimals(7).Should().Be(0m); + } + + [Fact] + public void GetDecimalPart() + { + 42.123m.GetDecimalPart(1, false).Should().Be(1); + 42.123m.GetDecimalPart(1, true).Should().Be(1); + 42.789m.GetDecimalPart(1, false).Should().Be(7); + 42.789m.GetDecimalPart(1, true).Should().Be(8); + 42.123m.GetDecimalPart(2, false).Should().Be(12); + 42.123m.GetDecimalPart(2, true).Should().Be(12); + 42.123m.GetDecimalPart(3, false).Should().Be(123); + 42.123m.GetDecimalPart(3, true).Should().Be(123); + 42.123456789m.GetDecimalPart(9, false).Should().Be(123456789); + 42.123456789m.GetDecimalPart(9, true).Should().Be(123456789); + 42.123456789m.GetDecimalPart(7, false).Should().Be(1234567); + 42.123456789m.GetDecimalPart(7, true).Should().Be(1234568); + (-42.987m).GetDecimalPart(2, false).Should().Be(-98); + (-42.987m).GetDecimalPart(2, true).Should().Be(-99); + 42m.GetDecimalPart(1, false).Should().Be(0); + 42m.GetDecimalPart(1, true).Should().Be(0); + 1.23m.GetDecimalPart(0, false).Should().Be(0); + 1.23m.GetDecimalPart(0, true).Should().Be(0); + } + + [Fact] + public void GetDecimalPart_Whole() + { + 42.1m.GetDecimalPart().Should().Be(1); + 0.12m.GetDecimalPart().Should().Be(12); + (-456.123m).GetDecimalPart().Should().Be(-123); + 42.123456789m.GetDecimalPart().Should().Be(123456789); + 123m.GetDecimalPart().Should().Be(0); + } +} diff --git a/testing/GM.Utility.Testing.Unit/DefaultedObjectTests.cs b/testing/GM.Utility.Testing.Unit/DefaultedObjectTests.cs new file mode 100644 index 0000000..7a17de6 --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/DefaultedObjectTests.cs @@ -0,0 +1,90 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +namespace GM.Utility.Testing.Unit; + +public class DefaultedObjectTests +{ + private class MyClass:DefaultedObject + { + internal const string DEFAULT = "DEFAULT TEXT"; + protected override string Default => DEFAULT; + +#pragma warning disable 0649 + public int IntField; + public int IntProperty { get; set; } + + public static string StaticPublicStringField; + internal static string staticInternalStringField; + protected static string StaticProtectedStringField; + public static string GetStaticProtectedStringField => StaticProtectedStringField; + private static string staticPrivateStringField; + public static string GetStaticPrivateStringField => staticPrivateStringField; + + public string PublicStringField; + internal string InternalStringField; + protected string ProtectedStringField; + public string GetProtectedStringField => ProtectedStringField; + private string PrivateStringField; + public string GetPrivateStringField => PrivateStringField; +#pragma warning restore 0649 + + public string PublicStringProperty { get; set; } + public string PublicStringPropertyWithInternalSetter { get; internal set; } + public string PublicStringPropertyWithProtectedSetter { get; protected set; } + public string PublicStringPropertyWithPrivateSetter { get; private set; } + internal string InternalStringProperty { get; set; } + protected string ProtectedStringProperty { get; set; } + public string GetProtectedStringProperty => ProtectedStringProperty; + private string PrivateStringProperty { get; set; } + public string GetPrivateStringProperty => PrivateStringProperty; + } + + [Fact] + public void Test() + { + var @object = new MyClass(); + Assert.Equal(default(int), @object.IntField); + Assert.Equal(default(int), @object.IntProperty); + Assert.Equal(MyClass.DEFAULT, @object.PublicStringField); + Assert.Equal(MyClass.DEFAULT, @object.InternalStringField); + Assert.Equal(MyClass.DEFAULT, @object.GetProtectedStringField); + Assert.Equal(MyClass.DEFAULT, @object.GetPrivateStringField); + Assert.Equal(MyClass.DEFAULT, @object.PublicStringProperty); + Assert.Equal(MyClass.DEFAULT, @object.PublicStringPropertyWithInternalSetter); + Assert.Equal(MyClass.DEFAULT, @object.PublicStringPropertyWithProtectedSetter); + Assert.Equal(MyClass.DEFAULT, @object.PublicStringPropertyWithPrivateSetter); + Assert.Equal(MyClass.DEFAULT, @object.InternalStringProperty); + Assert.Equal(MyClass.DEFAULT, @object.GetProtectedStringProperty); + Assert.Equal(MyClass.DEFAULT, @object.GetPrivateStringProperty); + Assert.Null(MyClass.StaticPublicStringField); + Assert.Null(MyClass.staticInternalStringField); + Assert.Null(MyClass.GetStaticProtectedStringField); + Assert.Null(MyClass.GetStaticPrivateStringField); + } +} diff --git a/testing/GM.Utility.Testing.Unit/DoubleUtilityTests.cs b/testing/GM.Utility.Testing.Unit/DoubleUtilityTests.cs new file mode 100644 index 0000000..fcca93d --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/DoubleUtilityTests.cs @@ -0,0 +1,85 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +namespace GM.Utility.Testing.Unit; + +public class DoubleUtilityTests +{ + [Fact] + public void GetDecimals() + { + Assert.Equal(0.123456789, 42.123456789.GetDecimals()); + Assert.Equal(-0.123456789, -42.123456789.GetDecimals()); + Assert.Equal(0.123456789, 0.123456789.GetDecimals()); + Assert.Equal(0.987654321, 1.987654321.GetDecimals()); + Assert.Equal(0d, 123d.GetDecimals()); + } + + [Fact] + public void GetDecimals_WithRounding() + { + Assert.Equal(0.123, 42.123456789.GetDecimals(3)); + Assert.Equal(-0.1235, -42.123456789.GetDecimals(4)); + Assert.Equal(0.12346, 0.123456789.GetDecimals(5)); + Assert.Equal(0.987654, 1.987654321.GetDecimals(6)); + Assert.Equal(0d, 123d.GetDecimals(7)); + } + + [Fact] + public void GetDecimalPart() + { + Assert.Equal(1, 42.123.GetDecimalPart(1, false)); + Assert.Equal(1, 42.123.GetDecimalPart(1, true)); + Assert.Equal(7, 42.789.GetDecimalPart(1, false)); + Assert.Equal(8, 42.789.GetDecimalPart(1, true)); + Assert.Equal(12, 42.123.GetDecimalPart(2, false)); + Assert.Equal(12, 42.123.GetDecimalPart(2, true)); + Assert.Equal(123, 42.123.GetDecimalPart(3, false)); + Assert.Equal(123, 42.123.GetDecimalPart(3, true)); + Assert.Equal(123456789, 42.123456789.GetDecimalPart(9, false)); + Assert.Equal(123456789, 42.123456789.GetDecimalPart(9, true)); + Assert.Equal(1234567, 42.123456789.GetDecimalPart(7, false)); + Assert.Equal(1234568, 42.123456789.GetDecimalPart(7, true)); + Assert.Equal(-98, -42.987.GetDecimalPart(2, false)); + Assert.Equal(-99, -42.987.GetDecimalPart(2, true)); + Assert.Equal(0, 42d.GetDecimalPart(1, false)); + Assert.Equal(0, 42d.GetDecimalPart(1, true)); + Assert.Equal(0, 1.23.GetDecimalPart(0, false)); + Assert.Equal(0, 1.23.GetDecimalPart(0, true)); + } + + [Fact] + public void GetDecimalPart_Whole() + { + Assert.Equal(1, 42.1.GetDecimalPart()); + Assert.Equal(12, 0.12.GetDecimalPart()); + Assert.Equal(-123, -456.123.GetDecimalPart()); + Assert.Equal(123456789, 42.123456789.GetDecimalPart()); + Assert.Equal(0, 123d.GetDecimalPart()); + } +} diff --git a/src/GM.Utility/GM.Utility.Test/EmailUtilityTest.cs b/testing/GM.Utility.Testing.Unit/EmailUtilityTests.cs similarity index 60% rename from src/GM.Utility/GM.Utility.Test/EmailUtilityTest.cs rename to testing/GM.Utility.Testing.Unit/EmailUtilityTests.cs index 1ceaa7d..fd611ac 100644 --- a/src/GM.Utility/GM.Utility.Test/EmailUtilityTest.cs +++ b/testing/GM.Utility.Testing.Unit/EmailUtilityTests.cs @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2020 Gregor Mohorko +Copyright (c) 2024 Gregor Mohorko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -21,28 +21,23 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Project: GM.Utility.Test -Created: 2020-01-16 -Author: Gregor Mohorko +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega */ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; +namespace GM.Utility.Testing.Unit; -namespace GM.Utility.Test +public class EmailUtilityTests { - [TestClass] - public class EmailUtilityTest + [Fact] + public void IsValid() { - [TestMethod] - public void IsValid() - { - Assert.IsTrue(EmailUtility.IsValid("example@mail.com")); - Assert.IsTrue(EmailUtility.IsValid("ExaMple.EXAMPLE@someDOMAIN.cOm")); - Assert.IsTrue(EmailUtility.IsValid("ALL.CAPS.MULTIPLE.DOTS@DOMAIN.COM")); - Assert.IsFalse(EmailUtility.IsValid("nodot@mailcom")); - Assert.IsFalse(EmailUtility.IsValid("no.dot@mail")); - Assert.IsFalse(EmailUtility.IsValid("no.no.no.no.dot@mydomain")); - } + Assert.True(EmailUtility.IsValid("example@mail.com")); + Assert.True(EmailUtility.IsValid("ExaMple.EXAMPLE@someDOMAIN.cOm")); + Assert.True(EmailUtility.IsValid("ALL.CAPS.MULTIPLE.DOTS@DOMAIN.COM")); + Assert.False(EmailUtility.IsValid("nodot@mailcom")); + Assert.False(EmailUtility.IsValid("no.dot@mail")); + Assert.False(EmailUtility.IsValid("no.no.no.no.dot@mydomain")); } } diff --git a/src/GM.Utility/GM.Utility.Test/EnumUtilityTest.cs b/testing/GM.Utility.Testing.Unit/EnumUtilityTests.cs similarity index 67% rename from src/GM.Utility/GM.Utility.Test/EnumUtilityTest.cs rename to testing/GM.Utility.Testing.Unit/EnumUtilityTests.cs index fc9246e..0be9b27 100644 --- a/src/GM.Utility/GM.Utility.Test/EnumUtilityTest.cs +++ b/testing/GM.Utility.Testing.Unit/EnumUtilityTests.cs @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2018 Grega Mohorko +Copyright (c) 2024 Gregor Mohorko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -21,26 +21,20 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Project: GM.Utility.Test -Created: 2018-3-28 -Author: GregaMohorko +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega */ -using System; -using System.Linq; -using Microsoft.VisualStudio.TestTools.UnitTesting; +namespace GM.Utility.Testing.Unit; -namespace GM.Utility.Test +public class EnumUtilityTests { - [TestClass] - public class EnumUtilityTest + [Fact] + public void GetValues() { - [TestMethod] - public void GetValues() - { - DayOfWeek[] daysOfWeek=EnumUtility.GetValues(); - DayOfWeek[] expected = Enum.GetValues(typeof(DayOfWeek)).Cast().ToArray(); - CollectionAssert.AreEqual(expected, daysOfWeek); - } + DayOfWeek[] daysOfWeek=EnumUtility.GetValues(); + DayOfWeek[] expected = Enum.GetValues(typeof(DayOfWeek)).Cast().ToArray(); + daysOfWeek.Should().Equal(expected); } } diff --git a/testing/GM.Utility.Testing.Unit/GM.Utility.Testing.Unit.csproj b/testing/GM.Utility.Testing.Unit/GM.Utility.Testing.Unit.csproj new file mode 100644 index 0000000..d677a5c --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/GM.Utility.Testing.Unit.csproj @@ -0,0 +1,27 @@ + + + + net6.0 + enable + false + true + + + + + + + + + + + + + + + + + + + + diff --git a/src/GM.Utility/GM.Utility.Test/GM.Utility.Test.licenseheader b/testing/GM.Utility.Testing.Unit/GM.Utility.Testing.Unit.licenseheader similarity index 96% rename from src/GM.Utility/GM.Utility.Test/GM.Utility.Test.licenseheader rename to testing/GM.Utility.Testing.Unit/GM.Utility.Testing.Unit.licenseheader index 5d5e4ad..06dbff7 100644 --- a/src/GM.Utility/GM.Utility.Test/GM.Utility.Test.licenseheader +++ b/testing/GM.Utility.Testing.Unit/GM.Utility.Testing.Unit.licenseheader @@ -3,7 +3,7 @@ extensions: .cs /* MIT License -Copyright (c) %CurrentYear% Grega Mohorko +Copyright (c) %CurrentYear% Gregor Mohorko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/testing/GM.Utility.Testing.Unit/IEnumerableUtilityTests.cs b/testing/GM.Utility.Testing.Unit/IEnumerableUtilityTests.cs new file mode 100644 index 0000000..03dc0bb --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/IEnumerableUtilityTests.cs @@ -0,0 +1,104 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +namespace GM.Utility.Testing.Unit; + +public class IEnumerableUtilityTests +{ + [Fact] + public void AllSame1() + { + char valueSelector1(string s) => s[0]; + char valueSelector3(string s) => s[2]; + var example = new List { "abc", "aac", "bac" }; + + Assert.Throws(delegate + { + IEnumerableUtility.AllSame(null, valueSelector1); + }); + Assert.Throws(delegate + { + IEnumerableUtility.AllSame(example, null); + }); + + // all strings have the same character in the third position + Assert.True(example.AllSame(valueSelector3)); + // not all strings have the same character in the first position + Assert.False(example.AllSame(valueSelector1)); + + // empty collections should return true, the same as LINQ All method + Assert.True(new List().AllSame(valueSelector1)); + } + + [Fact] + public void AllSame2() + { + char valueSelector1(string s) => s[0]; + char valueSelector2(string s) => s[1]; + char valueSelector3(string s) => s[2]; + char valueSelector4(string s) => s[3]; + var example = new List { "abcd", "aacd", "bacd" }; + + Assert.Throws(delegate + { + IEnumerableUtility.AllSame(null, valueSelector1, valueSelector1); + }); + Assert.Throws(delegate + { + IEnumerableUtility.AllSame(example, null, valueSelector1); + }); + Assert.Throws(delegate + { + IEnumerableUtility.AllSame(example, valueSelector1, null); + }); + + // all strings have the same character in the third and forth position + Assert.True(example.AllSame(valueSelector3,valueSelector4)); + // not all strings have the same character in the first and third position + Assert.False(example.AllSame(valueSelector1, valueSelector3)); + // not all strings have the same character in the third and first position + Assert.False(example.AllSame(valueSelector3, valueSelector1)); + // not all strings have the same character in the first and second position + Assert.False(example.AllSame(valueSelector1, valueSelector2)); + + // empty collections should return true, the same as LINQ All method + Assert.True(new List().AllSame(valueSelector1, valueSelector2)); + } + + [Fact] + public void Rotate() + { + var example = new List { 1, 2, 3, 4 }; + List rotated = example.Rotate(1).ToList(); + rotated.Should().Equal(new List { 4, 1, 2, 3 }); + + example = new List { 1, 2, 3, 4, 5 }; + rotated = example.Rotate(-2).ToList(); + rotated.Should().Equal(new List { 3, 4, 5, 1, 2 }); + } +} diff --git a/testing/GM.Utility.Testing.Unit/ReflectionUtilityTests.cs b/testing/GM.Utility.Testing.Unit/ReflectionUtilityTests.cs new file mode 100644 index 0000000..f89acac --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/ReflectionUtilityTests.cs @@ -0,0 +1,137 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +namespace GM.Utility.Testing.Unit; + +public class ReflectionUtilityTests +{ + private class ReflectionExampleClass + { +#pragma warning disable IDE0032 // Use auto property +#pragma warning disable IDE0044 // Add readonly modifier +#pragma warning disable 0649 // never assigned to +#pragma warning disable IDE0051 // Remove unused private members + public string PublicField; + internal string InternalField; + protected internal string ProtectedInternalField; + protected string ProtectedField; + public string GetProtectedField => ProtectedField; + private string privateField; + public string GetPrivateField => privateField; + private readonly string privateReadonlyField; + public string GetPrivateReadonlyField => privateReadonlyField; + + public string PublicProperty { get; set; } + public string PublicReadonlyProperty { get; } = "Public Readonly Property Value"; + internal string InternalProperty { get; set; } + protected string ProtectedProperty { get; set; } + private string PrivateProperty { get; set; } +#pragma warning restore IDE0051 // Remove unused private members +#pragma warning disable 0649 // never assigned to +#pragma warning restore IDE0044 // Add readonly modifier +#pragma warning restore IDE0032 // Use auto property + } + + [Fact] + public void AreAllPropertiesEqual() + { + _ = Assert.Throws(() => ReflectionUtility.AreAllPropertiesEqual(null)); + // at least two objects must be provided + _ = Assert.Throws(() => ReflectionUtility.AreAllPropertiesEqual(new object[0])); + _ = Assert.Throws(() => ReflectionUtility.AreAllPropertiesEqual(new object[1])); + // null objects are not allowed + _ = Assert.Throws(() => ReflectionUtility.AreAllPropertiesEqual(new object[2])); + _ = Assert.Throws(() => ReflectionUtility.AreAllPropertiesEqual(new ReflectionExampleClass[1024])); + // all objects must be of the same type + _ = Assert.Throws(() => ReflectionUtility.AreAllPropertiesEqual(new object[2] { "string", 42 })); + // primitive types are not allowed + _ = Assert.Throws(() => ReflectionUtility.AreAllPropertiesEqual(new object[2] { "string", "string" })); + + var objects = new ReflectionExampleClass[2] + { + new ReflectionExampleClass + { + // different field values and internal properties + PublicField = "Public field 0", + InternalField = "Internal field 0", + InternalProperty = "Internal property 0" + }, + new ReflectionExampleClass + { + // different field values and internal properties + PublicField = "Public field 1", + InternalField = "Internal field 1", + InternalProperty = "Internal property 1" + } + }; + + // set different values to private and protected properties + for(int i = 0; i < objects.Length; ++i) { + objects[i].SetProperty("PrivateProperty", $"Private property {i}"); + objects[i].SetProperty("ProtectedProperty", $"Protected property {i}"); + } + + // all public properties are null (have not been set) + Assert.True(ReflectionUtility.AreAllPropertiesEqual(objects)); + + objects.ForEach(obj => obj.PublicProperty = "some value"); + Assert.True(ReflectionUtility.AreAllPropertiesEqual(objects)); + + // set different public readonly properties + for(int i = 0; i < objects.Length; ++i) { + objects[i].SetField("privateField", $"Public readonly property {i}"); + } + Assert.False(ReflectionUtility.AreAllPropertiesEqual(objects)); + + // reset public readonly properties + objects.ForEach(obj => obj.SetField("privateField", "same readonly value")); + Assert.True(ReflectionUtility.AreAllPropertiesEqual(objects)); + + objects[0].PublicProperty = "different value"; + Assert.False(ReflectionUtility.AreAllPropertiesEqual(objects)); + } + + [Fact] + public void SetField() + { + var obj = new ReflectionExampleClass(); + + ReflectionUtility.SetField(obj, nameof(ReflectionExampleClass.PublicField), "publicValue"); + Assert.Equal("publicValue", obj.PublicField); + obj.SetField(nameof(ReflectionExampleClass.InternalField), "internalValue"); + Assert.Equal("internalValue", obj.InternalField); + obj.SetField(nameof(ReflectionExampleClass.ProtectedInternalField), "protectedInternalValue"); + Assert.Equal("protectedInternalValue", obj.ProtectedInternalField); + obj.SetField("ProtectedField", "protectedValue"); + Assert.Equal("protectedValue", obj.GetProtectedField); + obj.SetField("privateField", "privateValue"); + Assert.Equal("privateValue", obj.GetPrivateField); + obj.SetField("privateReadonlyField", "privateReadonlyValue"); + Assert.Equal("privateReadonlyValue", obj.GetPrivateReadonlyField); + } +} diff --git a/src/GM.Utility/GM.Utility.Test/ArrayUtilityTest.cs b/testing/GM.Utility.Testing.Unit/StringUtilityTests.cs similarity index 51% rename from src/GM.Utility/GM.Utility.Test/ArrayUtilityTest.cs rename to testing/GM.Utility.Testing.Unit/StringUtilityTests.cs index b95b429..ae30cf3 100644 --- a/src/GM.Utility/GM.Utility.Test/ArrayUtilityTest.cs +++ b/testing/GM.Utility.Testing.Unit/StringUtilityTests.cs @@ -1,7 +1,7 @@ /* MIT License -Copyright (c) 2018 Grega Mohorko +Copyright (c) 2024 Gregor Mohorko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -21,40 +21,29 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -Project: GM.Utility.Test -Created: 2018-4-16 -Author: GregaMohorko +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega */ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; +namespace GM.Utility.Testing.Unit; -namespace GM.Utility.Test +public class StringUtilityTests { - [TestClass] - public class ArrayUtilityTest + [Fact] + public void ShortenWith3Dots() { - [TestMethod] - public void Reset() - { - Assert.ThrowsException(delegate - { - ArrayUtility.Reset(null); - }); - Assert.ThrowsException(delegate - { - ArrayUtility.Reset(null,""); - }); - - var array1 = new int[] { 1,2,3,4,5,6,7,8,9,10 }; - array1.Reset(); - var expected1 = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - CollectionAssert.AreEqual(expected1, array1); - - var array2 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; - array2.Reset(42); - var expected2 = new int[] { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 }; - CollectionAssert.AreEqual(expected2, array2); - } + Assert.Throws(() => StringUtility.ShortenWith3Dots(null, -42)); + Assert.Throws(() => StringUtility.ShortenWith3Dots("", -1)); + Assert.Throws(() => StringUtility.ShortenWith3Dots("", -100)); + Assert.Throws(() => StringUtility.ShortenWith3Dots("", int.MinValue)); + Assert.Throws(() => StringUtility.ShortenWith3Dots("", 0)); + + string text = "Blues for the Red Sun"; + Assert.Equal(text, text.ShortenWith3Dots(int.MaxValue)); + Assert.Equal(text, text.ShortenWith3Dots(text.Length)); + Assert.Equal("B...", text.ShortenWith3Dots(1)); + Assert.Equal("Blues...", text.ShortenWith3Dots(5)); + Assert.Equal("Blues for the Red Su...", text.ShortenWith3Dots(20)); } } diff --git a/testing/GM.Utility.Testing.Unit/UriUtilityTests.cs b/testing/GM.Utility.Testing.Unit/UriUtilityTests.cs new file mode 100644 index 0000000..dbdc057 --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/UriUtilityTests.cs @@ -0,0 +1,38 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +namespace GM.Utility.Testing.Unit; + +public class UriUtilityTests +{ + [Fact] + public void Combine() + { + Assert.Equal("http://www.google.com/additional/paths/test", UriUtility.Combine("http://www.google.com/", "/additional/paths", "test").ToString()); + } +} diff --git a/testing/GM.Utility.Testing.Unit/UtilTests.cs b/testing/GM.Utility.Testing.Unit/UtilTests.cs new file mode 100644 index 0000000..585a37d --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/UtilTests.cs @@ -0,0 +1,46 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +namespace GM.Utility.Testing.Unit; + +public class UtilTests +{ + [Fact] + public void CombineWithParams() + { + // should throw exceptions + _ = Assert.Throws(() => Util.CombineWithParams(default(string), null)); + _ = Assert.Throws(() => Util.CombineWithParams(default(EventArgs), null)); + + // should not throw an exception + Util.CombineWithParams(default(int), null); + Util.CombineWithParams(default(TimeSpan), null); + Util.CombineWithParams(default(DateTime), null); + Util.CombineWithParams(default(DayOfWeek), null); + } +} diff --git a/testing/GM.Utility.Testing.Unit/WildcardUtilityTests.cs b/testing/GM.Utility.Testing.Unit/WildcardUtilityTests.cs new file mode 100644 index 0000000..7d97c6f --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/WildcardUtilityTests.cs @@ -0,0 +1,63 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +using System.Text.RegularExpressions; + +namespace GM.Utility.Testing.Unit; + +public class WildcardUtilityTests +{ + [Fact] + public void Insert() + { + string wildcard = "*/some/example/*/wildcard/*"; + string result = WildcardUtility.Insert(wildcard, new string[] { "first", "second", "last" }); + Assert.Equal("first/some/example/second/wildcard/last", result); + } + + [Fact] + public void WildcardToRegex() + { + string[] wildcards = + { + "*/some/example/*/wildcard/*", + "^*/some/example/*/wildcard/*", + "*/some/example/*/wildcard/*$", + "^*/some/example/*/wildcard/*$" + }; + foreach(string wildcard in wildcards) { + string regexPattern = WildcardUtility.WildcardToRegex(wildcard); + var regex = new Regex(regexPattern); + + Assert.Matches(regex, "test/some/example/test/wildcard/test"); + Assert.DoesNotMatch(regex, "some/example/test/wildcard/test"); + Assert.DoesNotMatch(regex, "test/some/example/wildcard/test"); + Assert.DoesNotMatch(regex, "test/some/example/test/wildcard"); + } + } +} From d3d69961c3a43c1780a2fb087c4509c748443cc1 Mon Sep 17 00:00:00 2001 From: Gregor Mohorko Date: Wed, 31 Jul 2024 02:51:17 +0200 Subject: [PATCH 4/6] feat: ThrottlerPerTime: Allow multiple limits --- src/GM.Utility/Throttling/ThrottlerPerTime.cs | 11 +-- .../Throttling/ThrottlerPerTimeTests.cs | 72 +++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 testing/GM.Utility.Testing.Unit/Throttling/ThrottlerPerTimeTests.cs diff --git a/src/GM.Utility/Throttling/ThrottlerPerTime.cs b/src/GM.Utility/Throttling/ThrottlerPerTime.cs index f50f900..73ddbea 100644 --- a/src/GM.Utility/Throttling/ThrottlerPerTime.cs +++ b/src/GM.Utility/Throttling/ThrottlerPerTime.cs @@ -128,17 +128,18 @@ public async Task WaitExecutionLimit(CancellationToken ct) while(true) { DateTime utcNow = DateTime.UtcNow; - DateTime nextAvailableExecutionAt = DateTime.MaxValue; + DateTime nextAvailableExecutionAt = DateTime.MinValue; lock(_executionLog) { - DateTime hm = _executionLog[_executionLogPosition]; foreach(var (Time, MaxExecutions) in Limits) { + if(MaxExecutions == 0) { + // no limit + continue; + } int previousRelevantLogPosition = (_executionLogPosition - MaxExecutions + _executionLog.Length) % _executionLog.Length; DateTime previousExecutionTime = _executionLog[previousRelevantLogPosition]; DateTime limitsNextAvailableExecutionAt = previousExecutionTime.Add(Time); - if(utcNow >= limitsNextAvailableExecutionAt - && limitsNextAvailableExecutionAt < nextAvailableExecutionAt - ) { + if(limitsNextAvailableExecutionAt > nextAvailableExecutionAt) { nextAvailableExecutionAt = limitsNextAvailableExecutionAt; } } diff --git a/testing/GM.Utility.Testing.Unit/Throttling/ThrottlerPerTimeTests.cs b/testing/GM.Utility.Testing.Unit/Throttling/ThrottlerPerTimeTests.cs new file mode 100644 index 0000000..aa10a48 --- /dev/null +++ b/testing/GM.Utility.Testing.Unit/Throttling/ThrottlerPerTimeTests.cs @@ -0,0 +1,72 @@ +/* +MIT License + +Copyright (c) 2024 Gregor Mohorko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Project: GM.Utility.Testing.Unit +Created: 2024-7-31 +Author: grega +*/ + +using GM.Utility.Throttling; + +namespace GM.Utility.Testing.Unit.Throttling; +public class ThrottlerPerTimeTests +{ + [Fact] + public async Task WaitExecutionLimit() + { + var throttler = new ThrottlerPerTime( + limits: new[] + { + // max 8 in the span of 200 ms + (TimeSpan.FromMilliseconds(200), 8), + // max 5 in the span of 50 ms + (TimeSpan.FromMilliseconds(50), 5) + } + ); + + const int EXECUTION_TARGET = 16; + int executionCount = 0; + + var executingThread = new Thread(async () => + { + for(int i = EXECUTION_TARGET; i > 0; --i) { + await throttler.WaitExecutionLimit(CancellationToken.None); + ++executionCount; + } + }); + + executingThread.Start(); + + await Task.Delay(30); + executionCount.Should().Be(5); + + await Task.Delay(150 - 30); + executionCount.Should().Be(8); + + await Task.Delay(230 - 150); + executionCount.Should().Be(8 + 5); + + await Task.Delay(300 - 230); + executionCount.Should().Be(EXECUTION_TARGET); + } +} From e37e2f874cc1bbd17501d5a4a7a6006215ad34c4 Mon Sep 17 00:00:00 2001 From: Gregor Mohorko Date: Wed, 31 Jul 2024 02:51:17 +0200 Subject: [PATCH 5/6] docs: Add ToString to ThrottlerPerTime --- src/GM.Utility/Throttling/ThrottlerPerTime.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/GM.Utility/Throttling/ThrottlerPerTime.cs b/src/GM.Utility/Throttling/ThrottlerPerTime.cs index 73ddbea..53ac15d 100644 --- a/src/GM.Utility/Throttling/ThrottlerPerTime.cs +++ b/src/GM.Utility/Throttling/ThrottlerPerTime.cs @@ -115,6 +115,14 @@ public ThrottlerPerTime((TimeSpan Time, int MaxExecutions)[] limits, ILogger log _executionLogPosition = 0; } + /// + /// Returns a string that represents this throttler. + /// + public override string ToString() + { + return string.Join(", ", Limits.Select(l => $"({l.MaxExecutions} per {l.Time})")); + } + /// /// Waits until the next time there can be an execution, according to the set throttling settings. /// Thread-safe. From 546d9f4af66d02a8e292434272e4e703cfd08d25 Mon Sep 17 00:00:00 2001 From: Gregor Mohorko Date: Wed, 31 Jul 2024 17:03:03 +0200 Subject: [PATCH 6/6] chore: Bump version to 1.7.0 --- src/GM.Utility/GM.Utility.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/GM.Utility/GM.Utility.csproj b/src/GM.Utility/GM.Utility.csproj index ec41a4b..4872c63 100644 --- a/src/GM.Utility/GM.Utility.csproj +++ b/src/GM.Utility/GM.Utility.csproj @@ -6,7 +6,7 @@ true false GM.StrongNameKey.snk - 1.6.1.0 + 1.7.0.0 GM.Utility Gregor Mohorko Gregor Mohorko @@ -16,9 +16,9 @@ Library with various static classes and tools that provide universally useful functions, extensions and utilities. Copyright © Gregor Mohorko 2024 true - Added additional logging to ThrottlerPerTime. - 1.6.1.0 - 1.6.1.0 + Added support for multiple limits to ThrottlerPerTime. + 1.7.0.0 + 1.7.0.0 https://github.com/GregaMohorko/GM.Utility Git LICENSE.md