blob: 93b1387ebebd01b53c207a65a241233c748878c2 [file] [log] [blame]
// Copyright 2007, 2008 The Apache Software Foundation
//
// 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.apache.tapestry5.internal.services;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.PropertyConduit;
import org.apache.tapestry5.beaneditor.BeanModel;
import org.apache.tapestry5.beaneditor.PropertyModel;
import org.apache.tapestry5.beaneditor.RelativePosition;
import org.apache.tapestry5.internal.test.InternalBaseTestCase;
import org.apache.tapestry5.internal.transform.pages.ReadOnlyBean;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.services.BeanModelSource;
import org.easymock.EasyMock;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.Collections;
/**
* Tests for the bean editor model source itself, as well as the model classes.
*/
public class BeanModelSourceImplTest extends InternalBaseTestCase
{
private BeanModelSource source;
@BeforeClass
public void setup()
{
source = getObject(BeanModelSource.class, null);
}
/**
* Tests defaults for property names, labels and conduits.
*/
@Test
public void default_model_for_bean()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
assertSame(model.getBeanType(), SimpleBean.class);
// Based on order of the getter methods (no longer alphabetical)
assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "lastName", "age"));
assertEquals(model.toString(),
"BeanModel[org.apache.tapestry5.internal.services.SimpleBean properties:firstName, lastName, age]");
PropertyModel age = model.get("age");
assertEquals(age.getLabel(), "Age");
assertSame(age.getPropertyType(), int.class);
assertEquals(age.getDataType(), "number");
PropertyModel firstName = model.get("firstName");
assertEquals(firstName.getLabel(), "First Name");
assertEquals(firstName.getPropertyType(), String.class);
assertEquals(firstName.getDataType(), "text");
assertEquals(model.get("lastName").getLabel(), "Last Name");
PropertyConduit conduit = model.get("lastName").getConduit();
SimpleBean instance = new SimpleBean();
instance.setLastName("Lewis Ship");
assertEquals(conduit.get(instance), "Lewis Ship");
conduit.set(instance, "TapestryDude");
assertEquals(instance.getLastName(), "TapestryDude");
// Now, one with some type coercion.
age.getConduit().set(instance, "40");
assertEquals(instance.getAge(), 40);
verify();
}
@Test
public void include_properties()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
assertSame(model.getBeanType(), SimpleBean.class);
model.include("lastname", "firstname");
// Based on order of the getter methods (no longer alphabetical)
assertEquals(model.getPropertyNames(), Arrays.asList("lastName", "firstName"));
verify();
}
@Test
public void add_before()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
PropertyConduit conduit = mockPropertyConduit();
Class propertyType = String.class;
train_getMessages(resources, messages);
stub_contains(messages, false);
expect(conduit.getPropertyType()).andReturn(propertyType).atLeastOnce();
expect(conduit.getAnnotation(EasyMock.isA(Class.class))).andStubReturn(null);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "lastName", "age"));
// Note the use of case insensitivity here.
PropertyModel property = model.add(RelativePosition.BEFORE, "lastname", "middleInitial", conduit);
assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "middleInitial", "lastName", "age"));
assertEquals(property.getPropertyName(), "middleInitial");
assertSame(property.getConduit(), conduit);
assertSame(property.getPropertyType(), propertyType);
verify();
}
/**
* TAPESTRY-2202
*/
@Test
public void new_instance()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel<SimpleBean> model = source.create(SimpleBean.class, true, resources);
SimpleBean s1 = model.newInstance();
assertNotNull(s1);
SimpleBean s2 = model.newInstance();
assertNotNull(s2);
assertNotSame(s1, s2);
verify();
}
@Test
public void add_before_using_default_conduit()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
model.exclude("firstname");
assertEquals(model.getPropertyNames(), Arrays.asList("lastName", "age"));
// Note the use of case insensitivity here.
PropertyModel property = model.add(RelativePosition.BEFORE, "lastname", "firstName");
assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "lastName", "age"));
assertEquals(property.getPropertyName(), "firstName");
assertSame(property.getPropertyType(), String.class);
verify();
}
@Test
public void add_after()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
PropertyConduit conduit = mockPropertyConduit();
Class propertyType = String.class;
train_getMessages(resources, messages);
stub_contains(messages, false);
expect(conduit.getPropertyType()).andReturn(propertyType).atLeastOnce();
expect(conduit.getAnnotation(EasyMock.isA(Class.class))).andStubReturn(null);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "lastName", "age"));
PropertyModel property = model.add(RelativePosition.AFTER, "firstname", "middleInitial", conduit);
assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "middleInitial", "lastName", "age"));
assertEquals(property.getPropertyName(), "middleInitial");
assertSame(property.getConduit(), conduit);
assertSame(property.getPropertyType(), propertyType);
verify();
}
@Test
public void filtering_out_read_only_properties()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(ReadOnlyBean.class, true, resources);
assertEquals(model.getPropertyNames(), Arrays.asList("value"));
model = source.create(ReadOnlyBean.class, false, resources);
assertEquals(model.getPropertyNames(), Arrays.asList("value", "readOnly"));
verify();
}
@Test
public void non_text_property()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(EnumBean.class, true, resources);
assertEquals(model.getPropertyNames(), Arrays.asList("token"));
assertEquals(model.get("token").getDataType(), "enum");
verify();
}
@Test
public void add_duplicate_property_name_is_failure()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
try
{
model.add("age");
unreachable();
}
catch (RuntimeException ex)
{
assertEquals(ex.getMessage(),
"Bean editor model for org.apache.tapestry5.internal.services.SimpleBean already contains a property model for property \'age\'.");
}
verify();
}
@Test
public void unknown_property_name()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
try
{
model.get("frobozz");
unreachable();
}
catch (RuntimeException ex)
{
assertEquals(ex.getMessage(),
"Bean editor model for org.apache.tapestry5.internal.services.SimpleBean does not contain a property named \'frobozz\'. " + "Available properties: age, firstName, lastName.");
}
verify();
}
@Test
public void unknown_property_id()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
model.add("shrub.foo()", null);
try
{
model.getById("frobozz");
unreachable();
}
catch (RuntimeException ex)
{
assertEquals(ex.getMessage(),
"Bean editor model for org.apache.tapestry5.internal.services.SimpleBean does not contain a property with id \'frobozz\'. "
+ "Available property ids: age, firstName, lastName, shrubfoo.");
}
verify();
}
@Test
public void get_added_property_by_name()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
PropertyModel pm = model.add("shrub.foo()", null);
assertSame(model.get("Shrub.Foo()"), pm);
verify();
}
@Test
public void get_added_property_by_id()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
PropertyModel pm = model.add("shrub.foo()", null);
assertSame(model.getById("ShrubFoo"), pm);
verify();
}
@Test
public void order_via_annotation()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(StoogeBean.class, true, resources);
assertEquals(model.getPropertyNames(), Arrays.asList("larry", "moe", "shemp", "curly"));
verify();
}
@Test
public void edit_property_label()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources).get("age").label("Decrepitude").model();
assertEquals(model.get("age").getLabel(), "Decrepitude");
verify();
}
@Test
public void label_from_component_messages()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
train_contains(messages, "age-label", true);
train_get(messages, "age-label", "Decrepitude");
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
assertEquals(model.get("age").getLabel(), "Decrepitude");
verify();
}
@Test
public void array_type_bean()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(StringArrayBean.class, true, resources);
// There's not editor for string arrays yet, so it won't show up normally.
PropertyModel propertyModel = model.add("array");
assertSame(propertyModel.getPropertyType(), String[].class);
String[] value = { "foo", "bar" };
StringArrayBean bean = new StringArrayBean();
PropertyConduit conduit = propertyModel.getConduit();
conduit.set(bean, value);
assertSame(bean.getArray(), value);
assertSame(conduit.get(bean), value);
verify();
}
@Test
public void composite_bean()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
train_contains(messages, "simpleage-label", true);
train_get(messages, "simpleage-label", "Years of Age");
replay();
BeanModel model = source.create(CompositeBean.class, true, resources);
// No editor for CompositeBean, so this will be empty.
assertEquals(model.getPropertyNames(), Collections.emptyList());
// There's not editor for string arrays yet, so it won't show up normally.
PropertyModel firstName = model.add("simple.firstName");
assertEquals(firstName.getLabel(), "First Name");
PropertyModel age = model.add("simple.age");
assertEquals(age.getLabel(), "Years of Age");
CompositeBean bean = new CompositeBean();
firstName.getConduit().set(bean, "Fred");
age.getConduit().set(bean, "97");
assertEquals(bean.getSimple().getFirstName(), "Fred");
assertEquals(bean.getSimple().getAge(), 97);
bean.getSimple().setAge(24);
assertEquals(age.getConduit().get(bean), new Integer(24));
verify();
}
@Test
public void default_properties_exclude_write_only()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(WriteOnlyBean.class, false, resources);
assertEquals(model.getPropertyNames(), Arrays.asList("readOnly", "readWrite"));
verify();
}
@Test
public void add_synthetic_property()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
PropertyModel property = model.add("placeholder", null);
assertFalse(property.isSortable());
assertSame(property.getPropertyType(), Object.class);
assertEquals(property.getLabel(), "Placeholder");
verify();
}
@Test
public void exclude_property()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
assertSame(model.exclude("age"), model);
assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "lastName"));
verify();
}
@Test
public void exclude_unknown_property_is_noop()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
assertSame(model.exclude("frobozz"), model);
assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "lastName", "age"));
verify();
}
@Test
public void nonvisual_properties_are_excluded()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(NonVisualBean.class, true, resources);
assertEquals(model.getPropertyNames(), Arrays.asList("name"));
verify();
}
@Test
public void reorder()
{
ComponentResources resources = mockComponentResources();
Messages messages = mockMessages();
train_getMessages(resources, messages);
stub_contains(messages, false);
replay();
BeanModel model = source.create(SimpleBean.class, true, resources);
assertSame(model.getBeanType(), SimpleBean.class);
// Based on order of the getter methods (no longer alphabetical)
assertEquals(model.getPropertyNames(), Arrays.asList("firstName", "lastName", "age"));
// Testing a couple of things here:
// 1) case insensitive
// 2) unreferenced property names added to the end.
model.reorder("lastname", "AGE");
assertEquals(model.getPropertyNames(), Arrays.asList("lastName", "age", "firstName"));
verify();
}
}