/**
* Copyright (C) 2015 Valkyrie RCP
*
* 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 org.valkyriercp.binding.value.support;
import org.junit.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanCreationException;
import org.valkyriercp.AbstractValkyrieTest;
import org.valkyriercp.binding.value.CommitTrigger;
import org.valkyriercp.binding.value.ValueModel;
import org.valkyriercp.test.TestPropertyChangeListener;
import java.util.*;
import static org.junit.Assert.*;
/**
* Test cases for {@link BufferedCollectionValueModel}
*
* @author oliverh
*/
public class BufferedCollectionValueModelTests extends AbstractValkyrieTest {
private Class[] supportedIterfaces = new Class[] {Collection.class, List.class, Set.class, SortedSet.class,};
private Class[] supportedClasses = new Class[] {ArrayList.class, HashSet.class, TreeSet.class,};
@Test
public void testCreating() {
try {
getBufferedCollectionValueModel(null, null);
fail("NULL wrappedType should not be supported");
}
catch (IllegalArgumentException e) {
// expected
}
try {
getBufferedCollectionValueModel(null, Object.class);
fail("wrappedType can only be an instance Collection or an array");
}
catch (IllegalArgumentException e) {
// expected
}
try {
getBufferedCollectionValueModel(null, int[].class);
fail("wrappedType can not be a primitive array");
}
catch (IllegalArgumentException e) {
// expected
}
for (int i = 0; i < supportedIterfaces.length; i++) {
getBufferedCollectionValueModel(null, supportedIterfaces[i]);
}
try {
getBufferedCollectionValueModel(null, CustomCollectionInterface.class);
fail("if wrappedType is an interface it must one of the standard JDK Collection interfaces");
}
catch (IllegalArgumentException e) {
// expected
}
getBufferedCollectionValueModel(null, Object[].class);
getBufferedCollectionValueModel(null, CustomCollectionClass.class);
for (int i = 0; i < supportedClasses.length; i++) {
getBufferedCollectionValueModel(null, supportedClasses[i]);
}
}
@Test
public void testGetAfterBackingObjectChange() {
Object[] backingArray = getArray(1);
BufferedCollectionValueModel vm = getBufferedCollectionValueModel(backingArray);
assertHasSameStructure((ListListModel)vm.getValue(), backingArray);
backingArray = getArray(2);
vm.getWrappedValueModel().setValue(backingArray);
assertHasSameStructure((ListListModel)vm.getValue(), backingArray);
vm.getWrappedValueModel().setValue(null);
assertEquals("ListListModel must have no elements when backing collection is NULL",
((ListListModel)vm.getValue()).size(), 0);
for (int i = 0; i < supportedClasses.length; i++) {
Collection backingCollection = getCollection(supportedClasses[i], i);
vm = getBufferedCollectionValueModel(backingCollection);
assertHasSameStructure((ListListModel)vm.getValue(), backingCollection);
backingCollection = getCollection(supportedClasses[i], i + 1);
vm.getWrappedValueModel().setValue(backingCollection);
assertHasSameStructure((ListListModel)vm.getValue(), backingCollection);
vm.getWrappedValueModel().setValue(null);
assertEquals("ListListModel must have no elements when backing collection is NULL",
((ListListModel)vm.getValue()).size(), 0);
}
}
@Test
public void testCreateWithEmptyCollection() {
BufferedCollectionValueModel vm = new BufferedCollectionValueModel(new ValueHolder(null), Collection.class);
assertTrue(vm.getValue() instanceof ListListModel);
assertEquals(0, ((ListListModel)vm.getValue()).size());
vm = new BufferedCollectionValueModel(new ValueHolder(new ArrayList()), Collection.class);
assertTrue(vm.getValue() instanceof ListListModel);
assertEquals(0, ((ListListModel)vm.getValue()).size());
vm = new BufferedCollectionValueModel(new ValueHolder(null), Object[].class);
assertTrue(vm.getValue() instanceof ListListModel);
assertEquals(0, ((ListListModel)vm.getValue()).size());
vm = new BufferedCollectionValueModel(new ValueHolder(new Object[0]), Object[].class);
assertTrue(vm.getValue() instanceof ListListModel);
assertEquals(0, ((ListListModel)vm.getValue()).size());
}
@Test
public void testChangesToListListModelWithBackingArray() {
Object[] backingArray = getArray(100);
BufferedCollectionValueModel vm = getBufferedCollectionValueModel(backingArray);
ListListModel llm = (ListListModel)vm.getValue();
llm.clear();
assertEquals("changes to ListListModel should be not be made to backing array unless commit is called",
vm.getWrappedValueModel().getValue(), backingArray);
backingArray = getArray(101);
vm.getWrappedValueModel().setValue(backingArray);
Object newValue = new Double(1);
llm.set(1, newValue);
vm.commit();
Object[] newBackingArray = (Object[])vm.getWrappedValueModel().getValue();
assertNotSame("change should not have been committed back to original array", newBackingArray, backingArray);
llm.add(newValue);
vm.commit();
newBackingArray = (Object[])vm.getWrappedValueModel().getValue();
assertNotSame("change should not have been committed back to original array", newBackingArray, backingArray);
assertTrue(newBackingArray.length == backingArray.length + 1);
assertEquals(newBackingArray[newBackingArray.length - 1], newValue);
llm.clear();
vm.commit();
newBackingArray = (Object[])vm.getWrappedValueModel().getValue();
assertEquals(newBackingArray.length, 0);
vm.getWrappedValueModel().setValue(null);
llm.clear();
vm.commit();
assertEquals("if backingCollection is NULL then a commit of an empty LLM should also be NULL",
vm.getWrappedValueModel().getValue(), null);
llm.add(newValue);
vm.commit();
newBackingArray = (Object[])vm.getWrappedValueModel().getValue();
assertEquals(newBackingArray.length, 1);
assertEquals(newBackingArray[0], newValue);
}
@Test
public void testChangesToListListModelWithBackingCollection() {
for (int i = 0; i < supportedClasses.length; i++) {
Collection backingCollection = getCollection(supportedClasses[i], 200 + i);
BufferedCollectionValueModel vm = getBufferedCollectionValueModel(backingCollection);
ListListModel llm = (ListListModel)vm.getValue();
llm.clear();
assertEquals("changes to LLM should be not be made to backing collection unless commit is called",
vm.getWrappedValueModel().getValue(), backingCollection);
backingCollection = getCollection(supportedClasses[i], 201 + i);
vm.getWrappedValueModel().setValue(backingCollection);
Object newValue = new Integer(-1);
backingCollection.remove(newValue);
int orgSize = backingCollection.size();
llm.set(1, newValue);
vm.commit();
Collection newBackingCollection = (Collection)vm.getWrappedValueModel().getValue();
assertTrue("change should not have been committed back to original array",
!backingCollection.contains(newValue));
assertTrue(newBackingCollection.contains(newValue));
assertTrue(orgSize == newBackingCollection.size());
newValue = new Integer(-2);
backingCollection.remove(newValue);
orgSize = backingCollection.size();
llm.add(newValue);
vm.commit();
newBackingCollection = (Collection)vm.getWrappedValueModel().getValue();
assertTrue(newBackingCollection.contains(newValue));
assertTrue(newBackingCollection.size() == orgSize + 1);
llm.clear();
vm.commit();
assertEquals(((Collection)vm.getWrappedValueModel().getValue()).size(), 0);
vm.getWrappedValueModel().setValue(null);
llm.clear();
vm.commit();
newBackingCollection = (Collection)vm.getWrappedValueModel().getValue();
assertEquals("if backingCollection is NULL then a commit of an empty LLM should also be NULL",
newBackingCollection, null);
llm.add(newValue);
vm.commit();
newBackingCollection = (Collection)vm.getWrappedValueModel().getValue();
assertTrue(supportedClasses[i].isAssignableFrom(newBackingCollection.getClass()));
assertEquals(newBackingCollection.size(), 1);
assertEquals(newBackingCollection.iterator().next(), newValue);
}
}
@Test
public void testListListModelKeepsStuctureOfBackingObjectAfterCommit() {
Collection backingCollection = getCollection(HashSet.class, 500);
int origLength = backingCollection.size();
BufferedCollectionValueModel vm = getBufferedCollectionValueModel(backingCollection);
ListListModel llm = (ListListModel)vm.getValue();
llm.add(backingCollection.iterator().next());
assertTrue(llm.size() == origLength + 1);
vm.commit();
assertTrue("adding a duplicate item should not change the size of a set", llm.size() == origLength);
assertHasSameStructure(llm, backingCollection);
backingCollection = getCollection(TreeSet.class, 501);
vm = getBufferedCollectionValueModel(backingCollection);
llm = (ListListModel)vm.getValue();
Collections.reverse(llm);
assertTrue(((Comparable)llm.get(0)).compareTo(llm.get(1)) > 0);
vm.commit();
assertTrue("LLM should be sorted the same way as backingCollection",
((Comparable)llm.get(0)).compareTo(llm.get(1)) < 0);
assertHasSameStructure(llm, backingCollection);
backingCollection = new TreeSet(new Comparator() {
public int compare(Object o1, Object o2) {
return ((Comparable)o2).compareTo(o1);
}
});
populateCollection(backingCollection, 502);
vm = getBufferedCollectionValueModel(backingCollection);
llm = (ListListModel)vm.getValue();
Collections.reverse(llm);
assertTrue(((Comparable)llm.get(0)).compareTo(llm.get(1)) < 0);
vm.commit();
assertTrue("LLM should be sorted the same way as backingCollection",
((Comparable)llm.get(0)).compareTo(llm.get(1)) > 0);
assertHasSameStructure(llm, backingCollection);
}
@Test
public void testIncompatibleCollections() {
try {
getBufferedCollectionValueModel(new ArrayList(), Set.class);
fail("backing object must be assignable to backingCollectionClass");
}
catch (IllegalArgumentException e) {
// expected
}
catch (BeanCreationException e) {
if(!(e.getCause() instanceof IllegalArgumentException))
throw e;
}
try {
getBufferedCollectionValueModel(new Double[0], Integer[].class);
fail("backing object must be assignable to backingCollectionClass");
}
catch (IllegalArgumentException e) {
// expected
}
catch (BeanCreationException e) {
if(!(e.getCause() instanceof IllegalArgumentException))
throw e;
}
}
@Test
public void testValueChangeNotification() {
Object[] backingArray = getArray(100);
BufferedCollectionValueModel vm = getBufferedCollectionValueModel(backingArray);
TestPropertyChangeListener vl = new TestPropertyChangeListener(ValueModel.VALUE_PROPERTY);
vm.addValueChangeListener(vl);
ListListModel llm = (ListListModel)vm.getValue();
assertEquals(0, vl.eventCount());
vl.reset();
llm.add(new Integer(100));
assertEquals(1, vl.eventCount());
llm.add(1, new Integer(102));
assertEquals(2, vl.eventCount());
vl.reset();
llm.addAll(getCollection(ArrayList.class, 101));
assertEquals(1, vl.eventCount());
llm.addAll(1, getCollection(ArrayList.class, 101));
assertEquals(2, vl.eventCount());
vl.reset();
llm.remove(1);
assertEquals(1, vl.eventCount());
llm.removeAll(getCollection(ArrayList.class, 101));
assertEquals(2, vl.eventCount());
vl.reset();
llm.set(1, llm.get(1));
assertEquals(0, vl.eventCount());
vl.reset();
llm.clear();
assertEquals(1, vl.eventCount());
}
@Test
public void testRevert() {
CommitTrigger commitTriger = new CommitTrigger();
Collection backingCollection = getCollection(HashSet.class, 700);
BufferedCollectionValueModel vm = getBufferedCollectionValueModel(backingCollection);
vm.setCommitTrigger(commitTriger);
ListListModel llm = (ListListModel)vm.getValue();
llm.clear();
commitTriger.revert();
assertHasSameStructure(llm, backingCollection);
}
private void assertHasSameStructure(ListListModel c1, Object[] c2) {
assertEquals("collections must be the same size", c1.size(), c2.length);
for (int i = 0; i < c2.length; i++) {
assertEquals("collections must have the same items in the same order", c1.get(i), c2[i]);
}
}
private void assertHasSameStructure(ListListModel c1, Collection c2) {
assertEquals("collections must be the same size", c2.size(), c1.size());
for (Iterator i = c1.iterator(), j = c2.iterator(); i.hasNext();) {
assertEquals("collections must have the same items in the same order", i.next(), j.next());
}
}
private Object[] getArray(long randomSeed) {
Random random = new Random(randomSeed);
return new Number[] {new Integer(random.nextInt()), new Integer(random.nextInt()),
new Integer(random.nextInt())};
}
private Collection getCollection(Class collectionClass, long randomSeed) {
return populateCollection((Collection) BeanUtils.instantiateClass(collectionClass), randomSeed);
}
private Collection populateCollection(Collection c, long randomSeed) {
Random random = new Random(randomSeed);
c.add(new Integer(random.nextInt()));
c.add(new Integer(random.nextInt()));
c.add(new Integer(random.nextInt()));
return c;
}
private BufferedCollectionValueModel getBufferedCollectionValueModel(Object backingCollecton) {
return getBufferedCollectionValueModel(backingCollecton, backingCollecton.getClass());
}
private BufferedCollectionValueModel getBufferedCollectionValueModel(Object backingCollecton,
Class backingCollectionClass) {
ValueModel vm = new ValueHolder(backingCollecton);
return new BufferedCollectionValueModel(vm, backingCollectionClass);
}
interface CustomCollectionInterface extends Collection {
}
class CustomCollectionClass extends ArrayList implements CustomCollectionInterface {
}
}