Skip to content

Content of file EMFFormsRevealServiceImpl_ITest.java

/*******************************************************************************
 * Copyright (c) 2019 Christian W. Damus 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:
 * Christian W. Damus - initial API and implementation
 ******************************************************************************/
package org.eclipse.emfforms.internal.core.services.reveal;

import static org.eclipse.emf.ecp.view.test.common.spi.EMFFormsRevealServiceFixture.isA;
import static org.eclipse.emf.ecp.view.test.common.spi.EMFFormsRevealServiceFixture.isListOf;
import static org.eclipse.emf.ecp.view.test.common.spi.EMFFormsRevealServiceFixture.pass;
import static org.eclipse.emf.ecp.view.test.common.spi.EMFMocking.eMock;
import static org.hamcrest.CoreMatchers.both;
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.hamcrest.CoreMatchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecp.view.spi.model.VControl;
import org.eclipse.emf.ecp.view.spi.model.VElement;
import org.eclipse.emf.ecp.view.test.common.spi.EMFFormsRevealServiceFixture;
import org.eclipse.emf.ecp.view.test.common.spi.EMFFormsRevealServiceFixture.TestProvider;
import org.eclipse.emf.ecp.view.test.common.spi.EMFFormsViewContextFixture.DomainModel;
import org.eclipse.emf.ecp.view.test.common.spi.EMFFormsViewContextFixture.ViewModel;
import org.eclipse.emf.ecp.view.test.common.spi.EMFMockingRunner;
import org.eclipse.emf.ecp.view.test.common.spi.EMock;
import org.eclipse.emfforms.bazaar.Bid;
import org.eclipse.emfforms.bazaar.Create;
import org.eclipse.emfforms.spi.core.services.reveal.DrillDown;
import org.eclipse.emfforms.spi.core.services.reveal.DrillUp;
import org.eclipse.emfforms.spi.core.services.reveal.EMFFormsRevealProvider;
import org.eclipse.emfforms.spi.core.services.reveal.Reveal;
import org.eclipse.emfforms.spi.core.services.reveal.RevealHelper;
import org.eclipse.emfforms.spi.core.services.reveal.RevealStep;
import org.eclipse.emfforms.spi.core.services.reveal.RevealStepKind;
import org.eclipse.emfforms.spi.core.services.view.EMFFormsViewContext;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;

/**
 * Integration tests covering the {@link EMFFormsRevealServiceImpl} class.
 */
@SuppressWarnings("nls")
@RunWith(EMFMockingRunner.class)
public class EMFFormsRevealServiceImpl_ITest {

	@EMock
	@ViewModel
	private VControl control;

	@EMock
	@DomainModel
	private EObject domainModelRoot;

	@EMock
	private EObject object;

	@Rule
	public final EMFFormsRevealServiceFixture<EMFFormsViewContext> fixture = EMFFormsRevealServiceFixture.create(this);

	/**
	 * Initializes me.
	 */
	public EMFFormsRevealServiceImpl_ITest() {
		super();
	}

	@Test
	public void reveal_noProviders() {
		assertThat("Should have failed to reveal", fixture.reveal(object), is(false));
		assertThat("Shoudl be a failure step", fixture.reveal(object, control), isA(RevealStepKind.FAILED));
	}

	@SuppressWarnings("unchecked")
	@Test
	public void provider_injection() {
		final List<Object> injectedIntoBid = new ArrayList<>(2);
		final List<Object> injectedIntoCreate = new ArrayList<>(3);

		final EMFFormsRevealProvider provider = new EMFFormsRevealProvider() {
			@Bid
			double bid(VElement viewModel, EObject domainModel) {
				injectedIntoBid.add(viewModel);
				injectedIntoBid.add(domainModel);
				return 1.0;
			}

			@Create
			RevealStep create(VElement viewModel, EObject domainModel, RevealHelper helper) {
				injectedIntoCreate.add(viewModel);
				injectedIntoCreate.add(domainModel);
				injectedIntoCreate.add(helper);
				return RevealStep.reveal(viewModel, domainModel, pass());
			}
		};

		fixture.addRevealProvider(provider);
		fixture.reveal(object);

		assertThat(injectedIntoBid, isListOf(control, object));
		assertThat(injectedIntoCreate,
			hasItems(sameInstance(control), sameInstance(object), instanceOf(RevealHelperImpl.class)));
	}

	@Test
	public void terminalStep() {
		final Runnable reveal = mock(Runnable.class, "reveal");

		final EMFFormsRevealProvider provider = new TestProvider() {
			@Create
			RevealStep create(VElement viewModel, EObject domainModel) {
				return RevealStep.reveal(viewModel, domainModel, reveal);
			}
		};

		fixture.addRevealProvider(provider);

		final boolean revealed = fixture.reveal(object);

		assertThat("Not revealed", revealed, is(true));
		verify(reveal).run();
	}

	@Test
	public void helper_defer() {
		final Runnable reveal = mock(Runnable.class, "reveal");

		final Object revealer = new Object() {
			@Reveal
			public RevealStep reveal(VElement viewModel, EObject domainModel) {
				return RevealStep.reveal(viewModel, domainModel, reveal);
			}
		};

		final EMFFormsRevealProvider provider = new TestProvider() {
			@Create
			RevealStep create(VElement viewModel, EObject domainModel, RevealHelper helper) {
				return helper.defer(revealer);
			}
		};

		fixture.addRevealProvider(provider);

		final RevealStep deferredStep = fixture.reveal(object, control);

		// It's deferred; that's the point
		verify(reveal, never()).run();

		assertThat(deferredStep, isA(RevealStepKind.TERMINAL));
		assertThat(deferredStep.getViewModel(), is(control));
		assertThat(deferredStep.getDomainModel(), is(object));

		deferredStep.reveal();

		verify(reveal).run();
	}

	@Test
	public void helper_drillDown_internal() {
		final Runnable outerReveal = mock(Runnable.class, "outerReveal");
		final Runnable innerReveal = mock(Runnable.class, "innerReveal");

		configureDrillDown(outerReveal, innerReveal);
		final RevealStep deferredStep = fixture.reveal(object, control);

		// They're deferred; that's the point
		verify(outerReveal, never()).run();
		verify(innerReveal, never()).run();

		assertThat(deferredStep, isA(RevealStepKind.INTERMEDIATE));
		assertThat(deferredStep.getViewModel(), is(control));
		assertThat(deferredStep.getDomainModel(), is(domainModelRoot));
		final RevealStep next = deferredStep.drillDown();

		assertThat(next, isA(RevealStepKind.TERMINAL));
		assertThat("Should have revealed in the child control", next.getViewModel(),
			both(not((VElement) control)).and(notNullValue()));
		next.reveal();

		final InOrder inOrder = inOrder(outerReveal, innerReveal);
		inOrder.verify(outerReveal).run();
		inOrder.verify(innerReveal).run();

		assertThat("Another computation performed", deferredStep.drillDown(), sameInstance(next));
	}

	private void configureDrillDown(Runnable outerReveal, Runnable innerReveal) {
		final List<VControl> children = Collections.singletonList(eMock(VControl.class, "childControl"));

		final Object computation = new Object() {
			@DrillDown
			public List<VControl> drillDown(EObject parent) {
				return children;
			}

			@Reveal
			public RevealStep reveal(VElement viewModel, EObject domainModel, RevealStep nextStep) {
				return RevealStep.reveal(nextStep.getViewModel(), domainModel, outerReveal);
			}
		};

		final EMFFormsRevealProvider provider = new TestProvider() {
			@Create
			RevealStep create(VElement viewModel, EObject domainModel, RevealHelper helper) {
				return viewModel == control
					? helper.drillDown(computation, computation)
					: RevealStep.reveal(viewModel, domainModel, innerReveal);
			}
		};

		fixture.addRevealProvider(provider);
	}

	@Test
	public void helper_drillDown_external() {
		final Runnable outerReveal = mock(Runnable.class, "outerReveal");
		final Runnable innerReveal = mock(Runnable.class, "innerReveal");

		configureDrillDown(outerReveal, innerReveal);
		fixture.reveal(object);

		final InOrder inOrder = inOrder(outerReveal, innerReveal);
		inOrder.verify(outerReveal).run();
		inOrder.verify(innerReveal).run();
	}

	@Test
	public void helper_masterDetail_internal() {
		final Runnable masterReveal = mock(Runnable.class, "masterReveal");
		final Runnable detailReveal = mock(Runnable.class, "detailReveal");
		final EObject detail = eMock(EObject.class, "detail");

		configureMasterDetail(detail, masterReveal, detailReveal);
		final RevealStep deferredStep = fixture.reveal(detail, control);

		// They're deferred; that's the point
		verify(masterReveal, never()).run();
		verify(detailReveal, never()).run();

		assertThat(deferredStep, isA(RevealStepKind.INTERMEDIATE));
		assertThat(deferredStep.getViewModel(), is(control));
// assertThat(deferredStep.getDomainModel(), is(object)); final RevealStep next = deferredStep.drillDown(); assertThat(next, isA(RevealStepKind.TERMINAL)); assertThat("Should have revealed in the detail control", next.getViewModel(), both(not((VElement) control)).and(notNullValue())); assertThat(deferredStep.getDomainModel(), is(detail)); next.reveal(); final InOrder inOrder = inOrder(masterReveal, detailReveal); inOrder.verify(masterReveal).run(); inOrder.verify(detailReveal).run(); assertThat("Another computation performed", deferredStep.drillDown(), sameInstance(next)); } private void configureMasterDetail(EObject detail, Runnable masterReveal, Runnable detailReveal) { final VControl detailView = eMock(VControl.class, "detailView"); final Object computation = new Object() { @DrillUp public EObject getMaster(EObject eObject) { return eObject == detail ? object : eObject; } @Reveal public RevealStep reveal(VElement viewModel, EObject domainModel) { return RevealStep.reveal(viewModel, domainModel, masterReveal); } }; final EMFFormsRevealProvider provider = new TestProvider() { @Create RevealStep create(VElement viewModel, EObject domainModel, RevealHelper helper) { return viewModel == control ? helper.masterDetail(computation, computation) : RevealStep.reveal(viewModel, domainModel, detailReveal); } }; // Supply the child context for the detail view of the master selection, // which is the 'object', the bespoke parent of the 'detail' object that // we are revealing fixture.createChildContext(control, "childContext", detailView, object); fixture.addRevealProvider(provider); } @Test public void helper_masterDetail_external() { final Runnable masterReveal = mock(Runnable.class, "masterReveal"); final Runnable detailReveal = mock(Runnable.class, "detailReveal"); final EObject detail = eMock(EObject.class, "detail"); configureMasterDetail(detail, masterReveal, detailReveal); fixture.reveal(detail); final InOrder inOrder = inOrder(masterReveal, detailReveal); inOrder.verify(masterReveal).run(); inOrder.verify(detailReveal).run(); } }