This repository has been archived by the owner on Jul 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #66 from NoxOrg/feature/Percentage
Percentage implementation
- Loading branch information
Showing
4 changed files
with
173 additions
and
5 deletions.
There are no files selected for viewing
13 changes: 13 additions & 0 deletions
13
src/Nox.Types.EntityFramework/Types/Percentage/PercentageConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; | ||
|
||
namespace Nox.Types.EntityFramework.Types; | ||
|
||
public class PercentageConverter : ValueConverter<Percentage, float> | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="PercentageConverter" /> class. | ||
/// </summary> | ||
public PercentageConverter() : base(percentage => percentage.Value, percentageValue => Percentage.From(percentageValue)) | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,70 @@ | ||
using System; | ||
using System.Globalization; | ||
|
||
namespace Nox.Types; | ||
|
||
/// <summary> | ||
/// Represents a Nox <see cref="Percentage"/> type and value object. | ||
/// </summary> | ||
public sealed class Percentage : ValueObject<float, Percentage> | ||
{ | ||
private PercentageTypeOptions _percentageTypeOptions = new(); | ||
|
||
/// <summary> | ||
/// Creates a new instance of <see cref="Percentage"/> class with the specified values. | ||
/// </summary> | ||
/// <param name="value">The value to create the <see cref="Percentage"/> with</param> | ||
/// <returns></returns> | ||
/// <exception cref="TypeValidationException"></exception> | ||
public static Percentage From(float value, PercentageTypeOptions options) | ||
{ | ||
var newObject = new Percentage | ||
{ | ||
Value = value, | ||
_percentageTypeOptions = options | ||
}; | ||
|
||
var validationResult = newObject.Validate(); | ||
|
||
if (!validationResult.IsValid) | ||
{ | ||
throw new TypeValidationException(validationResult.Errors); | ||
} | ||
|
||
return newObject; | ||
} | ||
|
||
/// <summary> | ||
/// Represents a Nox <see cref="Percentage"/> type and value object. | ||
/// Validates a <see cref="Percentage"/> object. | ||
/// </summary> | ||
/// <remarks>Placeholder, needs to be implemented</remarks> | ||
public sealed class Percentage : ValueObject<float, Percentage> | ||
/// <returns>true if the <see cref="Percentage"/> value is valid.</returns> | ||
internal override ValidationResult Validate() | ||
{ | ||
var result = base.Validate(); | ||
|
||
if (Value < _percentageTypeOptions.MinValue && !float.IsNaN(Value) && !float.IsInfinity(Value)) | ||
{ | ||
result.Errors.Add(new ValidationFailure(nameof(Value), $"Could not create a Nox Percentage type as value {Value} is less than than the minimum specified value of {_percentageTypeOptions.MinValue}")); | ||
} | ||
|
||
if (Value > _percentageTypeOptions.MaxValue && !float.IsNaN(Value) && !float.IsInfinity(Value)) | ||
{ | ||
result.Errors.Add(new ValidationFailure(nameof(Value), $"Could not create a Nox Percentage type a value {Value} is greater than than the maximum specified value of {_percentageTypeOptions.MaxValue}")); | ||
} | ||
|
||
Value = (float)Math.Round(Value, _percentageTypeOptions.Digits); | ||
|
||
return result; | ||
} | ||
|
||
public override string ToString() | ||
=> $"{(Value * 100).ToString($"0.{new string('#', _percentageTypeOptions.Digits)}", CultureInfo.InvariantCulture)}%"; | ||
|
||
/// <summary> | ||
/// Returns a string representation of the <see cref="Percentage"/> object using the specified <see cref="IFormatProvider"/>. | ||
/// </summary> | ||
/// <param name="formatProvider">The format provider for the length value.</param> | ||
/// <returns>A string representation of the <see cref="Percentage"/> object with the value formatted using the specified <see cref="IFormatProvider"/>.</returns> | ||
public string ToString(IFormatProvider formatProvider) | ||
=> $"{Value.ToString(formatProvider)}%"; | ||
} |
10 changes: 10 additions & 0 deletions
10
src/Nox.Types/Types/Percentage/TypeOptions/PercentageTypeOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace Nox.Types; | ||
public class PercentageTypeOptions | ||
{ | ||
public static readonly float DefaultMinValue = 0; | ||
public static readonly float DefaultMaxValue = 1; | ||
public float MinValue { get; set; } = DefaultMinValue; | ||
public float MaxValue { get; set; } = DefaultMaxValue; | ||
|
||
public int Digits { get; set; } = 2; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,95 @@ | ||
// ReSharper disable once CheckNamespace | ||
using FluentAssertions; | ||
using System.Globalization; | ||
|
||
namespace Nox.Types.Tests.Types; | ||
|
||
public class PercentageTests | ||
{ | ||
[Fact] | ||
public void When_Create_Should() | ||
public void Percentage_Constructor_ReturnsSameValue() | ||
{ | ||
var testPercentage = 0.5f; | ||
|
||
var number = Percentage.From(testPercentage); | ||
|
||
number.Value.Should().Be(testPercentage); | ||
} | ||
|
||
[Fact] | ||
public void Percentage_Constructor_ThrowsException_WhenValueExceedsMaxAllowed() | ||
{ | ||
var testPercentage = 3.2f; | ||
|
||
var action = () => Percentage.From(testPercentage); | ||
|
||
action.Should().Throw<TypeValidationException>() | ||
.And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", "Could not create a Nox Percentage type a value 3.2 is greater than than the maximum specified value of 1") }); | ||
|
||
} | ||
|
||
[Fact] | ||
public void Percentage_Constructor_ThrowsException_WhenValueIsLessThanMinAllowed() | ||
{ | ||
var testPercentage = -0.3f; | ||
|
||
var action = () => Percentage.From(testPercentage); | ||
|
||
action.Should().Throw<TypeValidationException>() | ||
.And.Errors.Should().BeEquivalentTo(new[] { new ValidationFailure("Value", "Could not create a Nox Percentage type as value -0.3 is less than than the minimum specified value of 0") }); | ||
} | ||
|
||
[Fact] | ||
public void Percentage_Constructor_RoundsFloatValues_WhenConstructedWithFloatInput() | ||
{ | ||
var testPercentage = 0.4f; | ||
|
||
var percentage = Percentage.From(testPercentage); | ||
|
||
percentage.Value.Should().Be(0.4f); | ||
} | ||
|
||
[Fact] | ||
public void Percentage_ToString_Returns_Value() | ||
{ | ||
void Test() | ||
{ | ||
var pecentageValue = 0.45f; | ||
|
||
var percentage = Percentage.From(pecentageValue); | ||
|
||
var percentageAsString = percentage.ToString(); | ||
|
||
Assert.Equal("45%", percentageAsString); | ||
} | ||
|
||
TestUtility.RunInInvariantCulture(Test); | ||
} | ||
|
||
[Theory] | ||
[InlineData("en-US")] | ||
[InlineData("pt-PT")] | ||
public void Percentage_ValueInFloat_ToString_IsCultureIndepdendent(string culture) | ||
{ | ||
void Test() | ||
{ | ||
var percentage = Percentage.From(0.25f); | ||
percentage.ToString().Should().Be("25%"); | ||
} | ||
|
||
TestUtility.RunInCulture(Test, culture); | ||
} | ||
|
||
[Theory] | ||
[InlineData("en-US", "0.43%")] | ||
[InlineData("pt-PT", "0,43%")] | ||
public void Percentage_ValueInFloat_ToString_IsCultureDependent(string culture, string expected) | ||
{ | ||
void Test() | ||
{ | ||
var percentage = Percentage.From(0.43f); | ||
percentage.ToString(new CultureInfo(culture)).Should().Be(expected); | ||
} | ||
|
||
TestUtility.RunInCulture(Test, culture); | ||
} | ||
} |