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 * @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 @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 * @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 * @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 * @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 * @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 * @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 * @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 @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 @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}