001/**
002 * Powerunit - A JDK1.8 test framework
003 * Copyright (C) 2014 Mathieu Boretti.
004 *
005 * This file is part of Powerunit
006 *
007 * Powerunit is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation, either version 3 of the License, or
010 * (at your option) any later version.
011 *
012 * Powerunit is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
019 */
020package ch.powerunit;
021
022import java.io.PrintStream;
023import java.util.Arrays;
024import java.util.function.BiConsumer;
025import java.util.function.Consumer;
026import java.util.function.Function;
027import java.util.function.Predicate;
028import java.util.function.Supplier;
029
030import org.hamcrest.Matcher;
031
032import ch.powerunit.exception.AssumptionError;
033import ch.powerunit.helpers.StreamParametersMapFunction;
034import ch.powerunit.rules.SystemPropertiesRule;
035import ch.powerunit.rules.SystemStreamRule;
036import ch.powerunit.rules.TemporaryFolder;
037import ch.powerunit.rules.TemporaryFolder.TemporaryFolderBuilder;
038import ch.powerunit.rules.TestListenerRule;
039import ch.powerunit.rules.impl.TemporaryFolderImpl;
040
041/**
042 * This is the interface to be implemented by test class, in order to have
043 * access to the test DSL.
044 * <p>
045 * This interface is only used to provide the DSL capabilities for the test ; It
046 * is not used as a marker by the framework.
047 * <p>
048 * Several functionalities are provided here :
049 * <ul>
050 * <li>Assertion capabilities (assertion on Object, Iterable, Function, Piece of
051 * code).</li>
052 * <li>Matchers to be used as end parameter of the assertion.</li>
053 * <li><code>{@link #before(Runnable...)}</code> to setup a before action.</li>
054 * <li><code>{@link #after(Runnable...)}</code> to setup a after action.</li>
055 * <li><code>{@link #mockitoRule()}</code> to setup mockito.</li>
056 * <li><code>{@link #systemPropertiesRule(String...)}</code> to restore
057 * properties system after test ; Several others method related to
058 * systemProperties exist.</li>
059 * <li><code>{@link #temporaryFolder()}</code> to support temporary folder.</li>
060 * <li><code>{@link #parametersMap(int, Function)}</code> to create Map function
061 * to be used on the stream to be provided by the {@link Parameters
062 * &#64;Parameters}. Other variants of this method may exist.</li>
063 * <li>Severals method of the form <code>tester...</code> (for instance
064 * <code>{@link #testerOfMatcher(Class)}</code>) that can be used with the
065 * <code>@{@link TestDelegate}</code> annotation to test some standard classes
066 * (like Matchers, Comparator, Function, etc).
067 * </ul>
068 *
069 * @author borettim
070 *
071 */
072public interface TestSuite extends Assert, Assume, Matchers,
073                TestFrameworkSupport, ConverterMethod {
074
075        /**
076         * A static field that is a testsuite (to avoid implementing TestSuite in
077         * test, in the rare case when it may be required).
078         * <p>
079         * The main use case is to access the stream functionnalities from a
080         * {@link Parameters &#64;Parameters} annotated method, as this method must
081         * be static.
082         */
083        static TestSuite DSL = new TestSuite() {
084        };
085
086        /**
087         * Build a before testrule.
088         * <p>
089         * The passed runnable will be used before each test. The exact location of
090         * the execution is depending on where this used on the testRule chain.
091         * <p>
092         * In the much simple case (just one method to be executed before each
093         * test), the syntax is :
094         * 
095         * <pre>
096         * &#064;Rule
097         * public TestRule rule = before(this::beforeMethodName);
098         * </pre>
099         * 
100         * @param befores
101         *            the befores
102         * @return {@link TestRule the rule chain}.
103         * @see Rule
104         */
105        default TestRule before(Runnable... befores) {
106                return Arrays.stream(befores).map(TestRule::before)
107                                .reduce((prev, next) -> prev.around(next)).get();
108        }
109
110        /**
111         * Build a before testrule that will receive the {@link TestContext}.
112         * <p>
113         * The passed consumer will be used before each test. The exact location of
114         * the execution is depending on where this used on the testRule chain.
115         * <p>
116         * In the much simple case (just one method to be executed before each
117         * test), the syntax is :
118         * 
119         * <pre>
120         * &#064;Rule
121         * public TestRule rule = beforeContextAware(this::beforeMethodName);
122         * </pre>
123         * 
124         * @param befores
125         *            the befores
126         * @return {@link TestRule the rule chain}.
127         * @see Rule
128         * @since 0.4.0
129         */
130        default TestRule beforeContextAware(
131                        Consumer<TestContext<Object>>... befores) {
132                return Arrays.stream(befores).map(TestRule::before)
133                                .reduce((prev, next) -> prev.around(next)).get();
134        }
135
136        /**
137         * Build a after testrule.
138         * <p>
139         * The passed runnable will be used after each test. The exact location of
140         * the execution is depending on where this used on the testRule chain.
141         * <p>
142         * In the much simple case (just one method to be executed after each test),
143         * the syntax is :
144         * 
145         * <pre>
146         * &#064;Rule
147         * public TestRule rule = after(this::afterMethodName);
148         * </pre>
149         * 
150         * @param afters
151         *            the afters
152         * @return {@link TestRule the rule chain}.
153         * @see Rule
154         */
155        default TestRule after(Runnable... afters) {
156                return Arrays.stream(afters).map(TestRule::after)
157                                .reduce((prev, next) -> prev.around(next)).get();
158        }
159
160        /**
161         * Build a after testrule that will receive the {@link TestContext}.
162         * <p>
163         * The passed consumer will be used after each test. The exact location of
164         * the execution is depending on where this used on the testRule chain.
165         * <p>
166         * In the much simple case (just one method to be executed after each test),
167         * the syntax is :
168         * 
169         * <pre>
170         * &#064;Rule
171         * public TestRule rule = afterContextAware(this::afterMethodName);
172         * </pre>
173         * 
174         * @param afters
175         *            the afters
176         * @return {@link TestRule the rule chain}.
177         * @see Rule
178         * @since 0.4.0
179         */
180        default TestRule afterContextAware(Consumer<TestContext<Object>>... afters) {
181                return Arrays.stream(afters).map(TestRule::after)
182                                .reduce((prev, next) -> prev.around(next)).get();
183        }
184
185        /**
186         * Create a rule to support mockito.
187         * <p>
188         * This provide a way to setup Mockito before each test.
189         * 
190         * @return {@link TestRule the rule chain}.
191         * @see Rule
192         */
193        default TestRule mockitoRule() {
194                return TestRule.mockitoRule();
195        }
196
197        /**
198         * Produces a new rule for the temporary folder.
199         * <p>
200         * As the {@link TemporaryFolder} rule provides several methods that are
201         * required for the test, except in the case when only this rule is
202         * required, a direct usage in the rule DSL is not adapted.
203         * 
204         * For instance, assuming that it is required to mix a before and the
205         * {@link TemporaryFolder} rule, the code will look like :
206         * 
207         * <pre>
208         * private TemporaryFolder temporary = temporaryFolder();
209         * 
210         * &#064;Rule
211         * public TestRule rule = before(this::beforeMethodName).around(temporary);
212         * </pre>
213         * 
214         * This is required to ensure that the method of the {@link TemporaryFolder}
215         * object can be used (using the field named <code>temporary</code>).
216         * 
217         * @return the temporary folder rule.
218         * @see Rule
219         */
220        default TemporaryFolder temporaryFolder() {
221                return temporaryFolderBuilder().build();
222        }
223
224        /**
225         * Produces a new rule builder for the temporary folder.
226         * <p>
227         * As the {@link TemporaryFolder} rule provides several methods that are
228         * required for the test, except in the case when only this rule is
229         * required, a direct usage in the rule DSL is not adapted.
230         * 
231         * For instance, assuming that it is required to mix a before and the
232         * {@link TemporaryFolder} rule, the code will look like :
233         * 
234         * <pre>
235         * private TemporaryFolder temporary = temporaryFolderBuilder().build();
236         * 
237         * &#064;Rule
238         * public TestRule rule = before(this::beforeMethodName).around(temporary);
239         * </pre>
240         * 
241         * This is required to ensure that the method of the {@link TemporaryFolder}
242         * object can be used (using the field named <code>temporary</code>).
243         * <p>
244         * The builder provide several capabilities to create initial folder
245         * structure at the same time than the temporary folder itself.
246         * 
247         * @return the temporary folder rule builder.
248         * @see Rule
249         */
250        default TemporaryFolderBuilder temporaryFolderBuilder() {
251                return new TemporaryFolderImpl.TemporaryFolderBuilderImpl();
252        }
253
254        /**
255         * Create a rule to restore some system properties after the test
256         * 
257         * @param propertiesName
258         *            the properties to be restored
259         * @return {@link TestRule the rule chain}.
260         * @see Rule
261         */
262        default TestRule systemPropertiesRule(String... propertiesName) {
263                return new SystemPropertiesRule(propertiesName);
264        }
265
266        /**
267         * Set a property before the run and ensure correct restore.
268         * 
269         * @param propertyName
270         *            the name of the property
271         * @param propertyValue
272         *            the value of the property
273         * @return {@link TestRule the rule chain}.
274         * @see Rule
275         */
276        default TestRule systemProperty(String propertyName,
277                        Supplier<String> propertyValue) {
278                return SystemPropertiesRule.setSystemPropertyBeforeTestAndRestoreAfter(
279                                propertyName, propertyValue);
280        }
281
282        /**
283         * Set a property before the run and ensure correct restore.
284         * 
285         * @param propertyName
286         *            the name of the property
287         * @param propertyValue
288         *            the value of the property
289         * @return {@link TestRule the rule chain}.
290         * @see Rule
291         */
292        default TestRule systemProperty(String propertyName, String propertyValue) {
293                return SystemPropertiesRule.setSystemPropertyBeforeTestAndRestoreAfter(
294                                propertyName, propertyValue);
295        }
296
297        /**
298         * Start building a Parameter Mapper function, with an initial converter.
299         * <p>
300         * Not specified index are considered transformed by identity function.
301         * 
302         * @param idx
303         *            The parameter index
304         * @param mapFunction
305         *            the function to be applied
306         * @return the function on the parameter array
307         * @param <T>
308         *            The input type for the function
309         * @param <R>
310         *            the result type for the function
311         */
312        default <T, R> StreamParametersMapFunction<T> parametersMap(int idx,
313                        Function<T, R> mapFunction) {
314                return StreamParametersMapFunction.map(idx, mapFunction);
315        }
316
317        /**
318         * Start building a Parameter Mapper function, assuming that the input are
319         * String, and using the type of the {@link Parameter &#64;Parameter} field.
320         * <p>
321         * Fields not supported will not be mapped and must be handled manually,
322         * using {@link StreamParametersMapFunction#andMap(int, Function) andMap}
323         * method to avoid any unexpected error.
324         * <p>
325         * The goal of this method is to provide a way to receive so generic
326         * parameter and not having to care about typing. Let's take for example the
327         * following use case :
328         * <ul>
329         * <li>As an input for the test parameters, a CSV file is used. In this
330         * case, a framework like <a
331         * href="http://opencsv.sourceforge.net/">OpenCSV</a> can be used to load
332         * all the parameters, but they are all String.</li>
333         * <li>On the produced stream, the
334         * {@link java.util.stream.Stream#map(Function) map} method can be used to
335         * transform the received data into another format. Here, using the result
336         * of this method as parameter of the map method will ensure the
337         * transformation of the String to the right type, for simple type.</li>
338         * <li>For undetected field type, it is possible to use the method
339         * {@link StreamParametersMapFunction#andMap(int, Function) andMap} (on the
340         * returned object of this method), to add manual transformation.</li>
341         * </ul>
342         * <p>
343         * In this context, as the {@link Parameters &#64;Parameters} annotated
344         * method must be static, access to this method can be done using
345         * {@link #DSL DSL.} prefix.
346         * 
347         * @param testClass
348         *            the testClass, as this method is to be used in static mode.
349         * @return the function on the parameter array
350         * @see <a href="./helpers/doc-files/convertedType.html">Supported automated
351         *      conversion</a>
352         */
353        default StreamParametersMapFunction<String> stringToParameterMap(
354                        Class<?> testClass) {
355                return StreamParametersMapFunction.stringToParameterMap(testClass);
356        }
357
358        /**
359         * Provide a way to add a field to each parameter line.
360         * 
361         * @param field
362         *            The field to be added.
363         * @return the function that can be used on the stream (
364         *         {@link java.util.stream.Stream#map(Function)}).
365         * @since 0.1.0
366         * @param <T>
367         *            The object type to be added.
368         */
369        default <T> Function<Object[], Object[]> addFieldToEachEntry(T field) {
370                return StreamParametersMapFunction.addFieldToEachEntry(field);
371        }
372
373        /**
374         * Provide a filter for stream parameters, to keep only parameters accepted
375         * by a matcher.
376         * 
377         * @param matcher
378         *            the matcher
379         * @return the stream filter
380         */
381        default Predicate<Object[]> parametersFilterUsingMatcher(
382                        Matcher<Object[]> matcher) {
383                return matcherPredicate(matcher);
384        }
385
386        /**
387         * Expose a matcher as a predicate.
388         * 
389         * @param matcher
390         *            the matcher.
391         * @return the predicate
392         * @param <T>
393         *            The target object type
394         */
395        default <T> Predicate<T> matcherPredicate(Matcher<T> matcher) {
396                return matcher::matches;
397        }
398
399        /**
400         * Provide a test rule that suppress both {@link java.lang.System#err system
401         * err} and {@link java.lang.System#out system out}.
402         * 
403         * @see ch.powerunit.rules.SystemStreamRule The complete description of the
404         *      functionnality of the rule.
405         * 
406         * @return the test rule.
407         * @since 0.4.0
408         */
409        default SystemStreamRule disableBothStreams() {
410                return SystemStreamRule.disableBothStreams();
411        }
412
413        /**
414         * Provide a test rule that replace both {@link java.lang.System#err system
415         * err} and {@link java.lang.System#out system out} with the provided one.
416         * 
417         * @param outReplacement
418         *            the replacement of the {@link java.lang.System#out system out}
419         *            stream.
420         * @param errRemplacement
421         *            the replacement of the {@link java.lang.System#err system err}
422         *            stream.
423         * 
424         * @see ch.powerunit.rules.SystemStreamRule The complete description of the
425         *      functionnality of the rule.
426         * 
427         * @return the test rule.
428         * @since 0.4.0
429         */
430        default SystemStreamRule replaceBothStream(PrintStream outReplacement,
431                        PrintStream errRemplacement) {
432                return SystemStreamRule.replaceBothStream(outReplacement,
433                                errRemplacement);
434        }
435
436        /**
437         * Provide a test rule that suppress the {@link java.lang.System#out system
438         * out} stream.
439         * 
440         * @see ch.powerunit.rules.SystemStreamRule The complete description of the
441         *      functionnality of the rule.
442         * 
443         * @return the test rule.
444         * @since 0.4.0
445         */
446        default SystemStreamRule disableOutStream() {
447                return SystemStreamRule.disableOutStream();
448        }
449
450        /**
451         * Provide a test rule that suppress the {@link java.lang.System#err system
452         * err} stream.
453         * 
454         * @see ch.powerunit.rules.SystemStreamRule The complete description of the
455         *      functionnality of the rule.
456         * 
457         * @return the test rule.
458         * @since 0.4.0
459         */
460        default SystemStreamRule disableErrStream() {
461                return SystemStreamRule.disableErrStream();
462        }
463
464        /**
465         * Privde a test rule that replace the {@link java.lang.System#out system
466         * out} stream with the provided one
467         * 
468         * @param outReplacement
469         *            the replacement of the {@link java.lang.System#out system out}
470         *            stream.
471         * 
472         * @see ch.powerunit.rules.SystemStreamRule The complete description of the
473         *      functionnality of the rule.
474         * 
475         * @return the test rule.
476         * @since 0.4.0
477         */
478        default SystemStreamRule replaceOutStream(PrintStream outReplacement) {
479                return SystemStreamRule.replaceOutStream(outReplacement);
480        }
481
482        /**
483         * Privde a test rule that replace the {@link java.lang.System#err system
484         * err} stream with the provided one
485         * 
486         * @param errReplacement
487         *            the replacement of the {@link java.lang.System#err system err}
488         *            stream.
489         * 
490         * @see ch.powerunit.rules.SystemStreamRule The complete description of the
491         *      functionnality of the rule.
492         * 
493         * @return the test rule.
494         * @since 0.4.0
495         */
496        default SystemStreamRule replaceErrStream(PrintStream errReplacement) {
497                return SystemStreamRule.replaceErrStream(errReplacement);
498        }
499
500        /**
501         * Build a {@link TestListenerRule} based on the various method.
502         * 
503         * @param onStart
504         *            {@link TestListenerRule#onStart(TestContext) the action to be
505         *            done before the test start}. If null, nothing is done.
506         * @param onEnd
507         *            {@link TestListenerRule#onEnd(TestContext) the action to be
508         *            done after the test end}. If null, nothing is done.
509         * @param onFailure
510         *            {@link TestListenerRule#onFailure(TestContext, AssertionError)
511         *            the action to be done in case of failure}. If null, nothing is
512         *            done.
513         * @param onError
514         *            {@link TestListenerRule#onError(TestContext, Throwable) the
515         *            action to be done in case of error}. If null, nothing is done.
516         * @param onAssumptionSkip
517         *            {@link TestListenerRule#onAssumptionSkip(TestContext, AssumptionError)
518         *            the action to be done in case of assumption skipped}. If null
519         *            nothing is done.
520         * @return the Test Rule.
521         * @since 0.4.0
522         */
523        default TestListenerRule testListenerRuleOf(
524                        Consumer<TestContext<Object>> onStart,
525                        Consumer<TestContext<Object>> onEnd,
526                        BiConsumer<TestContext<Object>, AssertionError> onFailure,
527                        BiConsumer<TestContext<Object>, Throwable> onError,
528                        BiConsumer<TestContext<Object>, AssumptionError> onAssumptionSkip) {
529                return TestListenerRule.of(onStart, onEnd, onFailure, onError,
530                                onAssumptionSkip);
531        }
532
533        /**
534         * Build a {@link TestListenerRule} with only an action at start.
535         * 
536         * @param onStart
537         *            {@link TestListenerRule#onStart(TestContext) the action to be
538         *            done before the test start}.
539         * @return the Test Rule.
540         * @since 0.4.0
541         */
542        default TestListenerRule testListenerRuleOnStart(
543                        Consumer<TestContext<Object>> onStart) {
544                return TestListenerRule.onStart(onStart);
545        }
546
547        /**
548         * Build a {@link TestListenerRule} with only an action at end.
549         * 
550         * @param onEnd
551         *            {@link TestListenerRule#onEnd(TestContext) the action to be
552         *            done after the test end}.
553         * @return the Test Rule.
554         * @since 0.4.0
555         */
556        default TestListenerRule testListenerRuleOnEnd(
557                        Consumer<TestContext<Object>> onEnd) {
558                return TestListenerRule.onEnd(onEnd);
559        }
560}