Ensured.java

1
package com.github.dakusui.actionunit.actions;
2
3
import com.github.dakusui.actionunit.core.Action;
4
import com.github.dakusui.actionunit.exceptions.ActionException;
5
6
import java.util.Formatter;
7
import java.util.LinkedList;
8
import java.util.List;
9
10
import static com.github.dakusui.actionunit.core.ActionSupport.nop;
11
import static com.github.dakusui.actionunit.exceptions.ActionException.wrap;
12
import static java.util.Objects.requireNonNull;
13
14
/**
15
 * An action whose success of the "target" is ensured by the "ensurer" actions.
16
 *
17
 * How it works?::
18
 * Each action returned by {@code Ensured#ensurers()} is performed one by one.
19
 * After an entry from {@code ensurers()} is performed successfully, the target action
20
 * will be performed ({@code target()}.
21
 * If the target is performed successfully, this action finishes immediately and  successfully.
22
 * If this step is tried for all the ensurers but no attempt finishes successfully, the entire action will fail.
23
 *
24
 * If an exception thrown by a target or an ensurer is not "recoverable", the entire action will fail immediately.
25
 * Whether it is recoverable or not is determined by the return value of a method {@code Ensured#isRecoverable(Throwable)}.
26
 *
27
 * @see Ensured#ensurers()
28
 * @see Ensured#target()
29
 * @see Ensured#isRecoverable(Throwable)
30
 */
31
public interface Ensured extends Action {
32
  /**
33
   * An exception which tells the framework that it should not be recovered by the
34
   * {@code Ensured} action mechanism.
35
   */
36
  class Abort extends ActionException {
37
    public Abort(String message) {
38
      super(message);
39
    }
40
  }
41
42
  /**
43
   * An exception which tells the framework that a recovery requested by the
44
   * {@code Ensured} action mechanism.
45
   */
46
  class RequestRetry extends ActionException {
47
    public RequestRetry(String message) {
48
      super(message);
49
    }
50
  }
51
52
  /**
53
   * Checks if a given `exception` is recoverable by this object.
54
   *
55
   * @param exception An exception to be checked.
56
   * @return `true` - Can be recovered / `false` - Otherwise.
57
   */
58
  default boolean isRecoverable(Throwable exception) {
59 1 1. isRecoverable : negated conditional → SURVIVED
    if (exception instanceof RequestRetry)
60 1 1. isRecoverable : replaced boolean return with false for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → KILLED
      return true;
61 1 1. isRecoverable : negated conditional → KILLED
    if (exception instanceof Abort)
62 1 1. isRecoverable : replaced boolean return with true for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → NO_COVERAGE
      return false;
63 1 1. isRecoverable : negated conditional → KILLED
    if ("IncompleteExecutionException".equals(exception.getClass().getSimpleName()))
64 1 1. isRecoverable : replaced boolean return with true for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → NO_COVERAGE
      return false;
65 1 1. isRecoverable : negated conditional → SURVIVED
    if ("AssertionFailedError".equals(exception.getClass().getSimpleName()))
66 1 1. isRecoverable : replaced boolean return with false for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → NO_COVERAGE
      return true;
67 2 1. isRecoverable : replaced boolean return with true for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → SURVIVED
2. isRecoverable : negated conditional → KILLED
    return !(exception instanceof Error);
68
  }
69
70
  /**
71
   * Rethrows a given `exception`, when it is not recoverable.
72
   *
73
   * @param exception An exception to be rethrown.
74
   * @param <T>       Type of the `exception`.
75
   * @return A type placeholder, never be returned.
76
   */
77
  default <T extends Throwable> T rethrow(T exception) {
78 1 1. rethrow : negated conditional → NO_COVERAGE
    if (exception instanceof Error)
79
      throw (Error) exception;
80 1 1. rethrow : negated conditional → NO_COVERAGE
    if (exception instanceof RuntimeException)
81
      throw (RuntimeException) exception;
82
    throw new ActionException(exception.getMessage(),exception);
83
  }
84
85
  /**
86
   * Returns a target action to be ensured its success.
87
   * This action will be performed repeatedly until it succeeds.
88
   *
89
   * @return A target action.
90
   * @see Ensured#ensurers()
91
   */
92
  Action target();
93
94
  /**
95
   * Returns a list of "ensurer" actions.
96
   *
97
   * An ensurer is an action that may make preconditions of the "target action".
98
   *
99
   * @return A list of "ensurer" actions.
100
   */
101
  List<Action> ensurers();
102
103
  @Override
104
  default void accept(Visitor visitor) {
105 1 1. accept : removed call to com/github/dakusui/actionunit/core/Action$Visitor::visit → KILLED
    visitor.visit(this);
106
  }
107
108
  @Override
109
  default void formatTo(Formatter formatter, int flags, int width, int precision) {
110
    formatter.format("ensure:%s using", this.target());
111
  }
112
113
  /**
114
   * An implementation of `Ensured` action's interface.
115
   */
116
  class Impl implements Ensured {
117
    private final List<Action> ensurers;
118
    private final Action       target;
119
120
    @SuppressWarnings("unchecked")
121
    public <T extends Throwable, R extends Throwable> Impl(Action target, List<Action> ensurers) {
122
      this.target = requireNonNull(target);
123
      this.ensurers = requireNonNull(ensurers);
124
    }
125
126
    @Override
127
    public Action target() {
128 1 1. target : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Impl::target → KILLED
      return this.target;
129
    }
130
131
    @Override
132
    public List<Action> ensurers() {
133 1 1. ensurers : replaced return value with Collections.emptyList for com/github/dakusui/actionunit/actions/Ensured$Impl::ensurers → KILLED
      return this.ensurers;
134
    }
135
  }
136
137
  /**
138
   * A builder class of `Ensured` action.
139
   *
140
   * @see Ensured
141
   */
142
  class Builder extends Action.Builder<Ensured> {
143
    private       Action       target;
144
    private final List<Action> ensurers = new LinkedList<>();
145
146
    /**
147
     * Sets `target` action to this builder.
148
     *
149
     * @param target A target action.
150
     * @return This object.
151
     */
152
    public Builder target(Action target) {
153
      this.target = requireNonNull(target);
154 1 1. target : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::target → SURVIVED
      return this;
155
    }
156
157
    /**
158
     * Adds an `ensurer` action to this builder object.
159
     *
160
     * @param ensurer An ensurer action to be added.
161
     * @return This object.
162
     */
163
    public Builder with(Action ensurer) {
164
      ensurers.add(requireNonNull(ensurer));
165 1 1. with : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::with → KILLED
      return this;
166
    }
167
168
    /**
169
     * Adds a "nop" (no operation) action to this builder object as an ensurer.
170
     * This method is useful, when the target action may succeed without any preparation.
171
     *
172
     * @return This object.
173
     */
174
    public Builder withNop() {
175 1 1. withNop : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::withNop → KILLED
      return this.with(nop());
176
    }
177
178
    /**
179
     * Builds and returns an `Ensured` action object.
180
     *
181
     * @return An `Ensured` action.
182
     */
183
    public Ensured build() {
184 1 1. build : replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::build → KILLED
      return new Impl(this.target, this.ensurers);
185
    }
186
  }
187
}

Mutations

59

1.1
Location : isRecoverable
Killed by : none
negated conditional → SURVIVED

60

1.1
Location : isRecoverable
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithThreeEnsurers_whenPerform_thenBehavesAsExpected(com.github.dakusui.actionunit.scenarios.EnsuredTest)
replaced boolean return with false for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → KILLED

61

1.1
Location : isRecoverable
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithThreeEnsurersFirstFailing_whenPerform_thenBehavesAsExpected(com.github.dakusui.actionunit.scenarios.EnsuredTest)
negated conditional → KILLED

62

1.1
Location : isRecoverable
Killed by : none
replaced boolean return with true for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → NO_COVERAGE

63

1.1
Location : isRecoverable
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithThreeEnsurersFirstFailing_whenPerform_thenBehavesAsExpected(com.github.dakusui.actionunit.scenarios.EnsuredTest)
negated conditional → KILLED

64

1.1
Location : isRecoverable
Killed by : none
replaced boolean return with true for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → NO_COVERAGE

65

1.1
Location : isRecoverable
Killed by : none
negated conditional → SURVIVED

66

1.1
Location : isRecoverable
Killed by : none
replaced boolean return with false for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → NO_COVERAGE

67

1.1
Location : isRecoverable
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithThreeEnsurersFirstFailing_whenPerform_thenBehavesAsExpected(com.github.dakusui.actionunit.scenarios.EnsuredTest)
negated conditional → KILLED

2.2
Location : isRecoverable
Killed by : none
replaced boolean return with true for com/github/dakusui/actionunit/actions/Ensured::isRecoverable → SURVIVED

78

1.1
Location : rethrow
Killed by : none
negated conditional → NO_COVERAGE

80

1.1
Location : rethrow
Killed by : none
negated conditional → NO_COVERAGE

105

1.1
Location : accept
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithTwoEnsurers_whenPerformActionPassingOnThirdAttempt_thenFail(com.github.dakusui.actionunit.scenarios.EnsuredTest)
removed call to com/github/dakusui/actionunit/core/Action$Visitor::visit → KILLED

128

1.1
Location : target
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithTwoEnsurers_whenPerformActionPassingOnThirdAttempt_thenFail(com.github.dakusui.actionunit.scenarios.EnsuredTest)
replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Impl::target → KILLED

133

1.1
Location : ensurers
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithThreeEnsurers_whenPerform_thenBehavesAsExpected(com.github.dakusui.actionunit.scenarios.EnsuredTest)
replaced return value with Collections.emptyList for com/github/dakusui/actionunit/actions/Ensured$Impl::ensurers → KILLED

154

1.1
Location : target
Killed by : none
replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::target → SURVIVED

165

1.1
Location : with
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithTwoEnsurers_whenPerformActionPassingOnThirdAttempt_thenFail(com.github.dakusui.actionunit.scenarios.EnsuredTest)
replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::with → KILLED

175

1.1
Location : withNop
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithTwoEnsurers_whenPerformActionPassingOnThirdAttempt_thenFail(com.github.dakusui.actionunit.scenarios.EnsuredTest)
replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::withNop → KILLED

184

1.1
Location : build
Killed by : com.github.dakusui.actionunit.scenarios.EnsuredTest.givenEnsureWithTwoEnsurers_whenPerformActionPassingOnThirdAttempt_thenFail(com.github.dakusui.actionunit.scenarios.EnsuredTest)
replaced return value with null for com/github/dakusui/actionunit/actions/Ensured$Builder::build → KILLED

Active mutators

Tests examined


Report generated by PIT 1.7.3