TestReportNode.java

package ship.test;

import static java.lang.System.currentTimeMillis;
import static java.util.Arrays.asList;
import static ship.test.TestReportNodeResult.Failure;
import static ship.test.TestReportNodeResult.Success;
import static ship.test.TestReportNodeResult.Unknown;

import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;

@NoArgsConstructor
public class TestReportNode<ResultDetailT> {

  @Getter
  @Setter
  protected String name;

  @Getter
  @Setter
  protected TestReportNodeResult result = Unknown;

  @Getter
  @Setter
  protected long startTime = currentTimeMillis();

  @Getter
  @Setter
  protected long endTime;

  @Getter
  @Setter
  protected ResultDetailT resultDetail;

  @Getter
  @Setter
  @NonNull
  protected List<TestReportNode<?>> children = new ArrayList<>();

  /**
   * Constructor with name, result, resultDetail and children.
   *
   * @param name node name
   * @param result test result
   * @param resultDetail result details
   * @param children child nodes
   */
  public TestReportNode(
      final String name,
      final TestReportNodeResult result,
      final ResultDetailT resultDetail,
      final TestReportNode<?>... children) {
    this.name = name;
    this.result = result;
    this.resultDetail = resultDetail;
    this.children.addAll(asList(children));
  }

  /**
   * Return if this node is success.
   *
   * @return if success
   */
  public boolean isSuccess() {
    switch (this.result) {
      case Success:
        return true;
      case Failure:
        return false;
      default:
        return children.stream().allMatch(child -> child.isSuccess());
    }
  }

  /**
   * Return if this node is failure.
   *
   * @return if failure
   */
  public boolean isFailure() {
    switch (this.result) {
      case Success:
        return false;
      case Failure:
        return true;
      default:
        return children.stream().anyMatch(child -> child.isFailure());
    }
  }

  /**
   * Return how many tests this node has.
   *
   * @return the number of tests
   */
  public int getTheNumberOfTests() {
    if (children.isEmpty()) {
      return 1;
    } else {
      return children.stream().map(TestReportNode::getTheNumberOfTests)
          .reduce((a, b) -> a + b).orElse(0);
    }
  }

  /**
   * Return how many successes this node has.
   *
   * @return the number of successes
   */
  public int getTheNumberOfSuccesses() {
    return aggregate(Success);
  }

  /**
   * Return how many failures this node has.
   *
   * @return the number of failures
   */
  public int getTheNumberOfFailures() {
    return aggregate(Failure);
  }

  protected int aggregate(final TestReportNodeResult filterValue) {
    if (children.isEmpty()) {
      if (this.result == filterValue) {
        return 1;
      } else {
        return 0;
      }
    } else {
      return children.stream().map(child -> child.aggregate(filterValue))
          .reduce((a, b) -> a + b).orElse(0);
    }
  }

  /**
   * Add child node.
   *
   * @param child node to add
   */
  public void addChild(TestReportNode<?> child) {
    this.children.add(child);
  }
}