All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dakusui.jcunit8.factorspace.fsm.Scenario Maven / Gradle / Ivy

The newest version!
package com.github.dakusui.jcunit8.factorspace.fsm;

import com.github.dakusui.jcunit.exceptions.InvalidTestException;
import com.github.dakusui.jcunit.fsm.Action;
import com.github.dakusui.jcunit.fsm.Args;
import com.github.dakusui.jcunit.fsm.FiniteStateMachine;
import com.github.dakusui.jcunit.fsm.State;
import com.github.dakusui.jcunit.fsm.spec.FsmSpec;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

import static java.util.stream.Collectors.toList;

public interface Scenario extends Stimulus {
  Sequence setUp();

  Sequence main();

  static > Scenario.Builder builder(String name, Class specClass) {
    return new Builder<>(name, specClass);
  }

  String name();

  class Impl implements Scenario {
    private final Sequence setUp;
    private final Sequence main;
    private final String        name;

    public Impl(String name, Sequence setUp, Sequence main) {
      this.setUp = setUp;
      this.main = main;
      this.name = Objects.requireNonNull(name);
    }

    @Override
    public Sequence setUp() {
      return this.setUp;
    }

    @Override
    public Sequence main() {
      return this.main;
    }

    @Override
    public String name() {
      return this.name;
    }

    @Override
    public void accept(Player player) {
      player.visit(this);
    }

    @Override
    public String toString() {
      return String.format("setUp:%s; main:%s", setUp, main);
    }
  }

  class Builder> {
    private final Class             spec;
    private final FiniteStateMachine fsm;
    private final String                  name;
    private       SPEC                    startFrom;
    private final List> edges = new LinkedList<>();

    public Builder(String name, Class spec) {
      this.name = name;
      this.spec = Objects.requireNonNull(spec);
      this.fsm = FiniteStateMachine.create(name, spec);
      this.startFrom(this.fsm.initialState().spec());
    }

    public Builder startFrom(SPEC state) {
      this.startFrom = Objects.requireNonNull(state);
      return this;
    }

    public Builder doAction(String name, Object... args) {
      Objects.requireNonNull(name);
      return this.doAction(
          findAction(name),
          new Args(args)
      );
    }

    public Scenario build() {
      Sequence setup = new FsmComposer<>(
          this.name,
          this.fsm,
          -1
      ).composeScenarioToBringUpFsmTo(
          findState(
              this.startFrom
          )
      );
      //noinspection Convert2MethodRef
      Sequence main = this.edges.stream().collect(
          () -> new Sequence.Builder<>(),
          Sequence.Builder::add,
          (Sequence.Builder builder1, Sequence.Builder builder2) -> {
            builder1.addAll(builder2.edges);
            builder2.addAll(builder1.edges);
          }
      ).build();
      return new Impl<>(this.name, setup, main);
    }

    private Action findAction(String name) {
      return this.fsm.actions().stream(
      ).filter(
          action -> action.id().startsWith(name)
      ).findFirst(
      ).orElseThrow(
          () -> new InvalidTestException(
              String.format(
                  "No action matching '%s' was found in '%s': [%s]",
                  name,
                  this.spec.getCanonicalName(),
                  this.fsm.actions().stream(
                  ).map(
                      Action::id
                  ).collect(
                      toList()
                  )
              )
          )
      );
    }

    private Builder doAction(Action action, Args args) {
      this.edges.add(new Edge.Builder<>(currentState())
          .with(action, args)
          .to(currentState().expectation(action, args).state)
          .build());
      return this;
    }

    private State findState(SPEC stateSpec) {
      return this.fsm.states().stream(
      ).filter(
          eachState -> eachState.spec().equals(stateSpec)
      ).findFirst(
      ).orElseThrow(
          () -> new InvalidTestException(
              String.format(
                  "No state matching '%s' was found in '%s': [%s]",
                  stateSpec,
                  this.spec.getCanonicalName(),
                  this.fsm.states().stream(
                  ).map(
                      eachState -> eachState == this.fsm.initialState() ?
                          String.format("*%s*", eachState.spec()) :
                          eachState.spec().toString()
                  ).collect(
                      toList()
                  )
              )
          )
      );
    }

    private State currentState() {
      return this.edges.isEmpty() ?
          findState(this.startFrom) :
          this.edges.get(this.edges.size() - 1).to;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy