@Test
  public void setFetchCount() {
    int newFetchCount = timeline.getFetchCount() + 1;

    timeline.setFetchCount(newFetchCount);

    assertEquals(newFetchCount, timeline.getFetchCount());
  }
  @Test
  public void fetchItemsIfNonAvailable() throws IOException {
    timeline.fetchItems();
    List<Item> actual = timeline.getItems();

    assertTrue(actual.isEmpty());
    verify(sessionStorage).storeTop(null);
  }
  @Test
  public void fetchItemsIfFetchCountExceedsAvailableItems() throws IOException {
    itemProvider.addItems(FIRST_ITEM, SECOND_ITEM);

    timeline.fetchItems();
    List<Item> actual = timeline.getItems();

    assertArrayEquals(new Item[] {SECOND_ITEM, FIRST_ITEM}, actual.toArray(new Item[2]));
    verify(sessionStorage).storeTop(SECOND_ITEM);
  }
  @Test
  public void fetchFirstItemsWithoutTopItemToRecover() throws IOException {
    itemProvider.addItems(FIRST_ITEM, SECOND_ITEM, THIRD_ITEM, FOURTH_ITEM);
    timeline.setFetchCount(2);

    timeline.fetchItems();
    List<Item> actual = timeline.getItems();

    assertArrayEquals(new Item[] {FOURTH_ITEM, THIRD_ITEM}, actual.toArray(new Item[2]));
    verify(sessionStorage).storeTop(FOURTH_ITEM);
  }
  @Test
  public void fetchItems() {
    itemProvider.addItems(FIRST_ITEM, SECOND_ITEM, THIRD_ITEM, FOURTH_ITEM, FIFTH_ITEM, SIXTH_ITEM);
    timeline.setFetchCount(2);
    timeline.fetchItems();

    timeline.fetchItems();
    List<Item> actual = timeline.getItems();

    assertArrayEquals(
        new Item[] {SIXTH_ITEM, FIFTH_ITEM, FOURTH_ITEM, THIRD_ITEM}, actual.toArray(new Item[2]));
  }
  @Test
  public void fetchItemWithRuntimeExceptionOnStoreTop() throws IOException {
    RuntimeException cause = new RuntimeException();
    doThrow(cause).when(sessionStorage).storeTop(any(Item.class));

    Throwable actual = thrownBy(() -> timeline.fetchItems());

    assertNotNull(actual);
    assertSame(cause, actual);
  }
  @Test
  public void setFetchCountExceedsLowerBound() {
    int tooSmall = FETCH_COUNT_LOWER_BOUND - 1;

    Throwable actual = thrownBy(() -> timeline.setFetchCount(tooSmall));

    assertNotNull(actual);
    assertTrue(actual instanceof IllegalArgumentException);
    assertTrue(actual.getMessage().contains(valueOf(tooSmall)));
    assertEquals(format(ERROR_EXCEEDS_LOWER_BOUND, tooSmall), actual.getMessage());
  }
  @Test
  public void fetchItemWithExceptionOnStoreTop() throws IOException {
    IOException cause = new IOException();
    doThrow(cause).when(sessionStorage).storeTop(any(Item.class));

    Throwable actual = thrownBy(() -> timeline.fetchItems());

    assertNotNull(actual);
    assertTrue(actual instanceof IllegalStateException);
    assertSame(cause, actual.getCause());
    assertEquals(Timeline.ERROR_STORE_TOP, actual.getMessage());
  }
 @Test
 public void initialState() {
   assertTrue(timeline.getFetchCount() > 0);
 }