blob: b5a9beb894168cb67c7191e813e2d782a0750adc [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* 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.google.gwt.editor.client;
import com.google.gwt.core.client.GWT;
import com.google.gwt.editor.client.adapters.EditorSource;
import com.google.gwt.editor.client.adapters.ListEditor;
import com.google.gwt.editor.client.adapters.OptionalFieldEditor;
import com.google.gwt.editor.client.adapters.SimpleEditor;
import com.google.gwt.junit.client.GWTTestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* Uses the SimpleBeanEditorTest to test core Editor behaviors as generated by
* AbstractEditorDriverGenerator.
*/
public class SimpleBeanEditorTest extends GWTTestCase {
class AddressCoEditorView extends LeafAddressEditor implements
IsEditor<LeafAddressEditor> {
private LeafAddressEditor addressEditor = new LeafAddressEditor();
public LeafAddressEditor asEditor() {
return addressEditor;
}
}
class AddressEditorView implements IsEditor<LeafAddressEditor> {
LeafAddressEditor addressEditor = new LeafAddressEditor();
public LeafAddressEditor asEditor() {
return addressEditor;
}
}
class LeafAddressEditor extends AddressEditor implements
LeafValueEditor<Address> {
/*
* These two fields are used to ensure that getValue() and setValue() aren't
* called excessively.
*/
int getValueCalled;
int setValueCalled;
Address value;
public Address getValue() {
getValueCalled++;
return value;
}
public void setValue(Address value) {
setValueCalled++;
value = new Address();
}
}
interface ListEditorDriver
extends
SimpleBeanEditorDriver<List<String>, ListEditor<String, SimpleEditor<String>>> {
}
class PersonEditorWithAddressEditorView implements Editor<Person> {
AddressEditorView addressEditor = new AddressEditorView();
SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED);
}
interface PersonEditorWithAddressEditorViewDriver extends
SimpleBeanEditorDriver<Person, PersonEditorWithAddressEditorView> {
}
class PersonEditorWithCoAddressEditorView implements Editor<Person> {
AddressCoEditorView addressEditor = new AddressCoEditorView();
SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED);
}
interface PersonEditorWithCoAddressEditorViewDriver extends
SimpleBeanEditorDriver<Person, PersonEditorWithCoAddressEditorView> {
}
class PersonEditorWithLeafAddressEditor implements Editor<Person> {
LeafAddressEditor addressEditor = new LeafAddressEditor();
SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED);
@Path("manager.name")
SimpleEditor<String> managerName = SimpleEditor.of(UNINITIALIZED);
}
interface PersonEditorWithLeafAddressEditorDriver extends
SimpleBeanEditorDriver<Person, PersonEditorWithLeafAddressEditor> {
}
interface PersonEditorWithOptionalAddressDriver extends
SimpleBeanEditorDriver<Person, PersonEditorWithOptionalAddressEditor> {
}
class PersonEditorWithOptionalAddressEditor implements Editor<Person> {
OptionalFieldEditor<Address, AddressEditor> address;
SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED);
public PersonEditorWithOptionalAddressEditor(AddressEditor delegate) {
address = OptionalFieldEditor.of(delegate);
}
}
class PersonEditorWithValueAwareAddressEditor implements Editor<Person> {
ValueAwareAddressEditor addressEditor = new ValueAwareAddressEditor();
SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED);
@Path("manager.name")
SimpleEditor<String> managerName = SimpleEditor.of(UNINITIALIZED);
}
interface PersonEditorWithValueAwareAddressEditorDriver extends
SimpleBeanEditorDriver<Person, PersonEditorWithValueAwareAddressEditor> {
}
class PersonEditorWithValueAwareLeafAddressEditor implements Editor<Person> {
ValueAwareLeafAddressEditor addressEditor = new ValueAwareLeafAddressEditor();
SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED);
@Path("manager.name")
SimpleEditor<String> managerName = SimpleEditor.of(UNINITIALIZED);
}
interface PersonEditorWithValueAwareLeafAddressEditorDriver
extends
SimpleBeanEditorDriver<Person, PersonEditorWithValueAwareLeafAddressEditor> {
}
class PersonWithList {
String name = "PersonWithList";
List<Address> addresses = new ArrayList<Address>();
public List<Address> getAddresses() {
return addresses;
}
public String getName() {
return name;
}
}
class PersonWithListEditor implements Editor<PersonWithList> {
SimpleEditor<String> nameEditor = SimpleEditor.of(UNINITIALIZED);
ListEditor<Address, AddressEditor> addressesEditor = ListEditor.of(new EditorSource<AddressEditor>() {
@Override
public AddressEditor create(int index) {
return new AddressEditor();
}
});
}
interface PersonWithListEditorDriver extends
SimpleBeanEditorDriver<PersonWithList, PersonWithListEditor> {
}
class ValueAwareAddressEditor extends AddressEditor implements
ValueAwareEditor<Address> {
int flushCalled;
int setDelegateCalled;
int setValueCalled;
Address value;
public void flush() {
flushCalled++;
}
public void onPropertyChange(String... paths) {
}
public void setDelegate(EditorDelegate<Address> delegate) {
setDelegateCalled++;
}
public void setValue(Address value) {
setValueCalled++;
this.value = value;
}
}
/**
* All the mix-ins. Not that this seems like a good idea...
*/
class ValueAwareLeafAddressEditor extends LeafAddressEditor implements
ValueAwareEditor<Address> {
int flushCalled;
int setDelegateCalled;
public void flush() {
flushCalled++;
}
public void onPropertyChange(String... paths) {
}
public void setDelegate(EditorDelegate<Address> delegate) {
setDelegateCalled++;
}
}
Person person;
Address personAddress;
Person manager;
static final String UNINITIALIZED = "uninitialized";
@Override
public String getModuleName() {
return "com.google.gwt.editor.Editor";
}
public void test() {
PersonEditorDriver driver = GWT.create(PersonEditorDriver.class);
PersonEditor editor = new PersonEditor();
driver.initialize(editor);
driver.edit(person);
assertEquals("Alice", editor.name.getValue());
assertEquals("City", editor.addressEditor.city.getValue());
assertEquals("Street", editor.addressEditor.street.getValue());
assertEquals("Bill", editor.managerName.getValue());
editor.name.setValue("Charles");
editor.addressEditor.city.setValue("Wootville");
editor.addressEditor.street.setValue("12345");
editor.managerName.setValue("David");
driver.flush();
assertEquals("Charles", person.name);
assertEquals("Wootville", person.address.city);
assertEquals("12345", person.address.street);
assertEquals("David", person.manager.name);
}
/**
* Test the use of the IsEditor interface that allows a view object to
* encapsulate its Editor.
*/
public void testIsEditorView() {
PersonEditorWithAddressEditorView personEditor = new PersonEditorWithAddressEditorView();
PersonEditorWithAddressEditorViewDriver driver = GWT.create(PersonEditorWithAddressEditorViewDriver.class);
testLeafAddressEditor(driver, personEditor,
personEditor.addressEditor.asEditor(), true);
}
/**
* Test the use of the IsEditor interface that allows a view object to
* encapsulate its Editor as well as be an editor itself.
*/
public void testIsEditorViewWithCoEditorA() {
PersonEditorWithCoAddressEditorView personEditor = new PersonEditorWithCoAddressEditorView();
PersonEditorWithCoAddressEditorViewDriver driver = GWT.create(PersonEditorWithCoAddressEditorViewDriver.class);
testLeafAddressEditor(driver, personEditor, personEditor.addressEditor,
true);
}
/**
* Test the use of the IsEditor interface that allows a view object to
* encapsulate its Editor as well as be an editor itself.
*/
public void testIsEditorViewWithCoEditorB() {
PersonEditorWithCoAddressEditorView personEditor = new PersonEditorWithCoAddressEditorView();
PersonEditorWithCoAddressEditorViewDriver driver = GWT.create(PersonEditorWithCoAddressEditorViewDriver.class);
testLeafAddressEditor(driver, personEditor,
personEditor.addressEditor.asEditor(), true);
}
/**
* We want to verify that the sub-editors of a LeafValueEditor are not
* initialized. Additonally, we want to ensure that the instance returned from
* the LVE is assigned into the owner type.
*/
public void testLeafValueEditorDeclaredInSlot() {
PersonEditorWithLeafAddressEditor personEditor = new PersonEditorWithLeafAddressEditor();
PersonEditorWithLeafAddressEditorDriver driver = GWT.create(PersonEditorWithLeafAddressEditorDriver.class);
LeafAddressEditor addressEditor = personEditor.addressEditor;
testLeafAddressEditor(driver, personEditor, addressEditor, true);
}
/**
* This tests a weird case where the user has put a LeafValueEditor into a
* plain Editor field. Because the Editor system relies heavily on static type
* information at compile time, this is not a supported configuration.
*/
public void testLeafValueEditorInPlainEditorSlot() {
PersonEditorDriver driver = GWT.create(PersonEditorDriver.class);
PersonEditor personEditor = new PersonEditor();
LeafAddressEditor addressEditor = new LeafAddressEditor();
// Runtime assignment of unexpected LeafValueEditor
personEditor.addressEditor = addressEditor;
testLeafAddressEditor(driver, personEditor, addressEditor, false);
}
public void testLifecycle() {
PersonEditorDriver driver = GWT.create(PersonEditorDriver.class);
try {
driver.edit(person);
fail("Should have thrown execption");
} catch (IllegalStateException expected) {
}
driver.initialize(new PersonEditor());
try {
driver.flush();
fail("Should have thrown exception");
} catch (IllegalStateException expected) {
}
driver.edit(person);
driver.flush();
}
/**
* Test a top-level ListEditor.
*/
public void testListEditor() {
final SortedMap<Integer, SimpleEditor<String>> positionMap = new TreeMap<Integer, SimpleEditor<String>>();
@SuppressWarnings("unchecked")
final SimpleEditor<String>[] disposed = new SimpleEditor[1];
class StringSource extends EditorSource<SimpleEditor<String>> {
public SimpleEditor<String> create(int index) {
SimpleEditor<String> editor = SimpleEditor.of();
positionMap.put(index, editor);
return editor;
}
public void dispose(SimpleEditor<String> editor) {
disposed[0] = editor;
positionMap.values().remove(editor);
}
public void setIndex(SimpleEditor<String> editor, int index) {
positionMap.values().remove(editor);
positionMap.put(index, editor);
}
};
ListEditorDriver driver = GWT.create(ListEditorDriver.class);
ListEditor<String, SimpleEditor<String>> editor = ListEditor.of(new StringSource());
driver.initialize(editor);
List<String> rawData = new ArrayList<String>(Arrays.asList("foo", "bar",
"baz"));
driver.edit(rawData);
List<SimpleEditor<String>> editors = editor.getEditors();
assertEquals(rawData.size(), editors.size());
assertEquals(rawData, Arrays.asList(editors.get(0).getValue(), editors.get(
1).getValue(), editors.get(2).getValue()));
assertEquals(editors, new ArrayList<SimpleEditor<String>>(
positionMap.values()));
List<String> mutableList = editor.getList();
assertEquals(rawData, mutableList);
// Test through wrapped list
mutableList.set(1, "Hello");
assertEquals("Hello", editors.get(1).getValue());
// Test using editor
editors.get(2).setValue("World");
assertEquals("baz", rawData.get(2));
driver.flush();
assertEquals("World", rawData.get(2));
// Change list size
mutableList.add("quux");
assertEquals(4, editors.size());
assertEquals("quux", editors.get(3).getValue());
assertEquals(editors, new ArrayList<SimpleEditor<String>>(
positionMap.values()));
// Delete an element
SimpleEditor<String> expectedDisposed = editors.get(0);
mutableList.remove(0);
assertSame(expectedDisposed, disposed[0]);
assertEquals(3, editors.size());
assertEquals("quux", editors.get(2).getValue());
assertEquals(editors, new ArrayList<SimpleEditor<String>>(
positionMap.values()));
}
/**
* Ensure that a ListEditor deeper in the chain is properly flushed.
*/
public void testListEditorChainFlush() {
PersonWithListEditorDriver driver = GWT.create(PersonWithListEditorDriver.class);
PersonWithList person = new PersonWithList();
Address a1 = new Address();
a1.city = "a1City";
a1.street = "a1Street";
Address a2 = new Address();
a2.city = "a2City";
a2.street = "a2Street";
person.addresses.add(a1);
person.addresses.add(a2);
PersonWithListEditor personEditor = new PersonWithListEditor();
// Initialize
driver.initialize(personEditor);
try {
personEditor.addressesEditor.getEditors();
// Address editors aren't created until edit() is called
fail();
} catch (IllegalStateException expected) {
}
// Edit
driver.edit(person);
AddressEditor addressEditor = personEditor.addressesEditor.getEditors().get(
1);
assertEquals("a2City", addressEditor.city.getValue());
addressEditor.city.setValue("edited");
// Flush
driver.flush();
assertEquals("edited", person.addresses.get(1).getCity());
}
public void testOptionalField() {
PersonEditorWithOptionalAddressDriver driver = GWT.create(PersonEditorWithOptionalAddressDriver.class);
person.address = null;
AddressEditor delegate = new AddressEditor();
PersonEditorWithOptionalAddressEditor editor = new PersonEditorWithOptionalAddressEditor(
delegate);
driver.initialize(editor);
// Make sure we don't blow up with the null field
driver.edit(person);
editor.address.setValue(personAddress);
assertEquals("City", delegate.city.getValue());
delegate.city.setValue("Hello");
driver.flush();
assertNotNull(person.address);
assertSame(personAddress, person.address);
assertEquals("Hello", personAddress.city);
editor.address.setValue(null);
driver.flush();
assertNull(person.address);
}
public void testValueAwareEditorInDeclaredSlot() {
PersonEditorWithValueAwareAddressEditorDriver driver = GWT.create(PersonEditorWithValueAwareAddressEditorDriver.class);
PersonEditorWithValueAwareAddressEditor personEditor = new PersonEditorWithValueAwareAddressEditor();
ValueAwareAddressEditor addressEditor = personEditor.addressEditor;
testValueAwareAddressEditor(driver, personEditor, addressEditor);
}
/**
* This is another instance of a LeafValueEditor found in a plain slot.
*/
public void testValueAwareEditorInPlainSlot() {
PersonEditorDriver driver = GWT.create(PersonEditorDriver.class);
PersonEditor personEditor = new PersonEditor();
ValueAwareAddressEditor addressEditor = new ValueAwareAddressEditor();
// Runtime assignment of unexpected LeafValueEditor
personEditor.addressEditor = addressEditor;
testValueAwareAddressEditor(driver, personEditor, addressEditor);
}
public void testValueAwareLeafValueEditorInDeclaredSlot() {
PersonEditorWithValueAwareLeafAddressEditor personEditor = new PersonEditorWithValueAwareLeafAddressEditor();
PersonEditorWithValueAwareLeafAddressEditorDriver driver = GWT.create(PersonEditorWithValueAwareLeafAddressEditorDriver.class);
ValueAwareLeafAddressEditor addressEditor = personEditor.addressEditor;
testLeafAddressEditor(driver, personEditor, addressEditor, true);
assertEquals(1, addressEditor.flushCalled);
assertEquals(1, addressEditor.setDelegateCalled);
}
public void testValueAwareLeafValueEditorInPlainEditorSlot() {
PersonEditorDriver driver = GWT.create(PersonEditorDriver.class);
PersonEditor personEditor = new PersonEditor();
ValueAwareLeafAddressEditor addressEditor = new ValueAwareLeafAddressEditor();
// Runtime assignment of unexpected LeafValueEditor
personEditor.addressEditor = addressEditor;
testLeafAddressEditor(driver, personEditor, addressEditor, false);
assertEquals(1, addressEditor.flushCalled);
assertEquals(1, addressEditor.setDelegateCalled);
}
@Override
protected void gwtSetUp() throws Exception {
personAddress = new Address();
personAddress.city = "City";
personAddress.street = "Street";
manager = new Person();
manager.name = "Bill";
person = new Person();
person.address = personAddress;
person.name = "Alice";
person.manager = manager;
}
private <T extends Editor<Person>> void testLeafAddressEditor(
SimpleBeanEditorDriver<Person, T> driver, T personEditor,
LeafAddressEditor addressEditor, boolean declaredAsLeaf) {
Address oldAddress = person.address;
// Initialize
driver.initialize(personEditor);
assertEquals(0, addressEditor.setValueCalled);
assertEquals(0, addressEditor.getValueCalled);
// Edit
driver.edit(person);
assertEquals(1, addressEditor.setValueCalled);
assertEquals(0, addressEditor.getValueCalled);
assertEquals(UNINITIALIZED, addressEditor.city.getValue());
// Flush
driver.flush();
assertEquals(1, addressEditor.setValueCalled);
assertEquals(1, addressEditor.getValueCalled);
if (declaredAsLeaf) {
assertNotSame(oldAddress, person.address);
assertSame(person.address, addressEditor.value);
} else {
assertSame(oldAddress, person.address);
assertNotSame(person.address, addressEditor.value);
}
}
private <T extends Editor<Person>> void testValueAwareAddressEditor(
SimpleBeanEditorDriver<Person, T> driver, T personEditor,
ValueAwareAddressEditor addressEditor) {
Address oldAddress = person.address;
// Initialize
driver.initialize(personEditor);
assertEquals(0, addressEditor.setValueCalled);
assertEquals(0, addressEditor.setDelegateCalled);
assertEquals(0, addressEditor.flushCalled);
// Edit
driver.edit(person);
assertEquals(1, addressEditor.setValueCalled);
assertEquals(1, addressEditor.setDelegateCalled);
assertEquals(0, addressEditor.flushCalled);
assertEquals("City", addressEditor.city.getValue());
// Flush
driver.flush();
assertEquals(1, addressEditor.setValueCalled);
assertEquals(1, addressEditor.setDelegateCalled);
assertEquals(1, addressEditor.flushCalled);
assertSame(oldAddress, person.address);
assertSame(person.address, addressEditor.value);
}
}