@DataProvider(value = {

    "OPEN   |   true    |   false",
    "OPEN   |   true    |   true",
    "OPEN   |   false   |   false",
    "CLOSED |   true    |   false",
    "CLOSED |   true    |   true",
    "CLOSED |   false   |   false",
}, splitBy = "\\|")
@Test
public void processSuccessfulCall_cancels_existing_half_open_scheduled_future_if_state_changed_and_future_exists_and_future_is_not_done(
    State stateBeforeCall, boolean futureExists, boolean futureIsDone) {
    // given
    cbSpy.currentState = stateBeforeCall;
    ScheduledFuture futureMock = futureExists ? mock(ScheduledFuture.class) : null;
    cbSpy.halfOpenScheduledFuture.set(futureMock);
    if (futureMock != null)
        doReturn(futureIsDone).when(futureMock).isDone();
    boolean expectStateChange = !stateBeforeCall.equals(State.CLOSED);
    boolean expectFutureToBeCanceled = expectStateChange && futureExists && !futureIsDone;
    // when
    cbSpy.processSuccessfulCall();
    // then
    if (expectStateChange)
        assertThat(cbSpy.halfOpenScheduledFuture.get()).isNull();
    else
        assertThat(cbSpy.halfOpenScheduledFuture.get()).isSameAs(futureMock);
    if (futureExists) {
        if (expectFutureToBeCanceled)
            verify(futureMock).cancel(false);
        else
            verify(futureMock, times(0)).cancel(false);
    }
}