diff --git a/Sluggy.Tests/CompositionStrategyTests.cs b/Sluggy.Tests/CompositionStrategyTests.cs new file mode 100644 index 0000000..989e153 --- /dev/null +++ b/Sluggy.Tests/CompositionStrategyTests.cs @@ -0,0 +1,73 @@ +using Moq; +using System.Linq; +using Xunit; + +namespace Sluggy.Tests +{ + public class CompositionStrategyTests + { + [Trait("Project", "Sluggy")] + [Fact(DisplayName = "Should Maintain the Strategies Order")] + public void MaintainsOrder() + { + const int numberOfStrategies = 30; + const string initialValue = "0"; + + var strategies = Enumerable + .Repeat(0, numberOfStrategies) + .Select((t, index) => + { + var mock = new Mock(); + var indexString = index.ToString(); + + mock.Setup(strat => strat.Translate(indexString)) + .Returns(text => (int.Parse(text) + 1).ToString()); + + return mock; + }) + .ToList(); + + var composite = new CompositeStrategy(strategies.Select(t => t.Object)); + + composite.Translate(initialValue); + + var assertionIndex = 0; + foreach (var curr in strategies) + { + curr.Verify(t => t.Translate(assertionIndex.ToString()), Times.Once); + assertionIndex++; + } + } + + [Trait("Project", "Sluggy")] + [Fact(DisplayName = "Should Execute All Strategies")] + public void AllStrategiesAreExecuted() + { + const int numberOfStrategies = 30; + const string textValue = "Dummy"; + + var strategies = Enumerable + .Repeat(0, numberOfStrategies) + .Select(t => + { + var mock = new Mock(); + + mock + .Setup(strat => strat.Translate(textValue)) + .Returns(textValue); + + return mock; + }) + .ToList(); + + var composite = new CompositeStrategy(strategies.Select(t => t.Object)); + + composite.Translate(textValue); + + foreach (var curr in strategies) + { + curr.Verify(t => t.Translate(textValue), Times.Once); + } + } + } +} \ No newline at end of file diff --git a/Sluggy.Tests/NormalizationStrategyTests.cs b/Sluggy.Tests/NormalizationStrategyTests.cs new file mode 100644 index 0000000..0347e99 --- /dev/null +++ b/Sluggy.Tests/NormalizationStrategyTests.cs @@ -0,0 +1,33 @@ +using System; +using Xunit; + +namespace Sluggy.Tests +{ + public class NormalizationStrategyTests + { + [Trait("Project", "Sluggy")] + [Theory(DisplayName = "Should Normalize string")] + [InlineData("áãâàóôòõêè", "aaaaooooee")] + [InlineData("ä ö ű ő", "a o u o")] + [InlineData("", "")] + public void ShouldNormalize(string value, string expectation) + { + var strategy = new NormalizationStrategy(); + + var translated = strategy.Translate(value); + + Assert.Equal(expectation, translated); + } + + [Trait("Project", "Sluggy")] + [Fact(DisplayName = "NormalizationStrategy Should Throw NullArgumentException")] + public void ShouldThrowNullArgumentException() + { + const string text = null; + + var strategy = new NormalizationStrategy(); + + Assert.Throws(() => strategy.Translate(text)); + } + } +} \ No newline at end of file diff --git a/Sluggy.Tests/SluggyIntegrationTests.cs b/Sluggy.Tests/SluggyIntegrationTests.cs index 64e6ff3..4bfca00 100644 --- a/Sluggy.Tests/SluggyIntegrationTests.cs +++ b/Sluggy.Tests/SluggyIntegrationTests.cs @@ -8,6 +8,7 @@ public class SluggyIntegrationTests [Theory(DisplayName = "Should Use Separator")] [InlineData("EU GOSTO DE TÁRTE", "euAgostoAdeAtarte", "A")] [InlineData("EU GOSTO", "euBananagosto", "Banana")] + [InlineData("", "", "")] public void ShouldUseSeparator(string value, string expectation, string separator) { var result = value.ToSlug(separator); diff --git a/Sluggy.Tests/SluggyUnitTests.cs b/Sluggy.Tests/SluggyUnitTests.cs index 059b24c..3403bb4 100644 --- a/Sluggy.Tests/SluggyUnitTests.cs +++ b/Sluggy.Tests/SluggyUnitTests.cs @@ -7,12 +7,12 @@ namespace Sluggy.Tests public class SluggyUnitTests { [Trait("Project", "Sluggy")] - [Fact(DisplayName = "Should Throw NullArgumentException")] + [Fact(DisplayName = "ToSlug Should Throw NullArgumentException")] public void ShouldThrowNullArgumentException() { - const string cena = null; + const string text = null; - Assert.Throws(() => cena.ToSlug()); + Assert.Throws(() => text.ToSlug()); } [Trait("Project", "Sluggy")] @@ -20,6 +20,7 @@ public void ShouldThrowNullArgumentException() [InlineData("EU GOSTO DE TRTE", "tarte-tarte-tarte-tarte")] [InlineData("EU GOSTO", "tarte-tarte")] [InlineData("EU no GOSTO", "tarte-tarte-tarte")] + [InlineData("", "")] public void ShouldReturnSlugifiedWithMocked(string value, string expectation) { const string translated = "tarte"; diff --git a/Sluggy.Tests/ToLowerInvarianStrategyTests.cs b/Sluggy.Tests/ToLowerInvarianStrategyTests.cs new file mode 100644 index 0000000..804300d --- /dev/null +++ b/Sluggy.Tests/ToLowerInvarianStrategyTests.cs @@ -0,0 +1,33 @@ +using System; +using Xunit; + +namespace Sluggy.Tests +{ + public class ToLowerInvarianStrategyTests + { + [Trait("Project", "Sluggy")] + [Theory(DisplayName = "Should LowerCase With InvariantCulture")] + [InlineData("AbcDEf", "abcdef")] + [InlineData("GHIJKL", "ghijkl")] + [InlineData("", "")] + public void ShouldLowerCaseWithInvariantCulture(string value, string expectation) + { + var strategy = new ToLowerInvariantStrategy(); + + var translated = strategy.Translate(value); + + Assert.Equal(expectation, translated); + } + + [Trait("Project", "Sluggy")] + [Fact(DisplayName = "ToLowerInvariantStrategy Should Throw NullArgumentException")] + public void ShouldThrowNullArgumentException() + { + const string text = null; + + var strategy = new ToLowerInvariantStrategy(); + + Assert.Throws(() => strategy.Translate(text)); + } + } +} \ No newline at end of file diff --git a/Sluggy/NormalizationStrategy.cs b/Sluggy/NormalizationStrategy.cs index 57edb45..9e50b80 100644 --- a/Sluggy/NormalizationStrategy.cs +++ b/Sluggy/NormalizationStrategy.cs @@ -1,4 +1,5 @@ -using System.Globalization; +using System; +using System.Globalization; using System.Linq; using System.Text; @@ -6,9 +7,17 @@ namespace Sluggy { public class NormalizationStrategy : ITranslationStrategy { - public string Translate(string text) => string - .Concat(text - .Normalize(NormalizationForm.FormD) - .Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)); + public string Translate(string text) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); + } + + return string + .Concat(text + .Normalize(NormalizationForm.FormD) + .Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)); + } } } \ No newline at end of file diff --git a/Sluggy/Sluggy.cs b/Sluggy/Sluggy.cs index e62fe05..d9def0a 100644 --- a/Sluggy/Sluggy.cs +++ b/Sluggy/Sluggy.cs @@ -9,6 +9,7 @@ public static class Sluggy public static readonly string DefaultSeparator = "-"; public static readonly ITranslationStrategy DefaultTranslationStrategy = new CompositeStrategy( + new ToLowerInvariantStrategy(), new NormalizationStrategy()); public static string ToSlug(this string text) @@ -36,7 +37,6 @@ public static string ToSlug(this string text, string separator, ITranslationStra return text .Split() .Where(t => t.Length != 0) - .Select(t => t.ToLowerInvariant()) .Select(t => strategy.Translate(t)) .Join(separator); } diff --git a/Sluggy/ToLowerInvariantStrategy.cs b/Sluggy/ToLowerInvariantStrategy.cs new file mode 100644 index 0000000..b846e01 --- /dev/null +++ b/Sluggy/ToLowerInvariantStrategy.cs @@ -0,0 +1,17 @@ +using System; + +namespace Sluggy +{ + public class ToLowerInvariantStrategy : ITranslationStrategy + { + public string Translate(string text) + { + if (text == null) + { + throw new ArgumentNullException(nameof(text)); + } + + return text.ToLowerInvariant(); + } + } +} diff --git a/SluggyUnidecode.Tests/SluggyUnidecodeIntegrationTests.cs b/SluggyUnidecode.Tests/SluggyUnidecodeIntegrationTests.cs index 3cf9e4a..0853bcc 100644 --- a/SluggyUnidecode.Tests/SluggyUnidecodeIntegrationTests.cs +++ b/SluggyUnidecode.Tests/SluggyUnidecodeIntegrationTests.cs @@ -11,6 +11,7 @@ public class SluggyUnidecodeIntegrationTests [InlineData("ä ö ű ő Ä Ö Ũ Ő", "ae-oe-u-o-ae-oe-u-o")] [InlineData("eu não gosto de pão da avó", "eu-nao-gosto-de-pao-da-avo")] [InlineData("Работа с кириллицей", "rabota-s-kirillitsey")] + [InlineData("ch\u00e2teau vi\u00f1edos", "chateau-vinedos")] public void ShouldConvertToSlugWithUnidecode(string value, string expectation) { var slugified = value.ToSlug(); diff --git a/SluggyUnidecode/SluggyUnidecode.csproj b/SluggyUnidecode/SluggyUnidecode.csproj index 4974b6f..6aeaa3a 100644 --- a/SluggyUnidecode/SluggyUnidecode.csproj +++ b/SluggyUnidecode/SluggyUnidecode.csproj @@ -17,7 +17,7 @@ Extends the Sluggy package by using the Unidecode.Net library for normalization. - +