Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#473. StepComposer implemented+tested. #474

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package com.selfxdsd.core.managers;

import com.selfxdsd.api.pm.Step;

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.
* <br/>
* It also provides composition support for
* {@link com.selfxdsd.api.pm.PreconditionCheck}.
* @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<Function<Step, Step>> callStack = new ArrayDeque<>();

/**
* Next Step in chain.
* @param stepFunction Step Function.
* @return Step, usually an Intermediary.
*/
public StepComposer next(final Function<Step, Step> stepFunction) {
callStack.push(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<Step, Step, Step> 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.
* @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 -> {});
}


/**
* StepComposer for a PreconditionCheck.
*/
public static final class ConditionComposer {

/**
* BiFunction providing onTrue, onFalse steps. Returning should be a
* PreconditionCheck.
*/
private final BiFunction<Step, Step, Step> when;

/**
* OnTrue Step supplier.
*/
private Supplier<Step> onTrue;

/**
* OnFalse Step supplier.
*/
private Supplier<Step> onFalse;

/**
* Private constructor.
* @param when BiFunction providing onTrue, onFalse. Returning
* should be a PreconditionCheck.
*/
private ConditionComposer(final BiFunction<Step, Step, Step> when) {
this.when = when;
}

/**
* OnTrue setter.
* @param onTrue OnTrue Step supplier.
* @return This ConditionComposer.
*/
public ConditionComposer onTrue(final Supplier<Step> onTrue){
this.onTrue = onTrue;
return this;
}

/**
* OnFalse setter.
* @param onFalse OnFalse Step supplier.
* @return This ConditionComposer.
*/
public ConditionComposer onFalse(final Supplier<Step> 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());
}
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
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"));
}

/**
* 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"));
}

}