From 1c2ebb4612f7d3b094c636fe8625dccc78b476b5 Mon Sep 17 00:00:00 2001 From: cristianpela Date: Fri, 21 Aug 2020 11:32:25 +0300 Subject: [PATCH 1/2] #473. StepComposer implemented+tested. --- .../selfxdsd/core/managers/StepComposer.java | 56 +++++++++++++++++++ .../core/managers/StepComposerTestCase.java | 49 ++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 self-core-impl/src/main/java/com/selfxdsd/core/managers/StepComposer.java create mode 100644 self-core-impl/src/test/java/com/selfxdsd/core/managers/StepComposerTestCase.java diff --git a/self-core-impl/src/main/java/com/selfxdsd/core/managers/StepComposer.java b/self-core-impl/src/main/java/com/selfxdsd/core/managers/StepComposer.java new file mode 100644 index 00000000..d158bde2 --- /dev/null +++ b/self-core-impl/src/main/java/com/selfxdsd/core/managers/StepComposer.java @@ -0,0 +1,56 @@ +package com.selfxdsd.core.managers; + +import com.selfxdsd.api.pm.Step; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.function.Function; + +/** + * Helper class that allows chaining {@link com.selfxdsd.api.pm.Intermediary} + * steps. + * @author criske + * @version $Id$ + * @since 0.0.20 + */ +public final class StepComposer { + + /** + * Call stack of step functions. Usually this functions produce + * {@link com.selfxdsd.api.pm.Intermediary} steps. + */ + private final Deque> callStack = new ArrayDeque<>(); + + /** + * Next Step in chain. + * @param stepFunction Step Function. + * @return Step, usually an Intermediary. + */ + public StepComposer next(final Function stepFunction) { + callStack.push(stepFunction); + return this; + } + + /** + * Finishes the chain into one step. + * @param lastStep Last Step. + * @return Composed Step. + */ + public Step finish(final Step lastStep) { + Step composedStep = lastStep; + while (!callStack.isEmpty()) { + composedStep = callStack.pop().apply(composedStep); + } + return composedStep; + } + + /** + * Finishes the chain into one step. + * @return Composed Step. + */ + public Step finish(){ + return finish(lastly -> {}); + } + +} + diff --git a/self-core-impl/src/test/java/com/selfxdsd/core/managers/StepComposerTestCase.java b/self-core-impl/src/test/java/com/selfxdsd/core/managers/StepComposerTestCase.java new file mode 100644 index 00000000..a9b6e414 --- /dev/null +++ b/self-core-impl/src/test/java/com/selfxdsd/core/managers/StepComposerTestCase.java @@ -0,0 +1,49 @@ +package com.selfxdsd.core.managers; + +import com.selfxdsd.api.Event; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Unit tests for {@link StepComposer}. + * @author criske + * @version $Id$ + * @since 0.0.20 + */ +public final class StepComposerTestCase { + + /** + * Executes the steps in order of chaining. + */ + @Test + public void executesStepsInOrder() { + final StringBuilder builder = new StringBuilder(); + final AtomicInteger counter = new AtomicInteger(); + new StepComposer() + .next(s -> e -> { + builder.append(counter.incrementAndGet()); + s.perform(e); + }) + .next(s -> e -> { + builder.append(counter.incrementAndGet()); + s.perform(e); + }) + .next(s -> e -> { + builder.append(counter.incrementAndGet()); + s.perform(e); + }) + .next(s -> e -> { + builder.append(counter.incrementAndGet()); + s.perform(e); + }) + .finish(lastly -> builder.append(counter.incrementAndGet())) + .perform(Mockito.mock(Event.class)); + final String order = builder.toString(); + MatcherAssert.assertThat(order, Matchers.equalTo("12345")); + } + +} From 605a79b5e2f9a5b395f3af0408e5e168a2baf5a4 Mon Sep 17 00:00:00 2001 From: cristianpela Date: Sat, 22 Aug 2020 14:27:59 +0300 Subject: [PATCH 2/2] #473. StepComposer implemented+tested. - support for PreConditionCheck. --- .../selfxdsd/core/managers/StepComposer.java | 85 +++++++++++++++++++ .../core/managers/StepComposerTestCase.java | 58 +++++++++++++ 2 files changed, 143 insertions(+) diff --git a/self-core-impl/src/main/java/com/selfxdsd/core/managers/StepComposer.java b/self-core-impl/src/main/java/com/selfxdsd/core/managers/StepComposer.java index d158bde2..5b28b3c8 100644 --- a/self-core-impl/src/main/java/com/selfxdsd/core/managers/StepComposer.java +++ b/self-core-impl/src/main/java/com/selfxdsd/core/managers/StepComposer.java @@ -4,11 +4,16 @@ import java.util.ArrayDeque; import java.util.Deque; +import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Supplier; /** * Helper class that allows chaining {@link com.selfxdsd.api.pm.Intermediary} * steps. + *
+ * It also provides composition support for + * {@link com.selfxdsd.api.pm.PreconditionCheck}. * @author criske * @version $Id$ * @since 0.0.20 @@ -31,6 +36,20 @@ public StepComposer next(final Function stepFunction) { return this; } + /** + * Stars a ConditionComposer. + * @param when BiFunction providing onTrue, onFalse. Returning should be a + * {@link com.selfxdsd.api.pm.PreconditionCheck}. + * @return ConditionComposer. + */ + public ConditionComposer when(final BiFunction when) { + if(!callStack.isEmpty()){ + throw new IllegalStateException("Condition composition can't be " + + " called after an next() call!"); + } + return new ConditionComposer(when); + } + /** * Finishes the chain into one step. * @param lastStep Last Step. @@ -52,5 +71,71 @@ public Step finish(){ return finish(lastly -> {}); } + + /** + * StepComposer for a PreconditionCheck. + */ + public static final class ConditionComposer { + + /** + * BiFunction providing onTrue, onFalse steps. Returning should be a + * PreconditionCheck. + */ + private final BiFunction when; + + /** + * OnTrue Step supplier. + */ + private Supplier onTrue; + + /** + * OnFalse Step supplier. + */ + private Supplier onFalse; + + /** + * Private constructor. + * @param when BiFunction providing onTrue, onFalse. Returning + * should be a PreconditionCheck. + */ + private ConditionComposer(final BiFunction when) { + this.when = when; + } + + /** + * OnTrue setter. + * @param onTrue OnTrue Step supplier. + * @return This ConditionComposer. + */ + public ConditionComposer onTrue(final Supplier onTrue){ + this.onTrue = onTrue; + return this; + } + + /** + * OnFalse setter. + * @param onFalse OnFalse Step supplier. + * @return This ConditionComposer. + */ + public ConditionComposer onFalse(final Supplier onFalse){ + this.onFalse = onFalse; + return this; + } + + /** + * Finishes the composition into a composed Step provided by `when`. + * @return Step. + */ + public Step finish(){ + if (onFalse == null) { + onFalse = () -> e -> { }; + } + if (onTrue == null) { + onTrue = () -> e -> { }; + } + return when.apply(onTrue.get(), onFalse.get()); + } + } + } diff --git a/self-core-impl/src/test/java/com/selfxdsd/core/managers/StepComposerTestCase.java b/self-core-impl/src/test/java/com/selfxdsd/core/managers/StepComposerTestCase.java index a9b6e414..6fa60052 100644 --- a/self-core-impl/src/test/java/com/selfxdsd/core/managers/StepComposerTestCase.java +++ b/self-core-impl/src/test/java/com/selfxdsd/core/managers/StepComposerTestCase.java @@ -46,4 +46,62 @@ public void executesStepsInOrder() { MatcherAssert.assertThat(order, Matchers.equalTo("12345")); } + /** + * Can perform conditional composition on true branch. + */ + @Test + public void shouldTakeTrueConditionBranch(){ + final StringBuilder builder = new StringBuilder(); + final AtomicInteger counter = new AtomicInteger(); + new StepComposer() + .when((tru, fls) -> e -> { + builder.append("true"); + tru.perform(e); + }) + .onTrue(() -> new StepComposer() + .next(s -> e -> { + builder.append(counter.incrementAndGet()); + s.perform(e); + }) + .next(s -> e -> { + builder.append(counter.incrementAndGet()); + s.perform(e); + }) + .finish()) + .finish() + .perform(Mockito.mock(Event.class)); + + final String order = builder.toString(); + MatcherAssert.assertThat(order, Matchers.equalTo("true12")); + } + + /** + * Can perform conditional composition on false branch. + */ + @Test + public void shouldTakeFalseConditionBranch(){ + final StringBuilder builder = new StringBuilder(); + final AtomicInteger counter = new AtomicInteger(); + new StepComposer() + .when((tru, fls) -> e -> { + builder.append("false"); + fls.perform(e); + }) + .onFalse(() -> new StepComposer() + .next(s -> e -> { + builder.append(counter.incrementAndGet()); + s.perform(e); + }) + .next(s -> e -> { + builder.append(counter.incrementAndGet()); + s.perform(e); + }) + .finish()) + .finish() + .perform(Mockito.mock(Event.class)); + + final String order = builder.toString(); + MatcherAssert.assertThat(order, Matchers.equalTo("false12")); + } + }