### Question:
ChainDataProvider { public SafeFuture<Optional<ValidatorResponse>> getValidatorDetails( final Optional<UInt64> maybeSlot, final Optional<Integer> maybeIndex) { if (!isStoreAvailable()) { throw new ChainDataUnavailableException(); } if (maybeSlot.isEmpty() || maybeIndex.isEmpty()) { return SafeFuture.completedFuture(Optional.empty()); } final int index = maybeIndex.get(); return combinedChainDataClient .getStateAtSlotExact(maybeSlot.get()) .thenApply( maybeState -> maybeState.map(state -> ValidatorResponse.fromState(state, index))); } ChainDataProvider(
      final RecentChainData recentChainData,
      final CombinedChainDataClient combinedChainDataClient); UInt64 getGenesisTime(); Optional<BeaconHead> getBeaconHead(); GetForkResponse getForkInfo(); SafeFuture<Optional<List<Committee>>> getCommitteesAtEpoch(final UInt64 epoch); SafeFuture<Optional<GetBlockResponse>> getBlockBySlot(final UInt64 slot); boolean isStoreAvailable(); Optional<Bytes32> getBestBlockRoot(); UInt64 getCurrentEpoch(); SafeFuture<Optional<GetBlockResponse>> getBlockByBlockRoot(final Bytes32 blockParam); SafeFuture<Optional<BeaconState>> getStateByBlockRoot(final Bytes32 blockRoot); SafeFuture<Optional<BeaconState>> getStateByStateRoot(final Bytes32 stateRoot); SafeFuture<Optional<BeaconState>> getStateAtSlot(final UInt64 slot); SafeFuture<Optional<Bytes32>> getStateRootAtSlot(final UInt64 slot); SafeFuture<Optional<BeaconValidators>> getValidatorsByValidatorsRequest(
      final ValidatorsRequest request); boolean isFinalized(final SignedBeaconBlock signedBeaconBlock); boolean isFinalized(final UInt64 slot); boolean isFinalizedEpoch(final UInt64 epoch); Optional<BeaconChainHead> getHeadState(); Optional<UInt64> stateParameterToSlot(final String pathParam); Optional<Integer> validatorParameterToIndex(final String validatorParameter); SafeFuture<Optional<Fork>> getForkAtSlot(final UInt64 slot); SafeFuture<Optional<ValidatorResponse>> getValidatorDetails(
      final Optional<UInt64> maybeSlot, final Optional<Integer> maybeIndex); Optional<Bytes32> getStateRootFromBlockRoot(final Bytes32 blockRoot);  }### Answer:
@Test public void getValidatorDetails_shouldThrowWhenStoreNotFound() { final ChainDataProvider provider = new ChainDataProvider(null, mockCombinedChainDataClient); assertThrows( ChainDataUnavailableException.class, () -> provider.getValidatorDetails(Optional.empty(), Optional.empty())); }
@Test public void validatorDetails_shouldReturnEmptyForFutureState() { final ChainDataProvider provider = new ChainDataProvider(recentChainData, combinedChainDataClient); Optional<ValidatorResponse> response = provider.getValidatorDetails(Optional.of(UInt64.valueOf(12345678)), Optional.of(1)).join(); assertThat(response).isEmpty(); }
@Test public void getValidatorDetails_shouldReturnEmptyFromEmptyState() { final ChainDataProvider provider = new ChainDataProvider(recentChainData, combinedChainDataClient); assertThat(provider.getValidatorDetails(Optional.empty(), Optional.of(1)).join()).isEmpty(); }
@Test public void getValidatorDetails_shouldReturnEmptyFromEmptyValidatorIndex() { final ChainDataProvider provider = new ChainDataProvider(recentChainData, combinedChainDataClient); assertThat(provider.getValidatorDetails(Optional.of(ONE), Optional.empty()).join()).isEmpty(); }