diff --git a/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs new file mode 100644 index 0000000000..7229d49c7f --- /dev/null +++ b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs @@ -0,0 +1,195 @@ +using System.Threading.Tasks; +using Content.Server.Chemistry.EntitySystems; +using Content.Shared.Chemistry.Components; +using Content.Shared.FixedPoint; +using NUnit.Framework; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; + +namespace Content.IntegrationTests.Tests.Chemistry; + + +// We are adding two non-reactive solutions in these tests +// To ensure volume(A) + volume(B) = volume(A+B) +// reactions can change this assumption +[TestFixture] +[TestOf(typeof(SolutionContainerSystem))] +public sealed class SolutionSystemTests : ContentIntegrationTest +{ + private const string Prototypes = @" +- type: entity + id: SolutionTarget + components: + - type: SolutionContainerManager + solutions: + beaker: + maxVol: 50 +"; + + [Test] + public async Task TryAddTwoNonReactiveReagent() + { + var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes }; + var server = StartServer(options); + + await server.WaitIdleAsync(); + + var entityManager = server.ResolveDependency(); + var mapManager = server.ResolveDependency(); + var coordinates = GetMainEntityCoordinates(mapManager); + + EntityUid beaker; + + server.Assert(() => + { + var oilQuantity = FixedPoint2.New(15); + var waterQuantity = FixedPoint2.New(10); + + var oilAdded = new Solution("Oil", oilQuantity); + var originalWater = new Solution("Water", waterQuantity); + + beaker = entityManager.SpawnEntity("SolutionTarget", coordinates); + Assert.That(EntitySystem.Get() + .TryGetSolution(beaker, "beaker", out var solution)); + + solution.AddSolution(originalWater); + Assert.That(EntitySystem.Get() + .TryAddSolution(beaker, solution, oilAdded)); + + solution.ContainsReagent("Water", out var water); + solution.ContainsReagent("Oil", out var oil); + Assert.That(water, Is.EqualTo(waterQuantity)); + Assert.That(oil, Is.EqualTo(oilQuantity)); + }); + + await server.WaitIdleAsync(); + } + + // This test mimics current behavior + // i.e. if adding too much `TryAddSolution` adding will fail + [Test] + public async Task TryAddTooMuchNonReactiveReagent() + { + var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes }; + var server = StartServer(options); + + await server.WaitIdleAsync(); + + var entityManager = server.ResolveDependency(); + var mapManager = server.ResolveDependency(); + var coordinates = GetMainEntityCoordinates(mapManager); + + EntityUid beaker; + + server.Assert(() => + { + var oilQuantity = FixedPoint2.New(1500); + var waterQuantity = FixedPoint2.New(10); + + var oilAdded = new Solution("Oil", oilQuantity); + var originalWater = new Solution("Water", waterQuantity); + + beaker = entityManager.SpawnEntity("SolutionTarget", coordinates); + Assert.That(EntitySystem.Get() + .TryGetSolution(beaker, "beaker", out var solution)); + + solution.AddSolution(originalWater); + Assert.That(EntitySystem.Get() + .TryAddSolution(beaker, solution, oilAdded), Is.False); + + solution.ContainsReagent("Water", out var water); + solution.ContainsReagent("Oil", out var oil); + Assert.That(water, Is.EqualTo(waterQuantity)); + Assert.That(oil, Is.EqualTo(FixedPoint2.Zero)); + }); + + await server.WaitIdleAsync(); + } + + // Unlike TryAddSolution this adds and two solution without then splits leaving only threshold in original + [Test] + public async Task TryMixAndOverflowTooMuchReagent() + { + var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes }; + var server = StartServer(options); + + await server.WaitIdleAsync(); + + var entityManager = server.ResolveDependency(); + var mapManager = server.ResolveDependency(); + var coordinates = GetMainEntityCoordinates(mapManager); + + EntityUid beaker; + + server.Assert(() => + { + int ratio = 9; + int threshold = 20; + var waterQuantity = FixedPoint2.New(10); + var oilQuantity = FixedPoint2.New(ratio * waterQuantity.Int()); + + var oilAdded = new Solution("Oil", oilQuantity); + var originalWater = new Solution("Water", waterQuantity); + + beaker = entityManager.SpawnEntity("SolutionTarget", coordinates); + Assert.That(EntitySystem.Get() + .TryGetSolution(beaker, "beaker", out var solution)); + + solution.AddSolution(originalWater); + Assert.That(EntitySystem.Get() + .TryMixAndOverflow(beaker, solution, oilAdded, threshold, out var overflowingSolution)); + + Assert.That(solution.CurrentVolume, Is.EqualTo(FixedPoint2.New(threshold))); + solution.ContainsReagent("Water", out var waterMix); + solution.ContainsReagent("Oil", out var oilMix); + Assert.That(waterMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1)))); + Assert.That(oilMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1) * ratio))); + + Assert.That(overflowingSolution.CurrentVolume, Is.EqualTo(FixedPoint2.New(80))); + overflowingSolution.ContainsReagent("Water", out var waterOverflow); + overflowingSolution.ContainsReagent("Oil", out var oilOverFlow); + Assert.That(waterOverflow, Is.EqualTo(waterQuantity - waterMix)); + Assert.That(oilOverFlow, Is.EqualTo(oilQuantity - oilMix)); + }); + + await server.WaitIdleAsync(); + } + + // TryMixAndOverflow will fail if Threshold larger than MaxVolume + [Test] + public async Task TryMixAndOverflowTooBigOverflow() + { + var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes }; + var server = StartServer(options); + + await server.WaitIdleAsync(); + + var entityManager = server.ResolveDependency(); + var mapManager = server.ResolveDependency(); + var coordinates = GetMainEntityCoordinates(mapManager); + + EntityUid beaker; + + server.Assert(() => + { + int ratio = 9; + int threshold = 60; + var waterQuantity = FixedPoint2.New(10); + var oilQuantity = FixedPoint2.New(ratio * waterQuantity.Int()); + + var oilAdded = new Solution("Oil", oilQuantity); + var originalWater = new Solution("Water", waterQuantity); + + beaker = entityManager.SpawnEntity("SolutionTarget", coordinates); + Assert.That(EntitySystem.Get() + .TryGetSolution(beaker, "beaker", out var solution)); + + solution.AddSolution(originalWater); + Assert.That(EntitySystem.Get() + .TryMixAndOverflow(beaker, solution, oilAdded, threshold, out _), + Is.False); + }); + + await server.WaitIdleAsync(); + } +} diff --git a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.Capabilities.cs b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.Capabilities.cs index 04f6e9570c..5ce2b05b68 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.Capabilities.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.Capabilities.cs @@ -1,156 +1,153 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Content.Server.Chemistry.Components.SolutionManager; -using Content.Server.Database; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; -using Robust.Shared.GameObjects; -namespace Content.Server.Chemistry.EntitySystems +namespace Content.Server.Chemistry.EntitySystems; + +public sealed partial class SolutionContainerSystem { - public sealed partial class SolutionContainerSystem + public void Refill(EntityUid targetUid, Solution targetSolution, Solution addedSolution, + RefillableSolutionComponent? refillableSolution = null) { - public void Refill(EntityUid targetUid, Solution targetSolution, Solution addedSolution, - RefillableSolutionComponent? refillableSolution = null) - { - if (!Resolve(targetUid, ref refillableSolution, false)) - return; + if (!Resolve(targetUid, ref refillableSolution, false)) + return; - TryAddSolution(targetUid, targetSolution, addedSolution); + TryAddSolution(targetUid, targetSolution, addedSolution); + } + + public void Inject(EntityUid targetUid, Solution targetSolution, Solution addedSolution, + InjectableSolutionComponent? injectableSolution = null) + { + if (!Resolve(targetUid, ref injectableSolution, false)) + return; + + TryAddSolution(targetUid, targetSolution, addedSolution); + } + + public Solution Draw(EntityUid targetUid, Solution solution, FixedPoint2 amount, + DrawableSolutionComponent? drawableSolution = null) + { + if (!Resolve(targetUid, ref drawableSolution, false)) + return new Solution(); + + return SplitSolution(targetUid, solution, amount); + } + + public Solution Drain(EntityUid targetUid, Solution targetSolution, FixedPoint2 amount, + DrainableSolutionComponent? drainableSolution = null) + { + if (!Resolve(targetUid, ref drainableSolution, false)) + return new Solution(); + + return SplitSolution(targetUid, targetSolution, amount); + } + + public bool TryGetInjectableSolution(EntityUid targetUid, + [NotNullWhen(true)] out Solution? solution, + InjectableSolutionComponent? injectable = null, + SolutionContainerManagerComponent? manager = null + ) + { + if (!Resolve(targetUid, ref manager, ref injectable, false) + || !manager.Solutions.TryGetValue(injectable.Solution, out solution)) + { + solution = null; + return false; } - public void Inject(EntityUid targetUid, Solution targetSolution, Solution addedSolution, - InjectableSolutionComponent? injectableSolution = null) - { - if (!Resolve(targetUid, ref injectableSolution, false)) - return; + return true; + } - TryAddSolution(targetUid, targetSolution, addedSolution); + public bool TryGetRefillableSolution(EntityUid targetUid, + [NotNullWhen(true)] out Solution? solution, + SolutionContainerManagerComponent? solutionManager = null, + RefillableSolutionComponent? refillable = null) + { + if (!Resolve(targetUid, ref solutionManager, ref refillable, false) + || !solutionManager.Solutions.TryGetValue(refillable.Solution, out var refillableSolution)) + { + solution = null; + return false; } - public Solution Draw(EntityUid targetUid, Solution solution, FixedPoint2 amount, - DrawableSolutionComponent? drawableSolution = null) - { - if (!Resolve(targetUid, ref drawableSolution, false)) - return new Solution(); + solution = refillableSolution; + return true; + } - return SplitSolution(targetUid, solution, amount); + public bool TryGetDrainableSolution(EntityUid uid, + [NotNullWhen(true)] out Solution? solution, + DrainableSolutionComponent? drainable = null, + SolutionContainerManagerComponent? manager = null) + { + if (!Resolve(uid, ref drainable, ref manager, false) + || !manager.Solutions.TryGetValue(drainable.Solution, out solution)) + { + solution = null; + return false; } - public Solution Drain(EntityUid targetUid, Solution targetSolution, FixedPoint2 amount, - DrainableSolutionComponent? drainableSolution = null) - { - if (!Resolve(targetUid, ref drainableSolution, false)) - return new Solution(); + return true; + } - return SplitSolution(targetUid, targetSolution, amount); + public bool TryGetDrawableSolution(EntityUid uid, + [NotNullWhen(true)] out Solution? solution, + DrawableSolutionComponent? drawable = null, + SolutionContainerManagerComponent? manager = null) + { + if (!Resolve(uid, ref drawable, ref manager, false) + || !manager.Solutions.TryGetValue(drawable.Solution, out solution)) + { + solution = null; + return false; } - public bool TryGetInjectableSolution(EntityUid targetUid, - [NotNullWhen(true)] out Solution? solution, - InjectableSolutionComponent? injectable = null, - SolutionContainerManagerComponent? manager = null - ) + return true; + } + + public FixedPoint2 DrainAvailable(EntityUid uid) + { + return !TryGetDrainableSolution(uid, out var solution) + ? FixedPoint2.Zero + : solution.CurrentVolume; + } + + public bool TryGetFitsInDispenser(EntityUid owner, + [NotNullWhen(true)] out Solution? solution, + FitsInDispenserComponent? dispenserFits = null, + SolutionContainerManagerComponent? solutionManager = null) + { + if (!Resolve(owner, ref dispenserFits, ref solutionManager, false) + || !solutionManager.Solutions.TryGetValue(dispenserFits.Solution, out solution)) { - if (!Resolve(targetUid, ref manager, ref injectable, false) - || !manager.Solutions.TryGetValue(injectable.Solution, out solution)) + solution = null; + return false; + } + + return true; + } + + public static string ToPrettyString(Solution solution) + { + var sb = new StringBuilder(); + sb.Append("["); + var first = true; + foreach (var (id, quantity) in solution.Contents) + { + if (first) { - solution = null; - return false; + first = false; + } + else + { + sb.Append(", "); } - return true; + sb.AppendFormat("{0}: {1}u", id, quantity); } - public bool TryGetRefillableSolution(EntityUid targetUid, - [NotNullWhen(true)] out Solution? solution, - SolutionContainerManagerComponent? solutionManager = null, - RefillableSolutionComponent? refillable = null) - { - if (!Resolve(targetUid, ref solutionManager, ref refillable, false) - || !solutionManager.Solutions.TryGetValue(refillable.Solution, out var refillableSolution)) - { - solution = null; - return false; - } - - solution = refillableSolution; - return true; - } - - public bool TryGetDrainableSolution(EntityUid uid, - [NotNullWhen(true)] out Solution? solution, - DrainableSolutionComponent? drainable = null, - SolutionContainerManagerComponent? manager = null) - { - if (!Resolve(uid, ref drainable, ref manager, false) - || !manager.Solutions.TryGetValue(drainable.Solution, out solution)) - { - solution = null; - return false; - } - - return true; - } - - public bool TryGetDrawableSolution(EntityUid uid, - [NotNullWhen(true)] out Solution? solution, - DrawableSolutionComponent? drawable = null, - SolutionContainerManagerComponent? manager = null) - { - if (!Resolve(uid, ref drawable, ref manager, false) - || !manager.Solutions.TryGetValue(drawable.Solution, out solution)) - { - solution = null; - return false; - } - - return true; - } - - public FixedPoint2 DrainAvailable(EntityUid uid) - { - return !TryGetDrainableSolution(uid, out var solution) - ? FixedPoint2.Zero - : solution.CurrentVolume; - } - - public bool TryGetFitsInDispenser(EntityUid owner, - [NotNullWhen(true)] out Solution? solution, - FitsInDispenserComponent? dispenserFits = null, - SolutionContainerManagerComponent? solutionManager = null) - { - if (!Resolve(owner, ref dispenserFits, ref solutionManager, false) - || !solutionManager.Solutions.TryGetValue(dispenserFits.Solution, out solution)) - { - solution = null; - return false; - } - - return true; - } - - public static string ToPrettyString(Solution solution) - { - var sb = new StringBuilder(); - sb.Append("["); - var first = true; - foreach (var (id, quantity) in solution.Contents) - { - if (first) - { - first = false; - } - else - { - sb.Append(", "); - } - sb.AppendFormat("{0}: {1}u", id, quantity); - - } - sb.Append(']'); - return sb.ToString(); - } + sb.Append(']'); + return sb.ToString(); } } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs index d0b96e947d..cd2ab59e8f 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionContainerSystem.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Content.Server.Chemistry.Components.SolutionManager; -using Content.Server.Fluids.Components; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reaction; @@ -10,385 +7,384 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Examine; using Content.Shared.FixedPoint; using JetBrains.Annotations; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; -using Robust.Shared.Log; using Robust.Shared.Prototypes; using Robust.Shared.Utility; -namespace Content.Server.Chemistry.EntitySystems +namespace Content.Server.Chemistry.EntitySystems; + +/// +/// This event alerts system that the solution was changed +/// +public sealed class SolutionChangedEvent : EntityEventArgs { - /// - /// This event alerts system that the solution was changed - /// - public sealed class SolutionChangedEvent : EntityEventArgs +} + +/// +/// Part of Chemistry system deal with SolutionContainers +/// +[UsedImplicitly] +public sealed partial class SolutionContainerSystem : EntitySystem +{ + [Dependency] + private readonly SharedChemicalReactionSystem _chemistrySystem = default!; + + [Dependency] + private readonly IPrototypeManager _prototypeManager = default!; + + public override void Initialize() { + base.Initialize(); + + SubscribeLocalEvent(InitSolution); + SubscribeLocalEvent(OnExamineSolution); } - /// - /// Part of Chemistry system deal with SolutionContainers - /// - [UsedImplicitly] - public sealed partial class SolutionContainerSystem : EntitySystem + private void InitSolution(EntityUid uid, SolutionContainerManagerComponent component, ComponentInit args) { - [Dependency] - private readonly SharedChemicalReactionSystem _chemistrySystem = default!; - - [Dependency] - private readonly IPrototypeManager _prototypeManager = default!; - - public override void Initialize() + foreach (var keyValue in component.Solutions) { - base.Initialize(); - - SubscribeLocalEvent(InitSolution); - SubscribeLocalEvent(OnExamineSolution); - } - - private void InitSolution(EntityUid uid, SolutionContainerManagerComponent component, ComponentInit args) - { - foreach (var keyValue in component.Solutions) + var solutionHolder = keyValue.Value; + if (solutionHolder.MaxVolume == FixedPoint2.Zero) { - var solutionHolder = keyValue.Value; - if (solutionHolder.MaxVolume == FixedPoint2.Zero) - { - solutionHolder.MaxVolume = solutionHolder.TotalVolume > solutionHolder.InitialMaxVolume - ? solutionHolder.TotalVolume - : solutionHolder.InitialMaxVolume; - } - - UpdateAppearance(uid, solutionHolder); - } - } - - private void OnExamineSolution(EntityUid uid, ExaminableSolutionComponent examinableComponent, - ExaminedEvent args) - { - SolutionContainerManagerComponent? solutionsManager = null; - if (!Resolve(args.Examined, ref solutionsManager) - || !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solutionHolder)) - return; - - if (solutionHolder.Contents.Count == 0) - { - args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container")); - return; - } - - var primaryReagent = solutionHolder.GetPrimaryReagentId(); - - if (!_prototypeManager.TryIndex(primaryReagent, out ReagentPrototype? proto)) - { - Logger.Error( - $"{nameof(Solution)} could not find the prototype associated with {primaryReagent}."); - return; - } - - var colorHex = solutionHolder.Color - .ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable. - var messageString = "shared-solution-container-component-on-examine-main-text"; - - args.PushMarkup(Loc.GetString(messageString, - ("color", colorHex), - ("wordedAmount", Loc.GetString(solutionHolder.Contents.Count == 1 - ? "shared-solution-container-component-on-examine-worded-amount-one-reagent" - : "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")), - ("desc", Loc.GetString(proto.PhysicalDescription)))); - } - - private void UpdateAppearance(EntityUid uid, Solution solution, - AppearanceComponent? appearanceComponent = null) - { - if (!EntityManager.EntityExists(uid) - || !Resolve(uid, ref appearanceComponent, false)) - return; - - var filledVolumePercent = solution.CurrentVolume.Float() / solution.MaxVolume.Float(); - appearanceComponent.SetData(SolutionContainerVisuals.VisualState, new SolutionContainerVisualState(solution.Color, filledVolumePercent)); - } - - /// - /// Removes part of the solution in the container. - /// - /// - /// - /// the volume of solution to remove. - /// The solution that was removed. - public Solution SplitSolution(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity) - { - var splitSol = solutionHolder.SplitSolution(quantity); - UpdateChemicals(targetUid, solutionHolder); - return splitSol; - } - - private void UpdateChemicals(EntityUid uid, Solution solutionHolder, bool needsReactionsProcessing = false) - { - // Process reactions - if (needsReactionsProcessing && solutionHolder.CanReact) - { - _chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume); + solutionHolder.MaxVolume = solutionHolder.TotalVolume > solutionHolder.InitialMaxVolume + ? solutionHolder.TotalVolume + : solutionHolder.InitialMaxVolume; } UpdateAppearance(uid, solutionHolder); - RaiseLocalEvent(uid, new SolutionChangedEvent()); } - - public void RemoveAllSolution(EntityUid uid, Solution solutionHolder) - { - if (solutionHolder.CurrentVolume == 0) - return; - - solutionHolder.RemoveAllSolution(); - UpdateChemicals(uid, solutionHolder); - } - - public void RemoveAllSolution(EntityUid uid, SolutionContainerManagerComponent? solutionContainerManager = null) - { - if (!Resolve(uid, ref solutionContainerManager)) - return; - - foreach (var solution in solutionContainerManager.Solutions.Values) - { - RemoveAllSolution(uid, solution); - } - } - - /// - /// Sets the capacity (maximum volume) of a solution to a new value. - /// - /// The entity containing the solution. - /// The solution to set the capacity of. - /// The value to set the capacity of the solution to. - public void SetCapacity(EntityUid targetUid, Solution targetSolution, FixedPoint2 capacity) - { - if (targetSolution.MaxVolume == capacity) - return; - - targetSolution.MaxVolume = capacity; - if (capacity < targetSolution.CurrentVolume) - targetSolution.RemoveSolution(targetSolution.CurrentVolume - capacity); - - UpdateChemicals(targetUid, targetSolution); - } - - /// - /// Adds reagent of an Id to the container. - /// - /// - /// Container to which we are adding reagent - /// The Id of the reagent to add. - /// The amount of reagent to add. - /// The amount of reagent successfully added. - /// If all the reagent could be added. - public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string reagentId, FixedPoint2 quantity, - out FixedPoint2 acceptedQuantity, float? temperature = null) - { - acceptedQuantity = targetSolution.AvailableVolume > quantity ? quantity : targetSolution.AvailableVolume; - targetSolution.AddReagent(reagentId, acceptedQuantity, temperature); - - if (acceptedQuantity > 0) - UpdateChemicals(targetUid, targetSolution, true); - - return acceptedQuantity == quantity; - } - - /// - /// Removes reagent of an Id to the container. - /// - /// - /// Solution container from which we are removing reagent - /// The Id of the reagent to remove. - /// The amount of reagent to remove. - /// If the reagent to remove was found in the container. - public bool TryRemoveReagent(EntityUid targetUid, Solution? container, string reagentId, FixedPoint2 quantity) - { - if (container == null || !container.ContainsReagent(reagentId)) - return false; - - container.RemoveReagent(reagentId, quantity); - UpdateChemicals(targetUid, container); - return true; - } - - /// - /// Adds a solution to the container, if it can fully fit. - /// - /// entity holding targetSolution - /// entity holding targetSolution - /// solution being added - /// If the solution could be added. - public bool TryAddSolution(EntityUid targetUid, Solution? targetSolution, Solution addedSolution) - { - if (targetSolution == null - || !targetSolution.CanAddSolution(addedSolution) || addedSolution.TotalVolume == 0) - return false; - - targetSolution.AddSolution(addedSolution); - UpdateChemicals(targetUid, targetSolution, true); - return true; - } - - /// - /// Adds a solution to the container, overflowing the rest. - /// Unlike TryAddSolution it will ignore size limits. - /// - /// entity holding targetSolution - /// The container to which we try to add. - /// solution being added - /// After addition this much will be left in targetSolution - /// Solution that exceeded overflowThreshold - /// - public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution, - Solution addedSolution, - FixedPoint2 overflowThreshold, - [NotNullWhen(true)] out Solution? overflowingSolution) - { - if (addedSolution.TotalVolume == 0) - { - overflowingSolution = null; - return false; - } - - targetSolution.AddSolution(addedSolution); - UpdateChemicals(targetUid, targetSolution, true); - overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, - targetSolution.CurrentVolume - overflowThreshold)); - return true; - } - - public bool TryGetSolution(EntityUid uid, string name, - [NotNullWhen(true)] out Solution? solution, - SolutionContainerManagerComponent? solutionsMgr = null) - { - if (!Resolve(uid, ref solutionsMgr, false)) - { - solution = null; - return false; - } - - return solutionsMgr.Solutions.TryGetValue(name, out solution); - } - - /// - /// Will ensure a solution is added to given entity even if it's missing solutionContainerManager - /// - /// EntityUid to which to add solution - /// name for the solution - /// solution components used in resolves - /// solution - public Solution EnsureSolution(EntityUid uid, string name, - SolutionContainerManagerComponent? solutionsMgr = null) - { - if (!Resolve(uid, ref solutionsMgr, false)) - { - solutionsMgr = EntityManager.EnsureComponent(uid); - } - - if (!solutionsMgr.Solutions.ContainsKey(name)) - { - var newSolution = new Solution(); - solutionsMgr.Solutions.Add(name, newSolution); - } - - return solutionsMgr.Solutions[name]; - } - - public string[] RemoveEachReagent(EntityUid uid, Solution solution, FixedPoint2 quantity) - { - var removedReagent = new string[solution.Contents.Count]; - if (quantity <= 0) - return Array.Empty(); - - var pos = 0; - for (var i = 0; i < solution.Contents.Count; i++) - { - var (reagentId, curQuantity) = solution.Contents[i]; - removedReagent[pos++] = reagentId; - if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype? proto)) - proto = new ReagentPrototype(); - - var newQuantity = curQuantity - quantity; - if (newQuantity <= 0) - { - solution.Contents.RemoveSwap(i); - solution.TotalVolume -= curQuantity; - } - else - { - solution.Contents[i] = new Solution.ReagentQuantity(reagentId, newQuantity); - solution.TotalVolume -= quantity; - } - } - - UpdateChemicals(uid, solution); - return removedReagent; - } - - public FixedPoint2 GetReagentQuantity(EntityUid owner, string reagentId) - { - var reagentQuantity = FixedPoint2.New(0); - if (EntityManager.EntityExists(owner) - && EntityManager.TryGetComponent(owner, out SolutionContainerManagerComponent? managerComponent)) - { - foreach (var solution in managerComponent.Solutions.Values) - { - reagentQuantity += solution.GetReagentQuantity(reagentId); - } - } - - return reagentQuantity; - } - - - // Thermal energy and temperature management. - #region Thermal Energy and Temperature - - /// - /// Sets the temperature of a solution to a new value and then checks for reaction processing. - /// - /// The entity in which the solution is located. - /// The solution to set the temperature of. - /// The new value to set the temperature to. - public void SetTemperature(EntityUid owner, Solution solution, float temperature) - { - if (temperature == solution.Temperature) - return; - - solution.Temperature = temperature; - UpdateChemicals(owner, solution, true); - } - - /// - /// Sets the thermal energy of a solution to a new value and then checks for reaction processing. - /// - /// The entity in which the solution is located. - /// The solution to set the thermal energy of. - /// The new value to set the thermal energy to. - public void SetThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy) - { - if (thermalEnergy == solution.ThermalEnergy) - return; - - solution.ThermalEnergy = thermalEnergy; - UpdateChemicals(owner, solution, true); - } - - /// - /// Adds some thermal energy to a solution and then checks for reaction processing. - /// - /// The entity in which the solution is located. - /// The solution to set the thermal energy of. - /// The new value to set the thermal energy to. - public void AddThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy) - { - if (thermalEnergy == 0.0f) - return; - - solution.ThermalEnergy += thermalEnergy; - UpdateChemicals(owner, solution, true); - } - - #endregion Thermal Energy and Temperature } + + private void OnExamineSolution(EntityUid uid, ExaminableSolutionComponent examinableComponent, + ExaminedEvent args) + { + SolutionContainerManagerComponent? solutionsManager = null; + if (!Resolve(args.Examined, ref solutionsManager) + || !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solutionHolder)) + return; + + if (solutionHolder.Contents.Count == 0) + { + args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container")); + return; + } + + var primaryReagent = solutionHolder.GetPrimaryReagentId(); + + if (!_prototypeManager.TryIndex(primaryReagent, out ReagentPrototype? proto)) + { + Logger.Error( + $"{nameof(Solution)} could not find the prototype associated with {primaryReagent}."); + return; + } + + var colorHex = solutionHolder.Color + .ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable. + var messageString = "shared-solution-container-component-on-examine-main-text"; + + args.PushMarkup(Loc.GetString(messageString, + ("color", colorHex), + ("wordedAmount", Loc.GetString(solutionHolder.Contents.Count == 1 + ? "shared-solution-container-component-on-examine-worded-amount-one-reagent" + : "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")), + ("desc", Loc.GetString(proto.PhysicalDescription)))); + } + + private void UpdateAppearance(EntityUid uid, Solution solution, + AppearanceComponent? appearanceComponent = null) + { + if (!EntityManager.EntityExists(uid) + || !Resolve(uid, ref appearanceComponent, false)) + return; + + var filledVolumePercent = solution.CurrentVolume.Float() / solution.MaxVolume.Float(); + appearanceComponent.SetData(SolutionContainerVisuals.VisualState, + new SolutionContainerVisualState(solution.Color, filledVolumePercent)); + } + + /// + /// Removes part of the solution in the container. + /// + /// + /// + /// the volume of solution to remove. + /// The solution that was removed. + public Solution SplitSolution(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity) + { + var splitSol = solutionHolder.SplitSolution(quantity); + UpdateChemicals(targetUid, solutionHolder); + return splitSol; + } + + private void UpdateChemicals(EntityUid uid, Solution solutionHolder, bool needsReactionsProcessing = false) + { + // Process reactions + if (needsReactionsProcessing && solutionHolder.CanReact) + { + _chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume); + } + + UpdateAppearance(uid, solutionHolder); + RaiseLocalEvent(uid, new SolutionChangedEvent()); + } + + public void RemoveAllSolution(EntityUid uid, Solution solutionHolder) + { + if (solutionHolder.CurrentVolume == 0) + return; + + solutionHolder.RemoveAllSolution(); + UpdateChemicals(uid, solutionHolder); + } + + public void RemoveAllSolution(EntityUid uid, SolutionContainerManagerComponent? solutionContainerManager = null) + { + if (!Resolve(uid, ref solutionContainerManager)) + return; + + foreach (var solution in solutionContainerManager.Solutions.Values) + { + RemoveAllSolution(uid, solution); + } + } + + /// + /// Sets the capacity (maximum volume) of a solution to a new value. + /// + /// The entity containing the solution. + /// The solution to set the capacity of. + /// The value to set the capacity of the solution to. + public void SetCapacity(EntityUid targetUid, Solution targetSolution, FixedPoint2 capacity) + { + if (targetSolution.MaxVolume == capacity) + return; + + targetSolution.MaxVolume = capacity; + if (capacity < targetSolution.CurrentVolume) + targetSolution.RemoveSolution(targetSolution.CurrentVolume - capacity); + + UpdateChemicals(targetUid, targetSolution); + } + + /// + /// Adds reagent of an Id to the container. + /// + /// + /// Container to which we are adding reagent + /// The Id of the reagent to add. + /// The amount of reagent to add. + /// The amount of reagent successfully added. + /// If all the reagent could be added. + public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string reagentId, FixedPoint2 quantity, + out FixedPoint2 acceptedQuantity, float? temperature = null) + { + acceptedQuantity = targetSolution.AvailableVolume > quantity ? quantity : targetSolution.AvailableVolume; + targetSolution.AddReagent(reagentId, acceptedQuantity, temperature); + + if (acceptedQuantity > 0) + UpdateChemicals(targetUid, targetSolution, true); + + return acceptedQuantity == quantity; + } + + /// + /// Removes reagent of an Id to the container. + /// + /// + /// Solution container from which we are removing reagent + /// The Id of the reagent to remove. + /// The amount of reagent to remove. + /// If the reagent to remove was found in the container. + public bool TryRemoveReagent(EntityUid targetUid, Solution? container, string reagentId, FixedPoint2 quantity) + { + if (container == null || !container.ContainsReagent(reagentId)) + return false; + + container.RemoveReagent(reagentId, quantity); + UpdateChemicals(targetUid, container); + return true; + } + + /// + /// Adds a solution to the container, if it can fully fit. + /// + /// entity holding targetSolution + /// entity holding targetSolution + /// solution being added + /// If the solution could be added. + public bool TryAddSolution(EntityUid targetUid, Solution? targetSolution, Solution addedSolution) + { + if (targetSolution == null + || !targetSolution.CanAddSolution(addedSolution) || addedSolution.TotalVolume == 0) + return false; + + targetSolution.AddSolution(addedSolution); + UpdateChemicals(targetUid, targetSolution, true); + return true; + } + + /// + /// Adds a solution to the container, overflowing the rest. + /// It will + /// Unlike it will ignore size limits. + /// + /// entity holding targetSolution + /// The container to which we try to add. + /// solution being added + /// After addition this much will be left in targetSolution. Should be less + /// than targetSolution.TotalVolume + /// Solution that exceeded overflowThreshold + /// + public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution, + Solution addedSolution, + FixedPoint2 overflowThreshold, + [NotNullWhen(true)] out Solution? overflowingSolution) + { + if (addedSolution.TotalVolume == 0 || overflowThreshold > targetSolution.MaxVolume) + { + overflowingSolution = null; + return false; + } + + targetSolution.AddSolution(addedSolution); + UpdateChemicals(targetUid, targetSolution, true); + overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, + targetSolution.CurrentVolume - overflowThreshold)); + return true; + } + + public bool TryGetSolution(EntityUid uid, string name, + [NotNullWhen(true)] out Solution? solution, + SolutionContainerManagerComponent? solutionsMgr = null) + { + if (!Resolve(uid, ref solutionsMgr, false)) + { + solution = null; + return false; + } + + return solutionsMgr.Solutions.TryGetValue(name, out solution); + } + + /// + /// Will ensure a solution is added to given entity even if it's missing solutionContainerManager + /// + /// EntityUid to which to add solution + /// name for the solution + /// solution components used in resolves + /// solution + public Solution EnsureSolution(EntityUid uid, string name, + SolutionContainerManagerComponent? solutionsMgr = null) + { + if (!Resolve(uid, ref solutionsMgr, false)) + { + solutionsMgr = EntityManager.EnsureComponent(uid); + } + + if (!solutionsMgr.Solutions.ContainsKey(name)) + { + var newSolution = new Solution(); + solutionsMgr.Solutions.Add(name, newSolution); + } + + return solutionsMgr.Solutions[name]; + } + + public string[] RemoveEachReagent(EntityUid uid, Solution solution, FixedPoint2 quantity) + { + var removedReagent = new string[solution.Contents.Count]; + if (quantity <= 0) + return Array.Empty(); + + var pos = 0; + for (var i = 0; i < solution.Contents.Count; i++) + { + var (reagentId, curQuantity) = solution.Contents[i]; + removedReagent[pos++] = reagentId; + if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype? proto)) + proto = new ReagentPrototype(); + + var newQuantity = curQuantity - quantity; + if (newQuantity <= 0) + { + solution.Contents.RemoveSwap(i); + solution.TotalVolume -= curQuantity; + } + else + { + solution.Contents[i] = new Solution.ReagentQuantity(reagentId, newQuantity); + solution.TotalVolume -= quantity; + } + } + + UpdateChemicals(uid, solution); + return removedReagent; + } + + public FixedPoint2 GetReagentQuantity(EntityUid owner, string reagentId) + { + var reagentQuantity = FixedPoint2.New(0); + if (EntityManager.EntityExists(owner) + && EntityManager.TryGetComponent(owner, out SolutionContainerManagerComponent? managerComponent)) + { + foreach (var solution in managerComponent.Solutions.Values) + { + reagentQuantity += solution.GetReagentQuantity(reagentId); + } + } + + return reagentQuantity; + } + + + // Thermal energy and temperature management. + + #region Thermal Energy and Temperature + + /// + /// Sets the temperature of a solution to a new value and then checks for reaction processing. + /// + /// The entity in which the solution is located. + /// The solution to set the temperature of. + /// The new value to set the temperature to. + public void SetTemperature(EntityUid owner, Solution solution, float temperature) + { + if (temperature == solution.Temperature) + return; + + solution.Temperature = temperature; + UpdateChemicals(owner, solution, true); + } + + /// + /// Sets the thermal energy of a solution to a new value and then checks for reaction processing. + /// + /// The entity in which the solution is located. + /// The solution to set the thermal energy of. + /// The new value to set the thermal energy to. + public void SetThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy) + { + if (thermalEnergy == solution.ThermalEnergy) + return; + + solution.ThermalEnergy = thermalEnergy; + UpdateChemicals(owner, solution, true); + } + + /// + /// Adds some thermal energy to a solution and then checks for reaction processing. + /// + /// The entity in which the solution is located. + /// The solution to set the thermal energy of. + /// The new value to set the thermal energy to. + public void AddThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy) + { + if (thermalEnergy == 0.0f) + return; + + solution.ThermalEnergy += thermalEnergy; + UpdateChemicals(owner, solution, true); + } + + #endregion Thermal Energy and Temperature } diff --git a/Content.Tests/Shared/Chemistry/Solution_Tests.cs b/Content.Tests/Shared/Chemistry/Solution_Tests.cs index 95ebba9a9c..f6008ed26e 100644 --- a/Content.Tests/Shared/Chemistry/Solution_Tests.cs +++ b/Content.Tests/Shared/Chemistry/Solution_Tests.cs @@ -1,484 +1,483 @@ using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.IoC; using Robust.Shared.Prototypes; using NUnit.Framework; -namespace Content.Tests.Shared.Chemistry +namespace Content.Tests.Shared.Chemistry; + +[TestFixture, Parallelizable, TestOf(typeof(Solution))] +public sealed class Solution_Tests : ContentUnitTest { - [TestFixture, Parallelizable, TestOf(typeof(Solution))] - public sealed class Solution_Tests : ContentUnitTest + [OneTimeSetUp] + public void Setup() { - [OneTimeSetUp] - public void Setup() - { - IoCManager.Resolve().Initialize(); - } - - [Test] - public void AddReagentAndGetSolution() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1000)); - var quantity = solution.GetReagentQuantity("water"); - - Assert.That(quantity.Int(), Is.EqualTo(1000)); - } - - [Test] - public void ConstructorAddReagent() - { - var solution = new Solution("water", FixedPoint2.New(1000)); - var quantity = solution.GetReagentQuantity("water"); - - Assert.That(quantity.Int(), Is.EqualTo(1000)); - } - - [Test] - public void NonExistingReagentReturnsZero() - { - var solution = new Solution(); - var quantity = solution.GetReagentQuantity("water"); - - Assert.That(quantity.Int(), Is.EqualTo(0)); - } - - [Test] - public void AddLessThanZeroReagentReturnsZero() - { - var solution = new Solution("water", FixedPoint2.New(-1000)); - var quantity = solution.GetReagentQuantity("water"); - - Assert.That(quantity.Int(), Is.EqualTo(0)); - } - - [Test] - public void AddingReagentsSumsProperly() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1000)); - solution.AddReagent("water", FixedPoint2.New(2000)); - var quantity = solution.GetReagentQuantity("water"); - - Assert.That(quantity.Int(), Is.EqualTo(3000)); - } - - [Test] - public void ReagentQuantitiesStayUnique() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1000)); - solution.AddReagent("fire", FixedPoint2.New(2000)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(1000)); - Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000)); - } - - [Test] - public void TotalVolumeIsCorrect() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1000)); - solution.AddReagent("fire", FixedPoint2.New(2000)); - - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(3000)); - } - - [Test] - public void CloningSolutionIsCorrect() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1000)); - solution.AddReagent("fire", FixedPoint2.New(2000)); - - var newSolution = solution.Clone(); - - Assert.That(newSolution.GetReagentQuantity("water").Int(), Is.EqualTo(1000)); - Assert.That(newSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000)); - Assert.That(newSolution.TotalVolume.Int(), Is.EqualTo(3000)); - } - - [Test] - public void RemoveSolutionRecalculatesProperly() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1000)); - solution.AddReagent("fire", FixedPoint2.New(2000)); - - solution.RemoveReagent("water", FixedPoint2.New(500)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500)); - Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2500)); - } - - [Test] - public void RemoveLessThanOneQuantityDoesNothing() - { - var solution = new Solution("water", FixedPoint2.New(100)); - - solution.RemoveReagent("water", FixedPoint2.New(-100)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(100)); - } - - [Test] - public void RemoveMoreThanTotalRemovesAllReagent() - { - var solution = new Solution("water", FixedPoint2.New(100)); - - solution.RemoveReagent("water", FixedPoint2.New(1000)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0)); - } - - [Test] - public void RemoveNonExistReagentDoesNothing() - { - var solution = new Solution("water", FixedPoint2.New(100)); - - solution.RemoveReagent("fire", FixedPoint2.New(1000)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(100)); - } - - [Test] - public void RemoveSolution() - { - var solution = new Solution("water", FixedPoint2.New(700)); - - solution.RemoveSolution(FixedPoint2.New(500)); - - //Check that edited solution is correct - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(200)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(200)); - } - - [Test] - public void RemoveSolutionMoreThanTotalRemovesAll() - { - var solution = new Solution("water", FixedPoint2.New(800)); - - solution.RemoveSolution(FixedPoint2.New(1000)); - - //Check that edited solution is correct - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0)); - } - - [Test] - public void RemoveSolutionRatioPreserved() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1000)); - solution.AddReagent("fire", FixedPoint2.New(2000)); - - solution.RemoveSolution(FixedPoint2.New(1500)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500)); - Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1000)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(1500)); - } - - [Test] - public void RemoveSolutionLessThanOneDoesNothing() - { - var solution = new Solution("water", FixedPoint2.New(800)); - - solution.RemoveSolution(FixedPoint2.New(-200)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(800)); - } - - [Test] - public void SplitSolution() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1000)); - solution.AddReagent("fire", FixedPoint2.New(2000)); - - var splitSolution = solution.SplitSolution(FixedPoint2.New(750)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(750)); - Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1500)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2250)); - - Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(250)); - Assert.That(splitSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(500)); - Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(750)); - } - - [Test] - public void SplitSolutionFractional() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1)); - solution.AddReagent("fire", FixedPoint2.New(2)); - - var splitSolution = solution.SplitSolution(FixedPoint2.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] - public void SplitSolutionFractionalOpposite() - { - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(1)); - solution.AddReagent("fire", FixedPoint2.New(2)); - - var splitSolution = solution.SplitSolution(FixedPoint2.New(2)); - - Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f)); - Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(1)); - - Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f)); - Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f)); - Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(2)); - } - - [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", FixedPoint2.New(initial)); - - var splitSolution = solution.SplitSolution(FixedPoint2.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] - [TestCase(2)] - [TestCase(10)] - [TestCase(100)] - [TestCase(1000)] - public void SplitRounding(int amount) - { - var solutionOne = new Solution(); - solutionOne.AddReagent("foo", FixedPoint2.New(amount)); - solutionOne.AddReagent("bar", FixedPoint2.New(amount)); - solutionOne.AddReagent("baz", FixedPoint2.New(amount)); - - var splitAmount = FixedPoint2.New(5); - var split = solutionOne.SplitSolution(splitAmount); - - Assert.That(split.TotalVolume, Is.EqualTo(splitAmount)); - } - - [Test] - public void SplitSolutionMoreThanTotalRemovesAll() - { - var solution = new Solution("water", FixedPoint2.New(800)); - - var splitSolution = solution.SplitSolution(FixedPoint2.New(1000)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0)); - - Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(800)); - Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(800)); - } - - [Test] - public void SplitSolutionLessThanOneDoesNothing() - { - var solution = new Solution("water", FixedPoint2.New(800)); - - var splitSolution = solution.SplitSolution(FixedPoint2.New(-200)); - - Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800)); - Assert.That(solution.TotalVolume.Int(), Is.EqualTo(800)); - - Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(0)); - Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(0)); - } - - [Test] - public void SplitSolutionZero() - { - var solution = new Solution(); - solution.AddReagent("Impedrezene", FixedPoint2.New(0.01 + 0.19)); - solution.AddReagent("Thermite", FixedPoint2.New(0.01 + 0.39)); - solution.AddReagent("Li", FixedPoint2.New(0.01 + 0.17)); - solution.AddReagent("F", FixedPoint2.New(0.01 + 0.17)); - solution.AddReagent("Na", FixedPoint2.New(0 + 0.13)); - solution.AddReagent("Hg", FixedPoint2.New(0.15 + 4.15)); - solution.AddReagent("Cu", FixedPoint2.New(0 + 0.13)); - solution.AddReagent("U", FixedPoint2.New(0.76 + 20.77)); - solution.AddReagent("Fe", FixedPoint2.New(0.01 + 0.36)); - solution.AddReagent("SpaceDrugs", FixedPoint2.New(0.02 + 0.41)); - solution.AddReagent("Al", FixedPoint2.New(0)); - solution.AddReagent("Glucose", FixedPoint2.New(0)); - solution.AddReagent("O", FixedPoint2.New(0)); - - solution.SplitSolution(FixedPoint2.New(0.98)); - } - - [Test] - public void AddSolution() - { - var solutionOne = new Solution(); - solutionOne.AddReagent("water", FixedPoint2.New(1000)); - solutionOne.AddReagent("fire", FixedPoint2.New(2000)); - - var solutionTwo = new Solution(); - solutionTwo.AddReagent("water", FixedPoint2.New(500)); - solutionTwo.AddReagent("earth", FixedPoint2.New(1000)); - - solutionOne.AddSolution(solutionTwo); - - Assert.That(solutionOne.GetReagentQuantity("water").Int(), Is.EqualTo(1500)); - Assert.That(solutionOne.GetReagentQuantity("fire").Int(), Is.EqualTo(2000)); - Assert.That(solutionOne.GetReagentQuantity("earth").Int(), Is.EqualTo(1000)); - Assert.That(solutionOne.TotalVolume.Int(), Is.EqualTo(4500)); - } - - // Tests concerning thermal energy and temperature. - #region Thermal Energy and Temperature - - [Test] - public void EmptySolutionHasNoHeatCapacity() - { - var solution = new Solution(); - Assert.That(solution.HeatCapacity, Is.EqualTo(0.0f)); - } - - [Test] - public void EmptySolutionHasNoThermalEnergy() - { - var solution = new Solution(); - Assert.That(solution.ThermalEnergy, Is.EqualTo(0.0f)); - } - - [Test] - public void AddReagentToEmptySolutionSetsTemperature() - { - const float testTemp = 100.0f; - - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(100), testTemp); - Assert.That(solution.Temperature, Is.EqualTo(testTemp)); - } - - [Test] - public void AddReagentWithNullTemperatureDoesNotEffectTemperature() - { - const float initialTemp = 100.0f; - - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(100), initialTemp); - - solution.AddReagent("water", FixedPoint2.New(100)); - Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); - - solution.AddReagent("earth", FixedPoint2.New(100)); - Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); - } - - [Test] - public void AddSolutionWithEqualTemperatureDoesNotChangeTemperature() - { - const float initialTemp = 100.0f; - - var solutionOne = new Solution(); - solutionOne.AddReagent("water", FixedPoint2.New(100)); - solutionOne.Temperature = initialTemp; - - var solutionTwo = new Solution(); - solutionTwo.AddReagent("water", FixedPoint2.New(100)); - solutionTwo.AddReagent("earth", FixedPoint2.New(100)); - solutionTwo.Temperature = initialTemp; - - solutionOne.AddSolution(solutionTwo); - Assert.That(solutionOne.Temperature, Is.EqualTo(initialTemp)); - } - - [Test] - public void RemoveReagentDoesNotEffectTemperature() - { - const float initialTemp = 100.0f; - - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(100), initialTemp); - solution.RemoveReagent("water", FixedPoint2.New(50)); - Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); - } - - [Test] - public void RemoveSolutionDoesNotEffectTemperature() - { - const float initialTemp = 100.0f; - - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(100), initialTemp); - solution.RemoveSolution(FixedPoint2.New(50)); - Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); - } - - [Test] - public void SplitSolutionDoesNotEffectTemperature() - { - const float initialTemp = 100.0f; - - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(100), initialTemp); - solution.SplitSolution(FixedPoint2.New(50)); - Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); - } - - [Test] - public void AddReagentWithSetTemperatureAdjustsTemperature() - { - const float temp = 100.0f; - - var solution = new Solution(); - solution.AddReagent("water", FixedPoint2.New(100), temp * 1); - Assert.That(solution.Temperature, Is.EqualTo(temp * 1)); - - solution.AddReagent("water", FixedPoint2.New(100), temp * 3); - Assert.That(solution.Temperature, Is.EqualTo(temp * 2)); - - solution.AddReagent("earth", FixedPoint2.New(100), temp * 5); - Assert.That(solution.Temperature, Is.EqualTo(temp * 3)); - } - - [Test] - public void AddSolutionCombinesThermalEnergy() - { - const float initialTemp = 100.0f; - - var solutionOne = new Solution(); - solutionOne.AddReagent("water", FixedPoint2.New(100), initialTemp); - - var solutionTwo = new Solution(); - solutionTwo.AddReagent("water", FixedPoint2.New(100), initialTemp); - solutionTwo.AddReagent("earth", FixedPoint2.New(100)); - - var thermalEnergyOne = solutionOne.ThermalEnergy; - var thermalEnergyTwo = solutionTwo.ThermalEnergy; - solutionOne.AddSolution(solutionTwo); - Assert.That(solutionOne.ThermalEnergy, Is.EqualTo(thermalEnergyOne + thermalEnergyTwo)); - } - - #endregion Thermal Energy and Temperature + IoCManager.Resolve().Initialize(); } + + [Test] + public void AddReagentAndGetSolution() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1000)); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity.Int(), Is.EqualTo(1000)); + } + + [Test] + public void ConstructorAddReagent() + { + var solution = new Solution("water", FixedPoint2.New(1000)); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity.Int(), Is.EqualTo(1000)); + } + + [Test] + public void NonExistingReagentReturnsZero() + { + var solution = new Solution(); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity.Int(), Is.EqualTo(0)); + } + + [Test] + public void AddLessThanZeroReagentReturnsZero() + { + var solution = new Solution("water", FixedPoint2.New(-1000)); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity.Int(), Is.EqualTo(0)); + } + + [Test] + public void AddingReagentsSumsProperly() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1000)); + solution.AddReagent("water", FixedPoint2.New(2000)); + var quantity = solution.GetReagentQuantity("water"); + + Assert.That(quantity.Int(), Is.EqualTo(3000)); + } + + [Test] + public void ReagentQuantitiesStayUnique() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1000)); + solution.AddReagent("fire", FixedPoint2.New(2000)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(1000)); + Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000)); + } + + [Test] + public void TotalVolumeIsCorrect() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1000)); + solution.AddReagent("fire", FixedPoint2.New(2000)); + + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(3000)); + } + + [Test] + public void CloningSolutionIsCorrect() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1000)); + solution.AddReagent("fire", FixedPoint2.New(2000)); + + var newSolution = solution.Clone(); + + Assert.That(newSolution.GetReagentQuantity("water").Int(), Is.EqualTo(1000)); + Assert.That(newSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000)); + Assert.That(newSolution.TotalVolume.Int(), Is.EqualTo(3000)); + } + + [Test] + public void RemoveSolutionRecalculatesProperly() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1000)); + solution.AddReagent("fire", FixedPoint2.New(2000)); + + solution.RemoveReagent("water", FixedPoint2.New(500)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500)); + Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2500)); + } + + [Test] + public void RemoveLessThanOneQuantityDoesNothing() + { + var solution = new Solution("water", FixedPoint2.New(100)); + + solution.RemoveReagent("water", FixedPoint2.New(-100)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(100)); + } + + [Test] + public void RemoveMoreThanTotalRemovesAllReagent() + { + var solution = new Solution("water", FixedPoint2.New(100)); + + solution.RemoveReagent("water", FixedPoint2.New(1000)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0)); + } + + [Test] + public void RemoveNonExistReagentDoesNothing() + { + var solution = new Solution("water", FixedPoint2.New(100)); + + solution.RemoveReagent("fire", FixedPoint2.New(1000)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(100)); + } + + [Test] + public void RemoveSolution() + { + var solution = new Solution("water", FixedPoint2.New(700)); + + solution.RemoveSolution(FixedPoint2.New(500)); + + //Check that edited solution is correct + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(200)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(200)); + } + + [Test] + public void RemoveSolutionMoreThanTotalRemovesAll() + { + var solution = new Solution("water", FixedPoint2.New(800)); + + solution.RemoveSolution(FixedPoint2.New(1000)); + + //Check that edited solution is correct + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0)); + } + + [Test] + public void RemoveSolutionRatioPreserved() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1000)); + solution.AddReagent("fire", FixedPoint2.New(2000)); + + solution.RemoveSolution(FixedPoint2.New(1500)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500)); + Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1000)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(1500)); + } + + [Test] + public void RemoveSolutionLessThanOneDoesNothing() + { + var solution = new Solution("water", FixedPoint2.New(800)); + + solution.RemoveSolution(FixedPoint2.New(-200)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(800)); + } + + [Test] + public void SplitSolution() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1000)); + solution.AddReagent("fire", FixedPoint2.New(2000)); + + var splitSolution = solution.SplitSolution(FixedPoint2.New(750)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(750)); + Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1500)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2250)); + + Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(250)); + Assert.That(splitSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(500)); + Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(750)); + } + + [Test] + public void SplitSolutionFractional() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1)); + solution.AddReagent("fire", FixedPoint2.New(2)); + + var splitSolution = solution.SplitSolution(FixedPoint2.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] + public void SplitSolutionFractionalOpposite() + { + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(1)); + solution.AddReagent("fire", FixedPoint2.New(2)); + + var splitSolution = solution.SplitSolution(FixedPoint2.New(2)); + + Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f)); + Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(1)); + + Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f)); + Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f)); + Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(2)); + } + + [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", FixedPoint2.New(initial)); + + var splitSolution = solution.SplitSolution(FixedPoint2.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] + [TestCase(2)] + [TestCase(10)] + [TestCase(100)] + [TestCase(1000)] + public void SplitRounding(int amount) + { + var solutionOne = new Solution(); + solutionOne.AddReagent("foo", FixedPoint2.New(amount)); + solutionOne.AddReagent("bar", FixedPoint2.New(amount)); + solutionOne.AddReagent("baz", FixedPoint2.New(amount)); + + var splitAmount = FixedPoint2.New(5); + var split = solutionOne.SplitSolution(splitAmount); + + Assert.That(split.TotalVolume, Is.EqualTo(splitAmount)); + } + + [Test] + public void SplitSolutionMoreThanTotalRemovesAll() + { + var solution = new Solution("water", FixedPoint2.New(800)); + + var splitSolution = solution.SplitSolution(FixedPoint2.New(1000)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0)); + + Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(800)); + Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(800)); + } + + [Test] + public void SplitSolutionLessThanOneDoesNothing() + { + var solution = new Solution("water", FixedPoint2.New(800)); + + var splitSolution = solution.SplitSolution(FixedPoint2.New(-200)); + + Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800)); + Assert.That(solution.TotalVolume.Int(), Is.EqualTo(800)); + + Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(0)); + Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(0)); + } + + [Test] + public void SplitSolutionZero() + { + var solution = new Solution(); + solution.AddReagent("Impedrezene", FixedPoint2.New(0.01 + 0.19)); + solution.AddReagent("Thermite", FixedPoint2.New(0.01 + 0.39)); + solution.AddReagent("Li", FixedPoint2.New(0.01 + 0.17)); + solution.AddReagent("F", FixedPoint2.New(0.01 + 0.17)); + solution.AddReagent("Na", FixedPoint2.New(0 + 0.13)); + solution.AddReagent("Hg", FixedPoint2.New(0.15 + 4.15)); + solution.AddReagent("Cu", FixedPoint2.New(0 + 0.13)); + solution.AddReagent("U", FixedPoint2.New(0.76 + 20.77)); + solution.AddReagent("Fe", FixedPoint2.New(0.01 + 0.36)); + solution.AddReagent("SpaceDrugs", FixedPoint2.New(0.02 + 0.41)); + solution.AddReagent("Al", FixedPoint2.New(0)); + solution.AddReagent("Glucose", FixedPoint2.New(0)); + solution.AddReagent("O", FixedPoint2.New(0)); + + solution.SplitSolution(FixedPoint2.New(0.98)); + } + + [Test] + public void AddSolution() + { + var solutionOne = new Solution(); + solutionOne.AddReagent("water", FixedPoint2.New(1000)); + solutionOne.AddReagent("fire", FixedPoint2.New(2000)); + + var solutionTwo = new Solution(); + solutionTwo.AddReagent("water", FixedPoint2.New(500)); + solutionTwo.AddReagent("earth", FixedPoint2.New(1000)); + + solutionOne.AddSolution(solutionTwo); + + Assert.That(solutionOne.GetReagentQuantity("water").Int(), Is.EqualTo(1500)); + Assert.That(solutionOne.GetReagentQuantity("fire").Int(), Is.EqualTo(2000)); + Assert.That(solutionOne.GetReagentQuantity("earth").Int(), Is.EqualTo(1000)); + Assert.That(solutionOne.TotalVolume.Int(), Is.EqualTo(4500)); + } + + // Tests concerning thermal energy and temperature. + + #region Thermal Energy and Temperature + + [Test] + public void EmptySolutionHasNoHeatCapacity() + { + var solution = new Solution(); + Assert.That(solution.HeatCapacity, Is.EqualTo(0.0f)); + } + + [Test] + public void EmptySolutionHasNoThermalEnergy() + { + var solution = new Solution(); + Assert.That(solution.ThermalEnergy, Is.EqualTo(0.0f)); + } + + [Test] + public void AddReagentToEmptySolutionSetsTemperature() + { + const float testTemp = 100.0f; + + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(100), testTemp); + Assert.That(solution.Temperature, Is.EqualTo(testTemp)); + } + + [Test] + public void AddReagentWithNullTemperatureDoesNotEffectTemperature() + { + const float initialTemp = 100.0f; + + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(100), initialTemp); + + solution.AddReagent("water", FixedPoint2.New(100)); + Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); + + solution.AddReagent("earth", FixedPoint2.New(100)); + Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); + } + + [Test] + public void AddSolutionWithEqualTemperatureDoesNotChangeTemperature() + { + const float initialTemp = 100.0f; + + var solutionOne = new Solution(); + solutionOne.AddReagent("water", FixedPoint2.New(100)); + solutionOne.Temperature = initialTemp; + + var solutionTwo = new Solution(); + solutionTwo.AddReagent("water", FixedPoint2.New(100)); + solutionTwo.AddReagent("earth", FixedPoint2.New(100)); + solutionTwo.Temperature = initialTemp; + + solutionOne.AddSolution(solutionTwo); + Assert.That(solutionOne.Temperature, Is.EqualTo(initialTemp)); + } + + [Test] + public void RemoveReagentDoesNotEffectTemperature() + { + const float initialTemp = 100.0f; + + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(100), initialTemp); + solution.RemoveReagent("water", FixedPoint2.New(50)); + Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); + } + + [Test] + public void RemoveSolutionDoesNotEffectTemperature() + { + const float initialTemp = 100.0f; + + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(100), initialTemp); + solution.RemoveSolution(FixedPoint2.New(50)); + Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); + } + + [Test] + public void SplitSolutionDoesNotEffectTemperature() + { + const float initialTemp = 100.0f; + + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(100), initialTemp); + solution.SplitSolution(FixedPoint2.New(50)); + Assert.That(solution.Temperature, Is.EqualTo(initialTemp)); + } + + [Test] + public void AddReagentWithSetTemperatureAdjustsTemperature() + { + const float temp = 100.0f; + + var solution = new Solution(); + solution.AddReagent("water", FixedPoint2.New(100), temp * 1); + Assert.That(solution.Temperature, Is.EqualTo(temp * 1)); + + solution.AddReagent("water", FixedPoint2.New(100), temp * 3); + Assert.That(solution.Temperature, Is.EqualTo(temp * 2)); + + solution.AddReagent("earth", FixedPoint2.New(100), temp * 5); + Assert.That(solution.Temperature, Is.EqualTo(temp * 3)); + } + + [Test] + public void AddSolutionCombinesThermalEnergy() + { + const float initialTemp = 100.0f; + + var solutionOne = new Solution(); + solutionOne.AddReagent("water", FixedPoint2.New(100), initialTemp); + + var solutionTwo = new Solution(); + solutionTwo.AddReagent("water", FixedPoint2.New(100), initialTemp); + solutionTwo.AddReagent("earth", FixedPoint2.New(100)); + + var thermalEnergyOne = solutionOne.ThermalEnergy; + var thermalEnergyTwo = solutionTwo.ThermalEnergy; + solutionOne.AddSolution(solutionTwo); + Assert.That(solutionOne.ThermalEnergy, Is.EqualTo(thermalEnergyOne + thermalEnergyTwo)); + } + + #endregion Thermal Energy and Temperature }