| /* | |
| * 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.Collections; | |
| 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 AddressEditorPartOne implements Editor<Address> { | |
| SimpleEditor<String> city = SimpleEditor.of(UNINITIALIZED); | |
| } | |
| class AddressEditorPartTwo implements Editor<Address> { | |
| SimpleEditor<String> street = SimpleEditor.of(UNINITIALIZED); | |
| } | |
| class AddressEditorView implements IsEditor<LeafAddressEditor> { | |
| LeafAddressEditor addressEditor = new LeafAddressEditor(); | |
| public LeafAddressEditor asEditor() { | |
| return addressEditor; | |
| } | |
| } | |
| /** | |
| * See <a | |
| * href="http://code.google.com/p/google-web-toolkit/issues/detail?id=6016" | |
| * >issue 6016</a> | |
| */ | |
| static class EditorWithGenericSubEditors implements Editor<Department> { | |
| PersonGenericEditor<Manager> manager = new PersonGenericEditor<Manager>(); | |
| PersonGenericEditor<Intern> intern = new PersonGenericEditor<Intern>(); | |
| } | |
| interface EditorWithGenericSubEditorsDriver extends | |
| SimpleBeanEditorDriver<Department, EditorWithGenericSubEditors> { | |
| } | |
| 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> { | |
| } | |
| /** | |
| * A test for assigning the object associated with an editor to an immediate | |
| * child editors. | |
| */ | |
| class PersonEditorWithAliasedSubEditors implements Editor<Person> { | |
| @Path("") | |
| PersonEditor e1 = new PersonEditor(); | |
| @Path("") | |
| PersonEditor e2 = new PersonEditor(); | |
| } | |
| interface PersonEditorWithAliasedSubEditorsDriver extends | |
| SimpleBeanEditorDriver<Person, PersonEditorWithAliasedSubEditors> { | |
| } | |
| class PersonEditorWithCoAddressEditorView implements Editor<Person> { | |
| AddressCoEditorView addressEditor = new AddressCoEditorView(); | |
| SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED); | |
| } | |
| interface PersonEditorWithCoAddressEditorViewDriver extends | |
| SimpleBeanEditorDriver<Person, PersonEditorWithCoAddressEditorView> { | |
| } | |
| static class PersonEditorWithDelegate extends PersonEditor implements HasEditorDelegate<Person> { | |
| EditorDelegate<Person> delegate; | |
| public void setDelegate(EditorDelegate<Person> delegate) { | |
| this.delegate = delegate; | |
| } | |
| } | |
| interface PersonEditorWithDelegateDriver extends | |
| SimpleBeanEditorDriver<Person, PersonEditorWithDelegate> { | |
| } | |
| 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> { | |
| } | |
| class PersonEditorWithManagerNameWithDelegate implements Editor<Person> { | |
| @Path("manager.name") | |
| SimpleEditorWithDelegate<String> managerName = new SimpleEditorWithDelegate<String>( | |
| UNINITIALIZED); | |
| } | |
| interface PersonEditorWithManagerNameWithDelegateDriver extends | |
| SimpleBeanEditorDriver<Person, PersonEditorWithManagerNameWithDelegate> { | |
| } | |
| class PersonEditorWithMultipleBindings implements Editor<Person> { | |
| @Editor.Path("address") | |
| AddressEditorPartOne one = new AddressEditorPartOne(); | |
| @Editor.Path("address") | |
| AddressEditorPartTwo two = new AddressEditorPartTwo(); | |
| } | |
| interface PersonEditorWithMultipleBindingsDriver extends | |
| SimpleBeanEditorDriver<Person, PersonEditorWithMultipleBindings> { | |
| } | |
| interface PersonEditorWithOptionalAddressDriver extends | |
| SimpleBeanEditorDriver<Person, PersonEditorWithOptionalAddressEditor> { | |
| } | |
| static 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> { | |
| } | |
| static class PersonGenericEditor<T extends Person> implements Editor<T> { | |
| SimpleEditor<String> name = SimpleEditor.of(UNINITIALIZED); | |
| } | |
| 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, ValueAwareAddressEditor> addressesEditor = ListEditor | |
| .of(new EditorSource<ValueAwareAddressEditor>() { | |
| @Override | |
| public ValueAwareAddressEditor create(int index) { | |
| return new ValueAwareAddressEditor(); | |
| } | |
| }); | |
| } | |
| interface PersonWithListEditorDriver extends | |
| SimpleBeanEditorDriver<PersonWithList, PersonWithListEditor> { | |
| } | |
| class SimpleEditorWithDelegate<T> extends SimpleEditor<T> implements HasEditorDelegate<T> { | |
| EditorDelegate<T> delegate; | |
| public SimpleEditorWithDelegate(T value) { | |
| super(value); | |
| } | |
| public void setDelegate(EditorDelegate<T> delegate) { | |
| this.delegate = delegate; | |
| } | |
| } | |
| 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; | |
| long now; | |
| 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(now, editor.localTime.getValue().longValue()); | |
| assertEquals("Alice", editor.name.getValue()); | |
| assertEquals("City", editor.addressEditor.city.getValue()); | |
| assertEquals("Street", editor.addressEditor.street.getValue()); | |
| assertEquals("Bill", editor.managerName.getValue()); | |
| editor.localTime.setValue(now + 1); | |
| editor.name.setValue("Charles"); | |
| editor.addressEditor.city.setValue("Wootville"); | |
| editor.addressEditor.street.setValue("12345"); | |
| editor.managerName.setValue("David"); | |
| driver.flush(); | |
| assertEquals(now + 1, person.localTime); | |
| assertEquals("Charles", person.name); | |
| assertEquals("Wootville", person.address.city); | |
| assertEquals("12345", person.address.street); | |
| assertEquals("David", person.manager.name); | |
| } | |
| public void testAliasedEditors() { | |
| PersonEditorWithAliasedSubEditors editor = new PersonEditorWithAliasedSubEditors(); | |
| PersonEditorWithAliasedSubEditorsDriver driver = | |
| GWT.create(PersonEditorWithAliasedSubEditorsDriver.class); | |
| driver.initialize(editor); | |
| driver.edit(person); | |
| assertEquals("Alice", editor.e1.name.getValue()); | |
| assertEquals("Alice", editor.e2.name.getValue()); | |
| /* | |
| * Expecting that aliased editors will be editing disjoint sets of | |
| * properties, but we want to at least have a predictable behavior if two | |
| * editors are assigned to the same property. | |
| */ | |
| editor.e1.name.setValue("Should not see this"); | |
| driver.flush(); | |
| assertEquals("Alice", person.getName()); | |
| editor.e2.name.setValue("Should see this"); | |
| driver.flush(); | |
| assertEquals("Should see this", person.getName()); | |
| } | |
| public void testDelegatePath() { | |
| PersonEditorWithManagerNameWithDelegate editor = new PersonEditorWithManagerNameWithDelegate(); | |
| PersonEditorWithManagerNameWithDelegateDriver driver = | |
| GWT.create(PersonEditorWithManagerNameWithDelegateDriver.class); | |
| driver.initialize(editor); | |
| driver.edit(person); | |
| assertEquals("manager.name", editor.managerName.delegate.getPath()); | |
| } | |
| /** | |
| * See <a | |
| * href="http://code.google.com/p/google-web-toolkit/issues/detail?id=6016" | |
| * >issue 6016</a> | |
| */ | |
| public void testEditorWithGenericSubEditors() { | |
| EditorWithGenericSubEditorsDriver driver = GWT.create(EditorWithGenericSubEditorsDriver.class); | |
| // Issue 6016 would make the above line fail (when generating the editor | |
| // driver), but let's try editing an object too, it doesn't cost much. | |
| driver.initialize(new EditorWithGenericSubEditors()); | |
| driver.edit(new Department()); | |
| } | |
| public void testEditorWithNullSubEditor() { | |
| PersonEditor editor = new PersonEditor(); | |
| editor.addressEditor = null; | |
| PersonEditorDriver driver = GWT.create(PersonEditorDriver.class); | |
| driver.initialize(editor); | |
| driver.edit(person); | |
| assertEquals("Alice", editor.name.getValue()); | |
| editor.name.setValue("New name"); | |
| driver.flush(); | |
| assertEquals("New name", person.getName()); | |
| /* | |
| * Verify that changing the editor structure without re-initializing is a | |
| * no-op. | |
| */ | |
| editor.name.setValue("Should see this"); | |
| editor.addressEditor = new AddressEditor(); | |
| editor.addressEditor.city.setValue("Should not see this"); | |
| driver.flush(); | |
| assertEquals("Should see this", person.getName()); | |
| assertEquals("City", person.getAddress().getCity()); | |
| // Re-initialize and check that flushing works again | |
| driver.initialize(editor); | |
| driver.edit(person); | |
| editor.addressEditor.city.setValue("Should see this"); | |
| driver.flush(); | |
| assertEquals("Should see this", person.getAddress().getCity()); | |
| } | |
| /** | |
| * 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, true); | |
| } | |
| 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())); | |
| // Change list outside editor: shouldn't impact editors | |
| rawData.clear(); | |
| rawData.addAll(Arrays.asList("able", "baker")); | |
| List<String> expectedList = Arrays.asList("Hello", "World", "quux"); | |
| assertEquals(expectedList, editor.getList()); | |
| assertEquals(expectedList.size(), editors.size()); | |
| assertEquals(expectedList, Arrays.asList(editors.get(0).getValue(), editors.get(1).getValue(), | |
| editors.get(2).getValue())); | |
| assertEquals(editors, new ArrayList<SimpleEditor<String>>(positionMap.values())); | |
| // Edit again: should reuse sub-editors and dispose unneeded ones | |
| disposed[0] = null; | |
| expectedDisposed = editors.get(2); | |
| @SuppressWarnings("unchecked") | |
| List<SimpleEditor<String>> expectedEditors = Arrays.asList(editors.get(0), editors.get(1)); | |
| driver.edit(rawData); | |
| assertEquals(expectedEditors, editors); | |
| assertEquals(expectedEditors, editor.getEditors()); | |
| assertEquals(rawData, editor.getList()); | |
| assertEquals(rawData.size(), editors.size()); | |
| assertEquals(rawData, Arrays.asList(editors.get(0).getValue(), editors.get(1).getValue())); | |
| assertEquals(editors, new ArrayList<SimpleEditor<String>>(positionMap.values())); | |
| assertEquals(expectedDisposed, disposed[0]); | |
| } | |
| /** | |
| * 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); | |
| // Address editors aren't created until edit() is called | |
| assertEquals(Collections.emptyList(), personEditor.addressesEditor.getEditors()); | |
| // Edit | |
| driver.edit(person); | |
| ValueAwareAddressEditor addressEditor = personEditor.addressesEditor.getEditors().get(1); | |
| // Check that setValue is only called once on sub-editors (issue 7038) | |
| assertEquals(1, addressEditor.setValueCalled); | |
| assertEquals("a2City", addressEditor.city.getValue()); | |
| addressEditor.city.setValue("edited"); | |
| // Flush | |
| driver.flush(); | |
| assertEquals("edited", person.addresses.get(1).getCity()); | |
| // Verify that setting the same list reuses sub-editors | |
| addressEditor.setValueCalled = 0; | |
| driver.edit(person); | |
| assertSame(addressEditor, personEditor.addressesEditor.getEditors().get(1)); | |
| // Check that setValue has correctly been called on the sub-editor anyway | |
| assertEquals(1, addressEditor.setValueCalled); | |
| // Edit with a null list | |
| person.addresses = null; | |
| driver.edit(person); | |
| assertNull(personEditor.addressesEditor.getList()); | |
| assertEquals(Collections.emptyList(), personEditor.addressesEditor.getEditors()); | |
| // Flushing should not throw: | |
| driver.flush(); | |
| assertNull(person.addresses); | |
| } | |
| public void testMultipleBinding() { | |
| PersonEditorWithMultipleBindingsDriver driver = | |
| GWT.create(PersonEditorWithMultipleBindingsDriver.class); | |
| PersonEditorWithMultipleBindings editor = new PersonEditorWithMultipleBindings(); | |
| driver.initialize(editor); | |
| driver.edit(person); | |
| assertEquals("City", editor.one.city.getValue()); | |
| assertEquals("Street", editor.two.street.getValue()); | |
| editor.one.city.setValue("Foo"); | |
| editor.two.street.setValue("Bar"); | |
| driver.flush(); | |
| assertEquals("Foo", person.getAddress().getCity()); | |
| assertEquals("Bar", person.getAddress().getStreet()); | |
| } | |
| 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, true); | |
| 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; | |
| person.localTime = now = System.currentTimeMillis(); | |
| } | |
| 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); | |
| // The DirtCollector will interrogate the leaf editors | |
| assertEquals(1, addressEditor.getValueCalled); | |
| // Flush | |
| driver.flush(); | |
| assertEquals(1, addressEditor.setValueCalled); | |
| assertEquals(2, addressEditor.getValueCalled); | |
| assertNotSame(oldAddress, person.address); | |
| assertSame(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); | |
| } | |
| } |