/*
* Copyright 2015 Jacek Marchwicki <jacek.marchwicki@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.appunite.detector;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import javax.annotation.Nonnull;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
public class ChangesDetectorTest {
private ChangesDetector<Cat, Cat> detector;
private ChangesDetector.ChangesAdapter adapter;
private static class Cat {
private final int id;
private final String name;
private Cat(int id, String name) {
this.id = id;
this.name = name;
}
Cat(int id) {
this.id = id;
name = generateName(id);
}
Cat withName(String name) {
return new Cat(id, name);
}
@Nonnull
private String generateName(int id) {
switch (id) {
case 0:
return "zero";
case 1:
return "one";
case 2:
return "two";
case 3:
return "tree";
case 4:
return "four";
case 5:
return "five";
default:
throw new RuntimeException("Unknown id: " + id);
}
}
@Override
public String toString() {
return "Cat{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
@Before
public void setUp() throws Exception {
detector = new ChangesDetector<>(new ChangesDetector.Detector<Cat, Cat>() {
@Nonnull
@Override
public Cat apply(@Nonnull Cat item) {
return item;
}
@Override
public boolean matches(@Nonnull Cat item, @Nonnull Cat newOne) {
return item.id == newOne.id;
}
@Override
public boolean same(@Nonnull Cat item, @Nonnull Cat newOne) {
return item.id == newOne.id && Objects.equal(item.name, newOne.name);
}
});
adapter = mock(ChangesDetector.ChangesAdapter.class);
}
@Test
public void testStart() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1)), false);
verify(adapter).notifyItemRangeInserted(0, 1);
}
@Test
public void testAfterChangeOrder_orderIsChangeIsNotified1() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(0), new Cat(1)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(0)), false);
verify(adapter).notifyItemMoved(1, 0);
verifyNoMoreInteractions(adapter);
}
@Test
public void testAfterChangeOrder_orderIsChangeIsNotified2() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(0), new Cat(1), new Cat(2)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(0), new Cat(2)), false);
verify(adapter).notifyItemMoved(1, 0);
verifyNoMoreInteractions(adapter);
}
@Test
public void testAfterChangeOrder_orderIsChangeIsNotified3() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(0), new Cat(1), new Cat(2)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(0)), false);
final InOrder inOrder = inOrder(adapter);
inOrder.verify(adapter).notifyItemMoved(1, 0); // 1, 0, 2
inOrder.verify(adapter).notifyItemMoved(2, 1); // 1, 2, 0
verifyNoMoreInteractions(adapter);
}
@Test
public void testAfterChangeOrderAndModifyItem_orderAndChangeAreNotified() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(0), new Cat(1)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(0).withName("zero_")), false);
final InOrder inOrder = inOrder(adapter);
inOrder.verify(adapter).notifyItemMoved(1, 0); // one, zero
inOrder.verify(adapter).notifyItemRangeChanged(1, 1); // one, zero_
verifyNoMoreInteractions(adapter);
}
@Test
public void testAfterChangeOrderAndDeleteSomeItem_orderAndDeleteAreNotified1() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(0), new Cat(1), new Cat(2)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(0)), false);
final InOrder inOrder = inOrder(adapter);
inOrder.verify(adapter).notifyItemMoved(1, 0);
inOrder.verify(adapter).notifyItemRangeRemoved(2, 1);
verifyNoMoreInteractions(adapter);
}
@Test
public void testAfterChangeOrderAndDeleteSomeItem_orderAndDeleteAreNotified2() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(0), new Cat(1), new Cat(2)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2)), false);
verify(adapter).notifyItemRangeRemoved(0, 1);
verifyNoMoreInteractions(adapter);
}
@Test
public void testAfterChangeOrderAndDeleteSomeItem_orderAndDeleteAreNotified3() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(0), new Cat(1), new Cat(2)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(2), new Cat(0)), false);
final InOrder inOrder = inOrder(adapter);
inOrder.verify(adapter).notifyItemMoved(2, 0); // 2, 0, 1
inOrder.verify(adapter).notifyItemRangeRemoved(2, 1); // 2, 0
verifyNoMoreInteractions(adapter);
}
@Test
public void testAfterChangeOrderAndDeleteSomeItem_orderAndDeleteAreNotified4() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(0), new Cat(1), new Cat(2)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(2), new Cat(1), new Cat(0)), false);
final InOrder inOrder = inOrder(adapter);
inOrder.verify(adapter).notifyItemMoved(2, 0); // 2, 0, 1
inOrder.verify(adapter).notifyItemMoved(2, 1); // 2, 1, 0
verifyNoMoreInteractions(adapter);
}
@Test
public void testAfterInsertAtFirstPlace_firstPlaceIsMarkedAsInserted() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(0), new Cat(1)), true);
verify(adapter).notifyItemRangeInserted(0, 1);
}
@Test
public void testForce() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1)), true);
verify(adapter).notifyItemRangeChanged(0, 1);
}
@Test
public void testForce2() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2)), true);
final InOrder inOrder = inOrder(adapter);
inOrder.verify(adapter).notifyItemRangeChanged(0, 1);
inOrder.verify(adapter).notifyItemRangeInserted(1, 1);
}
@Test
public void testAddItemAtTheEnd() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2)), false);
verify(adapter).notifyItemRangeInserted(1, 1);
}
@Test
public void testAddTwoItemsAtTheEnd() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3)), false);
verify(adapter).notifyItemRangeInserted(1, 2);
}
@Test
public void testAddItemAtTheBegining() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(2)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2)), false);
verify(adapter).notifyItemRangeInserted(0, 1);
}
@Test
public void testAddTwoItemsAtTheBegining() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(3)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3)), false);
verify(adapter).notifyItemRangeInserted(0, 2);
}
@Test
public void testAddItemInTheMiddle() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(3)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3)), false);
verify(adapter).notifyItemRangeInserted(1, 1);
}
@Test
public void testAddTwoItemsInTheMiddle() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(4)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3), new Cat(4)), false);
verify(adapter).notifyItemRangeInserted(1, 2);
}
@Test
public void testItemChanged() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(3)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1).withName("one1"), new Cat(3)), false);
verify(adapter).notifyItemRangeChanged(0, 1);
}
@Test
public void testTwoItemsChangedAtStart() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1).withName("one1"), new Cat(2).withName("two1"), new Cat(3)), false);
verify(adapter).notifyItemRangeChanged(0, 2);
}
@Test
public void testTwoItemsChangedInMiddle() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3), new Cat(4)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2).withName("two1"), new Cat(3).withName("tree1"), new Cat(4)), false);
verify(adapter).notifyItemRangeChanged(1, 2);
}
@Test
public void testTwoItemsChangedAtTheEnd() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2).withName("two1"), new Cat(3).withName("tree1")), false);
verify(adapter).notifyItemRangeChanged(1, 2);
}
@Test
public void testItemDeleted1() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(2), new Cat(3)), false);
verify(adapter).notifyItemRangeRemoved(0, 1);
}
@Test
public void testItemDeleted2() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(3)), false);
verify(adapter).notifyItemRangeRemoved(1, 1);
}
@Test
public void testItemDeleted4() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3), new Cat(4)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(3), new Cat(4)), false);
verify(adapter).notifyItemRangeRemoved(0, 2);
}
@Test
public void testItemDeleted5() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3), new Cat(4)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(4)), false);
verify(adapter).notifyItemRangeRemoved(1, 2);
}
@Test
public void testItemDeleted6() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3), new Cat(4)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2)), false);
verify(adapter).notifyItemRangeRemoved(2, 2);
}
@Test
public void testItemDeleted3() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(3)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2)), false);
verify(adapter).notifyItemRangeRemoved(2, 1);
}
@Test
public void testItemSwapped() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(3)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(2), new Cat(3)), false);
final InOrder inOrder = inOrder(adapter);
inOrder.verify(adapter).notifyItemRangeInserted(0, 1); // 2, 1, 3
inOrder.verify(adapter).notifyItemRangeRemoved(1, 1); // 2, 3
}
@Test
public void testItemSwappedTwo() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(2), new Cat(5)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(3), new Cat(4), new Cat(5)), false);
final InOrder inOrder = inOrder(adapter);
inOrder.verify(adapter).notifyItemRangeInserted(0, 2); // 3, 4, 1, 2, 5
inOrder.verify(adapter).notifyItemRangeRemoved(2, 2); // 3, 4, 5
}
@Test
public void testItemRemovedAndAdded() throws Exception {
detector.newData(adapter, ImmutableList.of(new Cat(1), new Cat(4)), false);
reset(adapter);
detector.newData(adapter, ImmutableList.of(new Cat(2), new Cat(3), new Cat(4)), false);
final InOrder inOrder = inOrder(adapter);
inOrder.verify(adapter).notifyItemRangeInserted(0, 2); // 2, 1, 4, than // 2, 3, 1, 4
inOrder.verify(adapter).notifyItemRangeRemoved(2, 1); // 2, 3, 4
}
}