/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package com.bc.ceres.binding;
import com.bc.ceres.binding.converters.DoubleConverter;
import com.bc.ceres.binding.converters.IntegerConverter;
import com.bc.ceres.binding.converters.StringConverter;
import junit.framework.TestCase;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.util.HashMap;
public class PropertyContainerTest extends TestCase {
public void testValueBackedValueContainer() throws ValidationException {
PropertyContainer pc = PropertyContainer.createValueBacked(Pojo.class);
MyPropertyChangeListener pcl = new MyPropertyChangeListener();
pc.addPropertyChangeListener(pcl);
testValueContainerModels(pc);
assertEquals("(name:null-->Ernie)(age:0-->16)(weight:0.0-->72.9)(code:" + '\0' + "-->#)", pcl.trace);
}
public void testMapBackedValueContainer() throws ValidationException {
final HashMap<String, Object> map = new HashMap<>();
PropertyContainer pc = PropertyContainer.createMapBacked(map, Pojo.class);
assertEquals(0, map.size());
MyPropertyChangeListener pcl = new MyPropertyChangeListener();
pc.addPropertyChangeListener(pcl);
testValueContainerModels(pc);
assertEquals("(name:null-->Ernie)(age:0-->16)(weight:0.0-->72.9)(code:" + '\0' + "-->#)", pcl.trace);
assertEquals('#', map.get("code"));
assertEquals("Ernie", map.get("name"));
assertEquals(16, (int)map.get("age"));
assertEquals(72.9, (double)map.get("weight"), 1.0e-6);
}
public void testObjectBackedValueContainer() throws ValidationException {
Pojo pojo = new Pojo();
PropertyContainer pc = PropertyContainer.createObjectBacked(pojo);
MyPropertyChangeListener pcl = new MyPropertyChangeListener();
pc.addPropertyChangeListener(pcl);
testValueContainerModels(pc);
assertEquals("(name:Hermann-->Ernie)(age:59-->16)(weight:82.5-->72.9)(code:X-->#)", pcl.trace);
assertEquals('#', pojo.code);
assertEquals("Ernie", pojo.name);
assertEquals(16, pojo.age);
assertEquals(72.9, pojo.weight);
}
private void testValueContainerModels(PropertyContainer vc) throws ValidationException {
final Property name = vc.getProperty("name");
assertNotNull(name);
name.setValue("Ernie");
assertEquals("Ernie", name.getValue());
try {
name.setValue(3);
fail("ValidationException expected");
} catch (ValidationException ignored) {
}
final Property age = vc.getProperty("age");
assertNotNull(age);
age.setValue(16);
assertEquals(16, (int)age.getValue());
try {
age.setValue("");
fail("ValidationException expected");
} catch (ValidationException ignored) {
}
final Property weight = vc.getProperty("weight");
assertNotNull(weight);
weight.setValue(72.9);
assertEquals(72.9, (double)weight.getValue(), 1.0e-6);
try {
weight.setValue("");
fail("ValidationException expected");
} catch (ValidationException ignored) {
}
final Property code = vc.getProperty("code");
assertNotNull(code);
code.setValue('#');
assertEquals('#', (char)code.getValue());
try {
code.setValue(2.5);
fail("ValidationException expected");
} catch (ValidationException ignored) {
}
final Property unknownModel = vc.getProperty("unknown");
assertNull(unknownModel);
}
public void testDefaultValues() throws ValidationException {
PropertyDescriptorFactory valueDescriptorFactory = new MyValueDescriptorFactory();
PropertyContainer container;
container = PropertyContainer.createObjectBacked(new Pojo(), valueDescriptorFactory);
testCurrentValuesUsed(container);
container.setDefaultValues();
testDefaultValuesUsed(container);
container = PropertyContainer.createValueBacked(Pojo.class, valueDescriptorFactory);
testDefaultValuesUsed(container);
container.setDefaultValues();
testDefaultValuesUsed(container);
HashMap<String, Object> map = new HashMap<>(5);
container = PropertyContainer.createMapBacked(map, Pojo.class, valueDescriptorFactory);
assertEquals(0, map.size());
testInitialValuesUsed(container);
container.setDefaultValues();
assertEquals(4, map.size()); // 4 default values set
testDefaultValuesUsed(container);
map = new HashMap<>(5);
map.put("code", 'X');
map.put("name", "Hermann");
map.put("age", 59);
map.put("weight", 82.5);
container = PropertyContainer.createMapBacked(map, Pojo.class, valueDescriptorFactory);
assertEquals(4, map.size());
testCurrentValuesUsed(container);
container.setDefaultValues();
assertEquals(4, map.size()); // no change in size, 4 default values set
testDefaultValuesUsed(container);
}
private void testInitialValuesUsed(PropertyContainer container) {
assertEquals('\0', (char)container.getValue("code"));
assertEquals(null, container.getValue("name"));
assertEquals(0, (int)container.getValue("age"));
assertEquals(0.0, (double)container.getValue("weight"), 1.0e-6);
testUnhandledValues(container);
}
private void testCurrentValuesUsed(PropertyContainer container) {
assertEquals('X', (char)container.getValue("code"));
assertEquals("Hermann", container.getValue("name"));
assertEquals(59, (int)container.getValue("age"));
assertEquals(82.5, (double)container.getValue("weight"), 1.0e-6);
testUnhandledValues(container);
}
private void testDefaultValuesUsed(PropertyContainer container) {
assertEquals('Y', (char)container.getValue("code"));
assertEquals("Kurt", container.getValue("name"));
assertEquals(42, (int)container.getValue("age"));
assertEquals(90.0, (double)container.getValue("weight"), 1.0e-6);
testUnhandledValues(container);
}
private void testUnhandledValues(PropertyContainer container) {
assertEquals('\0', (char)container.getValue("codeNoDefault"));
assertEquals(null, container.getValue("nameNoDefault"));
assertEquals(0, (int)container.getValue("ageNoDefault"));
assertEquals(0.0, (double)container.getValue("weightNoDefault"), 1.0e-6);
}
abstract static class PojoBase {
char code = 'X';
char codeNoDefault;
}
static class Pojo extends PojoBase {
String name = "Hermann";
int age = 59;
double weight = 82.5;
String nameNoDefault;
int ageNoDefault;
double weightNoDefault;
}
abstract static class A {
A() {
try {
getClass().getDeclaredField("x").setInt(this, 42);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
static class B extends A {
int x;
B() {
}
B(int x) {
this.x = x;
}
}
public void testDerivedClassReflectionWorksInBaseClassInitializer() {
assertEquals(42, new B().x);
assertEquals(99, new B(99).x);
}
private static class MyPropertyChangeListener implements PropertyChangeListener {
String trace = "";
public void propertyChange(PropertyChangeEvent evt) {
trace += "(" + evt.getPropertyName() + ":" + evt.getOldValue() + "-->" + evt.getNewValue() + ")";
}
}
private static class MyValueDescriptorFactory implements PropertyDescriptorFactory {
public PropertyDescriptor createValueDescriptor(Field field) {
PropertyDescriptor descriptor = new PropertyDescriptor(field.getName(), field.getType());
if (!field.getName().endsWith("NoDefault")) {
if (field.getType().equals(String.class)) {
descriptor.setConverter(new StringConverter());
descriptor.setDefaultValue("Kurt");
} else if (field.getType().equals(char.class)) {
descriptor.setConverter(new IntegerConverter());
descriptor.setDefaultValue('Y');
} else if (field.getType().equals(int.class)) {
descriptor.setConverter(new IntegerConverter());
descriptor.setDefaultValue(42);
} else if (field.getType().equals(double.class)) {
descriptor.setConverter(new DoubleConverter());
descriptor.setDefaultValue(90.0);
} else {
fail("Test is not prepared for " + field.getType() + " types.");
}
}
return descriptor;
}
}
}