AllStepCandidates.java

  1. package org.jbehave.core.embedder;

  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.Comparator;
  5. import java.util.EnumMap;
  6. import java.util.HashMap;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.Optional;
  10. import java.util.stream.Collector;
  11. import java.util.stream.Collector.Characteristics;
  12. import java.util.stream.Collectors;

  13. import org.jbehave.core.annotations.Conditional;
  14. import org.jbehave.core.annotations.ScenarioType;
  15. import org.jbehave.core.condition.StepConditionMatcher;
  16. import org.jbehave.core.steps.BeforeOrAfterStep;
  17. import org.jbehave.core.steps.CandidateSteps;
  18. import org.jbehave.core.steps.ConditionalStepCandidate;
  19. import org.jbehave.core.steps.StepCandidate;

  20. public class AllStepCandidates {
  21.     private final List<BeforeOrAfterStep> beforeStoriesSteps = new ArrayList<>();
  22.     private final List<BeforeOrAfterStep> afterStoriesSteps = new ArrayList<>();

  23.     private final List<BeforeOrAfterStep> beforeGivenStorySteps = new ArrayList<>();
  24.     private final List<BeforeOrAfterStep> afterGivenStorySteps = new ArrayList<>();

  25.     private final List<BeforeOrAfterStep> beforeStorySteps = new ArrayList<>();
  26.     private final List<BeforeOrAfterStep> afterStorySteps = new ArrayList<>();

  27.     private final Map<ScenarioType, List<BeforeOrAfterStep>> beforeScenarioSteps = new EnumMap<>(ScenarioType.class);
  28.     private final Map<ScenarioType, List<BeforeOrAfterStep>> afterScenarioSteps = new EnumMap<>(ScenarioType.class);

  29.     private final List<StepCandidate> regularSteps;

  30.     public AllStepCandidates(StepConditionMatcher stepConditionMatcher, List<CandidateSteps> candidateSteps) {

  31.         for (ScenarioType type : ScenarioType.values()) {
  32.             beforeScenarioSteps.put(type, new ArrayList<>());
  33.             afterScenarioSteps.put(type, new ArrayList<>());
  34.         }

  35.         for (CandidateSteps candidateStep : candidateSteps) {
  36.             beforeStoriesSteps.addAll(candidateStep.listBeforeStories());
  37.             afterStoriesSteps.addAll(candidateStep.listAfterStories());

  38.             beforeGivenStorySteps.addAll(candidateStep.listBeforeStory(true));
  39.             afterGivenStorySteps.addAll(candidateStep.listAfterStory(true));

  40.             beforeStorySteps.addAll(candidateStep.listBeforeStory(false));
  41.             afterStorySteps.addAll(candidateStep.listAfterStory(false));

  42.             candidateStep.listBeforeScenario().forEach(
  43.                     (scenarioType, steps) -> beforeScenarioSteps.get(scenarioType).addAll(steps));
  44.             candidateStep.listAfterScenario().forEach(
  45.                     (scenarioType, steps) -> afterScenarioSteps.get(scenarioType).addAll(steps));
  46.         }

  47.         this.regularSteps = candidateSteps.stream()
  48.                 .map(CandidateSteps::listCandidates)
  49.                 .flatMap(List::stream)
  50.                 .collect(stepCandidateCollector())
  51.                 .entrySet()
  52.                 .stream()
  53.                 .map(e -> {
  54.                     List<StepCandidate> candidates = e.getValue();
  55.                     boolean allCandidatesConditional = areAllCandidatesConditional(candidates);
  56.                     if (allCandidatesConditional) {
  57.                         return ConditionalStepCandidate.from(stepConditionMatcher, candidates);
  58.                     }
  59.                     if (candidates.size() == 1) {
  60.                         return candidates.get(0);
  61.                     }
  62.                     throw new DuplicateCandidateFound(e.getKey());
  63.                 })
  64.                 .collect(Collectors.toList());

  65.         sortBeforeSteps(beforeStoriesSteps);
  66.         sortAfterSteps(afterStoriesSteps);

  67.         sortBeforeSteps(beforeGivenStorySteps);
  68.         sortAfterSteps(afterGivenStorySteps);

  69.         sortBeforeSteps(beforeStorySteps);
  70.         sortAfterSteps(afterStorySteps);

  71.         beforeScenarioSteps.values().forEach(this::sortBeforeSteps);
  72.         afterScenarioSteps.values().forEach(this::sortAfterSteps);
  73.     }

  74.     private void sortBeforeSteps(List<BeforeOrAfterStep> beforeSteps) {
  75.         sortSteps(beforeSteps, Comparator.reverseOrder());
  76.     }

  77.     private void sortAfterSteps(List<BeforeOrAfterStep> afterSteps) {
  78.         sortSteps(afterSteps, Comparator.naturalOrder());
  79.     }

  80.     private void sortSteps(List<BeforeOrAfterStep> steps, Comparator<Integer> comparator) {
  81.         steps.sort(Comparator.comparing(BeforeOrAfterStep::getOrder, comparator));
  82.     }

  83.     public List<BeforeOrAfterStep> getBeforeStoriesSteps() {
  84.         return beforeStoriesSteps;
  85.     }

  86.     public List<BeforeOrAfterStep> getAfterStoriesSteps() {
  87.         return afterStoriesSteps;
  88.     }

  89.     public List<BeforeOrAfterStep> getBeforeStorySteps(boolean givenStory) {
  90.         return givenStory ? beforeGivenStorySteps : beforeStorySteps;
  91.     }

  92.     public List<BeforeOrAfterStep> getAfterStorySteps(boolean givenStory) {
  93.         return givenStory ? afterGivenStorySteps : afterStorySteps;
  94.     }

  95.     public List<BeforeOrAfterStep> getBeforeScenarioSteps(ScenarioType scenarioType) {
  96.         return beforeScenarioSteps.get(scenarioType);
  97.     }

  98.     public List<BeforeOrAfterStep> getAfterScenarioSteps(ScenarioType scenarioType) {
  99.         return afterScenarioSteps.get(scenarioType);
  100.     }

  101.     public List<StepCandidate> getRegularSteps() {
  102.         return regularSteps;
  103.     }

  104.     private static Collector<StepCandidate, Map<String, List<StepCandidate>>, Map<String, List<StepCandidate>>>
  105.         stepCandidateCollector() {
  106.         return Collector.of(HashMap::new, (map, candidate) -> {

  107.             String candidateWording = candidate.getStartingWord() + " " + candidate.getPatternAsString();

  108.             Optional<String> candidateKey = map.keySet().stream()
  109.                     .filter(k -> candidate.matches(k) && map.get(k).stream().allMatch(c -> c.matches(candidateWording)))
  110.                     .findFirst();

  111.             List<StepCandidate> candidates;
  112.             if (candidateKey.isPresent()) {
  113.                 candidates = map.get(candidateKey.get());
  114.             } else {
  115.                 candidates = new ArrayList<>();
  116.                 map.put(candidateWording, candidates);
  117.             }
  118.             candidates.add(candidate);
  119.         }, (l, r) -> l, Characteristics.IDENTITY_FINISH);
  120.     }

  121.     private boolean areAllCandidatesConditional(Collection<StepCandidate> candidates) {
  122.         return candidates.stream()
  123.                          .map(StepCandidate::getMethod)
  124.                          .allMatch(m -> m != null
  125.                              && (m.isAnnotationPresent(Conditional.class)
  126.                                      || m.getDeclaringClass().isAnnotationPresent(Conditional.class)));
  127.     }

  128. }