| Index: chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/InnerNodeTest.java
|
| diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/InnerNodeTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/InnerNodeTest.java
|
| index 07e9b5e4621062212d94fc4f472df8c2f853d6fb..2ba0adc99f7535ab1598c06ed74e78e77962b02d 100644
|
| --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/InnerNodeTest.java
|
| +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/InnerNodeTest.java
|
| @@ -6,11 +6,19 @@
|
|
|
| import static org.hamcrest.CoreMatchers.is;
|
| import static org.junit.Assert.assertThat;
|
| +import static org.junit.Assert.fail;
|
| +import static org.mockito.ArgumentMatchers.eq;
|
| +import static org.mockito.Mockito.doReturn;
|
| import static org.mockito.Mockito.mock;
|
| +import static org.mockito.Mockito.reset;
|
| +import static org.mockito.Mockito.spy;
|
| import static org.mockito.Mockito.verify;
|
| import static org.mockito.Mockito.verifyNoMoreInteractions;
|
| +import static org.mockito.Mockito.verifyZeroInteractions;
|
| import static org.mockito.Mockito.when;
|
|
|
| +import android.support.annotation.Nullable;
|
| +
|
| import org.junit.Before;
|
| import org.junit.Test;
|
| import org.junit.runner.RunWith;
|
| @@ -39,26 +47,15 @@
|
| @Before
|
| public void setUp() {
|
| MockitoAnnotations.initMocks(this);
|
| + mInnerNode = spy(new InnerNode());
|
|
|
| - for (int i = 0; i < ITEM_COUNTS.length; i++) {
|
| - TreeNode child = mock(TreeNode.class);
|
| - when(child.getItemCount()).thenReturn(ITEM_COUNTS[i]);
|
| + for (int childItemCount : ITEM_COUNTS) {
|
| + TreeNode child = makeDummyNode(childItemCount);
|
| mChildren.add(child);
|
| + mInnerNode.addChild(child);
|
| }
|
| - mInnerNode = new InnerNode(mParent) {
|
| - @Override
|
| - protected List<TreeNode> getChildren() {
|
| - return mChildren;
|
| - }
|
| - };
|
| - }
|
|
|
| - @Test
|
| - public void testInit() {
|
| - mInnerNode.init();
|
| - for (TreeNode child : mChildren) {
|
| - verify(child).init();
|
| - }
|
| + mInnerNode.setParent(mParent);
|
| }
|
|
|
| @Test
|
| @@ -112,37 +109,36 @@ public void testGetSuggestion() {
|
| }
|
|
|
| @Test
|
| - public void testDidAddChild() {
|
| - TreeNode child = mock(TreeNode.class);
|
| - when(child.getItemCount()).thenReturn(23);
|
| - mChildren.add(3, child);
|
| - mInnerNode.didAddChild(child);
|
| -
|
| - // The child should have been initialized and the parent notified about the added items.
|
| - verify(child).init();
|
| - verify(mParent).onItemRangeInserted(mInnerNode, 6, 23);
|
| -
|
| - TreeNode child2 = mock(TreeNode.class);
|
| - when(child2.getItemCount()).thenReturn(0);
|
| - mChildren.add(4, child2);
|
| - mInnerNode.didAddChild(child2);
|
| - verify(child2).init();
|
| + public void testAddChild() {
|
| + final int itemCountBefore = mInnerNode.getItemCount();
|
| +
|
| + TreeNode child = makeDummyNode(23);
|
| + mInnerNode.addChild(child);
|
| +
|
| + // The child should have been initialized and the parent hierarchy notified about it.
|
| + verify(child).setParent(eq(mInnerNode));
|
| + verify(mParent).onItemRangeInserted(mInnerNode, itemCountBefore, 23);
|
| +
|
| + TreeNode child2 = makeDummyNode(0);
|
| + mInnerNode.addChild(child2);
|
|
|
| // The empty child should have been initialized, but there should be no change
|
| // notifications.
|
| + verify(child2).setParent(eq(mInnerNode));
|
| verifyNoMoreInteractions(mParent);
|
| }
|
|
|
| @Test
|
| - public void testWillRemoveChild() {
|
| - mInnerNode.willRemoveChild(mChildren.get(4));
|
| - mChildren.remove(4);
|
| + public void testRemoveChild() {
|
| + TreeNode child = mChildren.get(4);
|
| + mInnerNode.removeChild(child);
|
|
|
| // The parent should have been notified about the removed items.
|
| verify(mParent).onItemRangeRemoved(mInnerNode, 6, 3);
|
|
|
| - mInnerNode.willRemoveChild(mChildren.get(3));
|
| - mChildren.remove(3);
|
| + reset(mParent); // Prepare for the #verifyNoMoreInteractions() call below.
|
| + TreeNode child2 = mChildren.get(3);
|
| + mInnerNode.removeChild(child2);
|
|
|
| // There should be no change notifications about the empty child.
|
| verifyNoMoreInteractions(mParent);
|
| @@ -160,5 +156,78 @@ public void testNotifications() {
|
| verify(mParent).onItemRangeChanged(mInnerNode, 6, 6502);
|
| verify(mParent).onItemRangeRemoved(mInnerNode, 11, 8086);
|
| }
|
| +
|
| + /**
|
| + * Tests that {@link ChildNode} sends the change notifications AFTER its child list is modified.
|
| + */
|
| + @Test
|
| + public void testChangeNotificationsTiming() {
|
| + // The MockModeParent will enforce a given number of items in the child when notified.
|
| + MockNodeParent parent = spy(new MockNodeParent());
|
| + InnerNode rootNode = new InnerNode();
|
| +
|
| + TreeNode[] children = {makeDummyNode(3), makeDummyNode(5)};
|
| + rootNode.addChildren(children);
|
| + rootNode.setParent(parent);
|
| +
|
| + assertThat(rootNode.getItemCount(), is(8));
|
| + verifyZeroInteractions(parent); // Before the parent is set, no notifications.
|
| +
|
| + parent.expectItemCount(24);
|
| + rootNode.addChildren(makeDummyNode(7), makeDummyNode(9)); // Should bundle the insertions.
|
| + verify(parent).onItemRangeInserted(eq(rootNode), eq(8), eq(16));
|
| +
|
| + parent.expectItemCount(28);
|
| + rootNode.addChild(makeDummyNode(4));
|
| + verify(parent).onItemRangeInserted(eq(rootNode), eq(24), eq(4));
|
| +
|
| + parent.expectItemCount(23);
|
| + rootNode.removeChild(children[1]);
|
| + verify(parent).onItemRangeRemoved(eq(rootNode), eq(3), eq(5));
|
| +
|
| + parent.expectItemCount(0);
|
| + rootNode.removeChildren(); // Bundles the removals in a single change notification
|
| + verify(parent).onItemRangeRemoved(eq(rootNode), eq(0), eq(23));
|
| + }
|
| +
|
| + /**
|
| + * Implementation of {@link NodeParent} that checks the item count from the node that
|
| + * sends notifications against defined expectations. Fails on unexpected calls.
|
| + */
|
| + private static class MockNodeParent implements NodeParent {
|
| + @Nullable
|
| + private Integer mNextExpectedItemCount;
|
| +
|
| + public void expectItemCount(int count) {
|
| + mNextExpectedItemCount = count;
|
| + }
|
| +
|
| + @Override
|
| + public void onItemRangeChanged(TreeNode child, int index, int count) {
|
| + checkCount(child);
|
| + }
|
| +
|
| + @Override
|
| + public void onItemRangeInserted(TreeNode child, int index, int count) {
|
| + checkCount(child);
|
| + }
|
| +
|
| + @Override
|
| + public void onItemRangeRemoved(TreeNode child, int index, int count) {
|
| + checkCount(child);
|
| + }
|
| +
|
| + private void checkCount(TreeNode child) {
|
| + if (mNextExpectedItemCount == null) fail("Unexpected call");
|
| + assertThat(child.getItemCount(), is(mNextExpectedItemCount));
|
| + mNextExpectedItemCount = null;
|
| + }
|
| + }
|
| +
|
| + private static TreeNode makeDummyNode(int itemCount) {
|
| + TreeNode node = mock(TreeNode.class);
|
| + doReturn(itemCount).when(node).getItemCount();
|
| + return node;
|
| + }
|
| }
|
|
|
|
|