View Javadoc
1   /*
2    * Copyright 2023 Adrian Herscu
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package dev.aherscu.qa.jgiven.commons.steps;
17  
18  import static dev.aherscu.qa.testing.utils.FileUtilsExtensions.*;
19  import static dev.aherscu.qa.testing.utils.ThreadUtils.*;
20  import static org.apache.commons.lang3.StringUtils.*;
21  
22  import java.io.*;
23  import java.time.*;
24  import java.util.function.*;
25  
26  import javax.annotation.concurrent.*;
27  
28  import org.apache.commons.io.filefilter.*;
29  
30  import com.tngtech.jgiven.annotation.*;
31  import com.tngtech.jgiven.base.*;
32  
33  import dev.aherscu.qa.jgiven.commons.formatters.*;
34  import dev.aherscu.qa.jgiven.commons.model.*;
35  import dev.aherscu.qa.jgiven.commons.utils.*;
36  import lombok.*;
37  import lombok.extern.slf4j.*;
38  
39  /**
40   * Generic actions.
41   *
42   * @param <SELF>
43   *            the type of the subclass
44   * @param <T>
45   *            type of scenario
46   * @author aherscu
47   */
48  @ThreadSafe
49  @Slf4j
50  public class GenericActions<T extends AnyScenarioType, SELF extends GenericActions<T, SELF>>
51      extends StageEx<SELF>
52      implements ScenarioType<T> {
53  
54      /**
55       * Logs the construction of this stage.
56       */
57      public GenericActions() {
58          log.trace("when stage {} constructed", this); //$NON-NLS-1$
59      }
60  
61      /**
62       * Comment to be reported.
63       *
64       * @param comment
65       *            comment to be added to generated report
66       * @return {@link #self()}
67       *
68       * @deprecated use {@link ScenarioTestBase#section(String)}
69       */
70      @Override
71      @Deprecated
72      public SELF comment(final String comment) {
73          return self();
74      }
75  
76      /**
77       * Concatenates all files in specified source directory recursing into
78       * sub-directories.
79       *
80       * @param fileFilter
81       *            a file filter
82       * @param sourceDirectory
83       *            the source directory
84       * @param targetFile
85       *            the target file into which to concatenate
86       * @return {@link #self()}
87       */
88      @SneakyThrows(IOException.class)
89      public SELF concatenate_$_files_from_$_into(
90          final IOFileFilter fileFilter,
91          final File sourceDirectory,
92          final File targetFile) {
93  
94          for (val sourceFile : listFiles(
95              sourceDirectory, fileFilter, FileFilterUtils.trueFileFilter())) {
96              log.debug("concatenating {} into {}", sourceFile, targetFile); //$NON-NLS-1$
97              append(sourceFile, targetFile);
98          }
99  
100         return self();
101     }
102 
103     /**
104      * Deletes directory from specified path.
105      *
106      * @param directory
107      *            the directory path
108      * @return {@link #self()}
109      */
110     @SneakyThrows(IOException.class)
111     public SELF deleting_directory(final File directory) {
112         log.debug("deleting directory {}", directory.toString()); //$NON-NLS-1$
113         deleteDirectory(directory);
114         return self();
115     }
116 
117     /**
118      * Does nothing.
119      *
120      * @return {@link #self()}
121      */
122     public SELF doing_nothing() {
123         return doing_nothing(0);
124     }
125 
126     /**
127      * Does nothing for specified duration.
128      *
129      * @param millis
130      *            how many milliseconds to do nothing
131      * @return {@link #self()}
132      */
133     @SuppressWarnings("boxing")
134     public SELF doing_nothing(
135         @UnitFormatter.Annotation("ms") final long millis) {
136         log.debug("sleeping {} millis", millis);
137         sleep(millis);
138         return self();
139     }
140 
141     /**
142      * Does nothing for specified duration.
143      *
144      * @param duration
145      *            the duration to do nothing
146      * @return {@link #self()}
147      */
148     @NestedSteps
149     public SELF doing_nothing(final Duration duration) {
150         return doing_nothing(duration.toMillis());
151     }
152 
153     /**
154      * Failing with specified throwable for self-testing purposes.
155      *
156      * @param throwable
157      *            the throwable
158      * @return {@link #self()}
159      */
160     @SneakyThrows
161     public SELF failing_on_purpose_with(final Throwable throwable) {
162         log.debug("about to throw {}", throwable.toString());
163         throw throwable;
164     }
165 
166     /**
167      * Retries specified step according to pre-configured {@link #retryPolicy}.
168      *
169      * @param step
170      *            the step to retry
171      * @return {@link #self()}
172      * @see #beforeScenarioConfigurePolling()
173      */
174     public final SELF retrying(final Function<SELF, SELF> step) {
175         return retrying(new StepWithDescription<>(EMPTY, step));
176     }
177 
178     /**
179      * Retries specified step according to pre-configured {@link #retryPolicy}.
180      *
181      * @param step
182      *            the step to retry
183      * @return {@link #self()}
184      * @see #beforeScenarioConfigurePolling()
185      */
186     public final SELF retrying(final StepWithDescription<SELF> step) {
187         return retry(() -> step.apply(self()));
188     }
189 
190     /**
191      * Safely executes specified step, swallowing all exceptions.
192      *
193      * <p>
194      * <strong>IMPORTANT:</strong>must not be called from step method that is
195      * annotated with {@link NestedSteps} since this interferes with exception
196      * handling.
197      * </p>
198      *
199      * @param step
200      *            the step to execute
201      * @return {@link #self()}
202      */
203     @Hidden
204     public final SELF safely(final Function<SELF, SELF> step) {
205         return safely(new StepWithDescription<>(EMPTY, step));
206     }
207 
208     /**
209      * Safely executes specified step, swallowing all exceptions.
210      *
211      * <p>
212      * <strong>IMPORTANT:</strong>must not be called from step method that is
213      * annotated with {@link NestedSteps} since this interferes with exception
214      * handling.
215      * </p>
216      *
217      * @param step
218      *            the step to execute
219      * @return {@link #self()}
220      */
221     @Hidden
222     public final SELF safely(final StepWithDescription<SELF> step) {
223         return safely(() -> step.apply(self()));
224     }
225 }