001// Generated by delombok at Sun Jul 30 17:21:56 UTC 2023 002package de.cuioss.test.jsf.converter; 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.component.UIComponent; 008import javax.faces.component.html.HtmlInputText; 009import javax.faces.context.FacesContext; 010import javax.faces.convert.Converter; 011import javax.faces.convert.ConverterException; 012import org.junit.jupiter.api.BeforeEach; 013import org.junit.jupiter.api.Test; 014import de.cuioss.test.generator.junit.EnableGeneratorController; 015import de.cuioss.test.jsf.config.ComponentConfigurator; 016import de.cuioss.test.jsf.config.decorator.ComponentConfigDecorator; 017import de.cuioss.test.jsf.junit5.EnableJsfEnvironment; 018import de.cuioss.test.jsf.junit5.JsfEnabledTestEnvironment; 019import de.cuioss.test.valueobjects.objects.ConfigurationCallBackHandler; 020import de.cuioss.test.valueobjects.objects.impl.DefaultInstantiator; 021import de.cuioss.tools.reflect.MoreReflection; 022// owolff we need to migrate this aspect later 023/** 024 * Base class for testing implementations of {@link Converter} within a Junit 5 025 * context 026 * <h3>Setup</h3> 027 * <p> 028 * The actual test must provide {@link EnableJsfEnvironment}, for the basic 029 * test-infrastructure. See the class-documentation for details. 030 * </p> 031 * <p> 032 * {@link #initConverter()}: Instantiates the concrete {@link Converter} using 033 * reflection. After this the method calls {@link #configure(Object)} that can 034 * be used for further configuration of the {@link Converter} 035 * </p> 036 * <p> 037 * In case you want you want to create the {@link Converter} yourself you can 038 * overwrite {@link #getConverter()} 039 * </p> 040 * <p> 041 * In case you want a pass another {@link UIComponent} as parameter to the 042 * {@link Converter} you can overwrite {@link #getComponent()} 043 * </p> 044 * <h3>Test-Methods</h3> The core test-methods are: 045 * <ul> 046 * <li>{@link #shouldFailOnInvalidObjects()}</li> 047 * <li>{@link #shouldFailOnInvalidStrings()}</li> 048 * <li>{@link #shouldPassOnValidObjects()}</li> 049 * <li>{@link #shouldPassOnValidStrings()}</li> 050 * <li>{@link #shouldRoundTripValidData()}</li> 051 * </ul> 052 * They call {@link #populate(TestItems)} in oder to create corresponding 053 * test-data. The implementation is in the actual test-class. 054 * <h3>API-Test</h3> The api as defined within {@link Converter} is tested with 055 * the methods 056 * <ul> 057 * <li>{@link #shouldFailOnNullComponentOnGetAsObject()}</li> 058 * <li>{@link #shouldFailOnNullComponentOnGetAsString()}</li> 059 * <li>{@link #shouldFailOnNullFacesContextOnGetAsObject()}</li> 060 * <li>{@link #shouldFailOnNullFacesContextOnGetAsString()}</li> 061 * <li>{@link #shouldReturnEmptyStringOnNullValue()}</li> 062 * </ul> 063 * <h3>Example</h3> Shows all variants of dealing with {@link TestItems} 064 * 065 * <pre> 066 * <code> 067 * @EnableJsfEnvironment 068 * class IntegerConverterTest extends AbstractConverterTest<IntegerConverter, Integer> { 069 * 070 * @Override 071 * public void populate(final TestItems<Integer> testItems) { 072 * testItems.addRoundtripValues("1", "122", "2132121").addInvalidString("a") 073 * .addInvalidStringWithMessage("a", "javax.faces.converter.IntegerConverter.INTEGER") 074 * .addInvalidObject(Boolean.TRUE) 075 * .addInvalidObjectWithMessage(Boolean.FALSE, "javax.faces.converter.STRING") 076 * .addValidString("13").addValidStringWithObjectResult("17", Integer.valueOf(17)) 077 * .addValidObject(Integer.valueOf(2)) 078 * .addValidObjectWithStringResult(Integer.valueOf(14), "14"); 079 * } 080 * </code> 081 * </pre> 082 * 083 * @param <C> identifying the concrete {@link Converter} to be tested. 084 * @param <T> identifying the type of elements to be used for values to be given 085 * to the {@link Converter} 086 * 087 * @author Oliver Wolff 088 */ 089@SuppressWarnings({"rawtypes", "unchecked"}) 090@EnableGeneratorController 091public abstract class AbstractConverterTest<C extends Converter, T> extends JsfEnabledTestEnvironment implements ConfigurationCallBackHandler<C>, ComponentConfigurator { 092 private static final String SHOULD_HAVE_THROWN_CONVERTER_EXCEPTION = "Should have thrown ConverterException for invalid Value: "; 093 private UIComponent component = new HtmlInputText(); 094 private C converter; 095 private TestItems<T> testItems; 096 097 /** 098 * Instantiates and initially configures a concrete {@link Converter} 099 */ 100 @BeforeEach 101 protected void initConverter() { 102 final Class<C> klazz = MoreReflection.extractFirstGenericTypeArgument(getClass()); 103 converter = new DefaultInstantiator<>(klazz).newInstance(); 104 configure(converter); 105 testItems = new TestItems<>(); 106 populate(testItems); 107 } 108 109 /** 110 * Populates the test-items 111 * 112 * @param testItems to be populated, is never null 113 */ 114 public abstract void populate(TestItems<T> testItems); 115 116 /** 117 * Callback method for interacting with the {@link ComponentConfigDecorator} at 118 * the correct time.<br> 119 * This method provide <b>extension point</b> to prepare needed test environment 120 * for your converter test. For example : 121 * 122 * <pre> 123 * // register some converter 124 * decorator.registerConverter(MyRequiredConverter.class); 125 * // register UIComponent 126 * ... 127 * </pre> 128 * 129 * @param decorator {@link ComponentConfigDecorator} is never null 130 */ 131 @Override 132 public void configureComponents(final ComponentConfigDecorator decorator) { 133 // default do nothing 134 } 135 136 /** 137 * Checks the api contract regarding {@code null} as parameter for 138 * {@link UIComponent}, see 139 * {@link Converter#getAsObject(FacesContext, UIComponent, String)} 140 */ 141 @Test 142 void shouldFailOnNullComponentOnGetAsObject() { 143 assertThrows(NullPointerException.class, () -> getConverter().getAsObject(getFacesContext(), null, null)); 144 } 145 146 /** 147 * Checks the api contract regarding {@code null} as parameter for 148 * {@link FacesContext}, see 149 * {@link Converter#getAsObject(FacesContext, UIComponent, String)} 150 */ 151 @Test 152 void shouldFailOnNullFacesContextOnGetAsObject() { 153 assertThrows(NullPointerException.class, () -> getConverter().getAsObject(null, getComponent(), null)); 154 } 155 156 /** 157 * Checks the api contract regarding {@code null} as parameter for 158 * {@link UIComponent}, see 159 * {@link Converter#getAsString(FacesContext, UIComponent, Object)} 160 */ 161 @Test 162 void shouldFailOnNullComponentOnGetAsString() { 163 assertThrows(NullPointerException.class, () -> getConverter().getAsString(getFacesContext(), null, null)); 164 } 165 166 /** 167 * Checks the api contract regarding {@code null} as parameter for 168 * {@link FacesContext}, see 169 * {@link Converter#getAsString(FacesContext, UIComponent, Object)} 170 */ 171 @Test 172 void shouldFailOnNullFacesContextOnGetAsString() { 173 assertThrows(NullPointerException.class, () -> getConverter().getAsString(null, getComponent(), null)); 174 } 175 176 /** 177 * Checks the api contract regarding {@code null} as parameter for the actual 178 * value, see {@link Converter#getAsString(FacesContext, UIComponent, Object)} 179 */ 180 @Test 181 void shouldReturnEmptyStringOnNullValue() { 182 assertEquals("", getConverter().getAsString(getFacesContext(), getComponent(), null)); 183 } 184 185 /** 186 * Core test for converter testing. It collects the test-data using 187 * {@link TestItems} and iterates them for the individual test. For each element 188 * there will be called the method 189 * {@link Converter#getAsObject(javax.faces.context.FacesContext, javax.faces.component.UIComponent, String)}, 190 * with the result again 191 * {@link Converter#getAsString(javax.faces.context.FacesContext, javax.faces.component.UIComponent, Object)} 192 * with the result being checked against the initial value. 193 */ 194 @Test 195 void shouldRoundTripValidData() { 196 for (final String value : getTestItems().getRoundtripValues()) { 197 final var converted = (T) getConverter().getAsObject(getFacesContext(), getComponent(), value); 198 final var roundTripped = getConverter().getAsString(getFacesContext(), getComponent(), converted); 199 assertEquals(value, roundTripped); 200 } 201 } 202 203 /** 204 * Tests the method 205 * {@link Converter#getAsString(javax.faces.context.FacesContext, javax.faces.component.UIComponent, Object)} 206 * with invalid objects, derived by {@link TestItems} 207 */ 208 @Test 209 void shouldFailOnInvalidObjects() { 210 for (final ConverterTestItem<T> item : getTestItems().getInvalidObjectTestItems()) { 211 try { 212 getConverter().getAsString(getFacesContext(), getComponent(), item.getTestValue()); 213 fail(SHOULD_HAVE_THROWN_CONVERTER_EXCEPTION + item); 214 } catch (final ConverterException e) { 215 verifyExpectedErrorMessage(item, e); 216 } 217 } 218 } 219 220 private void verifyExpectedErrorMessage(final ConverterTestItem<T> item, final ConverterException e) { 221 // Check message 222 if (null != item.getErrorMessage()) { 223 assertEquals(item.getErrorMessage(), e.getFacesMessage().getSummary(), "Wrong error message detected. TestItem was : " + item); 224 } 225 } 226 227 /** 228 * Tests the method 229 * {@link Converter#getAsString(javax.faces.context.FacesContext, javax.faces.component.UIComponent, Object)} 230 * with valid objects, derived by {@link TestItems} 231 */ 232 @Test 233 void shouldPassOnValidObjects() { 234 for (final ConverterTestItem<T> item : getTestItems().getValidObjectTestItems()) { 235 final var result = getConverter().getAsString(getFacesContext(), getComponent(), item.getTestValue()); 236 if (null != item.getStringValue()) { 237 assertEquals(item.getStringValue(), result, item.toString()); 238 } 239 } 240 } 241 242 /** 243 * Tests the method 244 * {@link Converter#getAsObject(javax.faces.context.FacesContext, javax.faces.component.UIComponent, String)} 245 * with invalid objects, derived by {@link TestItems} 246 */ 247 @Test 248 void shouldFailOnInvalidStrings() { 249 for (final ConverterTestItem<T> item : getTestItems().getInvalidStringTestItems()) { 250 try { 251 getConverter().getAsObject(getFacesContext(), getComponent(), item.getStringValue()); 252 fail(SHOULD_HAVE_THROWN_CONVERTER_EXCEPTION + item); 253 } catch (final ConverterException e) { 254 verifyExpectedErrorMessage(item, e); 255 } 256 } 257 } 258 259 /** 260 * Tests the method 261 * {@link Converter#getAsObject(javax.faces.context.FacesContext, javax.faces.component.UIComponent, String)} 262 * with valid String, derived by {@link TestItems} 263 */ 264 @Test 265 void shouldPassOnValidStrings() { 266 for (final ConverterTestItem<T> item : getTestItems().getValidStringTestItems()) { 267 final var result = (T) getConverter().getAsObject(getFacesContext(), getComponent(), item.getStringValue()); 268 if (null != item.getTestValue()) { 269 assertEquals(item.getTestValue(), result, item.toString()); 270 } 271 } 272 } 273 274 @java.lang.SuppressWarnings("all") 275 @lombok.Generated 276 public UIComponent getComponent() { 277 return this.component; 278 } 279 280 @java.lang.SuppressWarnings("all") 281 @lombok.Generated 282 public void setComponent(final UIComponent component) { 283 this.component = component; 284 } 285 286 @java.lang.SuppressWarnings("all") 287 @lombok.Generated 288 public C getConverter() { 289 return this.converter; 290 } 291 292 @java.lang.SuppressWarnings("all") 293 @lombok.Generated 294 protected TestItems<T> getTestItems() { 295 return this.testItems; 296 } 297}