void log(String msg) {
   if (mCollectLogs) {
     mLog.append(msg).append("\n");
   } else {
     Log.d(TAG, msg);
   }
 }
 void preProcess() {
   for (MockViewHolder vh : mViewHolders) {
     final int ind = mTestAdapter.mItems.indexOf(vh.mItem);
     assertEquals(
         "actual adapter position should match",
         ind,
         mAdapterHelper.applyPendingUpdatesToPosition(vh.mPosition));
   }
   mAdapterHelper.preProcess();
   for (int i = 0; i < mPreProcessClone.mItems.size(); i++) {
     TestAdapter.Item item = mPreProcessClone.mItems.get(i);
     final int preLayoutIndex = mPreLayoutItems.indexOf(item);
     final int endIndex = mTestAdapter.mItems.indexOf(item);
     if (preLayoutIndex != -1) {
       assertEquals(
           "find position offset should work properly for existing elements"
               + i
               + " at pre layout position "
               + preLayoutIndex
               + " and post layout position "
               + endIndex,
           endIndex,
           mAdapterHelper.findPositionOffset(preLayoutIndex));
     }
   }
   // make sure visible view holders still have continuous positions
   final StringBuilder vhLogBuilder = new StringBuilder();
   for (ViewHolder vh : mViewHolders) {
     vhLogBuilder.append("\n").append(vh.toString());
   }
   if (mViewHolders.size() > 0) {
     final String vhLog = vhLogBuilder.toString();
     final int start = mViewHolders.get(0).getLayoutPosition();
     for (int i = 1; i < mViewHolders.size(); i++) {
       assertEquals(
           "view holder positions should be continious in pre-layout" + vhLog,
           start + i,
           mViewHolders.get(i).getLayoutPosition());
     }
   }
   mAdapterHelper.consumePostponedUpdates();
   // now assert these two adapters have identical data.
   mPreProcessClone.applyOps(mFirstPassUpdates, mTestAdapter);
   mPreProcessClone.applyOps(mSecondPassUpdates, mTestAdapter);
   assertAdaptersEqual(mTestAdapter, mPreProcessClone);
 }