From 72b1913133afe088964fcfb4b13a99bc3ce316de Mon Sep 17 00:00:00 2001 From: magic56 Date: Thu, 27 Feb 2025 11:29:57 +0100 Subject: [PATCH 1/5] refactor: implement hashing functionality with IHashUtils interface and service class --- CodeLineCounter.Tests/HashUtilsMockTests.cs | 45 ++++++++++++ .../HashUtilsServiceTests.cs | 69 +++++++++++++++++++ CodeLineCounter.Tests/HashUtilsTests.cs | 10 ++- CodeLineCounter/AssemblyInfo.cs | 3 + CodeLineCounter/Utils/HashUtils.cs | 22 ++---- CodeLineCounter/Utils/HashUtilsService.cs | 27 ++++++++ CodeLineCounter/Utils/IHashUtils.cs | 7 ++ 7 files changed, 166 insertions(+), 17 deletions(-) create mode 100644 CodeLineCounter.Tests/HashUtilsMockTests.cs create mode 100644 CodeLineCounter.Tests/HashUtilsServiceTests.cs create mode 100644 CodeLineCounter/AssemblyInfo.cs create mode 100644 CodeLineCounter/Utils/HashUtilsService.cs create mode 100644 CodeLineCounter/Utils/IHashUtils.cs diff --git a/CodeLineCounter.Tests/HashUtilsMockTests.cs b/CodeLineCounter.Tests/HashUtilsMockTests.cs new file mode 100644 index 0000000..8491023 --- /dev/null +++ b/CodeLineCounter.Tests/HashUtilsMockTests.cs @@ -0,0 +1,45 @@ +using CodeLineCounter.Utils; +using Moq; + +namespace CodeLineCounter.Tests +{ + public class HashUtilsMockTests : TestBase + { + private readonly Mock _mockHashUtils; + private readonly IHashUtils _originalImplementation; + + public HashUtilsMockTests() + { + _originalImplementation = HashUtils.Implementation; + _mockHashUtils = new Mock(); + HashUtils.Implementation = _mockHashUtils.Object; + } + protected override void Dispose(bool disposing) + { + if (disposing) + { + _mockHashUtils.VerifyNoOtherCalls(); + HashUtils.Implementation = _originalImplementation; + } + + base.Dispose(disposing); + + } + + [Fact] + public void ComputeHash_WithMockedImplementation_CallsMockMethod() + { + // Arrange + string input = "Test"; + string expected = "mocked-hash"; + _mockHashUtils.Setup(m => m.ComputeHash(input)).Returns(expected); + + // Act + string result = HashUtils.ComputeHash(input); + + // Assert + Assert.Equal(expected, result); + _mockHashUtils.Verify(m => m.ComputeHash(input), Times.Once); + } + } +} \ No newline at end of file diff --git a/CodeLineCounter.Tests/HashUtilsServiceTests.cs b/CodeLineCounter.Tests/HashUtilsServiceTests.cs new file mode 100644 index 0000000..daaa96d --- /dev/null +++ b/CodeLineCounter.Tests/HashUtilsServiceTests.cs @@ -0,0 +1,69 @@ +using CodeLineCounter.Utils; + +namespace CodeLineCounter.Tests +{ + public class HashUtilsServiceTests + { + private readonly IHashUtils _hashUtils; + + public HashUtilsServiceTests() + { + _hashUtils = new HashUtilsService(); + } + + [Fact] + public void ComputeHash_EmptyString_ReturnsEmptyString() + { + // Arrange + string input = ""; + + // Act + string result = _hashUtils.ComputeHash(input); + + // Assert + Assert.Equal("", result); + } + + [Fact] + public void ComputeHash_NullString_ReturnsEmptyString() + { + // Arrange + string? input = null; + + // Act + string result = _hashUtils.ComputeHash(input); + + // Assert + Assert.Equal("", result); + } + + [Fact] + public void ComputeHash_ValidString_ReturnsHash() + { + // Arrange + string input = "Hello, World!"; + + // Act + string result = _hashUtils.ComputeHash(input); + + // Assert + Assert.NotEmpty(result); + Assert.IsType(result); + } + + [Fact] + public void ComputeHash_DuplicateStrings_ReturnSameHash() + { + // Arrange + string input1 = "Hello, World!"; + string input2 = "Hello, World!"; + + // Act + string result1 = _hashUtils.ComputeHash(input1); + string result2 = _hashUtils.ComputeHash(input2); + + // Assert + Assert.Equal(result1, result2); + } + } +} \ No newline at end of file diff --git a/CodeLineCounter.Tests/HashUtilsTests.cs b/CodeLineCounter.Tests/HashUtilsTests.cs index e15d2ab..32427b5 100644 --- a/CodeLineCounter.Tests/HashUtilsTests.cs +++ b/CodeLineCounter.Tests/HashUtilsTests.cs @@ -3,7 +3,7 @@ namespace CodeLineCounter.Tests { public class HashUtilsTests - { + { [Fact] public void ComputeHash_EmptyString_ReturnsEmptyString() { @@ -62,5 +62,13 @@ public void ComputeHash_DuplicateStrings_ReturnSameHash() // Assert Assert.Equal(result1, result2); } + + [Fact] + public void Implementation_IsInitializedByDefault() + { + // Act & Assert + Assert.NotNull(HashUtils.Implementation); + Assert.IsAssignableFrom(HashUtils.Implementation); + } } } \ No newline at end of file diff --git a/CodeLineCounter/AssemblyInfo.cs b/CodeLineCounter/AssemblyInfo.cs new file mode 100644 index 0000000..70937a3 --- /dev/null +++ b/CodeLineCounter/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("CodeLineCounter.Tests")] \ No newline at end of file diff --git a/CodeLineCounter/Utils/HashUtils.cs b/CodeLineCounter/Utils/HashUtils.cs index 59349d7..b5fd90f 100644 --- a/CodeLineCounter/Utils/HashUtils.cs +++ b/CodeLineCounter/Utils/HashUtils.cs @@ -5,23 +5,13 @@ namespace CodeLineCounter.Utils { public static class HashUtils { + private static readonly IHashUtils _defaultImplementation = new HashUtilsService(); + + internal static IHashUtils Implementation { get; set; } = _defaultImplementation; + public static string ComputeHash(string? input) { - if (string.IsNullOrEmpty(input)) - { - return ""; - } - - byte[] bytes = SHA256.HashData(Encoding.UTF8.GetBytes(input)); - - return string.Create(bytes.Length * 2, bytes, static (span, byteArray) => - { - const string format = "x2"; - for (int i = 0; i < byteArray.Length; i++) - { - byteArray[i].TryFormat(span.Slice(i * 2, 2), out _, format); - } - }); + return Implementation.ComputeHash(input); } } -} +} \ No newline at end of file diff --git a/CodeLineCounter/Utils/HashUtilsService.cs b/CodeLineCounter/Utils/HashUtilsService.cs new file mode 100644 index 0000000..195e68c --- /dev/null +++ b/CodeLineCounter/Utils/HashUtilsService.cs @@ -0,0 +1,27 @@ +using System.Security.Cryptography; +using System.Text; + +namespace CodeLineCounter.Utils +{ + public class HashUtilsService : IHashUtils + { + public string ComputeHash(string? input) + { + if (string.IsNullOrEmpty(input)) + { + return string.Empty; + } + + byte[] bytes = SHA256.HashData(Encoding.UTF8.GetBytes(input)); + + return string.Create(bytes.Length * 2, bytes, static (span, byteArray) => + { + const string format = "x2"; + for (int i = 0; i < byteArray.Length; i++) + { + byteArray[i].TryFormat(span.Slice(i * 2, 2), out _, format); + } + }); + } + } +} \ No newline at end of file diff --git a/CodeLineCounter/Utils/IHashUtils.cs b/CodeLineCounter/Utils/IHashUtils.cs new file mode 100644 index 0000000..060490f --- /dev/null +++ b/CodeLineCounter/Utils/IHashUtils.cs @@ -0,0 +1,7 @@ +namespace CodeLineCounter.Utils +{ + public interface IHashUtils + { + string ComputeHash(string? input); + } +} \ No newline at end of file From 110c01cd19599a5e583d45172015d2dfa759c850 Mon Sep 17 00:00:00 2001 From: magic56 Date: Thu, 27 Feb 2025 11:48:48 +0100 Subject: [PATCH 2/5] refactor: update HashUtilsServiceTests to use HashUtilsService directly --- CodeLineCounter.Tests/HashUtilsServiceTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeLineCounter.Tests/HashUtilsServiceTests.cs b/CodeLineCounter.Tests/HashUtilsServiceTests.cs index daaa96d..655147f 100644 --- a/CodeLineCounter.Tests/HashUtilsServiceTests.cs +++ b/CodeLineCounter.Tests/HashUtilsServiceTests.cs @@ -4,7 +4,7 @@ namespace CodeLineCounter.Tests { public class HashUtilsServiceTests { - private readonly IHashUtils _hashUtils; + private readonly HashUtilsService _hashUtils; public HashUtilsServiceTests() { From f31c89f158dd6edba81f7b5063b1fc92d1ef0c43 Mon Sep 17 00:00:00 2001 From: magic56 Date: Thu, 27 Feb 2025 11:56:28 +0100 Subject: [PATCH 3/5] refactor: remove unnecessary verification in HashUtilsMockTests and update type assertion in HashUtilsTests --- CodeLineCounter.Tests/HashUtilsMockTests.cs | 1 - CodeLineCounter.Tests/HashUtilsTests.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CodeLineCounter.Tests/HashUtilsMockTests.cs b/CodeLineCounter.Tests/HashUtilsMockTests.cs index 8491023..fd269d6 100644 --- a/CodeLineCounter.Tests/HashUtilsMockTests.cs +++ b/CodeLineCounter.Tests/HashUtilsMockTests.cs @@ -18,7 +18,6 @@ protected override void Dispose(bool disposing) { if (disposing) { - _mockHashUtils.VerifyNoOtherCalls(); HashUtils.Implementation = _originalImplementation; } diff --git a/CodeLineCounter.Tests/HashUtilsTests.cs b/CodeLineCounter.Tests/HashUtilsTests.cs index 32427b5..78f16a6 100644 --- a/CodeLineCounter.Tests/HashUtilsTests.cs +++ b/CodeLineCounter.Tests/HashUtilsTests.cs @@ -68,7 +68,7 @@ public void Implementation_IsInitializedByDefault() { // Act & Assert Assert.NotNull(HashUtils.Implementation); - Assert.IsAssignableFrom(HashUtils.Implementation); + Assert.IsType(HashUtils.Implementation, exactMatch: false); } } } \ No newline at end of file From 07a21518a783a87d01655ee2aa2f0cbdca0bab63 Mon Sep 17 00:00:00 2001 From: magic56 Date: Thu, 27 Feb 2025 12:05:14 +0100 Subject: [PATCH 4/5] Update CodeLineCounter/Utils/HashUtils.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- CodeLineCounter/Utils/HashUtils.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CodeLineCounter/Utils/HashUtils.cs b/CodeLineCounter/Utils/HashUtils.cs index b5fd90f..77fcf3d 100644 --- a/CodeLineCounter/Utils/HashUtils.cs +++ b/CodeLineCounter/Utils/HashUtils.cs @@ -7,8 +7,7 @@ public static class HashUtils { private static readonly IHashUtils _defaultImplementation = new HashUtilsService(); - internal static IHashUtils Implementation { get; set; } = _defaultImplementation; - + internal static IHashUtils Implementation { get; } = _defaultImplementation; public static string ComputeHash(string? input) { return Implementation.ComputeHash(input); From 141daceef437ab88fbfc5d087e5ee779fbc9667f Mon Sep 17 00:00:00 2001 From: magic56 Date: Thu, 27 Feb 2025 12:11:50 +0100 Subject: [PATCH 5/5] refactor: change Implementation property to be settable in HashUtils --- CodeLineCounter/Utils/HashUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeLineCounter/Utils/HashUtils.cs b/CodeLineCounter/Utils/HashUtils.cs index 77fcf3d..9d8eb22 100644 --- a/CodeLineCounter/Utils/HashUtils.cs +++ b/CodeLineCounter/Utils/HashUtils.cs @@ -7,7 +7,7 @@ public static class HashUtils { private static readonly IHashUtils _defaultImplementation = new HashUtilsService(); - internal static IHashUtils Implementation { get; } = _defaultImplementation; + internal static IHashUtils Implementation { get; set; } = _defaultImplementation; public static string ComputeHash(string? input) { return Implementation.ComputeHash(input);