package org.codefx.libfx.control.properties; import static org.junit.Assert.fail; import java.util.function.Consumer; import javafx.collections.FXCollections; import javafx.collections.ObservableMap; import org.codefx.libfx.listener.handle.CreateListenerHandle; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import com.nitorcreations.junit.runners.NestedRunner; /** * Tests the {@link ControlPropertyListenerBuilder}. */ @RunWith(NestedRunner.class) public class ControlPropertiesTest { /** * Tests the builder's contract. */ public static class BuilderContract { // #begin FIELDS /** * The key used to create the listeners. */ private static final Object KEY = "key"; /** * The processor which can be used when nothing needs to happen. */ private static final Consumer<Object> VOID_PROCESSOR = value -> {/* do nothing */}; /** * The property map used to create the listeners. */ private ObservableMap<Object, Object> properties; // #end FIELDS /** * Initializes the fields. */ @Before public void setUp() { properties = FXCollections.observableHashMap(); } // #begin TESTS // EXCEPTIONS DURING CONSTRUCTION /** * Tests whether starting on a null map throws the correct exception. */ @Test(expected = NullPointerException.class) public void testNullPointerExceptionOnNullMap() { ControlProperties.on(null); } /** * Tests whether using a null key throws the correct exception. */ @Test(expected = NullPointerException.class) public void testNullPointerExceptionOnNullKey() { ControlProperties.on(properties) .forKey(null); } /** * Tests whether using a null value type throws the correct exception. */ @Test(expected = NullPointerException.class) public void testNullPointerExceptionOnNullValueType() { ControlProperties.on(properties) .forValueType(null); } /** * Tests whether using a null value processor throws the correct exception. */ @Test(expected = NullPointerException.class) public void testNullPointerExceptionOnNullValueProcessor() { ControlProperties.on(properties) .processValue(null); } /** * Tests whether building with a missing key throws the correct exception. */ @Test(expected = IllegalStateException.class) public void testIllegalStateExceptionOnBuildWithoutKey() { ControlProperties.on(properties) .processValue(VOID_PROCESSOR) .buildDetached(); } /** * Tests whether building with a missing key value processor the correct exception. */ @Test(expected = IllegalStateException.class) public void testIllegalStateExceptionOnBuildWithoutValueProcessor() { ControlProperties.on(properties) .forKey(KEY) .buildDetached(); } // SUCCESSFUL CONSTRUCTION /** * Tests whether building is successful when the minimum of values is set. */ public void testSuccessfulBuild() { ControlProperties.<String> on(properties) .forKey(KEY) .processValue(VOID_PROCESSOR) .buildDetached(); } /** * Tests whether building with a value type works as well. */ public void testSuccessfulBuildWithValueType() { ControlProperties.<String> on(properties) .forKey(KEY) .forValueType(String.class) .processValue(VOID_PROCESSOR) .buildDetached(); } // #end TESTS } // #begin TESTS CREATED LISTENERS /** * Tests the created {@link CastingControlPropertyListenerHandle}. */ public static class CreatedCastingControlPropertyListener extends AbstractControlPropertyListenerHandleTest { @Override protected <T> ControlPropertyListenerHandle createListener( ObservableMap<Object, Object> properties, Object key, Class<T> valueType, Consumer<? super T> valueProcessor, CreateListenerHandle attachedOrDetached) { // parameterize the builder ControlPropertyListenerBuilder<T> builder = ControlProperties.<T> on(properties) .forKey(key) .processValue(valueProcessor); // in order to create a casting listener, do not set the builder type; // create the listener according to 'attachedOrDetached' ControlPropertyListenerHandle listener; if (attachedOrDetached == CreateListenerHandle.ATTACHED) listener = builder.buildAttached(); else if (attachedOrDetached == CreateListenerHandle.DETACHED) listener = builder.buildDetached(); else throw new IllegalArgumentException(); // check whether the correct type was created if (!(listener instanceof CastingControlPropertyListenerHandle)) fail(); return listener; } } /** * Tests the created {@link TypeCheckingControlPropertyListenerHandle}. */ public static class CreatedTypeCheckingControlPropertyListener extends AbstractControlPropertyListenerHandleTest { @Override protected <T> ControlPropertyListenerHandle createListener( ObservableMap<Object, Object> properties, Object key, Class<T> valueType, Consumer<? super T> valueProcessor, CreateListenerHandle attachedOrDetached) { // parameterize the builder ControlPropertyListenerBuilder<T> builder = ControlProperties.<T> on(properties) .forKey(key) .forValueType(valueType) .processValue(valueProcessor); // create the listener according to 'attachedOrDetached' ControlPropertyListenerHandle listener; if (attachedOrDetached == CreateListenerHandle.ATTACHED) listener = builder.buildAttached(); else if (attachedOrDetached == CreateListenerHandle.DETACHED) listener = builder.buildDetached(); else throw new IllegalArgumentException(); // check whether the correct type was created if (!(listener instanceof TypeCheckingControlPropertyListenerHandle)) fail(); return listener; } } // #end TESTS CREATED LISTENERS }