Skip to content

Commit

Permalink
feat(Inspector): add method Inspector.verifyWrapperChainContracts
Browse files Browse the repository at this point in the history
… ‍⚖️
  • Loading branch information
oldratlee committed Mar 30, 2024
1 parent 7546a5b commit e6f567a
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/main/java/io/foldright/inspectablewrappers/Inspector.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
* by static method {@link #containsInstanceOnWrapperChain(Object, Class)}
* <li>Retrieves the attachment of instance on the wrapper chain
* by static method {@link #getAttachmentFromWrapperChain(Object, Object)}
* <li>Verifies the compliance of wrapper chain with the specification contracts
* by static method {@link #verifyWrapperChainContracts(Object)}
* </ul>
*
* <h2>Advanced usages</h2>
Expand Down Expand Up @@ -99,6 +101,8 @@ private static boolean isInstanceOf(final Object o, final Class<?> clazz) {
* @throws ClassCastException if the return value is not type {@code <V>}
* @throws IllegalStateException if the adaptee of {@link WrapperAdapter} is type {@link Wrapper}
* @see Attachable#getAttachment(Object)
* @see Wrapper#unwrap()
* @see WrapperAdapter#adaptee()
*/
@Nullable
@SuppressWarnings("unchecked")
Expand All @@ -115,6 +119,28 @@ public static <W, K, V> V getAttachmentFromWrapperChain(final W wrapper, final K
}).orElse(null);
}

/**
* Verifies the compliance of wrapper chain with the specification contracts.
* <p>
* more about the specification contracts see the doc of below methods:
* <ul>
* <li>{@link Wrapper#unwrap()}
* <li>{@link WrapperAdapter#adaptee()}
* </ul>
*
* @param wrapper wrapper instance
* @param <W> the type of instances that be wrapped
* @throws NullPointerException if wrapped argument is null,
* 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 <W> void verifyWrapperChainContracts(final W wrapper) {
travelWrapperChain(wrapper, w -> Optional.empty());
}

/**
* Reports whether any instance on the wrapper chain satisfies the given {@code predicate}.
* <p>
Expand All @@ -130,6 +156,8 @@ public static <W, K, V> 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 <W> boolean testWrapperChain(final W wrapper, final Predicate<? super W> predicate) {
requireNonNull(wrapper, "wrapper is null");
Expand Down Expand Up @@ -158,6 +186,8 @@ public static <W> 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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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>, 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>, 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) {
}
}
}

0 comments on commit e6f567a

Please sign in to comment.