diff --git a/src/Moryx/Workflows/Implementation/ComparingProperties.cs b/src/Moryx/Workflows/Implementation/ComparingProperties.cs new file mode 100644 index 000000000..0acd48bbf --- /dev/null +++ b/src/Moryx/Workflows/Implementation/ComparingProperties.cs @@ -0,0 +1,18 @@ +using Moryx.Workplans; +using System.Collections.Generic; + +namespace Moryx.Workflows.Implementation +{ + public class ComparingProperties + { + public IWorkplanStep Step { get; set;} + public IWorkplanStep NewStep { get; set; } + public Workplan Workplan { get; set; } + public Workplan NewWorkplan { get; set; } + public List IsChecked { get; set; } + public List NeedToCheck { get; set; } + public List NewNeedToCheck { get; set; } + } + +} + diff --git a/src/Moryx/Workflows/Implementation/Workplan.cs b/src/Moryx/Workflows/Implementation/Workplan.cs index 15aa6650c..bf473a2bd 100644 --- a/src/Moryx/Workflows/Implementation/Workplan.cs +++ b/src/Moryx/Workflows/Implementation/Workplan.cs @@ -1,9 +1,8 @@ -// Copyright (c) 2023, Phoenix Contact GmbH & Co. KG -// Licensed under the Apache License, Version 2.0 - using System.Collections.Generic; using System.Runtime.Serialization; - +using System.Linq; +using Moryx.Workflows.Implementation; + namespace Moryx.Workplans { /// @@ -92,5 +91,91 @@ public static Workplan Restore(List connectors, List { return new Workplan(connectors, steps); } - } -} + + public static bool CompareOutputs(ComparingProperties outputProperties) + { + + for (int a = 0; a < outputProperties.Step.Outputs.Length; a++) + { + var connector = outputProperties.Step.Outputs[a]; + var newConnector = outputProperties.NewStep.Outputs[a]; + + bool isNotEndConnector = !(connector.Classification.Equals(NodeClassification.End)) && !(newConnector.Classification.Equals(NodeClassification.End)); + bool isNotFailedConnector = !(connector.Classification.Equals(NodeClassification.Failed)) && !(newConnector.Classification.Equals(NodeClassification.Failed)); + + if (isNotEndConnector && isNotFailedConnector) + { + var follower = outputProperties.Workplan.Steps.FirstOrDefault(x => x.Inputs.Any(y => y.Equals(connector))); + var newFollower = outputProperties.NewWorkplan.Steps.FirstOrDefault(x => x.Inputs.Any(y => y.Equals(newConnector))); + + bool isSameStep = CompareSteps(follower, newFollower); + if (!isSameStep) + { + return false; + } + + bool isAlreadyChecked = (outputProperties.IsChecked.Contains(follower)); + + if (!(isAlreadyChecked)) + { + outputProperties.NeedToCheck.Add(follower); + outputProperties.NewNeedToCheck.Add(newFollower); + } + } + } + return true; + } + + public static bool CompareSteps(IWorkplanStep step1, IWorkplanStep step2) + { + return step1.GetType() == step2.GetType(); + } + + /// + /// Compare two workplans + /// + /// + /// + /// + public static bool Equals(Workplan workplan, Workplan newWorkplan) + { + var step = workplan.Steps.FirstOrDefault(x => x.Inputs.Any(y => y.Classification.Equals(NodeClassification.Start))); + var newStep = newWorkplan.Steps.FirstOrDefault(x => x.Inputs.Any(y => y.Classification.Equals(NodeClassification.Start))); + + List needToCheck = new List() { step }; + List newNeedToCheck = new List() { newStep }; + + List isChecked = new List(); + + while (needToCheck.Count != 0 && newNeedToCheck.Count != 0) + { + + bool isSameStep = CompareSteps(step, newStep); + if (!isSameStep) + { + return false; + } + var properties = new ComparingProperties() {Step = step, NewStep = newStep, Workplan = workplan, NewWorkplan = newWorkplan,IsChecked = isChecked, NeedToCheck = needToCheck, NewNeedToCheck = newNeedToCheck }; + bool sameConnections = CompareOutputs(properties); + if (!sameConnections) + { + return false; + } + needToCheck.Remove(step); + newNeedToCheck.Remove(newStep); + + isChecked.Add(step); + + if (needToCheck.Count != 0 && newNeedToCheck.Count != 0) + { + step = needToCheck[0]; + newStep = newNeedToCheck[0]; + } + + } + + return true; + } + + } +} \ No newline at end of file diff --git a/src/Tests/Moryx.Tests/Moryx.Tests.csproj b/src/Tests/Moryx.Tests/Moryx.Tests.csproj index 1ff29d6a4..d7ba8634a 100644 --- a/src/Tests/Moryx.Tests/Moryx.Tests.csproj +++ b/src/Tests/Moryx.Tests/Moryx.Tests.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingActivity.cs b/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingActivity.cs new file mode 100644 index 000000000..5d21a8ca7 --- /dev/null +++ b/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingActivity.cs @@ -0,0 +1,23 @@ +using Moryx.AbstractionLayer; +using Moryx.AbstractionLayer.Capabilities; + +namespace Moryx.Tests.Workplans.Dummies +{ + [ActivityResults(typeof(DefaultActivityResult))] + public class AssemblingActivity : Activity + { + public override ProcessRequirement ProcessRequirement => ProcessRequirement.NotRequired; + + public override ICapabilities RequiredCapabilities => new AssemblingCapabilities(); + + protected override ActivityResult CreateResult(long resultNumber) + { + return ActivityResult.Create((DefaultActivityResult)resultNumber); + } + + protected override ActivityResult CreateFailureResult() + { + return ActivityResult.Create(DefaultActivityResult.Failed); + } + } +} diff --git a/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingCapabilities.cs b/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingCapabilities.cs new file mode 100644 index 000000000..9127e8f0d --- /dev/null +++ b/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingCapabilities.cs @@ -0,0 +1,23 @@ +using Moryx.AbstractionLayer.Capabilities; + +namespace Moryx.Tests.Workplans.Dummies +{ + + public class AssemblingCapabilities : CapabilitiesBase + { + public int Value { get; set; } + + protected override bool ProvidedBy(ICapabilities provided) + { + var providedAssembling = provided as AssemblingCapabilities; + if (providedAssembling == null) + return false; + + if (providedAssembling.Value < Value) // Provided must be greater or equal + return false; + + return true; + } + } + +} \ No newline at end of file diff --git a/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingParameters.cs b/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingParameters.cs new file mode 100644 index 000000000..18738be1f --- /dev/null +++ b/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingParameters.cs @@ -0,0 +1,17 @@ +using Moryx.AbstractionLayer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Moryx.Tests.Workplans.Dummies +{ + public class AssemblingParameters : Parameters + { + protected override void Populate(IProcess process, Parameters instance) + { + + } + } +} diff --git a/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingTask.cs b/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingTask.cs new file mode 100644 index 000000000..68acdaf26 --- /dev/null +++ b/src/Tests/Moryx.Tests/Workplans/Dummies/AssemblingTask.cs @@ -0,0 +1,16 @@ +using Moryx.AbstractionLayer; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Moryx.Tests.Workplans.Dummies +{ + [Display(Name = "Assembling Task", Description = "Task which does something with a product")] + public class AssemblingTask : TaskStep + { + } +} diff --git a/src/Tests/Moryx.Tests/Workplans/Dummies/ColorizingTask.cs b/src/Tests/Moryx.Tests/Workplans/Dummies/ColorizingTask.cs new file mode 100644 index 000000000..3bd3cf207 --- /dev/null +++ b/src/Tests/Moryx.Tests/Workplans/Dummies/ColorizingTask.cs @@ -0,0 +1,16 @@ +using Moryx.AbstractionLayer; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Moryx.Tests.Workplans.Dummies +{ + [Display(Name = "PackagingTask", Description = "Task which does something with a product")] + public class ColorizingTask : TaskStep + { + } +} \ No newline at end of file diff --git a/src/Tests/Moryx.Tests/Workplans/Dummies/PackagingTask.cs b/src/Tests/Moryx.Tests/Workplans/Dummies/PackagingTask.cs new file mode 100644 index 000000000..19f6ff315 --- /dev/null +++ b/src/Tests/Moryx.Tests/Workplans/Dummies/PackagingTask.cs @@ -0,0 +1,16 @@ +using Moryx.AbstractionLayer; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Moryx.Tests.Workplans.Dummies +{ + [Display(Name = "PackagingTask", Description = "Task which does something with a product")] + public class PackagingTask : TaskStep + { + } +} diff --git a/src/Tests/Moryx.Tests/Workplans/EqualTest.cs b/src/Tests/Moryx.Tests/Workplans/EqualTest.cs new file mode 100644 index 000000000..8d0c6a405 --- /dev/null +++ b/src/Tests/Moryx.Tests/Workplans/EqualTest.cs @@ -0,0 +1,127 @@ +using Moryx.Workplans; +using Moryx.AbstractionLayer; +using NUnit.Framework; +using Moryx.Tests.Workplans.Dummies; + +namespace Moryx.Tests.Workplans +{ + + [TestFixture] + public class EqualTest + { + private Workplan firstWorkplan; + private Workplan secondWorkplan; + private Workplan thirdWorkplan; + private Workplan fourthWorkplan; + private Workplan fifthWorkplan; + private Workplan sixthWorkplan; + + public Workplan CreateSimpleWorkplan() + { + var plan = new Workplan(); + + var start = plan.AddConnector("Start", NodeClassification.Start); + var end = plan.AddConnector("End", NodeClassification.End); + var failed = plan.AddConnector("Failed", NodeClassification.Failed); + + var input = start; + var outputA = plan.AddConnector("A"); + var outputB = plan.AddConnector("B"); + + plan.AddStep(new AssemblingTask(), new AssemblingParameters(), input, outputA, outputB, failed); + + input = outputA; + plan.AddStep(new PackagingTask(), new AssemblingParameters(), input, end, end, failed); + + input = outputB; + plan.AddStep(new ColorizingTask(), new AssemblingParameters(), input, end, failed, failed); + return plan; + } + + public Workplan CreateWorkplanWithLoop() + { + var plan = new Workplan(); + + var start = plan.AddConnector("Start", NodeClassification.Start); + var end = plan.AddConnector("End", NodeClassification.End); + var failed = plan.AddConnector("Failed", NodeClassification.Failed); + + var input = start; + var outptuA = input; + var outputB = plan.AddConnector("A"); + + plan.AddStep(new AssemblingTask(), new AssemblingParameters(), input, outptuA, outputB, failed); + + input = outputB; + plan.AddStep(new PackagingTask(), new AssemblingParameters(), input, outputB, end, failed); + + return plan; + } + + public Workplan CreateWorkplanWithLoopsAndBranches() + { + var plan = new Workplan(); + + var start = plan.AddConnector("Start", NodeClassification.Start); + var end = plan.AddConnector("End", NodeClassification.End); + var failed = plan.AddConnector("Failed", NodeClassification.Failed); + + var outputA = plan.AddConnector("A"); + var outputB = plan.AddConnector("B"); + + plan.AddStep(new AssemblingTask(), new AssemblingParameters(), start, outputA, outputB, failed); + + var input = outputA; + + plan.AddStep(new PackagingTask(), new AssemblingParameters(), input, start, end, failed); + + input = outputB; + + plan.AddStep(new ColorizingTask(), new AssemblingParameters(), input, outputA, end, failed); + + return plan; + } + + [SetUp] + public void SetUp() + { + firstWorkplan = CreateSimpleWorkplan(); + secondWorkplan = CreateSimpleWorkplan(); + + thirdWorkplan = CreateWorkplanWithLoop(); + fourthWorkplan = CreateWorkplanWithLoop(); + + fifthWorkplan = CreateWorkplanWithLoopsAndBranches(); + sixthWorkplan = CreateWorkplanWithLoopsAndBranches(); + } + + [Test] + public void TestEqualWorkplans() + { + bool result = Workplan.Equals(firstWorkplan, secondWorkplan); + Assert.That(result, Is.True); + } + + [Test] + public void TestEqualWorkplansSimpleLoop() + { + bool result = Workplan.Equals(thirdWorkplan, fourthWorkplan); + Assert.That(result, Is.True); + } + + [Test] + public void TestEqualWorkplansDoubleLoop() + { + bool result = Workplan.Equals(fifthWorkplan, sixthWorkplan); + Assert.That(result, Is.True); + } + + [Test] + public void TestUnequalWorkplans() + { + bool r = Workplan.Equals(firstWorkplan, sixthWorkplan); + Assert.That(r, Is.False); + } + } + +}