From eca5801d5a6ef0847dbd37c00bfe45be623291f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pacios?= Date: Tue, 6 Feb 2024 20:58:17 +0100 Subject: [PATCH 1/2] Added foreachAsync extension --- Directory.Build.props | 7 +++- .../Collections/EnumerableExtensions.cs | 19 ++++++++++ .../Collections/EnumerableExtensionsTest.cs | 37 +++++++++++++++++-- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 871b877..e46477e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,9 +1,12 @@  - 1 - $(VersionPrefix).1.0.0 + 1.1 + 0 + 0 + $(VersionBase).$(VersionFix).$(VersionSuffix) $(Version) + $(Version) René Pacios Copyright © $(Company) - $([System.DateTime]::Now.Year) diff --git a/src/Rene.Utils.Core/Extensions/Collections/EnumerableExtensions.cs b/src/Rene.Utils.Core/Extensions/Collections/EnumerableExtensions.cs index 6cbb2c0..988b483 100644 --- a/src/Rene.Utils.Core/Extensions/Collections/EnumerableExtensions.cs +++ b/src/Rene.Utils.Core/Extensions/Collections/EnumerableExtensions.cs @@ -43,6 +43,7 @@ namespace System.Collections.Generic using Rene.Utils.Core.Resources; using ComponentModel; using Data; + using Threading.Tasks; public static class EnumerableExtensions { @@ -65,6 +66,24 @@ public static void ForEach(this IEnumerable source, Action action) } } + /// + /// Extend internal ForEach Method add item index to where callback + /// + /// + /// + /// + /// + public static async Task ForEachAsync(this IEnumerable source, Func action) + { + if (source == null) throw new NullReferenceException(string.Format(CultureInfo.CurrentCulture, ExceptionMessages.NulleReferenceExceptioX0, nameof(source))); + if (action == null) throw new ArgumentNullException(string.Format(CultureInfo.CurrentCulture, ExceptionMessages.NulleReferenceExceptioX0, nameof(action))); + + foreach (var item in source) + { + await action(item); + + } + } /// /// Get ListItems after apply where to each item diff --git a/tests/Rene.Utils.Core.UnitTest/Extensions/Collections/EnumerableExtensionsTest.cs b/tests/Rene.Utils.Core.UnitTest/Extensions/Collections/EnumerableExtensionsTest.cs index c3e35d6..780d401 100644 --- a/tests/Rene.Utils.Core.UnitTest/Extensions/Collections/EnumerableExtensionsTest.cs +++ b/tests/Rene.Utils.Core.UnitTest/Extensions/Collections/EnumerableExtensionsTest.cs @@ -5,6 +5,8 @@ namespace Rene.Utils.Core.UnitTest.Extensions.Collections { using FluentAssertions; + using System; + using System.Threading.Tasks; public class EnumerableExtensionsTest { @@ -92,7 +94,7 @@ public void AnyNotNull_With_Null_Instances() source.AnyNotNull().Should().BeFalse(); source.Should().BeNull(); - + } @@ -110,17 +112,46 @@ public void AsEnumerableWithIndex() { tuple.item.Should().Be(source[i]); tuple.index.Should().Be(i); - + i++; } source.Should().HaveCount(i); - + } + [Fact] + public void ForEachAsync_With_Null_Instances() + { + List source = null; + + source + .Invoking(s => s.ForEachAsync(async w => await Task.CompletedTask)) + .Should() + .Throw(); + } + [Fact] + public void ForEachAsync_With_Null_Action() + { + var source = new List { 0, 1, 2, 3, 4, 5, 6, 7 }; + + source + .Invoking(s => s.ForEachAsync(null)) + .Should() + .Throw(); + } + + [Fact] + public void ForEachAsync_With_Action() + { + var source = new List { 0, 1, 2, 3, 4, 5, 6, 7 }; + + source.ForEachAsync(async w => await Task.CompletedTask); + } + } } From 0b8247e0ef29b8b31217062358c475ede07822ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Dario=20Pacios=20D=C3=ADaz?= Date: Fri, 19 Sep 2025 07:55:12 +0200 Subject: [PATCH 2/2] Added utils to string extensions --- Directory.Build.props | 2 +- .../Extensions/Primitives/StringExtensions.cs | 50 +++++ .../Resources/ExceptionMessages.Designer.cs | 9 + .../Resources/ExceptionMessages.resx | 3 + .../Primitives/StringExtensionsTest.cs | 179 +++++++++++++++++- 5 files changed, 234 insertions(+), 9 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index c5216e4..93ef608 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ 1 - $(VersionPrefix).3.0 + $(VersionPrefix).5.0 $(Version) René Pacios Copyright © $(Company) - $([System.DateTime]::Now.Year) diff --git a/src/Rene.Utils.Core/Extensions/Primitives/StringExtensions.cs b/src/Rene.Utils.Core/Extensions/Primitives/StringExtensions.cs index 2eb36e2..9c54133 100644 --- a/src/Rene.Utils.Core/Extensions/Primitives/StringExtensions.cs +++ b/src/Rene.Utils.Core/Extensions/Primitives/StringExtensions.cs @@ -35,6 +35,7 @@ included in all copies or substantial portions of the Software. */ using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text; // ReSharper disable once CheckNamespace @@ -175,5 +176,54 @@ public static T ToEnum(this string enumValue) } #endregion + + #region Comprobaciones + + + /// + /// Checks whether the string contains any of the specified substrings. + /// + /// The string to evaluate. + /// The substrings to search for. + /// true if at least one substring is found; otherwise, false. + /// Thrown if is null or empty. + public static bool ContainsAny(this string element, string[] substringsToCheck) + { + if (string.IsNullOrEmpty(element)) + return false; + + if(substringsToCheck==null || substringsToCheck.Length==0) + throw new ArgumentException(ExceptionMessages.ArrayNullOrEmptyArgumentFormat, nameof(substringsToCheck)); + + return substringsToCheck.Any(element.Contains); + } + + + /// + /// Inserts spaces into a CamelCase or PascalCase string. + /// Example: "MyTestVariable" → "My Test Variable". + /// + /// The input string. + /// A new string with spaces inserted before capital letters. + public static string AddSpacesToSentence(this string text) + { + if (string.IsNullOrWhiteSpace(text)) + return string.Empty; + + var sb = new StringBuilder(text.Length * 2); + sb.Append(text[0]); + + for (int i = 1; i < text.Length; i++) + { + if (char.IsUpper(text[i]) && text[i - 1] != ' ') + sb.Append(' '); + + sb.Append(text[i]); + } + + return sb.ToString(); + } + #endregion + } } \ No newline at end of file diff --git a/src/Rene.Utils.Core/Resources/ExceptionMessages.Designer.cs b/src/Rene.Utils.Core/Resources/ExceptionMessages.Designer.cs index 48966a5..60e9719 100644 --- a/src/Rene.Utils.Core/Resources/ExceptionMessages.Designer.cs +++ b/src/Rene.Utils.Core/Resources/ExceptionMessages.Designer.cs @@ -60,6 +60,15 @@ internal ExceptionMessages() { } } + /// + /// Looks up a localized string similar to Array is Null or Empty. + /// + public static string ArrayNullOrEmptyArgumentFormat { + get { + return ResourceManager.GetString("ArrayNullOrEmptyArgumentFormat", resourceCulture); + } + } + /// /// Looks up a localized string similar to The specified key does not have a valid size. /// diff --git a/src/Rene.Utils.Core/Resources/ExceptionMessages.resx b/src/Rene.Utils.Core/Resources/ExceptionMessages.resx index c056777..b72157a 100644 --- a/src/Rene.Utils.Core/Resources/ExceptionMessages.resx +++ b/src/Rene.Utils.Core/Resources/ExceptionMessages.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Array is Null or Empty + The specified key does not have a valid size diff --git a/tests/Rene.Utils.Core.UnitTest/Extensions/Primitives/StringExtensionsTest.cs b/tests/Rene.Utils.Core.UnitTest/Extensions/Primitives/StringExtensionsTest.cs index 531b1dd..1994f0f 100644 --- a/tests/Rene.Utils.Core.UnitTest/Extensions/Primitives/StringExtensionsTest.cs +++ b/tests/Rene.Utils.Core.UnitTest/Extensions/Primitives/StringExtensionsTest.cs @@ -34,7 +34,7 @@ public void ToBase64_Convert() Assert.Equal(expected, result); } -#endregion + #endregion #region ToGuid @@ -80,7 +80,7 @@ public void ToGuidOrDefault_Convert() public void ToGuidOrDefault_BadFormatGuid() { var strGuid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; - Guid expected=Guid.Empty; + Guid expected = Guid.Empty; var result = strGuid.ToGuidOrDefault(); @@ -91,9 +91,9 @@ public void ToGuidOrDefault_BadFormatGuid() public void ToGuidOrDefaultWithDefaultValue_BadFormatGuid() { var strGuid = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; - + Guid defaultValue = Guid.Parse("032aafff-dcc9-4d27-86bc-d8a7de04114b"); - Guid expected =defaultValue; + Guid expected = defaultValue; var result = strGuid.ToGuidOrDefault(defaultValue); @@ -135,6 +135,7 @@ public void ToInt_NullOrEmptyString_Must_Be_Zero() #endregion ToInt #region SplitTo + [Fact] public void SplitTo_Should_Be_As_Spectated() { @@ -213,7 +214,7 @@ public void ToEnum_ValidString_IgnoreCase_Should_Be_As_Spectated() "ONE".ToEnum() - .Should() + .Should() .BeAssignableTo() .And.Be(EnumSample.One); @@ -221,9 +222,9 @@ public void ToEnum_ValidString_IgnoreCase_Should_Be_As_Spectated() "one".ToEnum() - .Should() - .BeAssignableTo() - .And.Be(EnumSample.One); + .Should() + .BeAssignableTo() + .And.Be(EnumSample.One); @@ -271,5 +272,167 @@ public void ToEnum_InvalidStringValue__Should_Be_As_Spectated() } #endregion ToEnum + + #region ContainsAnyArray + + [Fact] + public void ContainsAnyArray_Should_Be_As_Spectated() + { + var input = "Hello World"; + var result = input.ContainsAny(new[] { "Hello", "Universe" }); + result.Should().BeTrue(); + } + + [Fact] + public void ContainsAnyArray_Should_Be_False() + { + var input = "Hello World"; + var result = input.ContainsAny(new[] { "Universe", "Galaxy" }); + result.Should().BeFalse(); + } + + [Fact] + public void ContainsAnyArray_NullOrEmptyString_Should_Be_False() + { + string input = null; + var result = input.ContainsAny(new[] { "Universe", "Galaxy" }); + result.Should().BeFalse(); + + input = string.Empty; + var result_1 = input.ContainsAny(new[] { "Universe", "Galaxy" }); + result_1.Should().BeFalse(); + } + + [Fact] + public void ContainsAnyArray_NullOrEmptyArray_Should_Be_False() + { + var input = "Hello World"; + + Action act1 = () => input.ContainsAny(null); + act1.Should() + .Throw(); + //.WithMessage(ExceptionMessages.ArrayNullOrEmptyArgumentFormat) // opcional: verificar el mensaje + + Action act2 = () => input.ContainsAny(Array.Empty()); + act2.Should() + .Throw(); + //.WithMessage(ExceptionMessages.ArrayNullOrEmptyArgumentFormat); + } + + [Fact] + public void ContainsAnyArray_Both_NullOrEmpty_Should_Be_False() + { + string input = null; + var result = input.ContainsAny(null); + result.Should().BeFalse(); + input = string.Empty; + var result_1 = input.ContainsAny(Array.Empty()); + result_1.Should().BeFalse(); + } + + + + #endregion + + #region AddSpacesToSentence + + public class StringExtensions_AddSpacesToSentence_Tests + { + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void Returns_Empty_For_Null_Or_Whitespace(string input) + { + // Act + var result = input.AddSpacesToSentence(); + + // Assert + result.Should().BeEmpty(); + } + + [Theory] + [InlineData("A", "A")] + [InlineData("a", "a")] + [InlineData("NoUpper", "No Upper")] + [InlineData("myTest", "my Test")] + [InlineData("MyTestVariable", "My Test Variable")] + [InlineData("HelloWorld!", "Hello World!")] + public void Inserts_Space_Before_Uppercase_When_Preceding_Is_Not_Space(string input, string expected) + { + // Act + var result = input.AddSpacesToSentence(); + + // Assert + result.Should().Be(expected); + } + + [Theory] + [InlineData("Already Spaced", "Already Spaced")] + [InlineData("This Is", "This Is")] // conserva espacios dobles ya existentes + [InlineData(" LeadingSpace", " Leading Space")] // agrega espacio antes de 'S' si procede + public void Preserves_Existing_Spaces(string input, string expected) + { + // Act + var result = input.AddSpacesToSentence(); + + // Assert + result.Should().Be(expected); + } + + [Theory] + [InlineData("HTMLParser", "H T M L Parser")] + [InlineData("JSON", "J S O N")] + [InlineData("XMLErrorCode", "X M L Error Code")] + public void Splits_Acronyms_Into_Individual_Letters_With_Spaces(string input, string expected) + { + // Act + var result = input.AddSpacesToSentence(); + + // Assert + result.Should().Be(expected); + } + + [Theory] + [InlineData("number9Test", "number9 Test")] + [InlineData("End2EndTest", "End2 End Test")] + public void Leaves_Digits_And_NonLetters_Intact_Only_Adds_Before_Uppercase(string input, string expected) + { + // Act + var result = input.AddSpacesToSentence(); + + // Assert + result.Should().Be(expected); + } + + [Fact] + public void Does_Not_Remove_Or_Change_Characters_Other_Than_Adding_Spaces_Before_Uppers() + { + // Arrange + var inputs = new[] + { + "MyTestVariable", + "Already Spaced", + "HelloWorld!", + "A", + "myTest", + "HTMLParser" + }; + + foreach (var input in inputs) + { + // Act + var result = input.AddSpacesToSentence(); + + // Assert: si quitamos espacios, debe quedar igual que el original sin espacios + result.Replace(" ", string.Empty) + .Should().Be(input.Replace(" ", string.Empty), + $"the function should not alter non-space characters for '{input}'"); + } + } + } + + #endregion + } } \ No newline at end of file