blob: 8fb9f2de3c77c1cfb42d9976121b23e57f585447 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Lucas Koehler - initial API and implementation
* Christian W. Damus - bug 547271
******************************************************************************/
package org.eclipse.emf.ecp.view.model.generator;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
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.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.eclipse.emf.common.command.BasicCommandStack;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.util.BasicExtendedMetaData.EClassifierExtendedMetaData;
import org.eclipse.emf.ecore.util.EObjectContainmentWithInverseEList;
import org.eclipse.emf.ecore.util.EObjectEList;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecp.view.spi.model.VControl;
import org.eclipse.emf.ecp.view.spi.model.VDomainModelReference;
import org.eclipse.emf.ecp.view.spi.model.VElement;
import org.eclipse.emf.ecp.view.spi.model.VFeaturePathDomainModelReference;
import org.eclipse.emf.ecp.view.spi.model.VView;
import org.eclipse.emf.ecp.view.spi.model.VViewFactory;
import org.eclipse.emf.ecp.view.spi.model.VViewModelLoadingProperties;
import org.eclipse.emf.ecp.view.spi.table.model.VTableControl;
import org.eclipse.emf.ecp.view.spi.table.model.VTableDomainModelReference;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.junit.Before;
import org.junit.Test;
/**
* Unit tests for {@link ViewProvider}.
*
* @author Lucas Koehler
*/
public class ViewProvider_Test {
private EClass eClass;
private EClass refType;
private ViewProvider viewProvider;
private VViewModelLoadingProperties viewProperties;
@Before
public void setUp() {
viewProvider = new ViewProvider();
viewProperties = VViewFactory.eINSTANCE.createViewModelLoadingProperties();
eClass = EcoreFactory.eINSTANCE.createEClass();
eClass.setName("Test");
refType = EcoreFactory.eINSTANCE.createEClass();
refType.setName("RefType");
final EPackage p = EcoreFactory.eINSTANCE.createEPackage();
p.setName("p");
p.setNsPrefix("p");
p.setNsURI("p");
p.getEClassifiers().add(eClass);
p.getEClassifiers().add(refType);
}
@Test
public void provideViewModel_attribute() {
final EAttribute attribute = EcoreFactory.eINSTANCE.createEAttribute();
attribute.setName("attribute");
attribute.setEType(EcorePackage.Literals.ESTRING);
eClass.getEStructuralFeatures().add(attribute);
final EObject object = EcoreUtil.create(eClass);
final VView view = viewProvider.provideViewModel(object, viewProperties);
assertView(view);
assertTrue(view.getChildren().get(0) instanceof VControl);
final VControl control = (VControl) view.getChildren().get(0);
assertNotNull(control.getUuid());
assertFalse(control.getUuid().isEmpty());
final VDomainModelReference dmr = control.getDomainModelReference();
assertTrue(dmr instanceof VFeaturePathDomainModelReference);
final VFeaturePathDomainModelReference featureDmr = (VFeaturePathDomainModelReference) dmr;
assertTrue(featureDmr.getDomainModelEReferencePath().isEmpty());
assertSame(attribute, featureDmr.getDomainModelEFeature());
}
@Test
public void provideViewModel_singleReference() {
final EReference singleRef = EcoreFactory.eINSTANCE.createEReference();
singleRef.setName("singleRef");
singleRef.setEType(refType);
eClass.getEStructuralFeatures().add(singleRef);
final EObject object = EcoreUtil.create(eClass);
final VView view = viewProvider.provideViewModel(object, viewProperties);
assertView(view);
assertTrue(view.getChildren().get(0) instanceof VControl);
final VControl control = (VControl) view.getChildren().get(0);
assertNotNull(control.getUuid());
assertFalse(control.getUuid().isEmpty());
final VDomainModelReference dmr = control.getDomainModelReference();
assertTrue(dmr instanceof VFeaturePathDomainModelReference);
final VFeaturePathDomainModelReference featureDmr = (VFeaturePathDomainModelReference) dmr;
assertTrue(featureDmr.getDomainModelEReferencePath().isEmpty());
assertSame(singleRef, featureDmr.getDomainModelEFeature());
}
@Test
public void provideViewModel_multiCrossReference() {
final EReference multiCrossRef = EcoreFactory.eINSTANCE.createEReference();
multiCrossRef.setName("multiCrossRef");
multiCrossRef.setEType(refType);
multiCrossRef.setUpperBound(-1); // multi ref
multiCrossRef.setContainment(false);
eClass.getEStructuralFeatures().add(multiCrossRef);
final EObject object = EcoreUtil.create(eClass);
final VView view = viewProvider.provideViewModel(object, viewProperties);
assertView(view);
assertTrue(view.getChildren().get(0) instanceof VControl);
final VControl control = (VControl) view.getChildren().get(0);
assertNotNull(control.getUuid());
assertFalse(control.getUuid().isEmpty());
final VDomainModelReference dmr = control.getDomainModelReference();
assertTrue(dmr instanceof VFeaturePathDomainModelReference);
final VFeaturePathDomainModelReference featureDmr = (VFeaturePathDomainModelReference) dmr;
assertTrue(featureDmr.getDomainModelEReferencePath().isEmpty());
assertSame(multiCrossRef, featureDmr.getDomainModelEFeature());
}
/** Verify that the generator generates a table control for multi containment refs. */
@Test
public void provideViewModel_multiContainmentReference() {
final EReference multiContainmentRef = EcoreFactory.eINSTANCE.createEReference();
multiContainmentRef.setName("multiContainmentRef");
multiContainmentRef.setEType(refType);
multiContainmentRef.setUpperBound(-1); // multi ref
multiContainmentRef.setContainment(true);
eClass.getEStructuralFeatures().add(multiContainmentRef);
final EObject object = EcoreUtil.create(eClass);
final VView view = viewProvider.provideViewModel(object, viewProperties);
assertView(view);
assertTrue(view.getChildren().get(0) instanceof VTableControl);
final VTableControl control = (VTableControl) view.getChildren().get(0);
assertNotNull(control.getUuid());
assertFalse(control.getUuid().isEmpty());
final VDomainModelReference controlDmr = control.getDomainModelReference();
assertTrue(controlDmr instanceof VTableDomainModelReference);
final VTableDomainModelReference tableDmr = (VTableDomainModelReference) controlDmr;
assertTrue(tableDmr.getDomainModelEReferencePath().isEmpty());
assertNull(tableDmr.getDomainModelEFeature());
assertTrue(tableDmr.getDomainModelReference() instanceof VFeaturePathDomainModelReference);
final VFeaturePathDomainModelReference featureDmr = (VFeaturePathDomainModelReference) tableDmr
.getDomainModelReference();
assertSame(multiContainmentRef, featureDmr.getDomainModelEFeature());
}
/**
* Verify that controls' generated UUIDs actually are unique within the view (there is no
* guarantee that they are unique globally, but the {@link ViewProvider} does not need that).
*/
@Test
public void controlsHaveUniqueUUIDs() {
final EClass eClass = mock(EClass.class,
withSettings().extraInterfaces(InternalEObject.class, EClassifierExtendedMetaData.Holder.class));
when(eClass.eContainer()).thenReturn(this.eClass.eContainer());
when(eClass.getEPackage()).thenReturn(this.eClass.getEPackage());
when(eClass.getName()).thenReturn("Mock");
when(eClass.getESuperTypes()).thenReturn(ECollections.emptyEList());
when(((EClassifierExtendedMetaData.Holder) eClass).getExtendedMetaData())
.thenReturn(mock(EClassifierExtendedMetaData.class));
// Repeat the exact same feature multiple times to create controls
final EList<EStructuralFeature> features = new EObjectContainmentWithInverseEList<>(EStructuralFeature.class,
(InternalEObject) eClass, EcorePackage.ECLASS__ESTRUCTURAL_FEATURES,
EcorePackage.ESTRUCTURAL_FEATURE__ECONTAINING_CLASS);
final EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setEType(refType);
ref.setName("ref");
final EList<EReference> references = new EObjectEList<>(EReference.class, (InternalEObject) eClass,
EcorePackage.ECLASS__EREFERENCES);
references.addAll(Collections.nCopies(500, ref));
features.addAll(references);
when(eClass.getEStructuralFeatures()).thenReturn(features);
when(eClass.getEAllStructuralFeatures()).thenReturn(ECollections.unmodifiableEList(features));
when(eClass.getEReferences()).thenReturn(references);
when(eClass.getEAllReferences()).thenReturn(references);
when(eClass.getEAttributes()).thenReturn(ECollections.emptyEList());
when(eClass.getEAllAttributes()).thenReturn(ECollections.emptyEList());
final EObject object = EcoreUtil.create(eClass);
final VView view = viewProvider.provideViewModel(object, viewProperties);
final Set<String> uuids = new HashSet<>();
controls(view).forEach(control -> {
final String uuid = control.getUuid();
assertThat("No UUID generated", uuid, notNullValue());
assertThat("Non-unique UUID: " + uuid, uuids.add(uuid));
});
assertThat("Didn't get a control for each occurrence of the feature", uuids.size(),
is(eClass.getEAllStructuralFeatures().size()));
}
/**
* Verify that the item provider is used to determine read-only state of controls.
*/
@Test
public void readOnlyControls() {
final EReference ref = EcoreFactory.eINSTANCE.createEReference();
ref.setEType(refType);
ref.setName("ref");
eClass.getEStructuralFeatures().add(ref);
final Map<Resource, Boolean> readOnly = new HashMap<>();
final EditingDomain domain = new AdapterFactoryEditingDomain(mock(AdapterFactory.class),
new BasicCommandStack(), readOnly);
final ResourceSet rset = domain.getResourceSet();
final Resource resource = new ResourceImpl(URI.createURI("test:/resource"));
final EObject object = EcoreUtil.create(eClass);
resource.getContents().add(object);
rset.getResources().add(resource);
readOnly.put(resource, true);
final VView view = viewProvider.provideViewModel(object, viewProperties);
final int[] count = { 0 };
controls(view)
.peek(__ -> count[0]++)
.forEach(control -> assertThat("Control not read-only", control.isEffectivelyReadonly(), is(true)));
assertThat("No controls found", count[0], not(0));
}
private void assertView(final VView view) {
assertNotNull(view);
assertNotNull(view.getUuid());
assertFalse(view.getUuid().isEmpty());
assertEquals(1, view.getChildren().size());
}
private Stream<VControl> controls(VElement viewModel) {
return StreamSupport
.stream(Spliterators.spliteratorUnknownSize(EcoreUtil.getAllContents(Collections.singleton(viewModel)),
Spliterator.DISTINCT | Spliterator.NONNULL | Spliterator.ORDERED), false)
.filter(VControl.class::isInstance).map(VControl.class::cast);
}
}