package com.codiform.moo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import com.codiform.moo.annotation.CollectionProperty;
import com.codiform.moo.curry.Update;
import com.codiform.moo.translator.CollectionMatcher;
public class CollectionUpdateTest {
public static class FieldValueSet implements Iterable<Value> {
@CollectionProperty(itemClass = Value.class, matcher = ValueIdMatcher.class, update = true)
private Set<Value> values;
public FieldValueSet() {
values = new HashSet<Value>();
}
public FieldValueSet(Value... values) {
this();
for( Value item : values ) {
add( item );
}
}
public void add(Value value) {
values.add( value );
}
@Override
public Iterator<Value> iterator() {
return values.iterator();
}
public int size() {
return values.size();
}
}
public static class MethodValueSet implements Iterable<Value> {
private Set<Value> values;
public MethodValueSet() {
values = new HashSet<Value>();
}
public MethodValueSet(Value... values) {
this();
for( Value item : values ) {
add( item );
}
}
public void add(Value value) {
values.add( value );
}
public Set<Value> getValues() {
return values;
}
@Override
public Iterator<Value> iterator() {
return values.iterator();
}
@CollectionProperty(itemClass = Value.class, matcher = ValueIdMatcher.class, update = true)
public void setValues(Set<Value> values) {
this.values = values;
}
public int size() {
return values.size();
}
}
public static class RetainValueSet extends MethodValueSet {
public RetainValueSet() {
super();
}
public RetainValueSet(Value... values) {
super( values );
}
@Override
@CollectionProperty(itemClass = Value.class, matcher = ValueIdMatcher.class, update = true, removeOrphans = false)
public void setValues(Set<Value> values) {
super.setValues( values );
}
}
public static class Value {
private Integer id;
private String name;
@SuppressWarnings("unused")
private Value() {
// for translation only
}
public Value(int id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
}
public static class ValueDto {
private Integer id;
private String name;
@SuppressWarnings("unused")
private ValueDto() {
// for translation only
}
public ValueDto(int id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
}
public static class ValueDtoList {
private List<ValueDto> values;
public ValueDtoList(ValueDto... dtos) {
values = new ArrayList<ValueDto>();
for( ValueDto item : dtos ) {
values.add( item );
}
}
public ValueDto get(int index) {
return values.get( index );
}
public List<ValueDto> getValues() {
return values;
}
}
public static class ValueIdMatcher implements
CollectionMatcher<ValueDto, Value> {
private Map<Integer, Value> valueById;
public ValueIdMatcher() {
valueById = new HashMap<Integer, Value>();
}
@Override
public Value getTarget(ValueDto source) {
return valueById.get( source.getId() );
}
@Override
public void setTargets(Collection<Value> targets) {
valueById.clear();
for( Value item : targets ) {
valueById.put( item.getId(), item );
}
}
}
public static class ValueList {
@CollectionProperty(itemClass = Value.class, update = true)
private List<Value> values;
public ValueList(Value... items) {
values = new ArrayList<Value>();
for( Value item : items ) {
values.add( item );
}
}
public Value get(int index) {
return values.get( index );
}
public int size() {
return values.size();
}
}
public static class RetainValueList {
@CollectionProperty(itemClass = Value.class, update = true, removeOrphans = false)
private List<Value> values;
public RetainValueList(Value... items) {
values = new ArrayList<Value>();
for( Value item : items ) {
values.add( item );
}
}
public Value get(int index) {
return values.get( index );
}
public int size() {
return values.size();
}
}
private void assertEqualValues(ValueDto expectedValues, Value actual) {
assertEquals( expectedValues.getId(), actual.getId() );
assertEquals( expectedValues.getName(), actual.getName() );
}
private void assertIdentityAndValues(Value expectedIdentity,
ValueDto expectedValues,
Value actual) {
assertSame( expectedIdentity, actual );
assertEqualValues( expectedValues, actual );
}
@Test
public void testUpdateCollectionPropertyUpdatesObjectInsideCollection() {
ValueDto dto = new ValueDto( 1, "Updated" );
ValueDtoList dtoList = new ValueDtoList( dto );
Value value = new Value( 1, "Original" );
ValueList valueList = new ValueList( value );
Update.from( dtoList ).to( valueList );
Value actual = valueList.get( 0 );
assertSame( value, actual );
assertEquals( Integer.valueOf( 1 ), actual.getId() );
assertEquals( "Updated", actual.getName() );
}
@Test
public void testUpdateCollectionViaMethodWithMatcherUpdatesObjectsByMatcher() {
ValueDto secondDto = new ValueDto( 2, "Updated Second" );
ValueDto firstDto = new ValueDto( 1, "Updated First" );
ValueDtoList dtoList = new ValueDtoList( secondDto, firstDto );
Value firstValue = new Value( 1, "First" );
Value secondValue = new Value( 2, "Second" );
MethodValueSet valueSet = new MethodValueSet( firstValue, secondValue );
Update.from( dtoList ).to( valueSet );
assertEquals( 2, valueSet.size() );
for( Value item : valueSet ) {
if( item.getId() == 1 )
assertIdentityAndValues( firstValue, firstDto, item );
else
assertIdentityAndValues( secondValue, secondDto, item );
}
}
@Test
public void testUpdateCollectionViaMethodWithMatcherWillRemoveItemNotPresentInSource() {
ValueDto firstDto = new ValueDto( 1, "Updated First" );
ValueDtoList dtoList = new ValueDtoList( firstDto );
Value firstValue = new Value( 1, "First" );
Value secondValue = new Value( 2, "Second" );
MethodValueSet valueSet = new MethodValueSet( secondValue, firstValue );
Update.from( dtoList ).to( valueSet );
assertEquals( 1, valueSet.size() );
Iterator<Value> updated = valueSet.iterator();
assertIdentityAndValues( firstValue, firstDto, updated.next() );
}
@Test
public void testUpdateCollectionWithMatcherUpdatesObjectsByMatcher() {
ValueDto secondDto = new ValueDto( 2, "Updated Second" );
ValueDto firstDto = new ValueDto( 1, "Updated First" );
ValueDtoList dtoList = new ValueDtoList( secondDto, firstDto );
Value firstValue = new Value( 1, "First" );
Value secondValue = new Value( 2, "Second" );
FieldValueSet valueSet = new FieldValueSet( firstValue, secondValue );
Update.from( dtoList ).to( valueSet );
assertEquals( 2, valueSet.size() );
for( Value item : valueSet ) {
if( item.getId() == 1 )
assertIdentityAndValues( firstValue, firstDto, item );
else
assertIdentityAndValues( secondValue, secondDto, item );
}
}
@Test
public void testUpdateCollectionWithMatcherWillInsertItemNotFoundByMatcher() {
ValueDto secondDto = new ValueDto( 2, "New Second" );
ValueDto firstDto = new ValueDto( 1, "Updated First" );
ValueDtoList dtoList = new ValueDtoList( secondDto, firstDto );
Value firstValue = new Value( 1, "First" );
FieldValueSet valueSet = new FieldValueSet( firstValue );
Update.from( dtoList ).to( valueSet );
assertEquals( 2, valueSet.size() );
for( Value item : valueSet ) {
if( item.getId() == 1 )
assertIdentityAndValues( firstValue, firstDto, item );
else
assertEqualValues( secondDto, item );
}
}
@Test
public void testUpdateCollectionWithMatcherWillRemoveItemNotPresentInSource() {
ValueDto firstDto = new ValueDto( 1, "Updated First" );
ValueDtoList dtoList = new ValueDtoList( firstDto );
Value firstValue = new Value( 1, "First" );
Value secondValue = new Value( 2, "Second" );
FieldValueSet valueSet = new FieldValueSet( secondValue, firstValue );
Update.from( dtoList ).to( valueSet );
assertEquals( 1, valueSet.size() );
Iterator<Value> updated = valueSet.iterator();
assertIdentityAndValues( firstValue, firstDto, updated.next() );
}
@Test
public void testUpdateListPropertyUpdatesObjectsInListByIndex() {
ValueDto firstDto = new ValueDto( 2, "Now First" );
ValueDto secondDto = new ValueDto( 1, "Now Second" );
ValueDtoList dtoList = new ValueDtoList( firstDto, secondDto );
Value firstValue = new Value( 1, "First" );
Value secondValue = new Value( 2, "Second" );
ValueList valueList = new ValueList( firstValue, secondValue );
Update.from( dtoList ).to( valueList );
assertIdentityAndValues( firstValue, firstDto, valueList.get( 0 ) );
assertIdentityAndValues( secondValue, secondDto, valueList.get( 1 ) );
}
@Test
public void testUpdateListWillInsertItemNotPresentInDestination() {
ValueDto firstDto = new ValueDto( 1, "Updated Original" );
ValueDto secondDto = new ValueDto( 2, "New to this Update" );
ValueDtoList dtoList = new ValueDtoList( firstDto, secondDto );
Value firstValue = new Value( 1, "Original" );
ValueList valueList = new ValueList( firstValue );
Update.from( dtoList ).to( valueList );
assertEquals( "Update should have added a new item to the value list.",
2, valueList.size() );
assertIdentityAndValues( firstValue, firstDto, valueList.get( 0 ) );
assertEqualValues( secondDto, valueList.get( 1 ) );
}
@Test
public void testUpdateListWillRemoveItemNotPresentInSource() {
ValueDto firstDto = new ValueDto( 1, "Still First" );
ValueDto secondDto = new ValueDto( 3, "Was Third, Now Second" );
ValueDtoList dtoList = new ValueDtoList( firstDto, secondDto );
Value firstValue = new Value( 1, "First" );
Value secondValue = new Value( 2, "Second" );
ValueList valueList = new ValueList( firstValue, secondValue,
new Value( 3, "Third" ) );
Update.from( dtoList ).to( valueList );
assertEquals(
"Update should have removed a value from the destination list.",
2, valueList.size() );
assertIdentityAndValues( firstValue, firstDto, valueList.get( 0 ) );
assertIdentityAndValues( secondValue, secondDto, valueList.get( 1 ) );
}
@Test
public void testUpdateListWillNotRemoveItemsNotPresentInSourceIfRemoveOrphansIsFalse() {
ValueDto firstDto = new ValueDto( 1, "Still First" );
ValueDto secondDto = new ValueDto( 3, "Was Third, Now Second" );
ValueDtoList dtoList = new ValueDtoList( firstDto, secondDto );
Value firstValue = new Value( 1, "First" );
Value secondValue = new Value( 2, "Second" );
RetainValueList valueList = new RetainValueList( firstValue,
secondValue,
new Value( 3, "Third" ) );
Update.from( dtoList ).to( valueList );
assertEquals(
"Update should not have removed a value from the destination list.",
3, valueList.size() );
assertIdentityAndValues( firstValue, firstDto, valueList.get( 0 ) );
assertIdentityAndValues( secondValue, secondDto, valueList.get( 1 ) );
}
@Test
public void testUpdateCollectionWithMatcherWillNotRemoveItemNotPresentInSourceIfRemoveOrphansIsFalse() {
ValueDtoList dtoList = new ValueDtoList( new ValueDto( 1,
"Updated First" ), new ValueDto( 3, "New Third" ) );
RetainValueSet valueSet = new RetainValueSet( new Value( 2, "Second" ),
new Value( 1, "First" ) );
Update.from( dtoList ).to( valueSet );
assertEquals( 3, valueSet.size() );
}
}