Skip to content

Content of file TemplateCreateNewModelElementStrategyProvider_Test.java

/*******************************************************************************
 * 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 - bugs 543461, 546974
 ******************************************************************************/
package org.eclipse.emfforms.internal.core.services.datatemplate;

import static org.hamcrest.CoreMatchers.anything;
import static org.hamcrest.CoreMatchers.both;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anySetOf;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.Collection;
import java.util.Hashtable;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.Predicate;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecp.common.spi.Labelizer;
import org.eclipse.emf.ecp.ui.view.swt.reference.CreateNewModelElementStrategy;
import org.eclipse.emf.ecp.ui.view.swt.reference.EClassSelectionStrategy;
import org.eclipse.emfforms.bazaar.Bid;
import org.eclipse.emfforms.bazaar.Create;
import org.eclipse.emfforms.bazaar.StaticBid;
import org.eclipse.emfforms.common.Optional;
import org.eclipse.emfforms.core.services.datatemplate.TemplateFilterService;
import org.eclipse.emfforms.core.services.datatemplate.TemplateProvider;
import org.eclipse.emfforms.core.services.datatemplate.test.model.audit.AdminUser;
import org.eclipse.emfforms.core.services.datatemplate.test.model.audit.AuditFactory;
import org.eclipse.emfforms.core.services.datatemplate.test.model.audit.AuditPackage;
import org.eclipse.emfforms.datatemplate.DataTemplateFactory;
import org.eclipse.emfforms.datatemplate.Template;
import org.hamcrest.CustomTypeSafeMatcher;
import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.osgi.service.component.ComponentContext;

/**
 * Test cases for the TemplateCreateNewModelElementStrategyProvider and its provided strategy.
 *
 * @author Lucas Koehler
 *
 */
public class TemplateCreateNewModelElementStrategyProvider_Test {

	private TemplateCreateNewModelElementStrategyProvider strategyProvider;

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		final ComponentContext context = mock(ComponentContext.class);
		when(context.getProperties()).thenReturn(new Hashtable<>());

		strategyProvider = new TemplateCreateNewModelElementStrategyProvider();
		strategyProvider.activate(context);
	}

	@Test
	public void testHandles_availableTemplates() {
		final TemplateProvider canProvide = mock(TemplateProvider.class);
		when(canProvide.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(true);

		final TemplateProvider cannotProvide = mock(TemplateProvider.class);
		when(cannotProvide.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(false);
		strategyProvider.registerTemplateProvider(canProvide);
		strategyProvider.registerTemplateProvider(cannotProvide);

		final EObject eObject = mock(EObject.class);
		final EReference eReference = mock(EReference.class);
		assertTrue(strategyProvider.handles(eObject, eReference));
		final InOrder inOrder = Mockito.inOrder(canProvide, cannotProvide);
		inOrder.verify(canProvide, Mockito.times(1)).canProvideTemplates(any(EObject.class), any(EReference.class));
		inOrder.verify(cannotProvide, Mockito.never()).canProvideTemplates(any(EObject.class), any(EReference.class));
	}

	@Test
	public void testHandles_noAvailableTemplates() {
		final TemplateProvider cannotProvide = mock(TemplateProvider.class);
		when(cannotProvide.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(false);
		strategyProvider.registerTemplateProvider(cannotProvide);

		final EObject eObject = mock(EObject.class);
		final EReference eReference = mock(EReference.class);
		assertFalse(strategyProvider.handles(eObject, eReference));
	}

	@Test
	public void testCollectAvailableTemplates() {
		final TemplateProvider canProvide = mock(TemplateProvider.class);
		when(canProvide.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(true);
		final LinkedHashSet<Template> canProvideTemplates = new LinkedHashSet<Template>(2);
		final Template template = mock(Template.class);
		canProvideTemplates.add(template);
		when(canProvide.provideTemplates(any(EObject.class), any(EReference.class))).thenReturn(canProvideTemplates);

		final TemplateProvider cannotProvide = mock(TemplateProvider.class);
		when(cannotProvide.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(false);
		strategyProvider.registerTemplateProvider(canProvide);
		strategyProvider.registerTemplateProvider(cannotProvide);

		final EObject eObject = mock(EObject.class);
		final EReference eReference = mock(EReference.class);
		final Set<Template> templates = strategyProvider.collectAvailableTemplates(eObject, eReference);

		assertEquals(1, templates.size());
		assertTrue(templates.contains(template));

		final InOrder canProvideOrder = inOrder(canProvide);
		canProvideOrder.verify(canProvide).canProvideTemplates(same(eObject), same(eReference));
		canProvideOrder.verify(canProvide).provideTemplates(same(eObject), same(eReference));
		verify(cannotProvide).canProvideTemplates(same(eObject), same(eReference));
		verify(cannotProvide, times(0)).provideTemplates(same(eObject), same(eReference));
	}

	/**
	 * Test creation of the strategy and its implementation of consistency of classes
	 * presented to the user with available templates.
	 *
	 * @see <a href="http://eclip.se/543461">bug 543461</a>
	 */
	@Test
	public void testCreateNewModelElementStrategy() {
		final TemplateProvider provider = mock(TemplateProvider.class);
		when(provider.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(true);

		final LinkedHashSet<Template> templates = new LinkedHashSet<Template>();
		final EDataType datatype = EcoreFactory.eINSTANCE.createEDataType();
		datatype.setName("Date"); //$NON-NLS-1$
		final Template dtTemplate = DataTemplateFactory.eINSTANCE.createTemplate();
		dtTemplate.setInstance(datatype);
		dtTemplate.setName("Example DataType"); //$NON-NLS-1$
		templates.add(dtTemplate);
		final EEnum enum_ = EcoreFactory.eINSTANCE.createEEnum();
		enum_.setName("YesNo"); //$NON-NLS-1$
		final Template enTemplate = DataTemplateFactory.eINSTANCE.createTemplate();
		enTemplate.setInstance(enum_);
		enTemplate.setName("Example Enum"); //$NON-NLS-1$
		templates.add(enTemplate);
		when(provider.provideTemplates(any(EObject.class), any(EReference.class))).thenReturn(templates);
		strategyProvider.registerTemplateProvider(provider);

		final ComponentContext componentContext = mock(ComponentContext.class);
		when(componentContext.getProperties()).thenReturn(new Hashtable<String, Object>());

		strategyProvider.activate(componentContext);

		final CreateNewModelElementStrategy strategy = strategyProvider.createCreateNewModelElementStrategy();
		assertThat(strategy, instanceOf(TemplateCreateNewModelElementStrategyProvider.Strategy.class));

		// Spy on the implementation to verify internals
		final TemplateCreateNewModelElementStrategyProvider.Strategy spy = spy(
			(TemplateCreateNewModelElementStrategyProvider.Strategy) strategy);

		// Mustn't actually try to show a wizard dialog
		doReturn(Optional.of(dtTemplate)).when(spy)
			.showSelectModelInstancesDialog(anySetOf(EClass.class), anySetOf(Template.class));

		final Optional<EObject> created = spy.createNewModelElement(AuditPackage.eINSTANCE,
			EcorePackage.Literals.EPACKAGE__ECLASSIFIERS);
		assertThat("Nothing created", created.isPresent(), is(true)); //$NON-NLS-1$
		assertThat("Wrong thing created", created.get(), eEqualTo(datatype)); //$NON-NLS-1$

		// Verify invocation of the wizard, that it didn't offer classes for which there
		// weren't any templates
		final Set<EClass> subClasses = new LinkedHashSet<>();
		subClasses.add(EcorePackage.Literals.EDATA_TYPE);
		subClasses.add(EcorePackage.Literals.EENUM);
		// not EcorePackage.Literals.ECLASS
		Mockito.verify(spy).showSelectModelInstancesDialog(subClasses, templates);
	}

	@Test
	public void testStrategy() {
		final ComponentContext componentContext = mock(ComponentContext.class);
		when(componentContext.getProperties()).thenReturn(new Hashtable<String, Object>());
		strategyProvider.activate(componentContext);

		final TemplateProvider canProvide = mock(TemplateProvider.class);
		when(canProvide.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(true);
		final LinkedHashSet<Template> canProvideTemplates = new LinkedHashSet<Template>(2);
		final Template template = DataTemplateFactory.eINSTANCE.createTemplate();
		final AdminUser adminUser = AuditFactory.eINSTANCE.createAdminUser();
		adminUser.setDisplayName("Test"); //$NON-NLS-1$
		template.setInstance(adminUser);
		canProvideTemplates.add(template);
		when(canProvide.provideTemplates(any(EObject.class), any(EReference.class))).thenReturn(canProvideTemplates);
		strategyProvider.registerTemplateProvider(canProvide);

		final EClassSelectionStrategy selectionStrategy = mock(EClassSelectionStrategy.class);
		when(selectionStrategy.collectEClasses(any(EObject.class), any(EReference.class),
			Matchers.<Collection<EClass>> any())).then(new Answer<Collection<EClass>>() {

				@SuppressWarnings("unchecked")
				@Override
				public Collection<EClass> answer(InvocationOnMock invocation) throws Throwable {
					return (Collection<EClass>) invocation.getArguments()[2];
				}

			});
		strategyProvider
			.addEClassSelectionStrategyProvider(new TestEClassSelectionStrategyProvider(1d, selectionStrategy));

		final CreateNewModelElementStrategy strategy = strategyProvider.createCreateNewModelElementStrategy();

		final EObject owner = AuditFactory.eINSTANCE.createUserGroup();
		final EReference reference = AuditPackage.Literals.USER_GROUP__ADMINS;
		final Optional<EObject> resultOptional = strategy.createNewModelElement(owner, reference);

		assertTrue(resultOptional.isPresent());
		assertTrue(resultOptional.get() instanceof AdminUser);
		final AdminUser createdElement = (AdminUser) resultOptional.get();
		assertEquals(adminUser.getDisplayName(), createdElement.getDisplayName());

		verify(selectionStrategy).collectEClasses(same(owner), same(reference), Matchers.<Collection<EClass>> any());
	}

	@Test
	public void testStrategyNoAvailableTemplate() {
		final ComponentContext componentContext = mock(ComponentContext.class);
		when(componentContext.getProperties()).thenReturn(new Hashtable<String, Object>());
		strategyProvider.activate(componentContext);

		final TemplateProvider canProvide = mock(TemplateProvider.class);
		when(canProvide.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(false);
		strategyProvider.registerTemplateProvider(canProvide);

		final EClassSelectionStrategy selectionStrategy = mock(EClassSelectionStrategy.class);
		strategyProvider
			.addEClassSelectionStrategyProvider(new TestEClassSelectionStrategyProvider(1d, selectionStrategy));

		final CreateNewModelElementStrategy strategy = strategyProvider.createCreateNewModelElementStrategy();

		final EObject owner = mock(EObject.class);
		final EReference reference = mock(EReference.class);
		final Optional<EObject> resultOptional = strategy.createNewModelElement(owner, reference);

		assertNotNull(resultOptional);
		assertFalse(resultOptional.isPresent());

		verify(selectionStrategy, times(0)).collectEClasses(any(EObject.class), any(EReference.class),
			Matchers.<Collection<EClass>> any());
	}

	@SuppressWarnings("nls")
	@Test
	public void testTemplateFilters() {
		final TemplateProvider canProvide = mock(TemplateProvider.class);
		when(canProvide.canProvideTemplates(any(EObject.class), any(EReference.class))).thenReturn(true);
		final Template template1 = mock(Template.class);
		when(template1.getName()).thenReturn("First Template");
		final Template template2 = mock(Template.class);
		when(template2.getName()).thenReturn("Second Template");
		final Template template3 = mock(Template.class);
		when(template3.getName()).thenReturn("Third Template");
		final Set<Template> canProvideTemplates = new LinkedHashSet<>(Arrays.asList(template1, template2, template3));
		when(canProvide.provideTemplates(any(EObject.class), any(EReference.class))).thenReturn(canProvideTemplates);
		strategyProvider.registerTemplateProvider(canProvide);

		final RegexFilterService.Provider filter1 = new RegexFilterService.Provider("^Template$");
		final RegexFilterService.Provider filter2 = new RegexFilterService.Provider("^\\w{5} .+$");
		strategyProvider.addFilterServiceProvider(filter1);
		strategyProvider.addFilterServiceProvider(filter2);

		final EObject eObject = mock(EObject.class);
		final EReference eReference = mock(EReference.class);
		Set<Template> templates = strategyProvider.collectAvailableTemplates(eObject, eReference);

		assertThat("Filters should have excluded everything", templates, not(hasItem(anything())));

		filter1.setRegex("^.+ Template$");
		templates = strategyProvider.collectAvailableTemplates(eObject, eReference);
		assertThat("Filters should have excluded only Second Template", templates,
			both(hasItems(template1, template3)).and(not(hasItem(template2))));

		strategyProvider.removeFilterServiceProvider(filter2);
		templates = strategyProvider.collectAvailableTemplates(eObject, eReference);
		assertThat("Filters should have excluded no templates", templates, hasItems(template1, template2, template3));
	}

	//
	// Test framework
	//

	static class RegexFilterService implements TemplateFilterService {
		private String regex;

		@Override
		public Predicate<? super Template> getTemplateFilter(EObject owner, EReference reference) {
			assertThat(owner, notNullValue());
			assertThat(reference, notNullValue());
return template -> // template.getName().matches(regex); } // // Nested types // @StaticBid(bid = 10.0) static final class Provider implements TemplateFilterService.Provider { private final RegexFilterService service = new RegexFilterService(); Provider(String regex) { super(); setRegex(regex); } void setRegex(String regex) { service.regex = regex; } @Create public TemplateFilterService create() { return service; } } } class TestEClassSelectionStrategyProvider implements EClassSelectionStrategy.Provider { private final Double bid; private final EClassSelectionStrategy strategy; TestEClassSelectionStrategyProvider(Double bid, EClassSelectionStrategy strategy) { super(); this.bid = bid; this.strategy = strategy; } @Bid public Double bid() { return bid; } @Create public EClassSelectionStrategy create() { return strategy; } } Matcher<EObject> eEqualTo(EObject other) { return new CustomTypeSafeMatcher<EObject>("structurally equal to " + Labelizer.get(other).getLabel(other)) { //$NON-NLS-1$ @Override protected boolean matchesSafely(EObject item) { return EcoreUtil.equals(item, other); } }; } }