blob: 3c0e06379deaba22d02b6522e50dbe86823db4ae [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2018 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* SAP AG - initial API and implementation
******************************************************************************/
package org.eclipse.ocl.examples.impactanalyzer.tests.derivedPropertyHandling;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.ocl.examples.eventmanager.EventManager;
import org.eclipse.ocl.examples.eventmanager.EventManagerFactory;
import org.eclipse.ocl.examples.impactanalyzer.DerivedPropertyNotifier;
import org.eclipse.ocl.examples.impactanalyzer.ImpactAnalyzerFactory;
import org.eclipse.ocl.examples.impactanalyzer.impl.DerivedPropertyNotifierImpl;
import org.eclipse.ocl.examples.impactanalyzer.testutils.BaseDepartmentTestWithOCL;
import org.eclipse.ocl.examples.impactanalyzer.util.OCLFactory;
import org.junit.Test;
import company.Employee;
/**
* This test will check, if the {@link DerivedPropertyNotifierImpl} works correctly.
*
* @author Martin Hanysz
*
*/
public class DerivedPropertyAdapterTest extends BaseDepartmentTestWithOCL {
protected EventManager eventManager;
@Override
public void setUp() {
super.setUp();
this.createInstances(2, 5, 3);
this.eventManager = EventManagerFactory.eINSTANCE.createEventManagerFor(rs);
}
@Override
public void tearDown() {
super.tearDown();
this.eventManager = null;
}
// Register an adapter at any derived feature we want to test and let it fetch the first notification it gets.
// Afterwards simply make a change that will affect this derived feature and see if the correct notification comes along.
/**
* Creates a new Company instance, expecting an event to be thrown for the derived
* <code>name</code> property by the {@link EventManager} but not by the element itself.
*/
@Test
public void testNewContextElementCausesNoNotificationOnElement() {
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(
comp, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
EObject newCompany = comp.getEFactoryInstance().create(companyClass);
NotificationCatchAdapter notificationCatcher1 = new NotificationCatchAdapter();
newCompany.eAdapters().add(notificationCatcher1);
NotificationCatchAdapter notificationCatcher2 = new NotificationCatchAdapter();
EventManager em = EventManagerFactory.eINSTANCE.getEventManagerFor(comp.eResource().getResourceSet());
em.subscribe(EventManagerFactory.eINSTANCE.createStructuralFeatureFilter(companyClass.getEStructuralFeature("name")),
notificationCatcher2);
// add newCompany to resource, triggering ADD event and hence the onNewContextNotification
// for derived property "name"
this.aCompany.eResource().getContents().add(newCompany);
Notification notification1 = notificationCatcher1.getCaughtNotification();
assertNull(notification1);
Notification notification2 = notificationCatcher2.getCaughtNotification();
assertNotNull(notification2);
assertEquals(companyClass.getEStructuralFeature("name"), notification2.getFeature());
assertNull(notification2.getOldStringValue());
assertNotNull(notification2.getNewStringValue());
}
@Test
public void testNonDerivedFeature() {
Exception exception = null;
try {
ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.employeeName, OCLFactory.getInstance());
}
catch(IllegalArgumentException e){
exception = e;
}
// We assert to get an IllegalArgumentException if we pass a non derived property to the DerivedPropertyAdapter.
assertNotNull(exception);
}
@Test
public void testTouch() {
// add a director to touch it by setting it again to the same value
this.aDivision.setDirector(this.aEmployee);
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.divisionDirector, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
NotificationCatchAdapter notificationCatcher = new NotificationCatchAdapter();
this.aCompany.eAdapters().add(notificationCatcher);
// Touch director of aDivision. That will not change the divisionDirector property of aCompany.
this.aDivision.setDirector(this.aEmployee);
// The DerivedPropertyAdapter will simply exit on receiving a touch notification.
Notification notification = notificationCatcher.getCaughtNotification();
// We assert to receive no notification at all because the derivedProperty didn't change and can't be touched because it's unchangeable.
assertNull(notification);
}
@Test
public void testSingleValuedFeatureSet() {
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.numberEmployeesOfTheMonth, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
NotificationCatchAdapter notificationCatcher = new NotificationCatchAdapter();
this.aDivision.eAdapters().add(notificationCatcher);
// Add an employee of the month to aDepartment. That will change the numberEmployeesOfTheMonth property of aDepartments division.
this.aDepartment.getEmployeeOfTheMonth().add(this.aEmployee);
// The DerivedPropertyAdapter will cause aDivision to send a change notification for it's derived property numberEmployeesOfTheMonth.
Notification notification = notificationCatcher.getCaughtNotification();
// We assert to receive a SET of aDivision.numberEmployeesOfTheMonth to 1.
assertNotNull(notification);
assertEquals(this.numberEmployeesOfTheMonth, notification.getFeature());
assertEquals(this.aDivision, notification.getNotifier());
assertTrue(notification.getEventType() == Notification.SET);
assertEquals(Integer.valueOf(1), notification.getNewValue());
}
@Test
public void testUnsettableSingleValuedFeatureSet() {
// unset the feature to set it later on
this.aDivision.unsetDirector();
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.divisionDirector, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
NotificationCatchAdapter notificationCatcher = new NotificationCatchAdapter();
this.aCompany.eAdapters().add(notificationCatcher);
// Set director of aDivision. That will change the divisionDirector property of aCompany.
this.aDivision.setDirector(this.aEmployee);
// The DerivedPropertyAdapter will cause aCompany to send a change notification for it's derived property divisionDirector.
Notification notification = notificationCatcher.getCaughtNotification();
// We assert to receive a SET of aCompany.divisionDirector to aEmployee.
assertNotNull(notification);
assertEquals(this.divisionDirector, notification.getFeature());
assertEquals(this.aCompany, notification.getNotifier());
assertTrue(notification.getEventType() == Notification.SET);
assertEquals(this.aEmployee, notification.getNewValue());
}
@Test
public void testUnsettableSingleValuedFeatureUnset() {
// add a director to unset
this.aDivision.setDirector(this.aEmployee);
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.divisionDirector, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
NotificationCatchAdapter notificationCatcher = new NotificationCatchAdapter();
this.aCompany.eAdapters().add(notificationCatcher);
// Unset director of aDivision. That will change the divisionDirector property of aCompany.
this.aDivision.unsetDirector();
// The DerivedPropertyAdapter will cause aCompany to send a change notification for it's derived property divisionDirector.
Notification notification = notificationCatcher.getCaughtNotification();
// We assert to receive a UNSET of aCompany.divisionDirector to null.
assertNotNull(notification);
assertEquals(this.divisionDirector, notification.getFeature());
assertEquals(this.aCompany, notification.getNotifier());
assertTrue(notification.getEventType() == Notification.UNSET);
assertEquals(null, notification.getNewValue());
}
@Test
public void testMultiValuedFeatureAddOne() {
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.divisionEmployeesOfTheMonth, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
NotificationCatchAdapter notificationCatcher = new NotificationCatchAdapter();
this.aDivision.eAdapters().add(notificationCatcher);
// Add an employee of the month to aDepartment. That will change the employeesOfTheMonth property of aDivision.
this.aDepartment.getEmployeeOfTheMonth().add(this.aEmployee);
// The DerivedPropertyAdapter will cause aDivision to send a change notification for it's derived property employeesOfTheMonth.
Notification notification = notificationCatcher.getCaughtNotification();
// We assert to receive a ADD of aDivision.employeesOfTheMonth to a collection containing aEmployee only.
assertNotNull(notification);
assertEquals(this.divisionEmployeesOfTheMonth, notification.getFeature());
assertEquals(this.aDivision, notification.getNotifier());
assertTrue(notification.getEventType() == Notification.ADD);
assertTrue(((List<?>)notification.getNewValue()).size() == 1);
assertTrue(((List<?>)notification.getNewValue()).contains(aEmployee));
}
@Test
public void testMultiValuedFeatureAddMany() {
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.divisionEmployeesOfTheMonth, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
NotificationCatchAdapter notificationCatcher = new NotificationCatchAdapter();
this.aDivision.eAdapters().add(notificationCatcher);
// Add two employees of the month to aDepartment. That will change the employeesOfTheMonth property of aDivision.
Collection<Employee> employeesToAdd = new ArrayList<Employee>();
employeesToAdd.add(this.aEmployee);
employeesToAdd.add(this.createEmployee());
this.aDepartment.getEmployeeOfTheMonth().addAll(employeesToAdd);
// The DerivedPropertyAdapter will cause aDivision to send a change notification for it's derived property employeesOfTheMonth.
Notification notification = notificationCatcher.getCaughtNotification();
// We assert to receive a ADD_MANY of aDivision.employeesOfTheMonth to a collection containing both employeesToAdd.
assertNotNull(notification);
assertEquals(this.divisionEmployeesOfTheMonth, notification.getFeature());
assertEquals(this.aDivision, notification.getNotifier());
assertTrue(notification.getEventType() == Notification.ADD_MANY);
assertTrue(((List<?>)notification.getNewValue()).size() == 2);
assertTrue(((List<?>)notification.getNewValue()).containsAll(employeesToAdd));
}
@Test
public void testMultiValuedFeatureRemoveOne() {
// set an employee to remove
this.aDepartment.getEmployeeOfTheMonth().add(this.aEmployee);
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.divisionEmployeesOfTheMonth, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
NotificationCatchAdapter notificationCatcher = new NotificationCatchAdapter();
this.aDivision.eAdapters().add(notificationCatcher);
// Remove an employee of the month of aDepartment. That will change the employeesOfTheMonth property of aDivision.
this.aDepartment.getEmployeeOfTheMonth().remove(this.aEmployee);
// The DerivedPropertyAdapter will cause aDivision to send a change notification for it's derived property employeesOfTheMonth.
Notification notification = notificationCatcher.getCaughtNotification();
// We assert to receive a REMOVE of aDivision.employeesOfTheMonth to an empty collection.
assertNotNull(notification);
assertEquals(this.divisionEmployeesOfTheMonth, notification.getFeature());
assertEquals(this.aDivision, notification.getNotifier());
assertTrue(notification.getEventType() == Notification.REMOVE);
assertTrue(((List<?>)notification.getNewValue()).size() == 0);
}
@Test
public void testMultiValuedFeatureRemoveMany() {
// set two employee to remove
Collection<Employee> employeesToRemove = new ArrayList<Employee>();
employeesToRemove.add(this.aEmployee);
employeesToRemove.add(this.createEmployee());
this.aDepartment.getEmployeeOfTheMonth().addAll(employeesToRemove);
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.divisionEmployeesOfTheMonth, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
NotificationCatchAdapter notificationCatcher = new NotificationCatchAdapter();
this.aDivision.eAdapters().add(notificationCatcher);
// Remove both employees of the month of aDepartment. That will change the employeesOfTheMonth property of aDivision.
this.aDepartment.getEmployeeOfTheMonth().removeAll(employeesToRemove);
// The DerivedPropertyAdapter will cause aDivision to send a change notification for it's derived property employeesOfTheMonth.
Notification notification = notificationCatcher.getCaughtNotification();
// We assert to receive a REMOVE_MANY of aDivision.employeesOfTheMonth to an empty collection.
assertNotNull(notification);
assertEquals(this.divisionEmployeesOfTheMonth, notification.getFeature());
assertEquals(this.aDivision, notification.getNotifier());
assertTrue(notification.getEventType() == Notification.REMOVE_MANY);
assertTrue(((List<?>)notification.getNewValue()).size() == 0);
}
@Test
public void testMultiValuedFeatureMove() {
// This test currently fails because the IA calculates there is no impact when changing the order of an ordered feature.
// TODO: clarify if this is wanted behavior and if so, edit the DerivedPropertyAdapter accordingly
// set two employee to shuffle around (Division.employeesOfTheMonth is actually ordered, which was not of interest in the previous tests)
List<Employee> employeesToShuffle = new ArrayList<Employee>();
employeesToShuffle.add(this.aEmployee);
employeesToShuffle.add(this.createEmployee());
this.aDepartment.getEmployeeOfTheMonth().addAll(employeesToShuffle);
DerivedPropertyNotifier derivedPropertyNotifier = ImpactAnalyzerFactory.INSTANCE.createDerivedPropertyNotifier(this.divisionEmployeesOfTheMonth, OCLFactory.getInstance());
derivedPropertyNotifier.subscribe(EventManagerFactory.eINSTANCE.getEventManagerFor(this.aCompany.eResource().getResourceSet()));
NotificationCatchAdapter notificationCatcher = new NotificationCatchAdapter();
this.aDivision.eAdapters().add(notificationCatcher);
// Move the first employee of the month of aDepartment. That will change the employeesOfTheMonth property of aDivision.
this.aDepartment.getEmployeeOfTheMonth().move(1, this.aEmployee);
// The DerivedPropertyAdapter will cause aDivision to send a change notification for it's derived property employeesOfTheMonth.
Notification notification = notificationCatcher.getCaughtNotification();
// We assert to receive a MOVE of aDivision.employeesOfTheMonth to a collection where aEmployee is the last entry.
assertNotNull(notification);
assertEquals(this.divisionEmployeesOfTheMonth, notification.getFeature());
assertEquals(this.aDivision, notification.getNotifier());
assertTrue(notification.getEventType() == Notification.MOVE);
assertTrue(((List<?>)notification.getNewValue()).size() == 2);
assertEquals(employeesToShuffle.get(1),((List<?>)notification.getNewValue()).get(0));
assertEquals(this.aEmployee,((List<?>)notification.getNewValue()).get(1));
}
/**
* A dummy {@link Adapter} that simply catches the first {@link Notification} it receives.
*
* @author Martin Hanysz
*
*/
private class NotificationCatchAdapter implements Adapter{
private Notification caughtNotification = null;
private Notifier target = null;
public Notification getCaughtNotification() {
return caughtNotification;
}
public void notifyChanged(Notification notification) {
if(caughtNotification == null)
caughtNotification = notification;
}
public Notifier getTarget() {
return target;
}
public void setTarget(Notifier newTarget) {
target = newTarget;
}
public boolean isAdapterForType(Object type) {
return type == DerivedPropertyNotifierImpl.class;
}
}
}