Statement.java

  1. /**
  2.  * Powerunit - A JDK1.8 test framework
  3.  * Copyright (C) 2014 Mathieu Boretti.
  4.  *
  5.  * This file is part of Powerunit
  6.  *
  7.  * Powerunit is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation, either version 3 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * Powerunit is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
  19.  */
  20. package ch.powerunit;

  21. import java.lang.reflect.InvocationTargetException;
  22. import java.lang.reflect.Method;
  23. import java.util.Objects;
  24. import java.util.function.Consumer;

  25. import ch.powerunit.exception.InternalError;

  26. /**
  27.  * Definition of a statement (piece of code that can thrown Throwable).
  28.  * <p>
  29.  * A statement can be used inside test (to isolate a code that must thrown an
  30.  * exception) and are used internally by the framework to compose and execute
  31.  * test sequence element.
  32.  *
  33.  * @author borettim
  34.  * @param <P>
  35.  *            The type of the parameter
  36.  * @param <T>
  37.  *            the exception type
  38.  */
  39. @FunctionalInterface
  40. public interface Statement<P, T extends Throwable> {

  41.     /**
  42.      * Executable code.
  43.      *
  44.      * @param parameter
  45.      *            A parameter for the statement
  46.      * @throws Throwable
  47.      *             in case of error.
  48.      */
  49.     void run(P parameter) throws Throwable;// should be T, but T seem to produce
  50.                                             // a bug in the compiler

  51.     /**
  52.      * Used to provide a name (for internal use purpose).
  53.      *
  54.      * @return the string, by default null.
  55.      * @since 0.1.0
  56.      */
  57.     default String getName() {
  58.         return null;
  59.     }

  60.     /**
  61.      * Aggregate this statement and then the following. The second statement is
  62.      * done, even in case of exception in the first one.
  63.      *
  64.      * @param after
  65.      *            the next statement
  66.      * @return the new statement
  67.      */
  68.     default Statement<P, T> andThenAlways(Statement<P, T> after) {
  69.         Objects.requireNonNull(after);
  70.         return (p) -> {
  71.             try {
  72.                 run(p);
  73.             } finally {
  74.                 after.run(p);
  75.             }
  76.         };
  77.     }

  78.     /**
  79.      * Aggregate this statement and then the following. The second statement is
  80.      * done except in case of exception in the first one.
  81.      *
  82.      * @param after
  83.      *            the next statement
  84.      * @return the new statement
  85.      */
  86.     default Statement<P, T> andThenOnlySuccess(Statement<P, T> after) {
  87.         Objects.requireNonNull(after);
  88.         return (p) -> {
  89.             run(p);
  90.             after.run(p);
  91.         };
  92.     }

  93.     /**
  94.      * Build a around statement (do something, then something others, and after
  95.      * one a third statement, event in case of exception.
  96.      *
  97.      * @param internal
  98.      *            the internal part
  99.      * @param before
  100.      *            the first statement
  101.      * @param after
  102.      *            the last statement, done event in case of exception.
  103.      * @return the new statement.
  104.      * @param <P>
  105.      *            The type of the parameter
  106.      * @param <T>
  107.      *            the exception type
  108.      */
  109.     static <P, T extends Throwable> Statement<P, T> around(
  110.             Statement<P, T> internal, Statement<P, T> before,
  111.             Statement<P, T> after) {
  112.         Objects.requireNonNull(internal);
  113.         Objects.requireNonNull(before);
  114.         Objects.requireNonNull(after);
  115.         return before.andThenOnlySuccess(internal).andThenAlways(after);
  116.     }

  117.     /**
  118.      * Build a statement based on a method-
  119.      *
  120.      * @param target
  121.      *            the target object
  122.      * @param method
  123.      *            the method
  124.      * @return the new statement.
  125.      * @param <P>
  126.      *            The type of the parameter
  127.      * @param <T>
  128.      *            the exception type
  129.      */
  130.     static <P, T extends Throwable> Statement<P, T> reflectionMethod(
  131.             Object target, Method method) {
  132.         Objects.requireNonNull(target);
  133.         Objects.requireNonNull(method);
  134.         return new Statement<P, T>() {

  135.             @Override
  136.             public void run(P parameter) throws Throwable {
  137.                 try {
  138.                     method.invoke(target);
  139.                 } catch (InvocationTargetException e) {
  140.                     throw e.getCause();
  141.                 } catch (IllegalAccessException | IllegalArgumentException e) {
  142.                     throw new InternalError("Unexpected error "
  143.                             + e.getMessage(), e);
  144.                 }
  145.             }

  146.             @Override
  147.             public String getName() {
  148.                 return method.getName();
  149.             }
  150.         };
  151.     }

  152.     /**
  153.      * Build a statement based on a method-
  154.      *
  155.      * @param method
  156.      *            the method
  157.      * @param param
  158.      *            the param
  159.      * @return the new statement.
  160.      * @param <P>
  161.      *            The type of the parameter
  162.      * @param <T>
  163.      *            the exception type
  164.      * @since 0.2.0
  165.      */
  166.     static <P, T extends Throwable> Statement<P, T> reflectionMethod(
  167.             Consumer<Object> method, Object param) {
  168.         Objects.requireNonNull(method);
  169.         return new Statement<P, T>() {

  170.             @Override
  171.             public void run(P parameter) throws Throwable {
  172.                 method.accept(param);
  173.             }

  174.             @Override
  175.             public String getName() {
  176.                 return "N/A";
  177.             }
  178.         };
  179.     }

  180. }