/** * Copyright (c) 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM - Initial API and implementation */ package org.eclipse.emf.test.databinding; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.core.databinding.observable.list.IListChangeListener; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.list.ListChangeEvent; import org.eclipse.core.databinding.observable.list.ListDiff; import org.eclipse.core.databinding.observable.map.IMapChangeListener; import org.eclipse.core.databinding.observable.map.IObservableMap; import org.eclipse.core.databinding.observable.map.MapChangeEvent; import org.eclipse.core.databinding.observable.map.MapDiff; import org.eclipse.core.databinding.observable.set.IObservableSet; import org.eclipse.core.databinding.observable.set.ISetChangeListener; import org.eclipse.core.databinding.observable.set.SetChangeEvent; import org.eclipse.core.databinding.observable.set.SetDiff; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.databinding.EMFProperties; import org.eclipse.emf.databinding.FeaturePath; import org.eclipse.emf.databinding.IEMFListProperty; import org.eclipse.emf.databinding.IEMFListProperty.ListElementAccess; import org.eclipse.emf.databinding.IEMFMapProperty; import org.eclipse.emf.databinding.IEMFSetProperty; import org.eclipse.emf.databinding.IEMFValueProperty; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; import org.eclipse.emf.test.common.TestUtil; import org.eclipse.emf.test.databinding.emfdb.A; import org.eclipse.emf.test.databinding.emfdb.B; import org.eclipse.emf.test.databinding.emfdb.EmfdbFactory; import org.eclipse.emf.test.databinding.emfdb.EmfdbPackage; import org.junit.Before; import org.junit.Test; public class EMFPropertiesTest { private Resource resource; private Realm testRealm; private SetDiff setDiff; private ListDiff listDiff; private MapDiff mapDiff; @Before public void setUp() throws Exception { ResourceSet resourceSet = new ResourceSetImpl(); resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put( Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()); URI uri = URI.createFileURI(TestUtil.getPluginDirectory("org.eclipse.emf.test.databinding") + "/model/A.xmi"); resource = resourceSet.getResource(uri, true); testRealm = new Realm() { @Override public boolean isCurrent() { return true; } }; } @Test public void testFeaturePath() { assertNotNull(FeaturePath.fromList(EmfdbPackage.Literals.A__BLIST)); try { FeaturePath.fromList(EmfdbPackage.Literals.A__BLIST, EmfdbPackage.Literals.B__STRING); fail("Traversing list feature"); } catch (IllegalArgumentException e) { // Ignore } } @Test public void testResourceProperty() { Realm.runWithDefault(testRealm, new Runnable() { public void run() { _testResourceProperty(); } }); } private void _testResourceProperty() { IEMFListProperty prop = EMFProperties.resource(); IObservableList list = prop.observe(resource); list.addListChangeListener(new IListChangeListener() { public void handleListChange(ListChangeEvent event) { listDiff = event.diff; } }); assertNull(listDiff); // Adding A a = EmfdbFactory.eINSTANCE.createA(); A a1 = EmfdbFactory.eINSTANCE.createA(); resource.getContents().add(a); assertNotNull(listDiff); assertEquals(1, listDiff.getDifferences().length); assertSame(a, listDiff.getDifferences()[0].getElement()); assertEquals(1, listDiff.getDifferences()[0].getPosition()); assertTrue(listDiff.getDifferences()[0].isAddition()); // Moving resource.getContents().move(0, a); assertEquals(2, listDiff.getDifferences().length); assertFalse(listDiff.getDifferences()[0].isAddition()); // Removal assertEquals(1, listDiff.getDifferences()[0].getPosition()); assertTrue(listDiff.getDifferences()[1].isAddition()); // Addition assertEquals(0, listDiff.getDifferences()[1].getPosition()); // Removing resource.getContents().remove(a); assertEquals(1, listDiff.getDifferences().length); assertFalse(listDiff.getDifferences()[0].isAddition()); // Removal assertEquals(0, listDiff.getDifferences()[0].getPosition()); // Adding many resource.getContents().addAll(Arrays.asList(a, a1)); assertEquals(2, listDiff.getDifferences().length); // Remove many resource.getContents().removeAll(Arrays.asList(a, a1)); assertEquals(2, listDiff.getDifferences().length); // ============================================================= // Changed through IObservableList // Add list.add(a); assertNotNull(listDiff); assertEquals(1, listDiff.getDifferences().length); assertSame(a, listDiff.getDifferences()[0].getElement()); assertEquals(1, listDiff.getDifferences()[0].getPosition()); assertTrue(listDiff.getDifferences()[0].isAddition()); // Moving list.move(1, 0); assertEquals(2, listDiff.getDifferences().length); assertFalse(listDiff.getDifferences()[0].isAddition()); // Removal assertEquals(1, listDiff.getDifferences()[0].getPosition()); assertTrue(listDiff.getDifferences()[1].isAddition()); // Addition assertEquals(0, listDiff.getDifferences()[1].getPosition()); // Removing list.remove(a); assertEquals(1, listDiff.getDifferences().length); assertFalse(listDiff.getDifferences()[0].isAddition()); // Removal assertEquals(0, listDiff.getDifferences()[0].getPosition()); // Adding many list.addAll(Arrays.asList(a, a1)); assertEquals(2, listDiff.getDifferences().length); // Remove many list.removeAll(Arrays.asList(a, a1)); assertEquals(2, listDiff.getDifferences().length); } @Test public void testSetProperty() { Realm.runWithDefault(testRealm, new Runnable() { public void run() { _testSetProperty(); } }); } public void _testSetProperty() { A a = (A)resource.getContents().get(0); IEMFSetProperty prop = EMFProperties.set(EmfdbPackage.Literals.A__BLIST); IObservableSet set = prop.observe(a); assertNotNull(set); set.addSetChangeListener(new ISetChangeListener() { public void handleSetChange(SetChangeEvent event) { setDiff = event.diff; } }); assertNull(setDiff); B b = EmfdbFactory.eINSTANCE.createB(); a.getBlist().add(b); assertNotNull(setDiff); assertEquals(1, setDiff.getAdditions().size()); assertSame(b, setDiff.getAdditions().iterator().next()); } @Test public void testListPropertyOnSingleFeature() { Realm.runWithDefault(testRealm, new Runnable() { public void run() { _testListPropertyOnSingleFeature(); } }); } public void _testListPropertyOnSingleFeature() { A a = (A)resource.getContents().get(0); IEMFListProperty prop = EMFProperties.list(EmfdbPackage.Literals.A__STRING); IObservableList l = prop.observe(a); assertEquals(1, l.size()); assertEquals("Instance 1", l.get(0)); a.setString("Bla"); assertEquals("Bla", l.get(0)); l.addListChangeListener(new IListChangeListener() { public void handleListChange(ListChangeEvent event) { assertEquals(2, event.diff.getDifferences().length); assertEquals(0, event.diff.getDifferences()[0].getPosition()); assertFalse(event.diff.getDifferences()[0].isAddition()); assertEquals("Bla", event.diff.getDifferences()[0].getElement()); assertEquals(0, event.diff.getDifferences()[1].getPosition()); assertTrue(event.diff.getDifferences()[1].isAddition()); assertEquals("Instance 1", event.diff.getDifferences()[1].getElement()); } }); a.setString("Instance 1"); } @Test public void testListElementProperty() { Realm.runWithDefault(testRealm, new Runnable() { public void run() { _testListElementProperty(); } }); } public void _testListElementProperty() { IEMFListProperty prop = EMFProperties.list(EmfdbPackage.Literals.A__BLIST); IEMFValueProperty valueProp = prop.value(new ListElementAccess<Object>() { @Override public int getReadValueIndex(List<Object> list) { return 0; } @Override public int getWriteValueIndex(List<Object> list) { return 0; } }); IEMFValueProperty detailValue = valueProp.value(EmfdbPackage.Literals.B__STRING); IObservableValue value = detailValue.observe(resource.getContents().get(0)); assertEquals("Instance 1", value.getValue()); A a = (A)resource.getContents().get(0); a.getBlist().get(0).setString("Bla Bla"); assertEquals("Bla Bla", value.getValue()); B b = EmfdbFactory.eINSTANCE.createB(); b.setString("New Element"); a.getBlist().add(0, b); assertEquals("New Element", value.getValue()); b = EmfdbFactory.eINSTANCE.createB(); b.setString("New Element 2"); IObservableValue aObservable = valueProp.observe(a); try { aObservable.setValue(b); } finally { aObservable.dispose(); } assertEquals("New Element 2", value.getValue()); } @Test public void testMapProperty() { Realm.runWithDefault(testRealm, new Runnable() { public void run() { _testMapProperty(); } }); } @SuppressWarnings("unchecked") public void _testMapProperty() { A a = (A)resource.getContents().get(0); IEMFMapProperty prop = EMFProperties.map(EmfdbPackage.Literals.A__CMAP); IObservableMap map = prop.observe(a); map.addMapChangeListener(new IMapChangeListener() { public void handleMapChange(MapChangeEvent event) { mapDiff = event.diff; } }); assertNull(mapDiff); // Changing existing key a.getCmap().put("key 1", "value 1 modified"); assertEquals(0, mapDiff.getAddedKeys().size()); assertEquals(1, mapDiff.getChangedKeys().size()); assertEquals("key 1", mapDiff.getChangedKeys().iterator().next()); assertEquals("value 1", mapDiff.getOldValue("key 1")); assertEquals("value 1 modified", mapDiff.getNewValue("key 1")); assertEquals(0, mapDiff.getRemovedKeys().size()); // Adding new key a.getCmap().put("key 3", "value 3"); assertEquals(1, mapDiff.getAddedKeys().size()); assertEquals("key 3", mapDiff.getAddedKeys().iterator().next()); assertNull(mapDiff.getOldValue("key 3")); assertEquals("value 3", mapDiff.getNewValue("key 3")); assertEquals(0, mapDiff.getChangedKeys().size()); assertEquals(0, mapDiff.getRemovedKeys().size()); // Removing key a.getCmap().removeKey("key 2"); assertEquals(0, mapDiff.getAddedKeys().size()); assertEquals(0, mapDiff.getChangedKeys().size()); assertEquals(1, mapDiff.getRemovedKeys().size()); assertEquals("key 2", mapDiff.getRemovedKeys().iterator().next()); assertEquals("value 2", mapDiff.getOldValue("key 2")); assertNull(mapDiff.getNewValue("key 2")); // putAll is implemented as a series of put calls, // which are already tested above, see BasicEMap.putAll() // Removing many keys a.getCmap().clear(); assertEquals(0, mapDiff.getAddedKeys().size()); assertEquals(0, mapDiff.getChangedKeys().size()); assertEquals(2, mapDiff.getRemovedKeys().size()); assertTrue(mapDiff.getRemovedKeys().contains("key 1")); assertTrue(mapDiff.getRemovedKeys().contains("key 3")); assertEquals("value 1 modified", mapDiff.getOldValue("key 1")); assertEquals("value 3", mapDiff.getOldValue("key 3")); assertNull(mapDiff.getNewValue("key 1")); assertNull(mapDiff.getNewValue("key 3")); // ============================================================= // Changed through IObservableMap // Adding new key map.put("key 1", "value 1"); assertEquals(1, mapDiff.getAddedKeys().size()); assertEquals("key 1", mapDiff.getAddedKeys().iterator().next()); assertNull(mapDiff.getOldValue("key 1")); assertEquals("value 1", mapDiff.getNewValue("key 1")); assertEquals(0, mapDiff.getChangedKeys().size()); assertEquals(0, mapDiff.getRemovedKeys().size()); // Adding many (including existing) keys Map<String, String> newValues = new HashMap<String, String>(); newValues.put("key 1", "value 1 modified"); newValues.put("key 2", "value 2"); newValues.put("key 3", "value 3"); map.putAll(newValues); assertEquals(2, mapDiff.getAddedKeys().size()); assertTrue(mapDiff.getAddedKeys().contains("key 2")); assertTrue(mapDiff.getAddedKeys().contains("key 3")); assertNull(mapDiff.getOldValue("key 2")); assertNull(mapDiff.getOldValue("key 3")); assertEquals("value 2", mapDiff.getNewValue("key 2")); assertEquals("value 3", mapDiff.getNewValue("key 3")); assertEquals(1, mapDiff.getChangedKeys().size()); assertEquals("key 1", mapDiff.getChangedKeys().iterator().next()); assertEquals("value 1", mapDiff.getOldValue("key 1")); assertEquals("value 1 modified", mapDiff.getNewValue("key 1")); assertEquals(0, mapDiff.getRemovedKeys().size()); // Removing map.remove("key 1"); assertEquals(0, mapDiff.getAddedKeys().size()); assertEquals(0, mapDiff.getChangedKeys().size()); assertEquals(1, mapDiff.getRemovedKeys().size()); assertEquals("key 1", mapDiff.getRemovedKeys().iterator().next()); assertEquals("value 1 modified", mapDiff.getOldValue("key 1")); assertNull(mapDiff.getNewValue("key 1")); // Removing many // The only way to remove many entries from IObservableMap is // to call clear(), but clear removes entries one by one, which // has already been tested above map.clear(); } @Test public void test_sublistElement() { Realm.runWithDefault(testRealm, new Runnable() { public void run() { _test_sublistElement(); } }); } public void _test_sublistElement() { A a = (A)resource.getContents().get(0); IEMFListProperty lProp1 = EMFProperties.list(EmfdbPackage.Literals.A__BLIST); IEMFValueProperty vProp1 = lProp1.value(new ListElementAccess<Object>() { @Override public int getReadValueIndex(List<Object> list) { return 0; } @Override public int getWriteValueIndex(List<Object> list) { return WriteData.NO_INDEX; } }); IEMFValueProperty vProp2 = vProp1.value(EmfdbPackage.Literals.B__D); IEMFListProperty lProp2 = vProp2.list(EmfdbPackage.Literals.D__ELIST); IEMFValueProperty vProp3 = lProp2.value(new ListElementAccess<Object>() { @Override public int getReadValueIndex(List<Object> list) { return list.size() - 1; } @Override public int getWriteValueIndex(List<Object> list) { return WriteData.NO_INDEX; } }); IEMFValueProperty detailValue = vProp3.value(EmfdbPackage.Literals.E__NAME); IObservableValue v = detailValue.observe(a); assertEquals(v.getValue(), "Last Element"); } }