diff --git a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ApiControllerBaseTests.cs b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ApiControllerBaseTests.cs new file mode 100644 index 0000000..c4fd10d --- /dev/null +++ b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ApiControllerBaseTests.cs @@ -0,0 +1,337 @@ +using AutoMapper; +using DavidBerry.Framework.ApiUtil.Controllers; +using DavidBerry.Framework.ApiUtil.Models; +using DavidBerry.Framework.Exceptions; +using DavidBerry.Framework.Functional; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Moq; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace DavidBerry.Framework.ApiUtil.Tests.Controllers; + +public class ApiControllerBaseTests +{ + + [Fact] + public void MapErrorResult_ReturnsBadRequest_WhenInvalidDataErrorInResult() + { + // Arrange + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + Result result = Result.Failure(new InvalidDataError("Invalid data")); + + // Act + var actionResult = mockController.Object.MapErrorResult(result); + + // Assert + actionResult.ShouldBeOfType(); + + var badRequestResult = actionResult as BadRequestObjectResult; + badRequestResult.Value.ShouldBeOfType(); + + var apiMessageModel = badRequestResult.Value as ApiMessageModel; + apiMessageModel.Message.ShouldBe("Invalid data"); + } + + + + [Fact] + public void MapErrorResult_ReturnsObjectNotFound_WhenObjectNotFoundErrorInResult() + { + // Arrange + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + Result result = Result.Failure(new ObjectNotFoundError("We looked everywhere, we could not find it")); + + // Act + var actionResult = mockController.Object.MapErrorResult(result); + + // Assert + actionResult.ShouldBeOfType(); + + var notFoundResult = actionResult as NotFoundObjectResult; + notFoundResult.Value.ShouldBeOfType(); + + var apiMessageModel = notFoundResult.Value as ApiMessageModel; + apiMessageModel.Message.ShouldBe("We looked everywhere, we could not find it"); + } + + + + [Fact] + public void CreateResponse_CallsSuccessFunction_WhenResultIsSuccess() + { + // Arrange + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + + var entity = new TestEntity { Id = 1, Name = "Test" }; + Result result = Result.Success(entity); + bool successFunctionCalled = false; + Func successFunction = (e) => + { + successFunctionCalled = true; + return new OkObjectResult(e); + }; + + // Act + var actionResult = mockController.Object.CreateResponse(result, successFunction); + + // Assert + successFunctionCalled.ShouldBeTrue(); + actionResult.ShouldBeOfType(); + var okResult = actionResult as OkObjectResult; + okResult.Value.ShouldBe(entity); + } + + [Fact] + public void CreateResponse_CallsMapErrorResult_WhenResultIsFailure() + { + // Arrange + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + Result result = Result.Failure(new ObjectNotFoundError("Not found")); + + + // Act + var actionResult = mockController.Object.CreateResponse(result, It.IsAny>()); + + // Assert + actionResult.ShouldBeOfType(); + + var notFoundResult = actionResult as NotFoundObjectResult; + notFoundResult.Value.ShouldBeOfType(); + + var apiMessageModel = notFoundResult.Value as ApiMessageModel; + apiMessageModel.Message.ShouldBe("Not found"); + } + + + + [Fact] + public void MapErrorResult_ReturnsBadRequest_WhenResultIsFailure_WithInvalidDataError() + { + // Arrange + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + Result result = Result.Failure(new InvalidDataError("Invalid data")); + + // Act + var actionResult = mockController.Object.MapErrorResult(result); + + // Assert + actionResult.ShouldBeOfType(); + + var badRequestResult = actionResult as BadRequestObjectResult; + badRequestResult.Value.ShouldBeOfType(); + + var apiMessageModel = badRequestResult.Value as ApiMessageModel; + apiMessageModel.Message.ShouldBe("Invalid data"); + + } + + + [Fact] + public void MapErrorResult_ReturnsNotFound_WhenResultIsFailure_WithObjectNotFoundError() + { + // Arrange + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + Result result = Result.Failure(new ObjectNotFoundError("The data was nowhere we looked")); + + // Act + var actionResult = mockController.Object.MapErrorResult(result); + + // Assert + actionResult.ShouldBeOfType(); + + var notFoundResult = actionResult as NotFoundObjectResult; + notFoundResult.Value.ShouldBeOfType(); + + var apiMessageModel = notFoundResult.Value as ApiMessageModel; + apiMessageModel.Message.ShouldBe("The data was nowhere we looked"); + + } + + + + [Fact] + public void MapErrorResult_ReturnsCreateObjectExistsConflictErrorResult_WhenResultIsFailure_WithObjectAlreadyExistsError() + { + // Arrange + TestEntity testEntity = new TestEntity() { Id = 1, Name = "I already exist" }; + + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + mockMapper.Setup(x => x.Map(testEntity)).Returns(new TestModel() { Id = 1, Name = "I already exist" }); + + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + Result result = Result.Failure(new ObjectAlreadyExistsError("The object already exists", testEntity)); + + // Act + var actionResult = mockController.Object.MapErrorResult(result); + + // Assert + actionResult.ShouldBeOfType(); + + var conflictResult = actionResult as ConflictObjectResult; + conflictResult.Value.ShouldBeOfType>(); + + var concurrencyErrorModel = conflictResult.Value as ConcurrencyErrorModel; + concurrencyErrorModel.Message.ShouldBe("The object already exists"); + + concurrencyErrorModel.CurrentObject.ShouldBeOfType(); + concurrencyErrorModel.CurrentObject.Id.ShouldBe(1); + concurrencyErrorModel.CurrentObject.Name.ShouldBe("I already exist"); + } + + + [Fact] + public void MapErrorResult_ReturnsConcurrencyConflict_WhenResultIsFailure_WithConcurrencyError() + { + // Arrange + TestEntity testEntity = new TestEntity() { Id = 1, Name = "Concurrency Error" }; + + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + mockMapper.Setup(x => x.Map(testEntity)).Returns(new TestModel() { Id = 1, Name = "Concurrency Error" }); + + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + Result result = Result.Failure(new ConcurrencyError("Someone else updated the object", testEntity)); + + // Act + var actionResult = mockController.Object.MapErrorResult(result); + + // Assert + actionResult.ShouldBeOfType(); + + var conflictResult = actionResult as ConflictObjectResult; + conflictResult.Value.ShouldBeOfType>(); + + var concurrencyErrorModel = conflictResult.Value as ConcurrencyErrorModel; + concurrencyErrorModel.Message.ShouldBe("Someone else updated the object"); + + concurrencyErrorModel.CurrentObject.ShouldBeOfType(); + concurrencyErrorModel.CurrentObject.Id.ShouldBe(1); + concurrencyErrorModel.CurrentObject.Name.ShouldBe("Concurrency Error"); + } + + + [Fact] + public void CreateConcurrencyConflictErrorResult_CreatesConflictObjectResult_WhenPassedConcurrencyException() + { + // Arrange + TestEntity testEntity = new TestEntity() { Id = 1, Name = "Concurrency Error" }; + + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + mockMapper.Setup(x => x.Map(testEntity)).Returns(new TestModel() { Id = 1, Name = "Concurrency Error" }); + + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + + var concurrencyException = new ConcurrencyException("Error Message", testEntity); + + // Act + var actionResult = mockController.Object.CreateConcurrencyConflictErrorResult(concurrencyException); + + // Assert + actionResult.ShouldBeOfType(); + + var conflictResult = actionResult as ConflictObjectResult; + conflictResult.Value.ShouldBeOfType>(); + + var errorModel = conflictResult.Value as ConcurrencyErrorModel; + errorModel.Message.ShouldBe("Error Message"); + errorModel.CurrentObject.ShouldBeOfType(); + errorModel.CurrentObject.Id.ShouldBe(1); + errorModel.CurrentObject.Name.ShouldBe("Concurrency Error"); + } + + + [Fact] + public void CreateConcurrencyConflictErrorResult_CreatesConflictObjectResult_WhenPassedConcurrencyError() + { + // Arrange + TestEntity testEntity = new TestEntity() { Id = 1, Name = "Concurrency Error" }; + + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + mockMapper.Setup(x => x.Map(testEntity)).Returns(new TestModel() { Id = 1, Name = "Concurrency Error" }); + + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + + var concurrencyError = new ConcurrencyError("Error Message", testEntity); + + // Act + var actionResult = mockController.Object.CreateConcurrencyConflictErrorResult(concurrencyError); + + // Assert + actionResult.ShouldBeOfType(); + + var conflictResult = actionResult as ConflictObjectResult; + conflictResult.Value.ShouldBeOfType>(); + + var errorModel = conflictResult.Value as ConcurrencyErrorModel; + errorModel.Message.ShouldBe("Error Message"); + errorModel.CurrentObject.ShouldBeOfType(); + errorModel.CurrentObject.Id.ShouldBe(1); + errorModel.CurrentObject.Name.ShouldBe("Concurrency Error"); + } + + + [Fact] + public void CreateObjectExistsConflictErrorResult_CreatesConflictObjectResult_WhenPassedObjectAlreadyExistsError() + { + // Arrange + TestEntity testEntity = new TestEntity() { Id = 1, Name = "Object Exists Error" }; + + Mock> mockLogger = new Mock>(); + Mock mockMapper = new Mock(); + mockMapper.Setup(x => x.Map(testEntity)).Returns(new TestModel() { Id = 1, Name = "Object Exists Error" }); + + Mock mockController = new Mock(mockLogger.Object, mockMapper.Object); + mockController.CallBase = true; + + var objectExistsError = new ObjectAlreadyExistsError("Error Message", testEntity); + + // Act + var actionResult = mockController.Object.CreateObjectExistsConflictErrorResult(objectExistsError); + + // Assert + actionResult.ShouldBeOfType(); + + var conflictResult = actionResult as ConflictObjectResult; + conflictResult.Value.ShouldBeOfType>(); + + var errorModel = conflictResult.Value as ConcurrencyErrorModel; + errorModel.Message.ShouldBe("Error Message"); + errorModel.CurrentObject.ShouldBeOfType(); + errorModel.CurrentObject.Id.ShouldBe(1); + errorModel.CurrentObject.Name.ShouldBe("Object Exists Error"); + } + +} \ No newline at end of file diff --git a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ControllerExtensionsTests.cs b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ControllerExtensionsTests.cs new file mode 100644 index 0000000..b6d5cbc --- /dev/null +++ b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/ControllerExtensionsTests.cs @@ -0,0 +1,85 @@ +using DavidBerry.Framework.ApiUtil.Controllers; +using DavidBerry.Framework.ApiUtil.Results; +using Microsoft.AspNetCore.Mvc; +using Moq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; +using Shouldly; + + +namespace DavidBerry.Framework.ApiUtil.Tests.Controllers; + + +public class ControllerExtensionsTests +{ + + [Fact] + public void ForbiddenExtensionMethod_ReturnsForbiddenResult() + { + // Arrange + var mockController = new Mock(); + mockController.CallBase = true; + + // Act + var result = mockController.Object.Forbidden(); + + // Assert + result.ShouldBeOfType(); + } + + + [Fact] + public void ForbiddenExtensionMethodWithValue_ReturnsForbiddenResultWithSameValue() + { + // Arrange + var mockController = new Mock(); + mockController.CallBase = true; + string message = "You do not have permission to access this resource."; + + // Act + var result = mockController.Object.Forbidden(message); + + // Assert + result.ShouldBeOfType(); + ((ForbiddenObjectResult)result).Value.ShouldBe(message); + } + + + + [Fact] + public void InternalServerErrorExtensionMethod_ReturnsInternalServerErrorResult() + { + // Arrange + var mockController = new Mock(); + mockController.CallBase = true; + + // Act + var result = mockController.Object.InternalServerError(); + + // Assert + result.ShouldBeOfType(); + } + + + + [Fact] + public void InternalServerErrorExtensionMethodWithValue_Returns_InternalServerErrorObjectResult_WithValue() + { + // Arrange + var mockController = new Mock(); + mockController.CallBase = true; + string message = "It all went terribly, terribly wrong!"; + + // Act + var result = mockController.Object.InternalServerError(message); + + // Assert + result.ShouldBeOfType(); + ((InternalServerErrorObjectResult)result).Value.ShouldBe(message); + } + +} \ No newline at end of file diff --git a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/TestEntity.cs b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/TestEntity.cs new file mode 100644 index 0000000..d219a1e --- /dev/null +++ b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil.Tests/Controllers/TestEntity.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DavidBerry.Framework.ApiUtil.Tests.Controllers; + +internal class TestEntity +{ + + public int Id { get; set; } + public string Name { get; set; } +} + + +internal class TestModel +{ + public int Id { get; set; } + public string Name { get; set; } + +} + diff --git a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/AssemblyOptions.cs b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/AssemblyOptions.cs new file mode 100644 index 0000000..d5364b5 --- /dev/null +++ b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/AssemblyOptions.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("DavidBerry.Framework.ApiUtil.Tests")] diff --git a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/Controllers/ApiControllerBase.cs b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/Controllers/ApiControllerBase.cs index 35b2fad..7d59b9e 100644 --- a/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/Controllers/ApiControllerBase.cs +++ b/DavidBerry.Framework.ApiUtil/DavidBerry.Framework.ApiUtil/Controllers/ApiControllerBase.cs @@ -41,7 +41,7 @@ public ApiControllerBase(ILogger logger, IMapper mapper) : ba /// /// /// - protected virtual IActionResult CreateConcurrencyConflictErrorResult(ConcurrencyException concurrencyException) + protected internal virtual IActionResult CreateConcurrencyConflictErrorResult(ConcurrencyException concurrencyException) { var conflictingObject = concurrencyException.TypedObject; var model = _mapper.Map(conflictingObject); @@ -54,7 +54,7 @@ protected virtual IActionResult CreateConcurrencyConflictErrorResult(ConcurrencyError concurrencyError) + protected internal virtual ActionResult CreateConcurrencyConflictErrorResult(ConcurrencyError concurrencyError) { var model = _mapper.Map(concurrencyError.ConflictingObject); var message = new ConcurrencyErrorModel() @@ -65,7 +65,7 @@ protected virtual ActionResult CreateConcurrencyConflictErrorResult(ObjectAlreadyExistsError objectExistsError) + protected internal virtual ActionResult CreateObjectExistsConflictErrorResult(ObjectAlreadyExistsError objectExistsError) { var model = _mapper.Map(objectExistsError.ExistingObject); var message = new ConcurrencyErrorModel() @@ -97,7 +97,7 @@ protected ActionResult CreateResponse(Result result) } - protected ActionResult CreateResponse(Result result, Func successFunction) + protected internal ActionResult CreateResponse(Result result, Func successFunction) { if (result.IsSuccess) { @@ -109,7 +109,6 @@ protected ActionResult CreateResponse(Result result, F } } - protected internal ActionResult MapErrorResult(Result result) { switch (result.Error) @@ -127,7 +126,6 @@ protected internal ActionResult MapErrorResult(Result result) } } - protected internal ActionResult MapErrorResult(Result result) { switch (result.Error) diff --git a/DavidBerry.Framework/DavidBerry.Framework.Tests/Data/IDataReaderExtensionsTests.cs b/DavidBerry.Framework/DavidBerry.Framework.Tests/Data/IDataReaderExtensionsTests.cs index 1463d39..03ba7ff 100644 --- a/DavidBerry.Framework/DavidBerry.Framework.Tests/Data/IDataReaderExtensionsTests.cs +++ b/DavidBerry.Framework/DavidBerry.Framework.Tests/Data/IDataReaderExtensionsTests.cs @@ -16,6 +16,30 @@ namespace DavidBerry.Framework.Tests.Data public class IDataReaderExtensionsTests { + #region GetFieldType + + [Fact] + public void GetFieldTypeBy_CallsGetFieldType_WithCorrectOrdinalColumn() + { + // Data + string columnName = "IsActive"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + mockDataReader.Setup(x => x.GetFieldType(ordinalPosition)).Returns(typeof(string)); + + // Act + var result = mockDataReader.Object.GetFieldType(columnName); + + // Assert + mockDataReader.Verify(x => x.GetFieldType(ordinalPosition), Times.Once); + } + + #endregion + + #region GetBoolean [Theory()] @@ -227,6 +251,216 @@ public void GetBooleanWithDefaultByName_ReturnsDefault_WhenValueIsNull(bool defa #endregion + #region GetChar + + [Theory()] + [InlineData('A')] + [InlineData('B')] + public void GetCharByName_WorksAsExpected_WhenPassingColumnName(char value) + { + // Data + string columnName = "IsActive"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + mockDataReader.Setup(x => x.GetChar(ordinalPosition)).Returns(value); + + // Act + var result = mockDataReader.Object.GetChar(columnName); + + // Assert + mockDataReader.Verify(x => x.GetChar(ordinalPosition), Times.Once); + result.ShouldBe(value); + } + + + [Theory()] + [InlineData('A')] + [InlineData('B')] + public void GetCharNullable_ReturnsValue_WhenValueNotNull(char value) + { + // Data + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(false); + mockDataReader.Setup(x => x.GetChar(ordinalPosition)).Returns(value); + + // Act + var result = mockDataReader.Object.GetCharNullable(ordinalPosition); + + // Assert + mockDataReader.Verify(x => x.GetChar(ordinalPosition), Times.Once); + result.ShouldBe(value); + } + + + [Fact] + public void GetCharNullable_ReturnsNull_WhenValueIsNull() + { + // Data + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(true); + + // Act + var result = mockDataReader.Object.GetCharNullable(ordinalPosition); + + // Assert + mockDataReader.Verify(x => x.GetChar(ordinalPosition), Times.Never); + result.ShouldBeNull(); + } + + + + [Theory()] + [InlineData('A')] + [InlineData('B')] + public void GetCharNullableByName_ReturnsValue_WhenValueIsNotNull(char value) + { + // Data + string columnName = "IsActive"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(false); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + mockDataReader.Setup(x => x.GetChar(ordinalPosition)).Returns(value); + + // Act + var result = mockDataReader.Object.GetCharNullable(columnName); + + // Assert + mockDataReader.Verify(x => x.GetChar(ordinalPosition), Times.Once); + result.ShouldBe(value); + } + + + [Fact()] + public void GetCharNullableByName_ReturnsNull_WhenValueIsNull() + { + // Data + string columnName = "IsActive"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(true); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + + // Act + var result = mockDataReader.Object.GetCharNullable(columnName); + + // Assert + mockDataReader.Verify(x => x.GetChar(ordinalPosition), Times.Never); + result.ShouldBeNull(); + } + + + [Theory()] + [InlineData('A', 'X')] + [InlineData('B', 'Z')] + public void GetCharWithDefault_ReturnsValue_WhenValueIsNotNull(char databaseValue, char defaultValue) + { + // Data + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(false); + mockDataReader.Setup(x => x.GetChar(ordinalPosition)).Returns(databaseValue); + + // Act + var result = mockDataReader.Object.GetCharWithDefault(ordinalPosition, defaultValue); + + // Assert + mockDataReader.Verify(x => x.GetChar(ordinalPosition), Times.Once); + result.ShouldBe(databaseValue); + result.ShouldNotBe(defaultValue); + } + + + [Theory()] + [InlineData('A')] + [InlineData('B')] + public void GetCharWithDefault_ReturnsDefault_WhenValueIsNull(char defaultValue) + { + // Data + int ordinalPosition = 10; + + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(true); + + // Act + var result = mockDataReader.Object.GetCharWithDefault(ordinalPosition, defaultValue); + + // Assert + mockDataReader.Verify(x => x.GetChar(ordinalPosition), Times.Never); + result.ShouldBe(defaultValue); + } + + + [Theory()] + [InlineData('A', 'X')] + [InlineData('B', 'Y')] + public void GetCharWithDefaultByName_ReturnsValue_WhenValueIsNotNull(char databaseValue, char defaultValue) + { + // Data + string columnName = "IsActive"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(false); + mockDataReader.Setup(x => x.GetChar(ordinalPosition)).Returns(databaseValue); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + + + // Act + var result = mockDataReader.Object.GetCharWithDefault(columnName, defaultValue); + + // Assert + mockDataReader.Verify(x => x.GetChar(ordinalPosition), Times.Once); + result.ShouldBe(databaseValue); + result.ShouldNotBe(defaultValue); + } + + + + [Theory()] + [InlineData('A')] + [InlineData('B')] + public void GetCharWithDefaultByName_ReturnsDefault_WhenValueIsNull(char defaultValue) + { + // Data + string columnName = "IsActive"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(true); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + + + // Act + var result = mockDataReader.Object.GetCharWithDefault(columnName, defaultValue); + + // Assert + mockDataReader.Verify(x => x.GetChar(ordinalPosition), Times.Never); + result.ShouldBe(defaultValue); + } + + + + #endregion #region Int16 @@ -295,7 +529,6 @@ public void GetInt16Nullable_ReturnsNull_WhenValueIsNull() } - [Theory()] [InlineData(3782)] [InlineData(-292)] @@ -649,8 +882,6 @@ public void GetInt32WithDefaultByName_ReturnsDefault_WhenValueIsNull(int default #endregion - - #region Int64 [Theory()] @@ -861,8 +1092,6 @@ public void GetInt64WithDefaultByName_ReturnsDefault_WhenValueIsNull(long defaul #endregion - - #region Float [Theory()] @@ -1283,6 +1512,216 @@ public void GetDoubleWithDefaultByName_ReturnsDefault_WhenValueIsNull(double def #endregion + #region Decimal + + [Theory()] + [InlineData(32.00)] + [InlineData(-46.50)] + public void GetDecimalByName_WorksAsExpected_WhenPassingColumnName(decimal value) + { + // Data + string columnName = "ColumnName"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + mockDataReader.Setup(x => x.GetDecimal(ordinalPosition)).Returns(value); + + // Act + var result = mockDataReader.Object.GetDecimal(columnName); + + // Assert + mockDataReader.Verify(x => x.GetDecimal(ordinalPosition), Times.Once); + result.ShouldBe(value); + } + + + [Theory()] + [InlineData(342.00)] + [InlineData(-292.25)] + public void GetDecimalNullable_ReturnsValue_WhenValueNotNull(decimal value) + { + // Data + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(false); + mockDataReader.Setup(x => x.GetDecimal(ordinalPosition)).Returns(value); + + // Act + var result = mockDataReader.Object.GetDecimalNullable(ordinalPosition); + + // Assert + mockDataReader.Verify(x => x.GetDecimal(ordinalPosition), Times.Once); + result.ShouldBe(value); + } + + + [Fact] + public void GetDecimalNullable_ReturnsNull_WhenValueIsNull() + { + // Data + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(true); + + // Act + var result = mockDataReader.Object.GetDecimalNullable(ordinalPosition); + + // Assert + mockDataReader.Verify(x => x.GetDecimal(ordinalPosition), Times.Never); + result.ShouldBeNull(); + } + + + + [Theory()] + [InlineData(3782.00)] + [InlineData(-292.75)] + public void GetDecimalNullableByName_ReturnsValue_WhenValueIsNotNull(decimal value) + { + // Data + string columnName = "ColumnName"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(false); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + mockDataReader.Setup(x => x.GetDecimal(ordinalPosition)).Returns(value); + + // Act + var result = mockDataReader.Object.GetDecimalNullable(columnName); + + // Assert + mockDataReader.Verify(x => x.GetDecimal(ordinalPosition), Times.Once); + result.ShouldBe(value); + } + + + [Fact()] + public void GetDecimalNullableByName_ReturnsNull_WhenValueIsNull() + { + // Data + string columnName = "IsActive"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(true); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + + // Act + var result = mockDataReader.Object.GetDecimalNullable(columnName); + + // Assert + mockDataReader.Verify(x => x.GetDecimal(ordinalPosition), Times.Never); + result.ShouldBeNull(); + } + + + [Theory()] + [InlineData(324.00, 0.00)] + [InlineData(0.50, 100.50)] + public void GetDecimalWithDefault_ReturnsValue_WhenValueIsNotNull(decimal databaseValue, decimal defaultValue) + { + // Data + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(false); + mockDataReader.Setup(x => x.GetDecimal(ordinalPosition)).Returns(databaseValue); + + // Act + var result = mockDataReader.Object.GetDecimalWithDefault(ordinalPosition, defaultValue); + + // Assert + mockDataReader.Verify(x => x.GetDecimal(ordinalPosition), Times.Once); + result.ShouldBe(databaseValue); + result.ShouldNotBe(defaultValue); + } + + + [Theory()] + [InlineData(0.00)] + [InlineData(100.550)] + public void GetDecimalWithDefault_ReturnsDefault_WhenValueIsNull(decimal defaultValue) + { + // Data + int ordinalPosition = 10; + + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(true); + + // Act + var result = mockDataReader.Object.GetDecimalWithDefault(ordinalPosition, defaultValue); + + // Assert + mockDataReader.Verify(x => x.GetDecimal(ordinalPosition), Times.Never); + result.ShouldBe(defaultValue); + } + + + [Theory()] + [InlineData(100.00, 0.00)] + [InlineData(0.125, 10.525)] + public void GetDecimalWithDefaultByName_ReturnsValue_WhenValueIsNotNull(decimal databaseValue, decimal defaultValue) + { + // Data + string columnName = "IsActive"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(false); + mockDataReader.Setup(x => x.GetDecimal(ordinalPosition)).Returns(databaseValue); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + + + // Act + var result = mockDataReader.Object.GetDecimalWithDefault(columnName, defaultValue); + + // Assert + mockDataReader.Verify(x => x.GetDecimal(ordinalPosition), Times.Once); + result.ShouldBe(databaseValue); + result.ShouldNotBe(defaultValue); + } + + + + [Theory()] + [InlineData(0.00)] + [InlineData(100.50)] + public void GetDecimalWithDefaultByName_ReturnsDefault_WhenValueIsNull(decimal defaultValue) + { + // Data + string columnName = "IsActive"; + int ordinalPosition = 10; + + // Arrange + Mock mockDataReader = new Mock(); + mockDataReader.Setup(x => x.IsDBNull(ordinalPosition)).Returns(true); + mockDataReader.Setup(x => x.GetOrdinal(columnName)).Returns(ordinalPosition); + + + // Act + var result = mockDataReader.Object.GetDecimalWithDefault(columnName, defaultValue); + + // Assert + mockDataReader.Verify(x => x.GetDecimal(ordinalPosition), Times.Never); + result.ShouldBe(defaultValue); + } + + + #endregion + #region String @@ -1494,7 +1933,6 @@ public void GetStringWithDefaultByName_ReturnsDefault_WhenValueIsNull(string def #endregion - #region DateTime diff --git a/DavidBerry.Framework/DavidBerry.Framework.Tests/DavidBerry.Framework.Tests.csproj b/DavidBerry.Framework/DavidBerry.Framework.Tests/DavidBerry.Framework.Tests.csproj index cf1b196..f7fd415 100644 --- a/DavidBerry.Framework/DavidBerry.Framework.Tests/DavidBerry.Framework.Tests.csproj +++ b/DavidBerry.Framework/DavidBerry.Framework.Tests/DavidBerry.Framework.Tests.csproj @@ -14,6 +14,8 @@ + + @@ -34,6 +36,15 @@ + + + + + PreserveNewest + + + PreserveNewest + diff --git a/DavidBerry.Framework/DavidBerry.Framework.Tests/EmbeddedResources/ExampleFile.txt b/DavidBerry.Framework/DavidBerry.Framework.Tests/EmbeddedResources/ExampleFile.txt new file mode 100644 index 0000000..31d27f4 --- /dev/null +++ b/DavidBerry.Framework/DavidBerry.Framework.Tests/EmbeddedResources/ExampleFile.txt @@ -0,0 +1 @@ +This is a test embedded resource file. \ No newline at end of file diff --git a/DavidBerry.Framework/DavidBerry.Framework.Tests/EmbeddedResources/dotnet-logo.png b/DavidBerry.Framework/DavidBerry.Framework.Tests/EmbeddedResources/dotnet-logo.png new file mode 100644 index 0000000..fb00ecf Binary files /dev/null and b/DavidBerry.Framework/DavidBerry.Framework.Tests/EmbeddedResources/dotnet-logo.png differ diff --git a/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/ChecksumExtensionsTests.cs b/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/ChecksumExtensionsTests.cs new file mode 100644 index 0000000..ce94dbb --- /dev/null +++ b/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/ChecksumExtensionsTests.cs @@ -0,0 +1,201 @@ +using DavidBerry.Framework.Util; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace DavidBerry.Framework.Tests.Util +{ + public class ChecksumExtensionsTests + { + + + + [Fact] + public void GetChecksum_FromByteArray_ReturnsCorrectChecksum_ForMd5() + { + // Arrange + byte[] data = Encoding.UTF8.GetBytes("This is a test string"); + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.MD5); + + // Assert + checksum.ToHexadecimalString().ShouldBe("C639EFC1E98762233743A75E7798DD9C"); + } + + [Fact] + public void GetChecksum_FromByteArray_ReturnsCorrectChecksum_ForSha1() + { + // Arrange + byte[] data = Encoding.UTF8.GetBytes("This is a test string"); + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA1); + + // Assert + checksum.ToHexadecimalString().ShouldBe("E2F67C772368ACDEEE6A2242C535C6CC28D8E0ED"); + } + + [Fact] + public void GetChecksum_FromByteArray_ReturnsCorrectChecksum_ForSha256() + { + // Arrange + byte[] data = Encoding.UTF8.GetBytes("This is a test string"); + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA256); + + // Assert + checksum.ToHexadecimalString().ShouldBe("717AC506950DA0CCB6404CDD5E7591F72018A20CBCA27C8A423E9C9E5626AC61"); + } + + + [Fact] + public void GetChecksum_FromByteArray_ReturnsCorrectChecksum_ForSha384() + { + // Arrange + byte[] data = Encoding.UTF8.GetBytes("This is a test string"); + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA384); + + // Assert + checksum.ToHexadecimalString().ShouldBe("9BD1F75EB75C8FFAD8F4B4C67C8F14DB32CC3D4177B942334ABD47F9E02E35B371D599CB4796185D7410E808F046E119"); + } + + + [Fact] + public void GetChecksum_FromByteArray_ReturnsCorrectChecksum_ForSha512() + { + // Arrange + byte[] data = Encoding.UTF8.GetBytes("This is a test string"); + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA512); + + // Assert + checksum.ToHexadecimalString().ShouldBe("B8EE69B29956B0B56E26D0A25C6A80713C858CF2902A12962AAD08D682345646B2D5F193BBE03997543A9285E5932F34BAF2C85C89459F25BA1CF43C4410793C"); + } + + + [Fact] + public void GetChecksum_FromByteArray_ReturnsCorrectChecksum_ForSha3_256() + { + // Arrange + byte[] data = Encoding.UTF8.GetBytes("This is a test string"); + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA3_256); + + // Assert + checksum.ToHexadecimalString().ShouldBe("22CDA3A2D2053F0A81FBF89AC531F724989F2308F0A2F29D894B07B4FEC0320E"); + } + + + [Fact] + public void GetChecksum_FromByteArray_ReturnsCorrectChecksum_ForSha3_384() + { + // Arrange + byte[] data = Encoding.UTF8.GetBytes("This is a test string"); + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA3_384); + + // Assert + checksum.ToHexadecimalString().ShouldBe("E31B4363776B1BC445BB5EE749ADDCB19F4CF22457FC36376D06CFE150D1E5C9D963A1D50E3AA8E65737E7C26BF817AE"); + } + + + [Fact] + public void GetChecksum_FromByteArray_ReturnsCorrectChecksum_ForSha3_512() + { + // Arrange + byte[] data = Encoding.UTF8.GetBytes("This is a test string"); + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA3_512); + + // Assert + checksum.ToHexadecimalString().ShouldBe("B8841178726F493E85FD41ED891CEC32B57781E707162ABF954C0D5E1C713262B84B37C68229017C698344CD8C7E0B4E7C1496DF7C303CFEA9F201A4DE9D12B2"); + } + + + + [Fact] + public void GetChecksum_FromString_ReturnsCorrectChecksum_ForMd5() + { + // Arrange + string data = "Chicago Illinois"; + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.MD5); + + // Assert + checksum.ToHexadecimalString().ShouldBe("EBBD525CE0186C584C244F00E9B6688E"); + } + + + + + [Fact] + public void GetChecksum_FromString_ReturnsCorrectChecksum_ForSha1() + { + // Arrange + string data = "Chicago Illinois"; + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA1); + + // Assert + checksum.ToHexadecimalString().ShouldBe("5569151800725DBB8C7A7CA8205A307E84BD2F47"); + } + + + + [Fact] + public void GetChecksum_FromString_ReturnsCorrectChecksum_ForSha256() + { + // Arrange + string data = "Chicago Illinois"; + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA256); + + // Assert + checksum.ToHexadecimalString().ShouldBe("7B9CE053B82E7C40721F62AAE31D2A96E3B671B989140B0467585DBD82E41F61"); + } + + + [Fact] + public void GetChecksum_FromString_ReturnsCorrectChecksum_ForSha384() + { + // Arrange + string data = "Chicago Illinois"; + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA384); + + // Assert + checksum.ToHexadecimalString().ShouldBe("40EF0273A8A18794FA1072211A5AA2DE1B256CE1EAC645BB642D8549C45F66F658FE924710D2651917A41626F1722889"); + } + + [Fact] + public void GetChecksum_FromString_ReturnsCorrectChecksum_ForSha512() + { + // Arrange + string data = "Chicago Illinois"; + + // Act + var checksum = data.GetChecksum(ChecksumAlgorithm.SHA512); + + // Assert + checksum.ToHexadecimalString().ShouldBe("9C23ED95E64268269D2ABD8E3E5E4B9F1601CF3ABF0CE1679583D19434A3C4DAA3A55A1488BB681DA844CC46BC0CFB7A0DBA8D8DF8BC84812854EFE79BA4933A"); + } + + + } +} diff --git a/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/CommonValidationsTests.cs b/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/CommonValidationsTests.cs new file mode 100644 index 0000000..0d5ba01 --- /dev/null +++ b/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/CommonValidationsTests.cs @@ -0,0 +1,251 @@ +using DavidBerry.Framework.Util; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Xunit; + +namespace DavidBerry.Framework.Tests.Util; + +public class CommonValidationsTests +{ + [Theory] + [InlineData("AL")] + [InlineData("AK")] + [InlineData("AZ")] + [InlineData("AR")] + [InlineData("CA")] + [InlineData("CO")] + [InlineData("CT")] + [InlineData("DE")] + [InlineData("FL")] + [InlineData("GA")] + [InlineData("HI")] + [InlineData("ID")] + [InlineData("IL")] + [InlineData("IN")] + [InlineData("IA")] + [InlineData("KS")] + [InlineData("KY")] + [InlineData("LA")] + [InlineData("ME")] + [InlineData("MD")] + [InlineData("MA")] + [InlineData("MI")] + [InlineData("MN")] + [InlineData("MS")] + [InlineData("MO")] + [InlineData("MT")] + [InlineData("NE")] + [InlineData("NV")] + [InlineData("NH")] + [InlineData("NJ")] + [InlineData("NM")] + [InlineData("NY")] + [InlineData("NC")] + [InlineData("ND")] + [InlineData("OH")] + [InlineData("OK")] + [InlineData("OR")] + [InlineData("PA")] + [InlineData("RI")] + [InlineData("SC")] + [InlineData("SD")] + [InlineData("TN")] + [InlineData("TX")] + [InlineData("UT")] + [InlineData("VT")] + [InlineData("VA")] + [InlineData("WA")] + [InlineData("WV")] + [InlineData("WI")] + [InlineData("WY")] + public void US_States_Validation_WorksForAllStateAbbreviations(string state) + { + // Act + var result = Regex.IsMatch(state, DavidBerry.Framework.Util.CommonValidations.US_STATES); + + // Assert + result.ShouldBeTrue(); + } + + + + [Theory] + [InlineData("al")] + [InlineData("ak")] + [InlineData("az")] + [InlineData("ar")] + [InlineData("ca")] + [InlineData("co")] + [InlineData("ct")] + [InlineData("de")] + [InlineData("fl")] + [InlineData("ga")] + [InlineData("hi")] + [InlineData("id")] + [InlineData("il")] + [InlineData("in")] + [InlineData("ia")] + [InlineData("ks")] + [InlineData("ky")] + [InlineData("la")] + [InlineData("me")] + [InlineData("md")] + [InlineData("ma")] + [InlineData("mi")] + [InlineData("mn")] + [InlineData("ms")] + [InlineData("mo")] + [InlineData("mt")] + [InlineData("ne")] + [InlineData("nv")] + [InlineData("nh")] + [InlineData("nj")] + [InlineData("nm")] + [InlineData("ny")] + [InlineData("nc")] + [InlineData("nd")] + [InlineData("oh")] + [InlineData("ok")] + [InlineData("or")] + [InlineData("pa")] + [InlineData("ri")] + [InlineData("sc")] + [InlineData("sr")] + [InlineData("tn")] + [InlineData("tx")] + [InlineData("ut")] + [InlineData("vt")] + [InlineData("va")] + [InlineData("wa")] + [InlineData("wv")] + [InlineData("wi")] + [InlineData("wy")] + public void US_States_Validation_ShouldFail_LowerCaseAbbreviations(string state) + { + // Act + var result = Regex.IsMatch(state, DavidBerry.Framework.Util.CommonValidations.US_STATES); + + // Assert + result.ShouldBeFalse(); + } + + + [Theory] + [InlineData("Alabama")] + [InlineData("")] + [InlineData("WYO")] + [InlineData("California ")] + [InlineData(" TX")] + [InlineData("New York")] + [InlineData("C")] + public void US_States_Validation_ShouldFail_InvalidAbbreviations(string state) + { + // Act + var result = Regex.IsMatch(state, CommonValidations.US_STATES); + + // Assert + result.ShouldBeFalse(); + } + + + [Theory] + [InlineData("11201")] + [InlineData("54911")] + [InlineData("60062")] + [InlineData("80401")] + [InlineData("94130")] + public void USZipCodes_Validation_WorksForValidZipCodes(string zipCode) + { + // Act + var result = Regex.IsMatch(zipCode, CommonValidations.US_ZIP_CODES); + + // Assert + result.ShouldBeTrue(); + } + + + + [Theory] + [InlineData("1201")] + [InlineData("54911 ")] + [InlineData("6066A")] + [InlineData("ZIPCD")] + [InlineData("")] + public void USZipCodes_Validation_FailsOnInvalidZipCodes(string zipCode) + { + // Act + var result = Regex.IsMatch(zipCode, CommonValidations.US_ZIP_CODES); + + // Assert + result.ShouldBeFalse(); + } + + + + [Theory] + [InlineData("https://www.github.com/")] + [InlineData("https://www.github.com")] + [InlineData("https://github.com/")] + [InlineData("https://github.com")] + public void Url_validation_PassesValidHttpsUrls(string url) + { + // Act + var result = Regex.IsMatch(url, CommonValidations.URL); + + // Assert + result.ShouldBeTrue(); + } + + + [Theory] + [InlineData("http://www.yahoo.com/")] + [InlineData("http://www.yahoo.com")] + [InlineData("http://yahoo.com/")] + [InlineData("http://yahoo.com")] + public void Url_validation_PassesValidHttpUrls(string url) + { + // Act + var result = Regex.IsMatch(url, CommonValidations.URL); + + // Assert + result.ShouldBeTrue(); + } + + + [Theory] + [InlineData("10.0.0.0")] + [InlineData("192.168.1.1")] + [InlineData("255.255.255.255")] + public void IpAddress_Validation_PassesValidIpAddresses(string ipAddress) + { + // Act + var result = Regex.IsMatch(ipAddress, CommonValidations.IP_ADDRESS); + + // Assert + result.ShouldBeTrue(); + } + + + [Theory] + [InlineData("")] + [InlineData("192.168.1.")] + [InlineData("255.255.255.255.255")] + public void IpAddress_Validation_FailsInvalidIpAddresses(string ipAddress) + { + // Act + var result = Regex.IsMatch(ipAddress, CommonValidations.IP_ADDRESS); + + // Assert + result.ShouldBeFalse(); + } + + +} + + diff --git a/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/EmbeddedResourceUtilTests.cs b/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/EmbeddedResourceUtilTests.cs new file mode 100644 index 0000000..bc5c43c --- /dev/null +++ b/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/EmbeddedResourceUtilTests.cs @@ -0,0 +1,56 @@ +using DavidBerry.Framework.Util; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace DavidBerry.Framework.Tests.Util; + +public class EmbeddedResourceUtilTests +{ + + + + [Fact] + public void ReadEmbeddedResourceTextFile_CorrectlyReadsTextFile() + { + // Arrange + var assembly = typeof(EmbeddedResourceUtilTests).Assembly; + var filename = "EmbeddedResources.ExampleFile.txt"; + + // Act + var contents = assembly.ReadEmbeddedResourceTextFile(filename); + + // Assert + contents.ShouldBe("This is a test embedded resource file."); + } + + + [Fact] + public void ReadEmbeddedResourceBinaryFile_CorrectlyReadsBinaryFile() + { + // Arrange + var assembly = typeof(EmbeddedResourceUtilTests).Assembly; + var filename = "EmbeddedResources.dotnet-logo.png"; + + // Act + var bytes = assembly.ReadEmbeddedResourceBinaryFile(filename); + + // Assert + using (var sha256 = SHA256.Create()) + { + var checksum = sha256.ComputeHash(bytes); + checksum.ToHexadecimalString().ShouldBe("8FCF6F6CD575C0F8C643691765A7DB2A4B3B104BFBFF34646555F5CCFFDB2895"); + } + } + + +} + + + + diff --git a/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/StringExtensionsTests.cs b/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/StringExtensionsTests.cs index f6b4ee0..b17c402 100644 --- a/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/StringExtensionsTests.cs +++ b/DavidBerry.Framework/DavidBerry.Framework.Tests/Util/StringExtensionsTests.cs @@ -217,5 +217,48 @@ public void ConvertToString_ProperlyDecodesByteArrayWithUnicode() result.ShouldBe("Chicago Illinois"); } + + [Fact] + public void ToHexadecimalString_ProperlyConvertsByteArrayToHexadecimalString() + { + // Arrange + byte[] bytes = new byte[] { 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x20, 0x49, 0x6c, 0x6c, 0x69, 0x6e, 0x6f, 0x69, 0x73 }; + + // Act + var result = bytes.ToHexadecimalString(); + + // Asset + result.ShouldBe("4368696361676F20496C6C696E6F6973"); + } + + [Fact] + public void ConvertToString_ProperlyConvertsByteArrayToStringAndBack_WhenEncodingSpecified() + { + // Arrange + string originalString = "Chicago Illinois"; + Encoding encoding = Encoding.UTF8; + + // Act + byte[] byteArray = originalString.ToByteArray(encoding); + string convertedString = byteArray.ConvertToString(encoding); + + // Asset + convertedString.ShouldBe(originalString); + } + + [Fact] + public void ConvertToString_ProperlyConvertsByteArrayToStringAndBack_WhenDefaultUtf8EncodingUsed() + { + // Arrange + string originalString = "Chicago Illinois"; + Encoding encoding = Encoding.UTF8; + + // Act + byte[] byteArray = originalString.ToByteArray(); + string convertedString = byteArray.ConvertToString(); + + // Asset + convertedString.ShouldBe(originalString); + } } diff --git a/DavidBerry.Framework/DavidBerry.Framework/Util/ChecksumAlgorithm.cs b/DavidBerry.Framework/DavidBerry.Framework/Util/ChecksumAlgorithm.cs new file mode 100644 index 0000000..7d94425 --- /dev/null +++ b/DavidBerry.Framework/DavidBerry.Framework/Util/ChecksumAlgorithm.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DavidBerry.Framework.Util; + +public enum ChecksumAlgorithm +{ + MD5, + SHA1, + SHA256, + SHA3_256, + SHA3_384, + SHA3_512, + SHA384, + SHA512 +} + diff --git a/DavidBerry.Framework/DavidBerry.Framework/Util/ChecksumExtensions.cs b/DavidBerry.Framework/DavidBerry.Framework/Util/ChecksumExtensions.cs new file mode 100644 index 0000000..767a166 --- /dev/null +++ b/DavidBerry.Framework/DavidBerry.Framework/Util/ChecksumExtensions.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Pipes; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DavidBerry.Framework.Util +{ + public static class ChecksumExtensions + { + + /// + /// Calculate the chacksum for the specified data using the specified algorithm + /// + /// A byte array of the data to calculate the checksum for + /// The Chcecksum Algorithm to use + /// + /// + public static byte[] GetChecksum(this byte[] data, ChecksumAlgorithm algorithm) + { + ArgumentNullException.ThrowIfNull(data); + return algorithm switch + { + ChecksumAlgorithm.MD5 => System.Security.Cryptography.MD5.HashData(data), + ChecksumAlgorithm.SHA1 => System.Security.Cryptography.SHA1.HashData(data), + ChecksumAlgorithm.SHA256 => System.Security.Cryptography.SHA256.HashData(data), + ChecksumAlgorithm.SHA384 => System.Security.Cryptography.SHA384.HashData(data), + ChecksumAlgorithm.SHA512 => System.Security.Cryptography.SHA512.HashData(data), + ChecksumAlgorithm.SHA3_256 => System.Security.Cryptography.SHA3_256.HashData(data), + ChecksumAlgorithm.SHA3_384 => System.Security.Cryptography.SHA3_384.HashData(data), + ChecksumAlgorithm.SHA3_512 => System.Security.Cryptography.SHA3_512.HashData(data), + _ => throw new NotSupportedException($"The specified checksum algorithm '{algorithm}' is not supported."), + }; + } + + + public static byte[] GetChecksum(this string data, ChecksumAlgorithm algorithm) + { + ArgumentNullException.ThrowIfNull(data); + return GetChecksum(Encoding.UTF8.GetBytes(data), algorithm); + } + + + public static byte[] GetChecksum(this Stream stream, ChecksumAlgorithm algorithm) + { + using (MemoryStream memoryStream = new MemoryStream()) + { + // Copy the data from the source stream to the memory stream + stream.CopyTo(memoryStream); + + // Convert the memory stream to a byte array + byte[] byteArray = memoryStream.ToArray(); + + return GetChecksum(byteArray, algorithm); + } + } + + public static byte[] GetChecksum(this FileInfo file, ChecksumAlgorithm algorithm) + { + return File.ReadAllBytes(file.FullName).GetChecksum(algorithm); + } + + } +} diff --git a/DavidBerry.Framework/DavidBerry.Framework/Util/EmbeddedResourceUtil.cs b/DavidBerry.Framework/DavidBerry.Framework/Util/EmbeddedResourceUtil.cs index 5a592c8..9a65123 100644 --- a/DavidBerry.Framework/DavidBerry.Framework/Util/EmbeddedResourceUtil.cs +++ b/DavidBerry.Framework/DavidBerry.Framework/Util/EmbeddedResourceUtil.cs @@ -9,7 +9,12 @@ namespace DavidBerry.Framework.Util public static class EmbeddedResourceUtil { - + /// + /// Reads an embedded resource text file from the specified assembly and returns its contents as a string + /// + /// + /// + /// public static string ReadEmbeddedResourceTextFile(this Assembly assembly, string filename) { var resourceName = $"{assembly.GetName().Name}.{filename}"; @@ -23,6 +28,18 @@ public static string ReadEmbeddedResourceTextFile(this Assembly assembly, string + public static byte[] ReadEmbeddedResourceBinaryFile(this Assembly assembly, string filename) + { + var resourceName = $"{assembly.GetName().Name}.{filename}"; + + using (BinaryReader reader = new BinaryReader(assembly.GetManifestResourceStream(resourceName))) + { + byte[] bytes = reader.ReadBytes((int)reader.BaseStream.Length); + return bytes; + } + } + + }