From 4e67f09488aede6959c8c526d2dc9b820396db22 Mon Sep 17 00:00:00 2001 From: PrPleGoo Date: Thu, 9 Apr 2020 20:40:59 +0200 Subject: [PATCH] Fixed comments ReagentUnit now implements IComparable and IEquateable. ReagentUnit now uses double internally. Added multiplication without shifting for ints. InvariantCulture for some string things. Added units tests for Equals and CompareTo. Added unit tests to Solution that deals with nasty fractionals. --- Content.Shared/Chemistry/ReagentUnit.cs | 55 ++++++++++++++++--- .../Shared/Chemistry/ReagentUnit_Tests.cs | 32 +++++++++++ .../Shared/Chemistry/Solution_Tests.cs | 35 ++++++++++++ 3 files changed, 115 insertions(+), 7 deletions(-) diff --git a/Content.Shared/Chemistry/ReagentUnit.cs b/Content.Shared/Chemistry/ReagentUnit.cs index 184f7aa5d7..63385fe297 100644 --- a/Content.Shared/Chemistry/ReagentUnit.cs +++ b/Content.Shared/Chemistry/ReagentUnit.cs @@ -1,21 +1,23 @@ using Robust.Shared.Interfaces.Serialization; using Robust.Shared.Serialization; using System; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Linq; namespace Content.Shared.Chemistry { [Serializable] - public struct ReagentUnit : ISelfSerialize + public struct ReagentUnit : ISelfSerialize, IComparable, IEquatable { private int _value; private static readonly int Shift = 2; public static ReagentUnit MaxValue => new ReagentUnit(int.MaxValue); - private decimal ShiftDown() + private double ShiftDown() { - return _value / (decimal)Math.Pow(10, Shift); + return _value / Math.Pow(10, Shift); } private ReagentUnit(int value) @@ -55,7 +57,7 @@ namespace Content.Shared.Chemistry private static float FloatFromString(string value) { - return float.Parse(value); + return float.Parse(value, CultureInfo.InvariantCulture); } public static ReagentUnit operator +(ReagentUnit a) => a; @@ -82,11 +84,22 @@ namespace Content.Shared.Chemistry } public static ReagentUnit operator *(ReagentUnit a, decimal b) + { + var aD = (decimal) a.ShiftDown(); + return New(aD * b); + } + + public static ReagentUnit operator *(ReagentUnit a, double b) { var aD = a.ShiftDown(); return New(aD * b); } + public static ReagentUnit operator *(ReagentUnit a, int b) + { + return new ReagentUnit(a._value * b); + } + public static ReagentUnit operator /(ReagentUnit a, ReagentUnit b) { if (b._value == 0) @@ -138,14 +151,17 @@ namespace Content.Shared.Chemistry return a._value > b._value; } - public override string ToString() => $"{ShiftDown()}"; - public float Float() { return (float) ShiftDown(); } public decimal Decimal() + { + return (decimal) ShiftDown(); + } + + public double Double() { return ShiftDown(); } @@ -157,7 +173,12 @@ namespace Content.Shared.Chemistry public static ReagentUnit Min(params ReagentUnit[] reagentUnits) { - return reagentUnits.OrderBy(x => x._value).First(); + return reagentUnits.Min(); + } + + public static ReagentUnit Min(ReagentUnit a, ReagentUnit b) + { + return a < b ? a : b; } public override bool Equals(object obj) @@ -176,9 +197,29 @@ namespace Content.Shared.Chemistry _value = FromFloat(FloatFromString(value)); } + public override string ToString() => $"{ShiftDown().ToString(CultureInfo.InvariantCulture)}"; + public string Serialize() { return ToString(); } + + public bool Equals([AllowNull] ReagentUnit other) + { + return _value == other._value; + } + + public int CompareTo([AllowNull] ReagentUnit other) + { + if(other._value > _value) + { + return -1; + } + if(other._value < _value) + { + return 1; + } + return 0; + } } } diff --git a/Content.Tests/Shared/Chemistry/ReagentUnit_Tests.cs b/Content.Tests/Shared/Chemistry/ReagentUnit_Tests.cs index 1cae6e1db2..46d391459b 100644 --- a/Content.Tests/Shared/Chemistry/ReagentUnit_Tests.cs +++ b/Content.Tests/Shared/Chemistry/ReagentUnit_Tests.cs @@ -118,5 +118,37 @@ namespace Content.Tests.Shared.Chemistry var result = (int) Math.Round(a * (float) Math.Pow(10, 2)); Assert.AreEqual(expected, result); } + + [Test] + public void ReagentUnitMin() + { + var unorderedList = new[] + { + ReagentUnit.New(5), + ReagentUnit.New(3), + ReagentUnit.New(1), + ReagentUnit.New(2), + ReagentUnit.New(4), + }; + var min = ReagentUnit.Min(unorderedList); + Assert.AreEqual(ReagentUnit.New(1), min); + } + + [Test] + [TestCase(1, 0, false)] + [TestCase(0, 0, true)] + [TestCase(-1, 0, false)] + [TestCase(null, 0, true)] + [TestCase(1, 1, true)] + [TestCase(0, 1, false)] + [TestCase(-1, 1, false)] + [TestCase(null, 1, false)] + public void ReagentUnitEquals(int a, int b, bool expected) + { + var parameter = ReagentUnit.New(a); + var comparison = ReagentUnit.New(b); + Assert.AreEqual(comparison.Equals(parameter), parameter.Equals(comparison)); + Assert.AreEqual(expected, comparison.Equals(parameter)); + } } } diff --git a/Content.Tests/Shared/Chemistry/Solution_Tests.cs b/Content.Tests/Shared/Chemistry/Solution_Tests.cs index e3024d3a07..2714ce2252 100644 --- a/Content.Tests/Shared/Chemistry/Solution_Tests.cs +++ b/Content.Tests/Shared/Chemistry/Solution_Tests.cs @@ -203,6 +203,41 @@ namespace Content.Tests.Shared.Chemistry Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(750)); } + [Test] + public void SplitSolutionFractional() + { + var solution = new Solution(); + solution.AddReagent("water", ReagentUnit.New(1)); + solution.AddReagent("fire", ReagentUnit.New(2)); + + var splitSolution = solution.SplitSolution(ReagentUnit.New(1)); + + Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f)); + Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2)); + + Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f)); + Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f)); + Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(1)); + } + + [Test] + [TestCase(0.03f, 0.01f, 0.02f)] + [TestCase(0.03f, 0.02f, 0.01f)] + public void SplitSolutionTinyFractionalBigSmall(float initial, float reduce, float remainder) + { + var solution = new Solution(); + solution.AddReagent("water", ReagentUnit.New(initial)); + + var splitSolution = solution.SplitSolution(ReagentUnit.New(reduce)); + + Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(remainder)); + Assert.That(solution.TotalVolume.Float(), Is.EqualTo(remainder)); + + Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(reduce)); + Assert.That(splitSolution.TotalVolume.Float(), Is.EqualTo(reduce)); + } + [Test] public void SplitSolutionMoreThanTotalRemovesAll() {