package net.bytebuddy.implementation.bind; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.test.utility.MockitoRule; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.mockito.Mock; import java.util.Arrays; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class MethodDelegationBinderProcessorTest { @Rule public TestRule mockitoRule = new MockitoRule(this); @Mock private MethodDescription source; @Mock private MethodDelegationBinder.AmbiguityResolver ambiguityResolver; @Mock private MethodDelegationBinder.MethodBinding boundDelegation, unboundDelegation, dominantBoundDelegation; @Mock private MethodDelegationBinder.Record boundRecord, unboundRecord, dominantBoundRecord; @Mock private MethodDelegationBinder.TerminationHandler terminationHandler; @Mock private MethodDelegationBinder.MethodInvoker methodInvoker; @Mock private Implementation.Target implementationTarget; @Mock private Assigner assigner; @Before public void setUp() throws Exception { when(boundDelegation.isValid()).thenReturn(true); when(unboundDelegation.isValid()).thenReturn(false); when(dominantBoundDelegation.isValid()).thenReturn(true); when(boundRecord.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner)).thenReturn(boundDelegation); when(unboundRecord.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner)).thenReturn(unboundDelegation); when(dominantBoundRecord.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner)).thenReturn(dominantBoundDelegation); when(ambiguityResolver.resolve(source, dominantBoundDelegation, boundDelegation)).thenReturn(MethodDelegationBinder.AmbiguityResolver.Resolution.LEFT); when(ambiguityResolver.resolve(source, boundDelegation, dominantBoundDelegation)).thenReturn(MethodDelegationBinder.AmbiguityResolver.Resolution.RIGHT); when(ambiguityResolver.resolve(source, boundDelegation, boundDelegation)).thenReturn(MethodDelegationBinder.AmbiguityResolver.Resolution.AMBIGUOUS); } @Test(expected = IllegalArgumentException.class) public void testNoBindableTarget() throws Exception { MethodDelegationBinder.Processor processor = new MethodDelegationBinder.Processor(Arrays.asList(unboundRecord, unboundRecord, unboundRecord), ambiguityResolver); processor.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); } @Test public void testOneBindableTarget() throws Exception { MethodDelegationBinder.Processor processor = new MethodDelegationBinder.Processor(Arrays.asList(unboundRecord, boundRecord, unboundRecord), ambiguityResolver); MethodDelegationBinder.MethodBinding result = processor.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); assertThat(result, is(boundDelegation)); verify(boundRecord, times(1)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(boundDelegation, atLeast(1)).isValid(); verify(unboundRecord, times(2)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(unboundDelegation, atLeast(2)).isValid(); verifyZeroInteractions(ambiguityResolver); } @Test public void testTwoBindableTargetsWithDominant() throws Exception { MethodDelegationBinder.Processor processor = new MethodDelegationBinder.Processor(Arrays.asList(unboundRecord, boundRecord, dominantBoundRecord), ambiguityResolver); MethodDelegationBinder.MethodBinding result = processor.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); assertThat(result, is(dominantBoundDelegation)); verify(unboundRecord, times(1)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(unboundDelegation, atLeast(1)).isValid(); verify(boundRecord, times(1)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(boundDelegation, atLeast(1)).isValid(); verify(dominantBoundRecord, times(1)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(dominantBoundDelegation, atLeast(1)).isValid(); verify(ambiguityResolver).resolve(source, boundDelegation, dominantBoundDelegation); verifyNoMoreInteractions(ambiguityResolver); } @Test(expected = IllegalArgumentException.class) public void testTwoBindableTargetsWithoutDominant() throws Exception { MethodDelegationBinder.Processor processor = new MethodDelegationBinder.Processor(Arrays.asList(unboundRecord, boundRecord, boundRecord), ambiguityResolver); processor.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); } @Test public void testThreeBindableTargetsDominantBindableFirst() throws Exception { MethodDelegationBinder.Processor processor = new MethodDelegationBinder.Processor(Arrays.asList(dominantBoundRecord, boundRecord, boundRecord), ambiguityResolver); MethodDelegationBinder.MethodBinding result = processor.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); assertThat(result, is(dominantBoundDelegation)); verify(boundRecord, times(2)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(boundDelegation, atLeast(2)).isValid(); verify(dominantBoundRecord, times(1)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(dominantBoundDelegation, atLeast(1)).isValid(); verify(ambiguityResolver, times(2)).resolve(source, dominantBoundDelegation, boundDelegation); verifyNoMoreInteractions(ambiguityResolver); } @Test public void testThreeBindableTargetsDominantBindableMid() throws Exception { MethodDelegationBinder.Processor processor = new MethodDelegationBinder.Processor(Arrays.asList(boundRecord, dominantBoundRecord, boundRecord), ambiguityResolver); MethodDelegationBinder.MethodBinding result = processor.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); assertThat(result, is(dominantBoundDelegation)); verify(boundRecord, times(2)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(boundDelegation, atLeast(2)).isValid(); verify(dominantBoundRecord, times(1)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(dominantBoundDelegation, atLeast(1)).isValid(); verify(ambiguityResolver).resolve(source, boundDelegation, dominantBoundDelegation); verify(ambiguityResolver).resolve(source, dominantBoundDelegation, boundDelegation); verifyNoMoreInteractions(ambiguityResolver); } @Test public void testThreeBindableTargetsDominantBindableLast() throws Exception { MethodDelegationBinder.Processor processor = new MethodDelegationBinder.Processor(Arrays.asList(boundRecord, boundRecord, dominantBoundRecord), ambiguityResolver); MethodDelegationBinder.MethodBinding result = processor.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); assertThat(result, is(dominantBoundDelegation)); verify(boundRecord, times(2)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(boundDelegation, atLeast(2)).isValid(); verify(dominantBoundRecord, times(1)).bind(implementationTarget, source, terminationHandler, methodInvoker, assigner); verify(dominantBoundDelegation, atLeast(1)).isValid(); verify(ambiguityResolver).resolve(source, boundDelegation, boundDelegation); verify(ambiguityResolver, times(2)).resolve(source, boundDelegation, dominantBoundDelegation); verifyNoMoreInteractions(ambiguityResolver); } @Test public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(MethodDelegationBinder.Processor.class).apply(); } }