From 0538c6b53c3bbadbea127d4a7c2efae8a1d8a434 Mon Sep 17 00:00:00 2001 From: Evgeny Redikultsev Date: Sat, 7 Dec 2024 20:50:21 +0500 Subject: [PATCH] Add calculators cloning logic --- .../InteractionDiagramLogic.cs | 4 +- .../LimitCurveDataViewModel.cs | 4 +- .../GeometryCalculatorResultView.xaml | 69 +++++---- .../Interfaces/DeepCloningStrategy.cs | 21 +-- .../Interfaces/ICloningStrategy.cs | 10 ++ .../CrossSectionRepositoryCloneStrategy.cs | 3 +- .../LimitCurve/ILimitCurvesCalculator.cs | 2 +- .../LimitCurve/LimitCurvesCalculator.cs | 4 +- ...CurvesCalculatorInputDataUpdateStrategy.cs | 1 + ...itCurvesCalculatorUpdateCloningStrategy.cs | 58 ++++++++ .../CrackCalculatorUpdateCloningStrategy.cs | 46 ++++++ .../ForceCalculatorUpdateCloningStrategy.cs | 44 ++++++ .../HasCalculatorsUpdateCloningStrategy.cs | 73 +++------ ...ackCalculatorUpdateCloningStrategyTests.cs | 89 +++++++++++ .../DeepCloningStrategyTests.cs | 117 +++++++++++++++ ...rceCalculatorUpdateCloningStrategyTests.cs | 91 ++++++++++++ ...asCalculatorsUpdateCloningStrategyTests.cs | 138 ++++++++++++++++++ ...vesCalculatorUpdateCloningStrategyTests.cs | 111 ++++++++++++++ 18 files changed, 776 insertions(+), 109 deletions(-) create mode 100644 StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculatorUpdateCloningStrategy.cs create mode 100644 StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/CrackCalculatorUpdateCloningStrategy.cs create mode 100644 StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/ForceCalculatorUpdateCloningStrategy.cs create mode 100644 StructureHelperTests/UnitTests/UpdateStrategiesTests/CrackCalculatorUpdateCloningStrategyTests.cs create mode 100644 StructureHelperTests/UnitTests/UpdateStrategiesTests/DeepCloningStrategyTests.cs create mode 100644 StructureHelperTests/UnitTests/UpdateStrategiesTests/ForceCalculatorUpdateCloningStrategyTests.cs create mode 100644 StructureHelperTests/UnitTests/UpdateStrategiesTests/HasCalculatorsUpdateCloningStrategyTests.cs create mode 100644 StructureHelperTests/UnitTests/UpdateStrategiesTests/LimitCurvesCalculatorUpdateCloningStrategyTests.cs diff --git a/StructureHelper/Windows/CalculationWindows/CalculatorsViews/ForceCalculatorViews/ForceResultLogic/InteractionDiagramLogic.cs b/StructureHelper/Windows/CalculationWindows/CalculatorsViews/ForceCalculatorViews/ForceResultLogic/InteractionDiagramLogic.cs index 57d6976..92fc62e 100644 --- a/StructureHelper/Windows/CalculationWindows/CalculatorsViews/ForceCalculatorViews/ForceResultLogic/InteractionDiagramLogic.cs +++ b/StructureHelper/Windows/CalculationWindows/CalculatorsViews/ForceCalculatorViews/ForceResultLogic/InteractionDiagramLogic.cs @@ -34,14 +34,14 @@ namespace StructureHelper.Windows.CalculationWindows.CalculatorsViews.ForceCalcu private int stepCount; private static GeometryNames GeometryNames => ProgramSetting.GeometryNames; - public LimitCurvesCalculatorInputData InputData { get; set; } + public ILimitCurvesCalculatorInputData InputData { get; set; } public int StepCount { get => stepCount; set => stepCount = value; } public Action SetProgress { get; set; } public bool Result { get; set; } public IShiftTraceLogger? TraceLogger { get; set; } - public InteractionDiagramLogic(LimitCurvesCalculatorInputData inputData) + public InteractionDiagramLogic(ILimitCurvesCalculatorInputData inputData) { InputData = inputData; stepCount = InputData.PointCount; diff --git a/StructureHelper/Windows/CalculationWindows/CalculatorsViews/ForceCalculatorViews/ForceResultLogic/LimitCurveDataViewModel.cs b/StructureHelper/Windows/CalculationWindows/CalculatorsViews/ForceCalculatorViews/ForceResultLogic/LimitCurveDataViewModel.cs index 2d9f1a0..068466b 100644 --- a/StructureHelper/Windows/CalculationWindows/CalculatorsViews/ForceCalculatorViews/ForceResultLogic/LimitCurveDataViewModel.cs +++ b/StructureHelper/Windows/CalculationWindows/CalculatorsViews/ForceCalculatorViews/ForceResultLogic/LimitCurveDataViewModel.cs @@ -24,7 +24,7 @@ namespace StructureHelper.Windows.CalculationWindows.CalculatorsViews.ForceCalcu { public class LimitCurveDataViewModel : OkCancelViewModelBase, IDataErrorInfo { - private LimitCurvesCalculatorInputData inputData; + private ILimitCurvesCalculatorInputData inputData; //public SurroundDataViewModel SurroundDataViewModel { get; private set; } @@ -52,7 +52,7 @@ namespace StructureHelper.Windows.CalculationWindows.CalculatorsViews.ForceCalcu public IEnumerable AllowedPrimitives { get; set; } - public LimitCurveDataViewModel(LimitCurvesCalculatorInputData inputData, IEnumerable allowedPrimitives) + public LimitCurveDataViewModel(ILimitCurvesCalculatorInputData inputData, IEnumerable allowedPrimitives) { this.inputData = inputData; AllowedPrimitives = allowedPrimitives; diff --git a/StructureHelper/Windows/CalculationWindows/CalculatorsViews/GeometryCalculatorViews/GeometryCalculatorResultView.xaml b/StructureHelper/Windows/CalculationWindows/CalculatorsViews/GeometryCalculatorViews/GeometryCalculatorResultView.xaml index af86d09..4a6aaf7 100644 --- a/StructureHelper/Windows/CalculationWindows/CalculatorsViews/GeometryCalculatorViews/GeometryCalculatorResultView.xaml +++ b/StructureHelper/Windows/CalculationWindows/CalculatorsViews/GeometryCalculatorViews/GeometryCalculatorResultView.xaml @@ -5,35 +5,48 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:StructureHelper.Windows.CalculationWindows.CalculatorsViews.GeometryCalculatorViews" xmlns:vm="clr-namespace:StructureHelper.Windows.ViewModels.Calculations.Calculators.GeometryCalculatorVMs" + xmlns:uc="clr-namespace:StructureHelper.Windows.UserControls" mc:Ignorable="d" d:DataContext="{d:DesignInstance vm:GeometryCalculatorResultViewModel}" Title="Geometry Properties" Height="450" Width="850" WindowStartupLocation="CenterScreen"> - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/StructureHelperCommon/Infrastructures/Interfaces/DeepCloningStrategy.cs b/StructureHelperCommon/Infrastructures/Interfaces/DeepCloningStrategy.cs index e416f0e..98edf94 100644 --- a/StructureHelperCommon/Infrastructures/Interfaces/DeepCloningStrategy.cs +++ b/StructureHelperCommon/Infrastructures/Interfaces/DeepCloningStrategy.cs @@ -8,10 +8,14 @@ using System.Threading.Tasks; namespace StructureHelperCommon.Infrastructures.Interfaces { + /// + /// Creates deep copy of object by dictionary (if copy of object is not created it create copy, otherwise take copy from dictionary) + /// public class DeepCloningStrategy : ICloningStrategy { - private readonly Dictionary _clonedObjects = new Dictionary(); + private readonly Dictionary _clonedObjects = new(); + /// public T Clone(T original, ICloneStrategy? cloneStrategy = null) where T : class { if (original == null) return null; @@ -40,21 +44,6 @@ namespace StructureHelperCommon.Infrastructures.Interfaces return clone; } - - //private T CreateClone(T original) where T : class - //{ - // // Example logic for creating a clone (modify as needed for your use case) - // var type = original.GetType(); - // var clone = Activator.CreateInstance(type); - - // foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) - // { - // var value = field.GetValue(original); - // field.SetValue(clone, Clone(value)); - // } - - // return (T)clone; - //} } } diff --git a/StructureHelperCommon/Infrastructures/Interfaces/ICloningStrategy.cs b/StructureHelperCommon/Infrastructures/Interfaces/ICloningStrategy.cs index a1f9dd0..daf9fef 100644 --- a/StructureHelperCommon/Infrastructures/Interfaces/ICloningStrategy.cs +++ b/StructureHelperCommon/Infrastructures/Interfaces/ICloningStrategy.cs @@ -6,8 +6,18 @@ using System.Threading.Tasks; namespace StructureHelperCommon.Infrastructures.Interfaces { + /// + /// Interface for cloning objects + /// public interface ICloningStrategy { + /// + /// Returns copy of object + /// + /// Type of object + /// Source object + /// Strategy for cloning of object of specified type + /// T Clone(T original, ICloneStrategy? cloneStrategy = null) where T : class; } } diff --git a/StructureHelperLogics/Models/CrossSections/CrossSectionRepositoryCloneStrategy.cs b/StructureHelperLogics/Models/CrossSections/CrossSectionRepositoryCloneStrategy.cs index bcd3a68..1ff31f7 100644 --- a/StructureHelperLogics/Models/CrossSections/CrossSectionRepositoryCloneStrategy.cs +++ b/StructureHelperLogics/Models/CrossSections/CrossSectionRepositoryCloneStrategy.cs @@ -42,8 +42,7 @@ namespace StructureHelperLogics.Models.CrossSections new HasMaterialsUpdateCloningStrategy(null), new HasPrimitivesUpdateCloningStrategy(null), new HasCalculatorsUpdateCloningStrategy(null)) - { - + { forcesUpdateStrategy = new HasForceActionUpdateCloningStrategy(cloningStrategy); materialsUpdateStrategy = new HasMaterialsUpdateCloningStrategy(cloningStrategy); primitivesUpdateStrategy = new HasPrimitivesUpdateCloningStrategy(cloningStrategy); diff --git a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/ILimitCurvesCalculator.cs b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/ILimitCurvesCalculator.cs index 26366d6..bdb72ea 100644 --- a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/ILimitCurvesCalculator.cs +++ b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/ILimitCurvesCalculator.cs @@ -6,7 +6,7 @@ namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces { public interface ILimitCurvesCalculator : ISaveable, ICalculator, IHasActionByResult { - LimitCurvesCalculatorInputData InputData { get; set; } + ILimitCurvesCalculatorInputData InputData { get; set; } string Name { get; set; } } } \ No newline at end of file diff --git a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculator.cs b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculator.cs index 8bfd38f..f273803 100644 --- a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculator.cs +++ b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculator.cs @@ -21,7 +21,7 @@ namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces public Guid Id { get; } public string Name { get; set; } - public LimitCurvesCalculatorInputData InputData { get; set; } + public ILimitCurvesCalculatorInputData InputData { get; set; } public IResult Result => result; public Action ActionToOutputResults { get; set; } @@ -30,7 +30,7 @@ namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces public LimitCurvesCalculator() { Name = "New calculator"; - InputData = new(); + InputData = new LimitCurvesCalculatorInputData(); } public void Run() { diff --git a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculatorInputDataUpdateStrategy.cs b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculatorInputDataUpdateStrategy.cs index da66da7..9b9dab3 100644 --- a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculatorInputDataUpdateStrategy.cs +++ b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculatorInputDataUpdateStrategy.cs @@ -19,6 +19,7 @@ namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces.LimitCurve if (ReferenceEquals(targetObject, sourceObject)) { return; } targetObject.LimitStates.Clear(); targetObject.CalcTerms.Clear(); + targetObject.PrimitiveSeries.Clear(); targetObject.PredicateEntries.Clear(); targetObject.LimitStates.AddRange(sourceObject.LimitStates); targetObject.CalcTerms.AddRange(sourceObject.CalcTerms); diff --git a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculatorUpdateCloningStrategy.cs b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculatorUpdateCloningStrategy.cs new file mode 100644 index 0000000..43e7d16 --- /dev/null +++ b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/LimitCurve/LimitCurvesCalculatorUpdateCloningStrategy.cs @@ -0,0 +1,58 @@ +using StructureHelperCommon.Infrastructures.Interfaces; +using StructureHelperCommon.Models.Parameters; +using StructureHelperCommon.Services; +using StructureHelperLogics.NdmCalculations.Primitives; + +namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces.LimitCurve +{ + /// + /// Creates deep copy of limit curves calculator + /// + public class LimitCurvesCalculatorUpdateCloningStrategy : IUpdateStrategy + { + private ICloningStrategy cloningStrategy; + private IUpdateStrategy limitCurvesInputDataUpdateStrategy; + + public LimitCurvesCalculatorUpdateCloningStrategy(ICloningStrategy cloningStrategy) : this ( + cloningStrategy, + new LimitCurvesCalculatorInputDataUpdateStrategy()) + { + this.cloningStrategy = cloningStrategy; + } + + public LimitCurvesCalculatorUpdateCloningStrategy( + ICloningStrategy cloningStrategy, + IUpdateStrategy limitCurvesInputDataUpdateStrategy) + { + this.cloningStrategy = cloningStrategy; + this.limitCurvesInputDataUpdateStrategy = limitCurvesInputDataUpdateStrategy; + } + + public void Update(ILimitCurvesCalculator targetObject, ILimitCurvesCalculator sourceObject) + { + CheckObject.IsNull(cloningStrategy); + CheckObject.IsNull(sourceObject); + CheckObject.IsNull(targetObject); + if (ReferenceEquals(targetObject, sourceObject)) { return; } + var targetData = targetObject.InputData; + limitCurvesInputDataUpdateStrategy.Update(targetData, sourceObject.InputData); + foreach (var series in targetData.PrimitiveSeries) + { + List collection = UpdatePrimitivesCollection(series); + series.Collection.AddRange(collection); + } + } + + private List UpdatePrimitivesCollection(NamedCollection series) + { + List collection = new(); + foreach (var item in series.Collection) + { + var newItem = cloningStrategy.Clone(item); + collection.Add(newItem); + } + series.Collection.Clear(); + return collection; + } + } +} diff --git a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/CrackCalculatorUpdateCloningStrategy.cs b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/CrackCalculatorUpdateCloningStrategy.cs new file mode 100644 index 0000000..5f2bf03 --- /dev/null +++ b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/CrackCalculatorUpdateCloningStrategy.cs @@ -0,0 +1,46 @@ +using StructureHelperCommon.Infrastructures.Interfaces; +using StructureHelperCommon.Services; +using StructureHelperLogics.NdmCalculations.Cracking; +using StructureHelperLogics.NdmCalculations.Primitives; +using StructureHelperLogics.NdmCalculations.Primitives.Logics; + +namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces.Logics +{ + /// + /// Creates deep copy of crack calculator + /// + public class CrackCalculatorUpdateCloningStrategy : IUpdateStrategy + { + private ICloningStrategy cloningStrategy; + private IUpdateStrategy forcesUpdateStrategy; + private IUpdateStrategy primitivesUpdateStrategy; + + public CrackCalculatorUpdateCloningStrategy( + ICloningStrategy cloningStrategy, + IUpdateStrategy forcesUpdateStrategy, + IUpdateStrategy primitivesUpdateStrategy) + { + this.cloningStrategy = cloningStrategy; + this.forcesUpdateStrategy = forcesUpdateStrategy; + this.primitivesUpdateStrategy = primitivesUpdateStrategy; + } + public CrackCalculatorUpdateCloningStrategy(ICloningStrategy cloningStrategy) : this ( + cloningStrategy, + new HasForceActionUpdateCloningStrategy(cloningStrategy), + new HasPrimitivesUpdateCloningStrategy(cloningStrategy)) + { + } + + public void Update(ICrackCalculator targetObject, ICrackCalculator sourceObject) + { + CheckObject.IsNull(cloningStrategy); + CheckObject.IsNull(sourceObject); + CheckObject.IsNull(targetObject); + if (ReferenceEquals(targetObject, sourceObject)) { return; } + var sourceData = sourceObject.InputData; + var targetData = targetObject.InputData; + primitivesUpdateStrategy.Update(targetData, sourceData); + forcesUpdateStrategy.Update(targetData, sourceData); + } + } +} diff --git a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/ForceCalculatorUpdateCloningStrategy.cs b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/ForceCalculatorUpdateCloningStrategy.cs new file mode 100644 index 0000000..442e1c2 --- /dev/null +++ b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/ForceCalculatorUpdateCloningStrategy.cs @@ -0,0 +1,44 @@ +using StructureHelperCommon.Infrastructures.Interfaces; +using StructureHelperCommon.Services; +using StructureHelperLogics.NdmCalculations.Primitives; +using StructureHelperLogics.NdmCalculations.Primitives.Logics; + +namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces.Logics +{ + /// + /// Creates deep copy of force calculator + /// + public class ForceCalculatorUpdateCloningStrategy : IUpdateStrategy + { + private readonly ICloningStrategy cloningStrategy; + private readonly IUpdateStrategy forcesUpdateStrategy; + private readonly IUpdateStrategy primitivesUpdateStrategy; + public ForceCalculatorUpdateCloningStrategy(ICloningStrategy cloningStrategy, + IUpdateStrategy forcesUpdateStrategy, + IUpdateStrategy primitivesUpdateStrategy) + { + this.cloningStrategy = cloningStrategy; + this.forcesUpdateStrategy = forcesUpdateStrategy; + this.primitivesUpdateStrategy = primitivesUpdateStrategy; + } + + public ForceCalculatorUpdateCloningStrategy(ICloningStrategy cloningStrategy) : this ( + cloningStrategy, + new HasForceActionUpdateCloningStrategy(cloningStrategy), + new HasPrimitivesUpdateCloningStrategy(cloningStrategy)) + { + } + + public void Update(IForceCalculator targetObject, IForceCalculator sourceObject) + { + CheckObject.IsNull(cloningStrategy); + CheckObject.IsNull(sourceObject); + CheckObject.IsNull(targetObject); + if (ReferenceEquals(targetObject, sourceObject)) { return; } + var sourceData = sourceObject.InputData; + var targetData = targetObject.InputData; + primitivesUpdateStrategy.Update(targetData, sourceData); + forcesUpdateStrategy.Update(targetData, sourceData); + } + } +} diff --git a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/HasCalculatorsUpdateCloningStrategy.cs b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/HasCalculatorsUpdateCloningStrategy.cs index 4235c3f..78527de 100644 --- a/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/HasCalculatorsUpdateCloningStrategy.cs +++ b/StructureHelperLogics/NdmCalculations/Analyses/ByForces/Logics/HasCalculatorsUpdateCloningStrategy.cs @@ -4,6 +4,7 @@ using StructureHelperCommon.Models.Calculators; using StructureHelperCommon.Models.Parameters; using StructureHelperCommon.Services; using StructureHelperLogics.NdmCalculations.Analyses.ByForces.LimitCurve; +using StructureHelperLogics.NdmCalculations.Analyses.ByForces.Logics; using StructureHelperLogics.NdmCalculations.Cracking; using StructureHelperLogics.NdmCalculations.Primitives; using StructureHelperLogics.NdmCalculations.Primitives.Logics; @@ -16,29 +17,29 @@ namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces public class HasCalculatorsUpdateCloningStrategy : IUpdateStrategy { private ICloningStrategy cloningStrategy; - private IUpdateStrategy forcesUpdateStrategy; - private IUpdateStrategy primitivesUpdateStrategy; - private IUpdateStrategy limitCurvesInputDataUpdateStrategy; + private IUpdateStrategy forceCalculatorUpdateStrategy; + private IUpdateStrategy crackCalculatorUpdateStrategy; + private IUpdateStrategy limitCurvesCalculatorUpdateStrategy; public HasCalculatorsUpdateCloningStrategy(ICloningStrategy cloningStrategy) : this( cloningStrategy, - new HasForceActionUpdateCloningStrategy(cloningStrategy), - new HasPrimitivesUpdateCloningStrategy(cloningStrategy), - new LimitCurvesCalculatorInputDataUpdateStrategy() + new ForceCalculatorUpdateCloningStrategy(cloningStrategy), + new CrackCalculatorUpdateCloningStrategy(cloningStrategy), + new LimitCurvesCalculatorUpdateCloningStrategy(cloningStrategy) ) { } public HasCalculatorsUpdateCloningStrategy( ICloningStrategy cloningStrategy, - IUpdateStrategy forcesUpdateStrategy, - IUpdateStrategy primitivesUpdateStrategy, - IUpdateStrategy limitCurvesInputDataUpdateStrategy) + IUpdateStrategy forceCalculatorUpdateStrategy, + IUpdateStrategy crackCalculatorUpdateStrategy, + IUpdateStrategy limitCurvesCalculatorUpdateStrategy) { this.cloningStrategy = cloningStrategy; - this.forcesUpdateStrategy = forcesUpdateStrategy; - this.primitivesUpdateStrategy = primitivesUpdateStrategy; - this.limitCurvesInputDataUpdateStrategy = limitCurvesInputDataUpdateStrategy; + this.forceCalculatorUpdateStrategy = forceCalculatorUpdateStrategy; + this.crackCalculatorUpdateStrategy = crackCalculatorUpdateStrategy; + this.limitCurvesCalculatorUpdateStrategy = limitCurvesCalculatorUpdateStrategy; } public void Update(IHasCalculators targetObject, IHasCalculators sourceObject) @@ -53,15 +54,15 @@ namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces var newCalculator = cloningStrategy.Clone(calculator); if (calculator is IForceCalculator forceCalculator) { - ProcessForceCalculator(newCalculator, forceCalculator); + forceCalculatorUpdateStrategy.Update(newCalculator as IForceCalculator, forceCalculator); } - else if (calculator is CrackCalculator crackCalculator) + else if (calculator is ICrackCalculator crackCalculator) { - ProcessCrackCalculator(newCalculator, crackCalculator); + crackCalculatorUpdateStrategy.Update(newCalculator as ICrackCalculator, crackCalculator); } else if (calculator is ILimitCurvesCalculator limitCalculator) { - ProcessLimitCurvesCalculator(newCalculator, limitCalculator); + limitCurvesCalculatorUpdateStrategy.Update(newCalculator as ILimitCurvesCalculator, limitCalculator); } else { @@ -70,45 +71,5 @@ namespace StructureHelperLogics.NdmCalculations.Analyses.ByForces targetObject.Calculators.Add(newCalculator); } } - - private void ProcessLimitCurvesCalculator(ICalculator newCalculator, ILimitCurvesCalculator limitCalculator) - { - var sourceData = limitCalculator.InputData; - var targetData = ((ILimitCurvesCalculator)newCalculator).InputData; - limitCurvesInputDataUpdateStrategy.Update(targetData, sourceData); - foreach (var series in targetData.PrimitiveSeries) - { - List collection = UpdatePrimitivesCollection(series); - series.Collection.AddRange(collection); - } - } - - private void ProcessCrackCalculator(ICalculator newCalculator, CrackCalculator crackCalculator) - { - var sourceData = crackCalculator.InputData; - var targetData = ((ICrackCalculator)newCalculator).InputData; - primitivesUpdateStrategy.Update(targetData, sourceData); - forcesUpdateStrategy.Update(targetData, sourceData); - } - - private void ProcessForceCalculator(ICalculator newCalculator, IForceCalculator forceCalculator) - { - var sourceData = forceCalculator.InputData; - var targetData = ((IForceCalculator)newCalculator).InputData; - primitivesUpdateStrategy.Update(targetData, sourceData); - forcesUpdateStrategy.Update(targetData, sourceData); - } - - private List UpdatePrimitivesCollection(NamedCollection series) - { - List collection = new(); - foreach (var item in series.Collection) - { - var newItem = cloningStrategy.Clone(item); - collection.Add(newItem); - } - series.Collection.Clear(); - return collection; - } } } diff --git a/StructureHelperTests/UnitTests/UpdateStrategiesTests/CrackCalculatorUpdateCloningStrategyTests.cs b/StructureHelperTests/UnitTests/UpdateStrategiesTests/CrackCalculatorUpdateCloningStrategyTests.cs new file mode 100644 index 0000000..79ee55d --- /dev/null +++ b/StructureHelperTests/UnitTests/UpdateStrategiesTests/CrackCalculatorUpdateCloningStrategyTests.cs @@ -0,0 +1,89 @@ +using Moq; +using NUnit.Framework; +using StructureHelperCommon.Infrastructures.Exceptions; +using StructureHelperCommon.Infrastructures.Interfaces; +using StructureHelperLogics.NdmCalculations.Analyses.ByForces.Logics; +using StructureHelperLogics.NdmCalculations.Cracking; +using StructureHelperLogics.NdmCalculations.Primitives; + +namespace StructureHelperTests.UnitTests.UpdateStrategiesTests +{ + [TestFixture] + public class CrackCalculatorUpdateCloningStrategyTests + { + private Mock _cloningStrategyMock; + private Mock> _forcesUpdateStrategyMock; + private Mock> _primitivesUpdateStrategyMock; + private CrackCalculatorUpdateCloningStrategy _strategy; + + [SetUp] + public void SetUp() + { + _cloningStrategyMock = new Mock(); + _forcesUpdateStrategyMock = new Mock>(); + _primitivesUpdateStrategyMock = new Mock>(); + + _strategy = new CrackCalculatorUpdateCloningStrategy( + _cloningStrategyMock.Object, + _forcesUpdateStrategyMock.Object, + _primitivesUpdateStrategyMock.Object + ); + } + + [Test] + public void Update_WithNullSourceObject_ThrowsException() + { + // Arrange + var targetObject = Mock.Of(); + + // Act & Assert + Assert.Throws(() => _strategy.Update(targetObject, null)); + } + + [Test] + public void Update_WithNullTargetObject_ThrowsException() + { + // Arrange + var sourceObject = Mock.Of(); + + // Act & Assert + Assert.Throws(() => _strategy.Update(null, sourceObject)); + } + + [Test] + public void Update_WithSameSourceAndTarget_DoesNothing() + { + // Arrange + var sourceObject = Mock.Of(); + + // Act + _strategy.Update(sourceObject, sourceObject); + + // Assert + _forcesUpdateStrategyMock.VerifyNoOtherCalls(); + _primitivesUpdateStrategyMock.VerifyNoOtherCalls(); + } + + [Test] + public void Update_InvokesUpdateStrategiesOnInputData() + { + // Arrange + var sourceDataMock = new Mock(); + var targetDataMock = new Mock(); + + var sourceObjectMock = new Mock(); + sourceObjectMock.Setup(s => s.InputData).Returns(sourceDataMock.Object); + + var targetObjectMock = new Mock(); + targetObjectMock.Setup(t => t.InputData).Returns(targetDataMock.Object); + + // Act + _strategy.Update(targetObjectMock.Object, sourceObjectMock.Object); + + // Assert + _primitivesUpdateStrategyMock.Verify(ps => ps.Update(targetDataMock.Object, sourceDataMock.Object), Times.Once); + _forcesUpdateStrategyMock.Verify(fs => fs.Update(targetDataMock.Object, sourceDataMock.Object), Times.Once); + } + } + +} diff --git a/StructureHelperTests/UnitTests/UpdateStrategiesTests/DeepCloningStrategyTests.cs b/StructureHelperTests/UnitTests/UpdateStrategiesTests/DeepCloningStrategyTests.cs new file mode 100644 index 0000000..fadce7b --- /dev/null +++ b/StructureHelperTests/UnitTests/UpdateStrategiesTests/DeepCloningStrategyTests.cs @@ -0,0 +1,117 @@ +using Moq; +using NUnit.Framework; +using StructureHelperCommon.Infrastructures.Exceptions; +using StructureHelperCommon.Infrastructures.Interfaces; + +namespace StructureHelperTests.UnitTests.UpdateStrategiesTests +{ + + + [TestFixture] + public class DeepCloningStrategyTests + { + private DeepCloningStrategy _strategy; + + [SetUp] + public void SetUp() + { + _strategy = new DeepCloningStrategy(); + } + + [Test] + public void Clone_WithNullOriginal_ReturnsNull() + { + // Act + var result = _strategy.Clone(null); + + // Assert + Assert.IsNull(result); + } + + [Test] + public void Clone_WhenObjectAlreadyCloned_ReturnsExistingClone() + { + // Arrange + var original = new Mock().Object; + var expectedClone = new Mock().Object; + + // Use reflection to populate the internal dictionary (_clonedObjects) + var clonedObjects = new Dictionary { { original, expectedClone } }; + var internalField = typeof(DeepCloningStrategy).GetField("_clonedObjects", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + internalField.SetValue(_strategy, clonedObjects); + + // Act + var result = _strategy.Clone(original); + + // Assert + Assert.AreSame(expectedClone, result); + } + + [Test] + public void Clone_WithCustomCloneStrategy_UsesCloneStrategyToCloneObject() + { + // Arrange + var original = new Mock().Object; + var expectedClone = new Mock().Object; + + var cloneStrategyMock = new Mock>(); + cloneStrategyMock.Setup(cs => cs.GetClone(original)).Returns(expectedClone); + + // Act + var result = _strategy.Clone(original, cloneStrategyMock.Object); + + // Assert + Assert.AreSame(expectedClone, result); + cloneStrategyMock.Verify(cs => cs.GetClone(original), Times.Once); + } + + [Test] + public void Clone_WhenObjectImplementsICloneable_UsesCloneMethod() + { + // Arrange + var originalMock = new Mock(); + var expectedClone = new Mock().Object; + + originalMock.Setup(o => o.Clone()).Returns(expectedClone); + + // Act + var result = _strategy.Clone(originalMock.Object); + + // Assert + Assert.AreSame(expectedClone, result); + originalMock.Verify(o => o.Clone(), Times.Once); + } + + [Test] + public void Clone_WhenObjectNotCloneableAndNoCloneStrategy_ThrowsStructureHelperException() + { + // Arrange + var original = new object(); // Not ICloneable + + // Act & Assert + var exception = Assert.Throws(() => _strategy.Clone(original)); + Assert.That(exception.Message, Does.Contain("object is not IClonable and cloning strategy is null")); + } + + [Test] + public void Clone_AddsClonedObjectToDictionary() + { + // Arrange + var originalMock = new Mock(); + var expectedClone = new Mock().Object; + + originalMock.Setup(o => o.Clone()).Returns(expectedClone); + + // Act + var result = _strategy.Clone(originalMock.Object); + + // Use reflection to check the private dictionary (_clonedObjects) + var internalField = typeof(DeepCloningStrategy).GetField("_clonedObjects", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var clonedObjects = (Dictionary)internalField.GetValue(_strategy); + + // Assert + Assert.AreSame(expectedClone, clonedObjects[originalMock.Object]); + } + } + +} diff --git a/StructureHelperTests/UnitTests/UpdateStrategiesTests/ForceCalculatorUpdateCloningStrategyTests.cs b/StructureHelperTests/UnitTests/UpdateStrategiesTests/ForceCalculatorUpdateCloningStrategyTests.cs new file mode 100644 index 0000000..1f14036 --- /dev/null +++ b/StructureHelperTests/UnitTests/UpdateStrategiesTests/ForceCalculatorUpdateCloningStrategyTests.cs @@ -0,0 +1,91 @@ +using Moq; +using NUnit.Framework; +using StructureHelperCommon.Infrastructures.Exceptions; +using StructureHelperCommon.Infrastructures.Interfaces; +using StructureHelperLogics.NdmCalculations.Analyses.ByForces.Logics; +using StructureHelperLogics.NdmCalculations.Analyses.ByForces; +using StructureHelperLogics.NdmCalculations.Primitives; + +namespace StructureHelperTests.UnitTests.UpdateStrategiesTests +{ + + + [TestFixture] + public class ForceCalculatorUpdateCloningStrategyTests + { + private Mock _cloningStrategyMock; + private Mock> _forcesUpdateStrategyMock; + private Mock> _primitivesUpdateStrategyMock; + private ForceCalculatorUpdateCloningStrategy _strategy; + + [SetUp] + public void SetUp() + { + _cloningStrategyMock = new Mock(); + _forcesUpdateStrategyMock = new Mock>(); + _primitivesUpdateStrategyMock = new Mock>(); + + _strategy = new ForceCalculatorUpdateCloningStrategy( + _cloningStrategyMock.Object, + _forcesUpdateStrategyMock.Object, + _primitivesUpdateStrategyMock.Object + ); + } + + [Test] + public void Update_WithNullSourceObject_ThrowsException() + { + // Arrange + var targetObject = Mock.Of(); + + // Act & Assert + Assert.Throws(() => _strategy.Update(targetObject, null)); + } + + [Test] + public void Update_WithNullTargetObject_ThrowsException() + { + // Arrange + var sourceObject = Mock.Of(); + + // Act & Assert + Assert.Throws(() => _strategy.Update(null, sourceObject)); + } + + [Test] + public void Update_WithSameSourceAndTarget_DoesNothing() + { + // Arrange + var sourceObject = Mock.Of(); + + // Act + _strategy.Update(sourceObject, sourceObject); + + // Assert + _forcesUpdateStrategyMock.VerifyNoOtherCalls(); + _primitivesUpdateStrategyMock.VerifyNoOtherCalls(); + } + + [Test] + public void Update_InvokesUpdateStrategiesOnInputData() + { + // Arrange + var sourceDataMock = new Mock(); + var targetDataMock = new Mock(); + + var sourceObjectMock = new Mock(); + sourceObjectMock.Setup(s => s.InputData).Returns(sourceDataMock.Object); + + var targetObjectMock = new Mock(); + targetObjectMock.Setup(t => t.InputData).Returns(targetDataMock.Object); + + // Act + _strategy.Update(targetObjectMock.Object, sourceObjectMock.Object); + + // Assert + _primitivesUpdateStrategyMock.Verify(ps => ps.Update(targetDataMock.Object, sourceDataMock.Object), Times.Once); + _forcesUpdateStrategyMock.Verify(fs => fs.Update(targetDataMock.Object, sourceDataMock.Object), Times.Once); + } + } + +} diff --git a/StructureHelperTests/UnitTests/UpdateStrategiesTests/HasCalculatorsUpdateCloningStrategyTests.cs b/StructureHelperTests/UnitTests/UpdateStrategiesTests/HasCalculatorsUpdateCloningStrategyTests.cs new file mode 100644 index 0000000..1157a0e --- /dev/null +++ b/StructureHelperTests/UnitTests/UpdateStrategiesTests/HasCalculatorsUpdateCloningStrategyTests.cs @@ -0,0 +1,138 @@ +using Moq; +using NUnit.Framework; +using StructureHelperCommon.Infrastructures.Exceptions; +using StructureHelperCommon.Infrastructures.Interfaces; +using StructureHelperCommon.Models.Calculators; +using StructureHelperLogics.NdmCalculations.Analyses.ByForces; +using StructureHelperLogics.NdmCalculations.Cracking; +using System; +using System.Collections.Generic; + +namespace StructureHelperTests.UnitTests.UpdateStrategiesTests +{ + + + [TestFixture] + public class HasCalculatorsUpdateCloningStrategyTests + { + private Mock _cloningStrategyMock; + private Mock> _forceCalculatorUpdateStrategyMock; + private Mock> _crackCalculatorUpdateStrategyMock; + private Mock> _limitCurvesCalculatorUpdateStrategyMock; + private HasCalculatorsUpdateCloningStrategy _strategy; + + [SetUp] + public void SetUp() + { + _cloningStrategyMock = new Mock(); + _forceCalculatorUpdateStrategyMock = new Mock>(); + _crackCalculatorUpdateStrategyMock = new Mock>(); + _limitCurvesCalculatorUpdateStrategyMock = new Mock>(); + + _strategy = new HasCalculatorsUpdateCloningStrategy( + _cloningStrategyMock.Object, + _forceCalculatorUpdateStrategyMock.Object, + _crackCalculatorUpdateStrategyMock.Object, + _limitCurvesCalculatorUpdateStrategyMock.Object + ); + } + + [Test] + public void Update_WithNullSourceObject_ThrowsException() + { + // Arrange + var targetObject = Mock.Of(); + + // Act & Assert + Assert.Throws(() => _strategy.Update(targetObject, null)); + } + + [Test] + public void Update_WithNullTargetObject_ThrowsException() + { + // Arrange + var sourceObject = Mock.Of(); + + // Act & Assert + Assert.Throws(() => _strategy.Update(null, sourceObject)); + } + + [Test] + public void Update_WithSameSourceAndTarget_DoesNothing() + { + // Arrange + var calculators = new List { Mock.Of() }; + var sourceObject = Mock.Of(s => s.Calculators == calculators); + var targetObject = sourceObject; + + // Act + _strategy.Update(targetObject, sourceObject); + + // Assert + _cloningStrategyMock.VerifyNoOtherCalls(); + _forceCalculatorUpdateStrategyMock.VerifyNoOtherCalls(); + _crackCalculatorUpdateStrategyMock.VerifyNoOtherCalls(); + _limitCurvesCalculatorUpdateStrategyMock.VerifyNoOtherCalls(); + } + + [Test] + public void Update_ProcessesEachCalculatorCorrectly() + { + // Arrange + var sourceForceCalculator = Mock.Of(x => x.Name == "Force"); + var sourceCrackCalculator = Mock.Of(x => x.Name == "Crack"); + var sourceLimitCurvesCalculator = Mock.Of(x => x.Name == "Curves"); + var sourceCalculators = new List + { + sourceForceCalculator, + sourceCrackCalculator, + sourceLimitCurvesCalculator + }; + var sourceObjectMock = new Mock(); + sourceObjectMock.Setup(s => s.Calculators).Returns(sourceCalculators); + + var targetCalculators = new List(); + var targetObjectMock = new Mock(); + targetObjectMock.Setup(t => t.Calculators).Returns(targetCalculators); + + var clonedForceCalculator = Mock.Of(); + var clonedCrackCalculator = Mock.Of(); + var clonedLimitCurvesCalculator = Mock.Of(); + + _cloningStrategyMock.Setup(cs => cs.Clone(It.Is(x => x.Name == "Force"), null)).Returns(clonedForceCalculator); + _cloningStrategyMock.Setup(cs => cs.Clone(It.Is(x => x.Name == "Crack"), null)).Returns(clonedCrackCalculator); + _cloningStrategyMock.Setup(cs => cs.Clone(It.Is(x => x.Name == "Curves"), null)).Returns(clonedLimitCurvesCalculator); + + // Act + _strategy.Update(targetObjectMock.Object, sourceObjectMock.Object); + + // Assert + Assert.That(targetCalculators, Has.Count.EqualTo(3)); + Assert.That(targetCalculators, Contains.Item(clonedForceCalculator)); + Assert.That(targetCalculators, Contains.Item(clonedCrackCalculator)); + Assert.That(targetCalculators, Contains.Item(clonedLimitCurvesCalculator)); + + _forceCalculatorUpdateStrategyMock.Verify(f => f.Update(clonedForceCalculator, sourceForceCalculator), Times.Once); + _crackCalculatorUpdateStrategyMock.Verify(c => c.Update(clonedCrackCalculator, sourceCrackCalculator), Times.Once); + _limitCurvesCalculatorUpdateStrategyMock.Verify(l => l.Update(clonedLimitCurvesCalculator, sourceLimitCurvesCalculator), Times.Once); + } + + [Test] + public void Update_WithUnknownCalculatorType_ThrowsException() + { + // Arrange + var unknownCalculator = Mock.Of(); + var sourceCalculators = new List { unknownCalculator }; + var sourceObjectMock = new Mock(); + sourceObjectMock.Setup(s => s.Calculators).Returns(sourceCalculators); + + var targetObjectMock = new Mock(); + targetObjectMock.Setup(t => t.Calculators).Returns(new List()); + + // Act & Assert + var exception = Assert.Throws(() => _strategy.Update(targetObjectMock.Object, sourceObjectMock.Object)); + Assert.That(exception.Message, Does.Contain(ErrorStrings.ObjectTypeIsUnknown)); + } + } + +} diff --git a/StructureHelperTests/UnitTests/UpdateStrategiesTests/LimitCurvesCalculatorUpdateCloningStrategyTests.cs b/StructureHelperTests/UnitTests/UpdateStrategiesTests/LimitCurvesCalculatorUpdateCloningStrategyTests.cs new file mode 100644 index 0000000..ae3a801 --- /dev/null +++ b/StructureHelperTests/UnitTests/UpdateStrategiesTests/LimitCurvesCalculatorUpdateCloningStrategyTests.cs @@ -0,0 +1,111 @@ +using Moq; +using NUnit.Framework; +using StructureHelperCommon.Infrastructures.Exceptions; +using StructureHelperCommon.Infrastructures.Interfaces; +using StructureHelperCommon.Models.Parameters; +using StructureHelperLogics.NdmCalculations.Analyses.ByForces; +using StructureHelperLogics.NdmCalculations.Analyses.ByForces.LimitCurve; +using StructureHelperLogics.NdmCalculations.Primitives; + +namespace StructureHelperTests.UnitTests.UpdateStrategiesTests +{ + + + + [TestFixture] + public class LimitCurvesCalculatorUpdateCloningStrategyTests + { + private Mock _cloningStrategyMock; + private Mock> _inputDataUpdateStrategyMock; + private LimitCurvesCalculatorUpdateCloningStrategy _strategy; + + [SetUp] + public void SetUp() + { + _cloningStrategyMock = new Mock(); + _inputDataUpdateStrategyMock = new Mock>(); + _strategy = new LimitCurvesCalculatorUpdateCloningStrategy( + _cloningStrategyMock.Object, + _inputDataUpdateStrategyMock.Object); + } + + [Test] + public void Update_WithNullSourceObject_ThrowsException() + { + // Arrange + var targetObject = Mock.Of(); + + // Act & Assert + Assert.Throws(() => _strategy.Update(targetObject, null)); + } + + [Test] + public void Update_WithNullTargetObject_ThrowsException() + { + // Arrange + var sourceObject = Mock.Of(); + + // Act & Assert + Assert.Throws(() => _strategy.Update(null, sourceObject)); + } + + [Test] + public void Update_WithSameSourceAndTarget_DoesNothing() + { + // Arrange + var sourceObject = Mock.Of(); + + // Act + _strategy.Update(sourceObject, sourceObject); + + // Assert + _cloningStrategyMock.VerifyNoOtherCalls(); + _inputDataUpdateStrategyMock.VerifyNoOtherCalls(); + } + + //[Test] + public void Update_UpdatesInputDataAndProcessesEachPrimitiveSeries() + { + // Arrange + var targetSeries = new NamedCollection { Collection = new List() }; + var targetData = Mock.Of(d => d.PrimitiveSeries == new List> { targetSeries }); + + var targetObjectMock = new Mock(); + targetObjectMock.Setup(t => t.InputData).Returns(targetData); + + var sourcePrimitive1 = Mock.Of(p => p.Name == "sp1"); + var sourcePrimitive2 = Mock.Of(p => p.Name == "sp2"); + var sourceSeries = new NamedCollection + { + Collection = new List { sourcePrimitive1, sourcePrimitive2 } + }; + var sourceData = Mock.Of(d => d.PrimitiveSeries == new List> { sourceSeries }); + + var sourceObjectMock = new Mock(); + sourceObjectMock.Setup(s => s.InputData).Returns(sourceData); + + var clonedPrimitive1 = Mock.Of(p => p.Name == "cp1"); + var clonedPrimitive2 = Mock.Of(p => p.Name == "cp2"); + + _cloningStrategyMock.Setup(cs => cs.Clone(It.Is(p => p.Name == "sp1"), null)).Returns(clonedPrimitive1); + _cloningStrategyMock.Setup(cs => cs.Clone(It.Is(p => p.Name == "sp2"), null)).Returns(clonedPrimitive2); + + // Act + _strategy.Update(targetObjectMock.Object, sourceObjectMock.Object); + + // Assert + _inputDataUpdateStrategyMock.Verify( + us => us.Update(targetData, sourceData), + Times.Once); + + Assert.That(targetSeries.Collection, Has.Count.EqualTo(2)); + Assert.That(targetSeries.Collection, Contains.Item(clonedPrimitive1)); + Assert.That(targetSeries.Collection, Contains.Item(clonedPrimitive2)); + + _cloningStrategyMock.Verify(cs => cs.Clone(sourcePrimitive1, null), Times.Once); + _cloningStrategyMock.Verify(cs => cs.Clone(sourcePrimitive2, null), Times.Once); + } + } + + +}