void verifyWrapperChainContracts(final W wrapper) {
+ requireNonNull(wrapper, "wrapper is null");
+ travelWrapperChain(wrapper, w -> Optional.empty());
+ }
+
/**
* Reports whether any instance on the wrapper chain satisfies the given {@code predicate}.
*
@@ -130,6 +157,8 @@ public static V getAttachmentFromWrapperChain(final W wrapper, final K
* or any wrapper {@link Wrapper#unwrap()} returns null,
* or the adaptee of {@link WrapperAdapter} is null
* @throws IllegalStateException if the adaptee of {@link WrapperAdapter} is type {@link Wrapper}
+ * @see Wrapper#unwrap()
+ * @see WrapperAdapter#adaptee()
*/
public static boolean testWrapperChain(final W wrapper, final Predicate super W> predicate) {
requireNonNull(wrapper, "wrapper is null");
@@ -158,6 +187,8 @@ public static boolean testWrapperChain(final W wrapper, final Predicate su
* or any wrapper {@link Wrapper#unwrap()} returns null,
* or the adaptee of {@link WrapperAdapter} is null
* @throws IllegalStateException if the adaptee of {@link WrapperAdapter} is type {@link Wrapper}
+ * @see Wrapper#unwrap()
+ * @see WrapperAdapter#adaptee()
*/
@NonNull
@SuppressWarnings("unchecked")
diff --git a/src/test/java/io/foldright/inspectablewrappers/SpecificationContractsTest.java b/src/test/java/io/foldright/inspectablewrappers/SpecificationContractsTest.java
new file mode 100644
index 0000000..6e5f8eb
--- /dev/null
+++ b/src/test/java/io/foldright/inspectablewrappers/SpecificationContractsTest.java
@@ -0,0 +1,86 @@
+package io.foldright.inspectablewrappers;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.Executor;
+
+import static io.foldright.inspectablewrappers.Inspector.verifyWrapperChainContracts;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+class SpecificationContractsTest {
+
+ private static final Executor DUMMY = command -> {
+ };
+
+ @Test
+ void test_null_unwrap() {
+ Executor w = new WrapperImpl(null);
+
+ NullPointerException e = Assertions.assertThrowsExactly(NullPointerException.class, () -> verifyWrapperChainContracts(w));
+ String expected = "unwrap of Wrapper(io.foldright.inspectablewrappers.SpecificationContractsTest$WrapperImpl) is null";
+ assertEquals(expected, e.getMessage());
+ }
+
+ @Test
+ void test_null_adaptee() {
+ Executor w = new WrapperAdapterImpl(DUMMY, null);
+
+ NullPointerException e = Assertions.assertThrowsExactly(NullPointerException.class, () -> verifyWrapperChainContracts(w));
+ String expected = "adaptee of WrapperAdapter(io.foldright.inspectablewrappers.SpecificationContractsTest$WrapperAdapterImpl) is null";
+ assertEquals(expected, e.getMessage());
+ }
+
+ @Test
+ void test_Wrap_type_adaptee() {
+ Executor w = new WrapperAdapterImpl(DUMMY, new WrapperImpl(null));
+
+ IllegalStateException e = Assertions.assertThrowsExactly(IllegalStateException.class, () -> verifyWrapperChainContracts(w));
+ String expected = "adaptee(io.foldright.inspectablewrappers.SpecificationContractsTest$WrapperImpl)" +
+ " of WrapperAdapter(io.foldright.inspectablewrappers.SpecificationContractsTest$WrapperAdapterImpl) is type Wrapper," +
+ " adapting a Wrapper to a Wrapper is unnecessary!";
+ assertEquals(expected, e.getMessage());
+ }
+
+ private static class WrapperImpl implements Wrapper, Executor {
+ private final Executor instance;
+
+ WrapperImpl(Executor instance) {
+ this.instance = instance;
+ }
+
+ @Override
+ public Executor unwrap() {
+ return instance;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ }
+ }
+
+ private static class WrapperAdapterImpl implements WrapperAdapter, Executor {
+ private final Executor wrapper;
+ private final Executor adaptee;
+
+ WrapperAdapterImpl(Executor wrapper, Executor adaptee) {
+ this.wrapper = wrapper;
+ this.adaptee = adaptee;
+ }
+
+ @Override
+ public Executor unwrap() {
+ return wrapper;
+ }
+
+ @Override
+ public Executor adaptee() {
+ return adaptee;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ }
+ }
+}