/*
* Copyright (C) 2012-2015 DataStax Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.datastax.driver.core;
import com.datastax.driver.core.DelegatingClusterIntegrationTest.SimpleDelegatingCluster;
import com.google.common.collect.ImmutableSet;
import org.mockito.Mockito;
import org.mockito.exceptions.verification.WantedButNotInvoked;
import org.mockito.invocation.Invocation;
import org.testng.annotations.Test;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Set;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
public class DelegatingClusterTest {
private static final Set<String> NON_DELEGATED_METHODS = ImmutableSet.of("getClusterName");
/**
* Checks that all methods of {@link DelegatingCluster} invoke their counterpart in {@link Cluster}.
* This protects us from forgetting to add a method to the former when it gets added to the latter.
* <p>
* Note that a much better, compile-time solution would be to make {@link Cluster} an interface, but that's a
* breaking change so it will have to wait until the next major version.
*/
@Test(groups = "unit")
public void should_call_delegate_methods() throws Exception {
Cluster delegate = mock(Cluster.class);
SimpleDelegatingCluster delegatingCluster = new SimpleDelegatingCluster(delegate);
for (Method method : Cluster.class.getMethods()) {
if ((method.getModifiers() & Modifier.STATIC) == Modifier.STATIC ||
NON_DELEGATED_METHODS.contains(method.getName()) ||
method.getDeclaringClass() == Object.class) {
continue;
}
// we can leave all parameters to null since we're invoking a mock
Object[] parameters = new Object[method.getParameterTypes().length];
try {
method.invoke(delegatingCluster, parameters);
} catch (Exception ignored) {
}
verify(delegate, method, parameters);
reset(delegate);
}
}
private static void verify(Object mock, Method expectedMethod, Object... expectedArguments) {
out:
for (Invocation invocation : Mockito.mockingDetails(mock).getInvocations()) {
if (invocation.getMethod().equals(expectedMethod)) {
Object[] actualArguments = invocation.getArguments();
assert actualArguments.length == expectedArguments.length; // because it's the same method
for (int i = 0; i < actualArguments.length; i++) {
Object actual = actualArguments[i];
Object expected = expectedArguments[i];
boolean equal = (actual == null) ? expected == null : actual.equals(expected);
if (!equal) {
continue out;
}
}
invocation.markVerified();
return;
}
}
throw new WantedButNotInvoked("Not delegated: " + expectedMethod.toString());
}
}