From 24c34f2937e8cd30a665717c1dc661e6d8b19cee Mon Sep 17 00:00:00 2001 From: Denis Vieira <137417381+denisvieira-dev@users.noreply.github.com> Date: Tue, 4 Jul 2023 09:12:38 -0300 Subject: [PATCH] Year implementation (#54) * Year implementation * Tests * Name convention * Including YearTypeOptions * Update src/Nox.Types/Types/Year/TypeOptions/YearTypeOptions.cs Co-authored-by: Ricardo Rocha * Name consistent * Change to FluentAssertions * Tests changes --------- Co-authored-by: Ricardo Rocha Co-authored-by: Denis Vieira dos Anjos --- .../Types/Year/YearConverter.cs | 8 ++ .../Types/Year/TypeOptions/YearTypeOptions.cs | 11 ++ src/Nox.Types/Types/Year/Year.cs | 68 ++++++++++- tests/Nox.Types.Tests/Types/Year/YearTests.cs | 113 +++++++++++++++++- 4 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 src/Nox.Types.EntityFramework/Types/Year/YearConverter.cs create mode 100644 src/Nox.Types/Types/Year/TypeOptions/YearTypeOptions.cs diff --git a/src/Nox.Types.EntityFramework/Types/Year/YearConverter.cs b/src/Nox.Types.EntityFramework/Types/Year/YearConverter.cs new file mode 100644 index 0000000..ce2a9bf --- /dev/null +++ b/src/Nox.Types.EntityFramework/Types/Year/YearConverter.cs @@ -0,0 +1,8 @@ +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Nox.Types.EntityFramework.Types; + +public class YearToUShortConverter : ValueConverter +{ + public YearToUShortConverter() : base(year => year.Value, n => Year.From(n)) { } +} diff --git a/src/Nox.Types/Types/Year/TypeOptions/YearTypeOptions.cs b/src/Nox.Types/Types/Year/TypeOptions/YearTypeOptions.cs new file mode 100644 index 0000000..0127ee8 --- /dev/null +++ b/src/Nox.Types/Types/Year/TypeOptions/YearTypeOptions.cs @@ -0,0 +1,11 @@ + +namespace Nox.Types; + +public class YearTypeOptions +{ + public static readonly ushort DefaultMinValue= 1900; + public static readonly ushort DefaultMaxValue = 3000; + public ushort MinValue { get; set; } = DefaultMinValue; + public ushort MaxValue { get; set; } = DefaultMaxValue; + public bool AllowFutureOnly { get; set; } = false; +} diff --git a/src/Nox.Types/Types/Year/Year.cs b/src/Nox.Types/Types/Year/Year.cs index 9a284c2..7f94079 100644 --- a/src/Nox.Types/Types/Year/Year.cs +++ b/src/Nox.Types/Types/Year/Year.cs @@ -1,9 +1,71 @@ +using System; + namespace Nox.Types; +/// +/// Represents a Nox type and value object. +/// +public sealed class Year : ValueObject +{ + private YearTypeOptions _yearTypeOptions = new(); + + public Year() { Value = 0; } + /// - /// Represents a Nox type and value object. + /// Creates a new instance of using the specified /// - /// Placeholder, needs to be implemented - public sealed class Year : ValueObject + /// The number to create the with + /// The containing constraints for the value object + /// + /// + public static Year From(ushort value, YearTypeOptions options) + { + var newObject = new Year + { + Value = value, + _yearTypeOptions = options + }; + + var validationResult = newObject.Validate(); + + if (!validationResult.IsValid) + { + throw new TypeValidationException(validationResult.Errors); + } + + return newObject; + } + + /// + /// Validates the object. + /// + /// A validation result indicating whether the object is valid or not. + internal override ValidationResult Validate() + { + var result = base.Validate(); + + if (Value < _yearTypeOptions.MinValue) + { + result.Errors.Add(new ValidationFailure(nameof(Value), $"Could not create a Nox Year type as value {Value} is less than the minimum specified value of {_yearTypeOptions.MinValue}")); + } + + if (Value > _yearTypeOptions.MaxValue) + { + result.Errors.Add(new ValidationFailure(nameof(Value), $"Could not create a Nox Year type a value {Value} is greater than the maximum specified value of {_yearTypeOptions.MaxValue}")); + } + + if (_yearTypeOptions.AllowFutureOnly && Value < DateTime.Now.Year) + { + result.Errors.Add(new ValidationFailure(nameof(Value), $"Could not create a Nox Year type a value {Value} is less than the current year")); + } + + + return result; + } + + /// + public override string ToString() { + return Value.ToString("0000"); } +} \ No newline at end of file diff --git a/tests/Nox.Types.Tests/Types/Year/YearTests.cs b/tests/Nox.Types.Tests/Types/Year/YearTests.cs index be40c94..5bf68f3 100644 --- a/tests/Nox.Types.Tests/Types/Year/YearTests.cs +++ b/tests/Nox.Types.Tests/Types/Year/YearTests.cs @@ -1,11 +1,120 @@ -// ReSharper disable once CheckNamespace +using FluentAssertions; + namespace Nox.Types.Tests.Types; public class YearTests { [Fact] - public void When_Create_Should() + public void Year_Constructor_ReturnsSameValue() + { + var testYear = (ushort)1900; + + var number = Year.From(testYear); + + number.Value.Should().Be(testYear); + } + + [Theory] + [InlineData((ushort)0)] + [InlineData((ushort)(100))] + [InlineData((ushort)(1889))] + [InlineData((ushort)(1880))] + public void Year_Constructor_WithValueLess_ThanMinimiunSpecified_ThrowsValidationException(ushort value) + { + // Arrange & Act + var action = () => Year.From(value); + + // Assert + action.Should().Throw().And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", $"Could not create a Nox Year type as value {value} is less than the minimum specified value of 1900") }); + } + + [Theory] + [InlineData((ushort)3001)] + [InlineData((ushort)(4001))] + [InlineData((ushort)(5000))] + [InlineData((ushort)(9999))] + public void Year_Constructor_WithValueGreater_ThanMaximunSpecified_ThrowsValidationException(ushort value) + { + // Arrange & Act + var action = () => Year.From(value); + + // Assert + action.Should().Throw().And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", $"Could not create a Nox Year type a value {value} is greater than the maximum specified value of 3000") }); + } + + [Fact] + public void Year_Equal_Tests() + { + // Arrange + var year1 = Year.From(1900); + + var year2 = Year.From(1900); + + // Assert + year1.Should().Be(year2); + } + + [Fact] + public void Year_NotEqual_Tests() + { + // Arrange + var year1 = Year.From(2000); + + var year2 = Year.From(2002); + + // Assert + year1.Should().NotBe(year2); + } + + + [Fact] + public void Year_ToString_ReturnsString() + { + // Arrange + var year = Year.From(1900); + var year2 = Year.From(1990); + + // Assert + year.ToString().Should().Be("1900"); + year2.ToString().Should().Be("1990"); + } + + [Fact] + public void Year_Constructor_SpecifyingAllowFutureOnly_WithPassYearInput_ThrowsException() { + // Arrange + var yearValue = (ushort)2020; + + // Act + var action = () => Year.From(yearValue, new YearTypeOptions { AllowFutureOnly = true }); + + // Assert + action.Should().Throw().And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", $"Could not create a Nox Year type a value 2020 is less than the current year") }); + } + + [Fact] + public void Year_Constructor_SpecifyingMaxValue_WithGreaterValueInput_ThrowsException() + { + // Arrange + var yearValue = (ushort)1900; + + // Act + var action = () => Year.From(yearValue, new YearTypeOptions { MaxValue = 10 }); + + // Assert + action.Should().Throw().And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", $"Could not create a Nox Year type a value 1900 is greater than the maximum specified value of 10") }); + } + + [Fact] + public void Year_Constructor_SpecifyingMinValue_WithLesserValueInput_ThrowsException() + { + // Arrange + var yearValue = (ushort)1; + + // Act + var action = () => Year.From(yearValue, new YearTypeOptions { MinValue = 50 }); + // Assert + action.Should().Throw().And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", $"Could not create a Nox Year type as value 1 is less than the minimum specified value of 50") }); } } \ No newline at end of file