@Override public void run(TestResult result) { super.run(result); if (!result.wasSuccessful()) { result.addFailure(this, new AssertionFailedError(mLog.toString())); } }
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); }
@Test public void testChangeAll() throws Exception { try { setupBasic(5, 0, 3); up(0, 5); mAdapterHelper.preProcess(); } catch (Throwable t) { throw new Exception(mLog.toString()); } }
@Test public void testScenerio33() throws Throwable { try { mCollectLogs = true; setupBasic(10, 7, 1); mv(0, 6); up(0, 7); preProcess(); } catch (Throwable t) { throw new Throwable(t.getMessage() + "\n" + mLog.toString()); } }
@Test public void testScenerio37() throws Throwable { try { mCollectLogs = true; setupBasic(10, 5, 2); mv(3, 6); rm(4, 4); rm(3, 2); preProcess(); } catch (Throwable t) { throw new Throwable(t.getMessage() + "\n" + mLog.toString()); } }
@Test public void testRandom() throws Throwable { mCollectLogs = true; Random random = new Random(System.nanoTime()); for (int i = 0; i < 100; i++) { try { Log.d(TAG, "running random test " + i); randomTest(random, Math.max(40, 10 + nextInt(random, i))); } catch (Throwable t) { throw new Throwable( "failure at random test " + i + "\n" + t.getMessage() + "\n" + mLog.toString(), t); } } }
@Before public void cleanState() { mLog.setLength(0); mPreLayoutItems = new ArrayList<TestAdapter.Item>(); mViewHolders = new ArrayList<MockViewHolder>(); mFirstPassUpdates = new ArrayList<AdapterHelper.UpdateOp>(); mSecondPassUpdates = new ArrayList<AdapterHelper.UpdateOp>(); mPreProcessClone = null; mAdapterHelper = new AdapterHelper( new AdapterHelper.Callback() { @Override public RecyclerView.ViewHolder findViewHolder(int position) { for (ViewHolder vh : mViewHolders) { if (vh.mPosition == position && !vh.isRemoved()) { return vh; } } return null; } @Override public void offsetPositionsForRemovingInvisible(int positionStart, int itemCount) { final int positionEnd = positionStart + itemCount; for (ViewHolder holder : mViewHolders) { if (holder.mPosition >= positionEnd) { holder.offsetPosition(-itemCount, true); } else if (holder.mPosition >= positionStart) { holder.flagRemovedAndOffsetPosition(positionStart - 1, -itemCount, true); } } } @Override public void offsetPositionsForRemovingLaidOutOrNewView( int positionStart, int itemCount) { final int positionEnd = positionStart + itemCount; for (ViewHolder holder : mViewHolders) { if (holder.mPosition >= positionEnd) { holder.offsetPosition(-itemCount, false); } else if (holder.mPosition >= positionStart) { holder.flagRemovedAndOffsetPosition(positionStart - 1, -itemCount, false); } } } @Override public void markViewHoldersUpdated(int positionStart, int itemCount) { final int positionEnd = positionStart + itemCount; for (ViewHolder holder : mViewHolders) { if (holder.mPosition >= positionStart && holder.mPosition < positionEnd) { holder.addFlags(ViewHolder.FLAG_UPDATE); } } } @Override public void onDispatchFirstPass(AdapterHelper.UpdateOp updateOp) { if (DEBUG) { log("first pass:"******"update op should not match any existing view holders", viewHolder.getLayoutPosition() == updateOp.positionStart + i); } } mFirstPassUpdates.add(updateOp); } @Override public void onDispatchSecondPass(AdapterHelper.UpdateOp updateOp) { if (DEBUG) { log("second pass:" + updateOp.toString()); } mSecondPassUpdates.add(updateOp); } @Override public void offsetPositionsForAdd(int positionStart, int itemCount) { for (ViewHolder holder : mViewHolders) { if (holder != null && holder.mPosition >= positionStart) { holder.offsetPosition(itemCount, false); } } } @Override public void offsetPositionsForMove(int from, int to) { final int start, end, inBetweenOffset; if (from < to) { start = from; end = to; inBetweenOffset = -1; } else { start = to; end = from; inBetweenOffset = 1; } for (ViewHolder holder : mViewHolders) { if (holder == null || holder.mPosition < start || holder.mPosition > end) { continue; } if (holder.mPosition == from) { holder.offsetPosition(to - from, false); } else { holder.offsetPosition(inBetweenOffset, false); } } } }, true); }