001// Generated by delombok at Sun Jul 30 17:21:56 UTC 2023
002package de.cuioss.test.jsf.validator;
003
004import static org.junit.jupiter.api.Assertions.assertEquals;
005import static org.junit.jupiter.api.Assertions.assertThrows;
006import static org.junit.jupiter.api.Assertions.fail;
007import javax.faces.application.FacesMessage;
008import javax.faces.component.UIComponent;
009import javax.faces.component.html.HtmlInputText;
010import javax.faces.context.FacesContext;
011import javax.faces.validator.Validator;
012import javax.faces.validator.ValidatorException;
013import org.junit.jupiter.api.BeforeEach;
014import org.junit.jupiter.api.Test;
015import de.cuioss.test.generator.junit.EnableGeneratorController;
016import de.cuioss.test.jsf.junit5.EnableJsfEnvironment;
017import de.cuioss.test.jsf.junit5.JsfEnabledTestEnvironment;
018import de.cuioss.test.valueobjects.objects.ConfigurationCallBackHandler;
019import de.cuioss.test.valueobjects.objects.impl.DefaultInstantiator;
020import de.cuioss.tools.reflect.MoreReflection;
021// owolff we need to migrate this aspect later
022/**
023 * Base Class for testing implementations of {@link Validator} within a Junit 5
024 * context
025 * <h3>Setup</h3>
026 * <p>
027 * It uses {@link EnableJsfEnvironment}, for the basic test-infrastructure.See
028 * the class-documentation for details.
029 * </p>
030 * <p>
031 * {@link #initValidator()}: Instantiates the concrete {@link Validator} using
032 * reflection. After this the method calls {@link #configure(Object)} that can
033 * be used for further configuration of the {@link Validator}
034 * </p>
035 * <p>
036 * In case you want you want to create the {@link Validator} yourself you can
037 * overwrite {@link #getValidator()}
038 * </p>
039 * <p>
040 * In case you want a pass another {@link UIComponent} as parameter to the
041 * {@link Validator} you can overwrite {@link #getComponent()}
042 * </p>
043 * <h3>Test-Methods</h3>
044 * <p>
045 * The core test-methods are {@link #shouldFailOnInvalidTestdata()} and
046 * {@link #shouldHandleValidTestdata()}. They call {@link #populate(TestItems)}
047 * in oder to create corresponding test-data. The implementation is in the
048 * actual test-class.
049 * </p>
050 * <h3>API-Test</h3>
051 * <p>
052 * The api as defined within {@link Validator} is tested with the methods
053 * {@link #shouldFailOnNullComponent()}, {@link #shouldFailOnNullFacesContext()}
054 * and {@link #shouldHandleNullValue()}
055 * </p>
056 * <h3>Example</h3>
057 *
058 * <pre>
059 * <code>
060 * &#64;EnableJsfEnvironment
061 * class LengthValidatorTest extends AbstractValidatorTest&lt;LengthValidator, String&gt; {
062 *
063 *    &#64;Override
064 *    public void populate(final TestItems&lt;String&gt; testItems) {
065 *        testItems.addValid("1").addValid("abc").addInvalidWithMessage("123456",
066 *                LengthValidator.MAXIMUM_MESSAGE_ID);
067 *    }
068 *
069 *    &#64;Override
070 *    public void configure(final LengthValidator validator) {
071 *        validator.setMaximum(5);
072 *    }
073 *   }
074 * </code>
075 * </pre>
076 * <p>
077 *
078 * @author Oliver Wolff
079 * @param <V> identifying the concrete {@link Validator} to be tested.
080 * @param <T> identifying the type of elements to be passed into the validator
081 */
082@SuppressWarnings({"rawtypes", "unchecked"})
083@EnableGeneratorController
084public abstract class AbstractValidatorTest<V extends Validator, T> extends JsfEnabledTestEnvironment implements ConfigurationCallBackHandler<V> {
085    private final UIComponent component = new HtmlInputText();
086    private V validator;
087
088    /**
089     * Instantiates and initially configures a concrete {@link Validator}
090     */
091    @BeforeEach
092    void initValidator() {
093        final Class<V> klazz = MoreReflection.extractFirstGenericTypeArgument(getClass());
094        validator = new DefaultInstantiator<>(klazz).newInstance();
095        configure(validator);
096    }
097
098    /**
099     * Checks the api contract regarding {@code null} as parameter for
100     * {@link UIComponent}, see
101     * {@link Validator#validate(javax.faces.context.FacesContext, UIComponent, Object)}
102     */
103    @Test
104    void shouldFailOnNullComponent() {
105        assertThrows(NullPointerException.class, () -> getValidator().validate(getFacesContext(), null, null));
106    }
107
108    /**
109     * Checks the api contract regarding {@code null} as parameter for
110     * {@link FacesContext}, see
111     * {@link Validator#validate(javax.faces.context.FacesContext, UIComponent, Object)}
112     */
113    @Test
114    void shouldFailOnNullFacesContext() {
115        assertThrows(NullPointerException.class, () -> getValidator().validate(null, getComponent(), null));
116    }
117
118    /**
119     * Checks the api contract regarding {@code null} as parameter for the actual
120     * value, see
121     * {@link Validator#validate(javax.faces.context.FacesContext, UIComponent, Object)}
122     */
123    @Test
124    void shouldHandleNullValue() {
125        getValidator().validate(getFacesContext(), getComponent(), null);
126    }
127
128    /**
129     * Tests whether the valid {@link TestItems} are validated without
130     * {@link ValidatorException}
131     */
132    @Test
133    void shouldHandleValidTestdata() {
134        final var items = new TestItems<T>();
135        populate(items);
136        items.allValid().forEach(item -> validator.validate(getFacesContext(), getComponent(), item.getTestValue()));
137    }
138
139    /**
140     * Tests whether the invalid {@link TestItems} fail to validate by throwing
141     * {@link ValidatorException}. In case the single {@link TestItems} provide a
142     * message, it will be compared as well.
143     */
144    @Test
145    void shouldFailOnInvalidTestdata() {
146        final var items = new TestItems<T>();
147        populate(items);
148        for (final TestItem<T> item : items.allInvalid()) {
149            try {
150                validator.validate(getFacesContext(), getComponent(), item.getTestValue());
151                fail("Validation should have thrown a ValidatorException for testValue" + item);
152            } catch (final ValidatorException e) {
153                assertEquals(FacesMessage.SEVERITY_ERROR, e.getFacesMessage().getSeverity());
154                if (null != item.getErrorMessage()) {
155                    assertEquals(item.getErrorMessage(), e.getFacesMessage().getSummary(), "The validation failed as expected, but the messages are not equal as expected");
156                }
157            }
158        }
159    }
160
161    /**
162     * Populates the test-items
163     *
164     * @param testItems to be populated, is never null
165     */
166    public abstract void populate(TestItems<T> testItems);
167
168    @java.lang.SuppressWarnings("all")
169    @lombok.Generated
170    public UIComponent getComponent() {
171        return this.component;
172    }
173
174    @java.lang.SuppressWarnings("all")
175    @lombok.Generated
176    public V getValidator() {
177        return this.validator;
178    }
179}