| /* |
| * 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(); |
| |
| @Override |
| 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(); |
| |
| @Override |
| public LeafAddressEditor asEditor() { |
| return addressEditor; |
| } |
| } |
| |
| static class DepartmentWithList extends Department { |
| List<Intern> interns = new ArrayList<Intern>(); |
| |
| public List<Intern> getInterns() { |
| return interns; |
| } |
| |
| public void setInterns(List<Intern> interns) { |
| this.interns = new ArrayList<Intern>(interns); |
| } |
| } |
| |
| static class DepartmentWithListEditor implements Editor<DepartmentWithList> { |
| PersonEditor manager = new PersonEditor(); |
| ListEditor<Intern, PersonEditor> interns = ListEditor.of(new EditorSource<PersonEditor>() { |
| @Override |
| public PersonEditor create(int index) { |
| return new PersonEditor(); |
| } |
| }); |
| } |
| |
| interface DepartmentWithListEditorDriver extends |
| SimpleBeanEditorDriver<DepartmentWithList, DepartmentWithListEditor> { |
| } |
| |
| /** |
| * 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; |
| |
| @Override |
| public Address getValue() { |
| getValueCalled++; |
| return value; |
| } |
| |
| @Override |
| 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; |
| |
| @Override |
| 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); |
| } |
| |
| @Override |
| public void setDelegate(EditorDelegate<T> delegate) { |
| this.delegate = delegate; |
| } |
| } |
| |
| class ValueAwareAddressEditor extends AddressEditor implements ValueAwareEditor<Address> { |
| int flushCalled; |
| int setDelegateCalled; |
| int setValueCalled; |
| Address value; |
| |
| @Override |
| public void flush() { |
| flushCalled++; |
| } |
| |
| @Override |
| public void onPropertyChange(String... paths) { |
| } |
| |
| @Override |
| public void setDelegate(EditorDelegate<Address> delegate) { |
| setDelegateCalled++; |
| } |
| |
| @Override |
| 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; |
| |
| @Override |
| public void flush() { |
| flushCalled++; |
| } |
| |
| @Override |
| public void onPropertyChange(String... paths) { |
| } |
| |
| @Override |
| public void setDelegate(EditorDelegate<Address> delegate) { |
| setDelegateCalled++; |
| } |
| } |
| |
| class TaggedItemAddressEditor implements Editor<TaggedItem<Address>> { |
| @Path("item.city") SimpleEditor<String> itemCityEditor = SimpleEditor.of(UNINITIALIZED); |
| @Path("item.street") SimpleEditor<String> itemStreetEditor = SimpleEditor.of(UNINITIALIZED); |
| @Path("tag") SimpleEditor<String> tagEditor = SimpleEditor.of(UNINITIALIZED); |
| } |
| |
| interface TaggedItemAddressEditorDriver extends |
| SimpleBeanEditorDriver<TaggedItem<Address>, TaggedItemAddressEditor> { |
| } |
| |
| 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="https://code.google.com/p/google-web-toolkit/issues/detail?id=6139" |
| * >issue 6139</a> |
| */ |
| public void testEditorOfSuperclass() { |
| DepartmentWithList dpt = new DepartmentWithList(); |
| Manager manager = new Manager(); |
| manager.name = "manager"; |
| dpt.setManager(manager); |
| Intern intern = new Intern(); |
| intern.name = "intern"; |
| dpt.interns.add(intern); |
| |
| DepartmentWithListEditor editor = new DepartmentWithListEditor(); |
| DepartmentWithListEditorDriver driver = GWT.create(DepartmentWithListEditorDriver.class); |
| driver.initialize(editor); |
| |
| driver.edit(dpt); |
| |
| assertEquals("manager", editor.manager.name.getValue()); |
| assertEquals("intern", editor.interns.getEditors().get(0).name.getValue()); |
| |
| editor.manager.name.setValue("MANAGER"); |
| editor.interns.getEditors().get(0).name.setValue("INTERN"); |
| |
| driver.flush(); |
| |
| assertEquals("MANAGER", manager.name); |
| assertEquals("INTERN", intern.name); |
| } |
| |
| /** |
| * 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>> { |
| @Override |
| public SimpleEditor<String> create(int index) { |
| SimpleEditor<String> editor = SimpleEditor.of(); |
| positionMap.put(index, editor); |
| return editor; |
| } |
| |
| @Override |
| public void dispose(SimpleEditor<String> editor) { |
| disposed[0] = editor; |
| positionMap.values().remove(editor); |
| } |
| |
| @Override |
| 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); |
| } |
| |
| public void testEditorWithParameterizedModel() { |
| TaggedItemAddressEditorDriver driver = GWT.create(TaggedItemAddressEditorDriver.class); |
| TaggedItemAddressEditor editor = new TaggedItemAddressEditor(); |
| driver.initialize(editor); |
| |
| TaggedItem<Address> taggedAddress = new TaggedItem<Address>(); |
| taggedAddress.setTag("tag1"); |
| taggedAddress.setItem(personAddress); |
| driver.edit(taggedAddress); |
| |
| assertEquals("tag1", editor.tagEditor.getValue()); |
| assertEquals("City", editor.itemCityEditor.getValue()); |
| assertEquals("Street", editor.itemStreetEditor.getValue()); |
| |
| editor.tagEditor.setValue("tag2"); |
| editor.itemCityEditor.setValue("Town"); |
| editor.itemStreetEditor.setValue("Road"); |
| driver.flush(); |
| |
| assertEquals("tag2", taggedAddress.getTag()); |
| assertEquals("Town", taggedAddress.getItem().getCity()); |
| assertEquals("Road", taggedAddress.getItem().getStreet()); |
| } |
| |
| @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); |
| } |
| } |