// should set both nextCursor and previousCursor to be non-null
 @Test
 public void testPreviousCallback_successFirstReceivedItems() {
   delegate = new TimelineDelegate<>(mockTimeline, mockObservable, testItems);
   final TimelineStateHolder timelineStateHolder = new TimelineStateHolder();
   final TimelineDelegate.PreviousCallback cb = delegate.new PreviousCallback(timelineStateHolder);
   cb.success(new Result<>(new TimelineResult<>(TEST_TIMELINE_CURSOR, testExtraItems), null));
   // assert the previous TimelineCursor is set on the ScrollStateHolder
   assertEquals(TEST_MAX_POSITION, timelineStateHolder.positionForNext());
   assertEquals(TEST_MIN_POSITION, timelineStateHolder.positionForPrevious());
 }
 // should do nothing
 @Test
 public void testPreviousCallback_successReceivedZeroItems() {
   delegate = new TimelineDelegate<>(mockTimeline, mockObservable, testItems);
   final TimelineStateHolder timelineStateHolder = new TimelineStateHolder();
   final TimelineDelegate.PreviousCallback cb = delegate.new PreviousCallback(timelineStateHolder);
   cb.success(
       new Result<>(new TimelineResult<>(TEST_TIMELINE_CURSOR, Collections.emptyList()), null));
   // assert that the cursors and itemList are left unmodified
   assertNull(timelineStateHolder.positionForNext());
   assertNull(timelineStateHolder.positionForPrevious());
   assertEquals(testItems.size(), delegate.itemList.size());
   verifyZeroInteractions(mockObservable);
 }
 // should clear items with result items, set next cursor, and call notifyChanged
 @Test
 public void testRefreshCallback_successReceivedItems() {
   delegate = new TimelineDelegate<>(mockTimeline, mockObservable, testItems);
   final TimelineStateHolder timelineStateHolder =
       new TimelineStateHolder(
           new TimelineCursor(ANY_POSITION, ANY_POSITION),
           new TimelineCursor(ANY_POSITION, ANY_POSITION));
   final TimelineDelegate.RefreshCallback cb =
       delegate.new RefreshCallback(null, timelineStateHolder);
   cb.success(new Result<>(new TimelineResult<>(TEST_TIMELINE_CURSOR, testExtraItems), null));
   // assert the next TimelineCursor is set on the ScrollStateHolder, previous unchanged
   assertEquals(TEST_MAX_POSITION, timelineStateHolder.positionForNext());
   assertEquals(ANY_POSITION, timelineStateHolder.positionForPrevious());
   // assert that extra items replaced the old items
   assertEquals(testExtraItems.size(), delegate.itemList.size());
   assertEquals(TEST_ITEM_4, delegate.getItem(0));
   assertEquals(TEST_ITEM_3, delegate.getItem(1));
   // assert observer's notifyChanged is called
   verify(mockObservable).notifyChanged();
 }
 // should append result items, set previous cursor, and call notifyChanged
 @Test
 public void testPreviousCallback_successReceivedItems() {
   delegate = new TimelineDelegate<>(mockTimeline, mockObservable, testItems);
   final TimelineStateHolder timelineStateHolder =
       new TimelineStateHolder(
           new TimelineCursor(ANY_POSITION, ANY_POSITION),
           new TimelineCursor(ANY_POSITION, ANY_POSITION));
   final TimelineDelegate.PreviousCallback cb = delegate.new PreviousCallback(timelineStateHolder);
   cb.success(new Result<>(new TimelineResult<>(TEST_TIMELINE_CURSOR, testExtraItems), null));
   // assert the previous TimelineCursor is set on the ScrollStateHolder
   assertEquals(TEST_MIN_POSITION, timelineStateHolder.positionForPrevious());
   assertEquals(ANY_POSITION, timelineStateHolder.positionForNext());
   // assert that extra items were appended in order received
   assertEquals(TOTAL_ITEMS, delegate.itemList.size());
   assertEquals(TEST_ITEM_2, delegate.getItem(0));
   assertEquals(TEST_ITEM_1, delegate.getItem(1));
   assertEquals(TEST_ITEM_4, delegate.getItem(2));
   assertEquals(TEST_ITEM_3, delegate.getItem(3));
   // assert observer's notifyChanged is called
   verify(mockObservable).notifyChanged();
 }