blob: f7c5bf139261644df73e287ee48fa1310ac65309 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 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.instanceScope;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.ocl.ecore.ExpressionInOCL;
import org.eclipse.ocl.ecore.OCLExpression;
import org.eclipse.ocl.examples.impactanalyzer.ImpactAnalyzerFactory;
import org.eclipse.ocl.examples.impactanalyzer.benchmark.preparation.notifications.NotificationHelper;
import org.eclipse.ocl.examples.impactanalyzer.configuration.OptimizationActivation;
import org.eclipse.ocl.examples.impactanalyzer.testutils.BaseDepartmentTestWithOCL;
import org.eclipse.ocl.examples.impactanalyzer.util.OCLFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import company.Company;
import company.CompanyFactory;
import company.Department;
import company.Division;
import company.Employee;
import company.Freelance;
import company.Student;
import junit.framework.AssertionFailedError;
/**
* Tests whether the right context instances are computed. This is done as follows: A simple instance of the company model is
* created. Each test tests only one statement. The statement is analyzed and a set of relevant events is generated and reported
* to IA. The IA compute the affected context instances with the help of the InstanceScopeAnalysis. This set is then compared to a
* set of expected context instances.
*
*/
public class RevPathComputationTest extends BaseDepartmentTestWithOCL {
private Division div;
private Department dep1;
private Department dep2;
private Employee e1;
private Freelance e2;
private Employee e3;
private Freelance e4;
private Employee boss1;
private Employee boss2;
private Employee director;
private Employee secretary;
private Student stud1;
private Student stud2;
private Company company;
@Override
@Before
public void setUp() {
super.setUp();
createInstances();
}
@Override
@After
public void tearDown() {
EcoreUtil.delete(this.div);
EcoreUtil.delete(this.dep1);
EcoreUtil.delete(this.dep2);
EcoreUtil.delete(this.e1);
EcoreUtil.delete(this.e2);
EcoreUtil.delete(this.e3);
EcoreUtil.delete(this.e4);
EcoreUtil.delete(this.boss1);
EcoreUtil.delete(this.boss2);
EcoreUtil.delete(this.director);
EcoreUtil.delete(this.secretary);
EcoreUtil.delete(this.stud1);
EcoreUtil.delete(this.stud2);
super.tearDown();
}
@Test
public void testAnalysisOfASimpleRecursiveOperation() {
// construct something like "new HumbaClass1().m()"
final Department d1 = CompanyFactory.eINSTANCE.createDepartment();
d1.setName("d1");
d1.setBudget(10000);
final Department d2 = CompanyFactory.eINSTANCE.createDepartment();
d2.setName("d2");
d2.setBudget(10000);
final Department d3 = CompanyFactory.eINSTANCE.createDepartment();
d3.setName("d3");
d3.setBudget(10000);
final Department d4 = CompanyFactory.eINSTANCE.createDepartment();
d4.setName("d4");
d4.setBudget(10000);
d1.getSubDepartment().add(d2);
d2.getSubDepartment().add(d3);
d2.getSubDepartment().add(d4);
this.comp.eResource().getContents().add(d1);
Notification noti = NotificationHelper.createAttributeChangeNotification(d4, departmentBudget,
d4.getBudget(), d4.getBudget()+1000);
Collection<EObject> instances = computeAffectedInstances(this.getSumBudgetLimitAST(), noti);
compareInstances(instances, new EObject[] { d1, d2, d4 });
}
@Test
public void testBossHighestSalaryEmployeeSalaryChange() {
// context Department inv BossHighestSalary:
// self.employee->select(
// e|e.salary >= self.boss.salary)->size() <= 1
debugPrintln("Testing BossHighestSalaryEmployeeSalaryChange\n");
Notification noti;
// change salary of an employee
noti = NotificationHelper.createAttributeChangeNotification(this.e1, this.employeeSalary, this.e1.getSalary(),
this.e1.getSalary()+1);
Collection<EObject> instances = computeAffectedInstances(this.getBossHighestSalaryAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testBossHighestSalaryBossSalaryChange() {
// context Department inv BossHighestSalary:
// self.employee->select(
// e|e.salary >= self.boss.salary)->size() <= 1
debugPrintln("Testing BossHighestSalaryBossSalaryChange\n");
Notification noti;
Collection<EObject> instances;
// change salary of the boss
noti = NotificationHelper.createAttributeChangeNotification(this.boss1, this.employeeSalary, this.boss1
.getSalary(), this.boss1.getSalary()+1);
instances = computeAffectedInstances(this.getBossHighestSalaryAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testBossHighestSalaryAddEmployee() {
// context Department inv BossHighestSalary:
// self.employee->select(
// e|e.salary >= self.boss.salary)->size() <= 1
debugPrintln("Testing BossHighestSalaryAddEmployee\n");
Notification noti;
Collection<EObject> instances;
// add new employee
noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.employeeRef, CompanyFactory.eINSTANCE
.createEmployee());
instances = computeAffectedInstances(this.getBossHighestSalaryAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testBossHighestSalaryAddBoss() {
// context Department inv BossHighestSalary:
// self.employee->select(
// e|e.salary >= self.boss.salary)->size() <= 1
debugPrintln("Testing BossHighestSalaryAddBoss\n");
Notification noti;
Collection<EObject> instances;
// add new boss
noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.bossRef, this.boss2);
instances = computeAffectedInstances(this.getBossHighestSalaryAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testBossIsOldestEmployeeAgeChange() {
// context Employee inv BossIsOldest:
// self.age <= self.employer.boss.age
debugPrintln("Testing BossIsOldestEmployeeAgeChange\n");
Collection<EObject> instances;
Notification noti;
// change age of an employee
noti = NotificationHelper.createAttributeChangeNotification(this.e2, this.employeeAge, this.e2.getAge(),
this.e2.getAge()+1);
instances = computeAffectedInstances(this.getBossIsOldestAST(), noti);
compareInstances(instances, new EObject[] { this.e2 });
}
@Test
public void testBossIsOldestBossAgeChange() {
// context Employee inv BossIsOldest:
// self.age <= self.employer.boss.age
debugPrintln("Testing BossIsOldestBossAgeChange\n");
Collection<EObject> instances;
Notification noti;
// change age of the boss
noti = NotificationHelper.createAttributeChangeNotification(this.boss1, this.employeeAge, this.boss1.getAge(),
this.boss1.getAge()+1);
instances = computeAffectedInstances(this.getBossIsOldestAST(), noti);
compareInstances(instances, new EObject[] { this.e1, this.e2, this.boss1, this.stud1 });
}
@Test
public void testBossIsOldestAddEmployee() {
// context Employee inv BossIsOldest:
// self.age <= self.employer.boss.age
debugPrintln("Testing BossIsOldestAddEmployee\n");
Set<EObject> expectedInstances = new HashSet<EObject>();
expectedInstances.add(this.e2);
Collection<EObject> instances;
Notification noti;
// add new employee
noti = NotificationHelper.createReferenceAddNotification(this.e1, this.employerRef, this.dep2);
instances = computeAffectedInstances(this.getBossIsOldestAST(), noti);
compareInstances(instances, new EObject[] { this.e1 });
}
@Test
public void testBossIsOldestAddBoss() {
// context Employee inv BossIsOldest:
// self.age <= self.employer.boss.age
debugPrintln("Testing BossIsOldestAddBoss\n");
Set<EObject> expectedInstances = new HashSet<EObject>();
expectedInstances.add(this.e2);
Collection<EObject> instances;
Notification noti;
// add new boss
noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.bossRef, this.boss2);
instances = computeAffectedInstances(this.getBossIsOldestAST(), noti);
compareInstances(instances, new EObject[] { this.e1, this.e2, this.boss1, this.stud1 });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testNotBossFreelance() {
// context Department
// inv NotBossFreelance:
// not self.boss.oclIsTypeOf(Freelance)
debugPrintln("Testing NotBossFreelance\n");
Notification noti = null;
// add new boss
noti = NotificationHelper.createReferenceAddNotification(this.dep2, this.bossRef, this.boss1);
Collection<EObject> instances = computeAffectedInstances(this.getNotBossFreelanceAST(), noti);
compareInstances(instances, new EObject[] { this.dep2 });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testOldEmployeeEmployeeAgeChange() {
// context Department
// inv OldEmployee:
// self.employee->exists(e | e.age > 45)
debugPrintln("Testing OldEmployeeEmployeeAgeChange\n");
Notification noti;
Collection<EObject> instances;
// change age of an employee
noti = NotificationHelper.createAttributeChangeNotification(this.e2, this.employeeAge, this.e2.getAge(),
this.e2.getAge()+30);
instances = computeAffectedInstances(this.getOldEmployeeAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testOldEmployeeBossAgeChange() {
// context Department
// inv OldEmployee:
// self.employee->exists(e | e.age > 45)
debugPrintln("Testing OldEmployeeBossAgeChange\n");
Notification noti;
Collection<EObject> instances;
// change age of the boss
noti = NotificationHelper.createAttributeChangeNotification(this.boss1, this.employeeAge, this.boss1.getAge(),
this.boss1.getAge()+30);
instances = computeAffectedInstances(this.getOldEmployeeAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testOldEmployeeAddEmployee() {
// context Department
// inv OldEmployee:
// self.employee->exists(e | e.age > 45)
debugPrintln("Testing OldEmployeeAddEmployee\n");
Notification noti;
Collection<EObject> instances;
Employee newEmployee = CompanyFactory.eINSTANCE.createEmployee();
newEmployee.setAge(46);
// add new employee
noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.employeeRef, newEmployee);
instances = computeAffectedInstances(this.getOldEmployeeAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testUniqueNamesEmployeeNameChange() {
// context Employee
// inv UniqueNames:
// Employee.allInstances()->forAll(e |
// e <> self implies e.name <> self.name)
debugPrintln("Testing UniqueNamesEmployeeNameChange\n");
// change name of an employee
// this does not trigger the allInstances change handling
Notification noti = NotificationHelper.createAttributeChangeNotification(this.e2, this.employeeName, this.e2.getName(),
this.e2.getName()+"Humba");
Collection<EObject> instances = computeAffectedInstances(this.getUniqueNamesAST(), noti);
compareInstances(instances, new EObject[] { this.e1, this.e2, this.e3, this.e4, this.boss1, this.boss2, this.director,
this.secretary, this.stud1, this.stud2 });
}
@Test
public void testUniqueNamesEmployeeAdd() {
// context Employee
// inv UniqueNames:
// Employee.allInstances()->forAll(e |
// e <> self implies e.name <> self.name)
debugPrintln("Testing UniqueNamesEmployeeAdd\n");
// add a new employee
Employee newEmployee = CompanyFactory.eINSTANCE.createEmployee();
Notification noti = NotificationHelper.createElementAddNotification( rs.getResources().iterator().next(), null, newEmployee);
Collection<EObject> instances = computeAffectedInstances(this.getUniqueNamesAST(), noti);
compareInstances(instances, new EObject[] { this.e1, this.e2, this.e3, this.e4, this.boss1, this.boss2, this.director,
this.secretary, this.stud1, this.stud2, newEmployee });
// remove the added employee to prevent him from appearing in other test cases
EcoreUtil.delete(newEmployee);
}
@Test
public void testUniqueNamesEmployeeRemove() {
// context Employee
// inv UniqueNames:
// Employee.allInstances()->forAll(e |
// e <> self implies e.name <> self.name)
debugPrintln("Testing UniqueNamesEmployeeRemove\n");
// remove an employee
Notification noti = NotificationHelper.createElementDeleteNotification( this.e1 );
Collection<EObject> instances = computeAffectedInstances(this.getUniqueNamesAST(), noti);
compareInstances(instances, new EObject[] { this.e2, this.e3, this.e4, this.boss1, this.boss2, this.director,
this.secretary, this.stud1, this.stud2});
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testValidAssignment() {
// context Freelance
// inv ValidAssignment:
// self.assignment >= 5 and self.assignment <= 30
debugPrintln("Testing ValidAssignment\n");
// change age of an employee far enough
Notification noti = NotificationHelper.createAttributeChangeNotification(this.e4, this.freelanceAssignment,
this.e4.getAssignment(), 31);
Collection<EObject> instances = computeAffectedInstances(this.getValidAssignmentAST(), noti);
compareInstances(instances, new EObject[] { this.e4 });
// change age of an employee not far enough
Notification noti2 = NotificationHelper.createAttributeChangeNotification(this.e4, this.freelanceAssignment,
this.e4.getAssignment(), 29);
Collection<EObject> instances2 = computeAffectedInstances(this.getValidAssignmentAST(), noti2);
compareInstances(instances2, new EObject[] { });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testMaxJuniorsEmployeeAgeChange() {
// context Department inv MaxJuniors:
// self.employee->select(e|e.age < 25)->size() < self.maxJuniors
debugPrintln("Testing MaxJuniorsEmployeeAgeChange\n");
Notification noti;
Collection<EObject> instances;
// change age of an employee so that it now falls under 25
noti = NotificationHelper.createAttributeChangeNotification(this.e2, this.employeeAge, this.e2.getAge(),
23);
instances = computeAffectedInstances(this.getMaxJuniorsAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
// change age of an employee so that it does not fall under 25
noti = NotificationHelper.createAttributeChangeNotification(this.e2, this.employeeAge, this.e2.getAge(),
this.e2.getAge()+1);
instances = computeAffectedInstances(this.getMaxJuniorsAST(), noti);
compareInstances(instances, new EObject[] { });
}
@Test
public void testMaxJuniorsDepartmentMaxJuniorsChange() {
// context Department inv MaxJuniors:
// self.employee->select(e|e.age < 25)->size() < self.maxJuniors
debugPrintln("Testing MaxJuniorsDepartmentMaxJuniorsChange\n");
Notification noti;
Collection<EObject> instances;
// change maxJuniors of a Department
noti = NotificationHelper.createAttributeChangeNotification(this.dep1, this.departmentMaxJuniors, this.dep1
.getMaxJuniors(), this.dep1.getMaxJuniors()+1);
instances = computeAffectedInstances(this.getMaxJuniorsAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testMaxJuniorsAddEmployee() {
// context Department inv MaxJuniors:
// self.employee->select(e|e.age < 25)->size() < self.maxJuniors
debugPrintln("Testing MaxJuniorsAddEmployee\n");
Notification noti;
Collection<EObject> instances;
// add new employee
noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.employeeRef, CompanyFactory.eINSTANCE
.createEmployee());
instances = computeAffectedInstances(this.getMaxJuniorsAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testNastyConstraintAddDepartment() {
// context Division
// inv nasty:
// self.department->collect(d|
// d.employee->including(d.boss)).salary->sum() < budget";
debugPrintln("Testing nastyAddDepartment\n");
Notification noti;
Collection<EObject> instances;
// add new department
noti = NotificationHelper.createReferenceAddNotification(this.div, this.departmentRef, CompanyFactory.eINSTANCE
.createDepartment());
instances = computeAffectedInstances(this.getNastyConstraintAST(), noti);
compareInstances(instances, new EObject[] { this.div });
}
@Test
public void testNastyConstraintAddEmployee() {
// context Division
// inv nasty:
// self.department->collect(d|
// d.employee->including(d.boss)).salary->sum() < budget";
debugPrintln("Testing nastyAddEmployee\n");
Notification noti;
Collection<EObject> instances;
// add new employee
noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.employeeRef, CompanyFactory.eINSTANCE
.createEmployee());
instances = computeAffectedInstances(this.getNastyConstraintAST(), noti);
compareInstances(instances, new EObject[] { this.div });
}
@Test
public void testNastyConstraintAddBoss() {
// context Division
// inv nasty:
// self.department->collect(d|
// d.employee->including(d.boss)).salary->sum() < budget";
debugPrintln("Testing nastyAddBoss\n");
Notification noti;
Collection<EObject> instances;
// add new boss
noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.bossRef, this.boss2);
instances = computeAffectedInstances(this.getNastyConstraintAST(), noti);
compareInstances(instances, new EObject[] { this.div });
}
@Test
public void testNastyConstraintEmployeeSalaryChange() {
// context Division
// inv nasty:
// self.department->collect(d|
// d.employee->including(d.boss)).salary->sum() < budget";
debugPrintln("Testing nastyEmployeeSalaryChange\n");
Notification noti;
Collection<EObject> instances;
// change salary of an employee
noti = NotificationHelper.createAttributeChangeNotification(this.e1, this.employeeSalary, this.e1.getSalary(),
this.e1.getSalary()+1);
instances = computeAffectedInstances(this.getNastyConstraintAST(), noti);
compareInstances(instances, new EObject[] { this.div });
}
@Test
public void testNastyConstraintBossSalaryChange() {
// context Division
// inv nasty:
// self.department->collect(d|
// d.employee->including(d.boss)).salary->sum() < budget";
debugPrintln("Testing nastyBossSalaryChange\n");
Notification noti;
Collection<EObject> instances;
// change salary of the boss
noti = NotificationHelper.createAttributeChangeNotification(this.boss1, this.employeeSalary, this.boss1
.getSalary(), this.boss1.getSalary()+1);
instances = computeAffectedInstances(this.getNastyConstraintAST(), noti);
compareInstances(instances, new EObject[] { this.div });
}
@Test
public void testNastyConstraintDivisionBudgetChange() {
// context Division
// inv nasty:
// self.department->collect(d|
// d.employee->including(d.boss)).salary->sum() < budget";
debugPrintln("Testing nastyDivisionBudgetChange\n");
Notification noti;
Collection<EObject> instances;
// change budget of the division
noti = NotificationHelper.createAttributeChangeNotification(this.div, this.divisionBudget,
this.div.getBudget(), this.div.getBudget()+1);
instances = computeAffectedInstances(this.getNastyConstraintAST(), noti);
compareInstances(instances, new EObject[] { this.div });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testSecretaryOlderThanBossAddDirector() {
// context Employee \n"
// inv secretaryOlderThanBoss: \n"
// if self.directed->notEmpty() and \n"
// not self.secretary.oclIsUndefined() then \n"
// self.age < self.secretary.age \n"
// else true \n"
// endif";
debugPrintln("Testing secretaryOlderThanBossAddDirector\n");
Notification noti;
Collection<EObject> instances;
// add new director
noti = NotificationHelper.createReferenceAddNotification(this.director, this.directedRef, CompanyFactory.eINSTANCE.createDivision());
instances = computeAffectedInstances(this.getSecretaryOlderThanBossAST(), noti);
compareInstances(instances, new EObject[] { this.director });
}
@Test
public void testSecretaryOlderThanBossRemoveDirector() {
// context Employee \n"
// inv secretaryOlderThanBoss: \n"
// if self.directed->notEmpty() and \n"
// not self.secretary.oclIsUndefined() then \n"
// self.age < self.secretary.age \n"
// else true \n"
// endif";
debugPrintln("Testing secretaryOlderThanBossRemoveDirector\n");
Notification noti;
Collection<EObject> instances;
// remove director
noti = NotificationHelper.createReferenceRemoveNotification(this.director, this.directedRef, this.div);
instances = computeAffectedInstances(this.getSecretaryOlderThanBossAST(), noti);
compareInstances(instances, new EObject[] { this.director });
}
@Test
public void testSecretaryOlderThanBossDirectorSecretaryChange() {
// context Employee \n"
// inv secretaryOlderThanBoss: \n"
// if self.directed->notEmpty() and \n"
// not self.secretary.oclIsUndefined() then \n"
// self.age < self.secretary.age \n"
// else true \n"
// endif";
debugPrintln("Testing secretaryOlderThanBossDirectorSecretaryChange\n");
Notification noti;
Collection<EObject> instances;
// change secretary of the director
Employee newEmployee = CompanyFactory.eINSTANCE.createEmployee();
noti = NotificationHelper.createReferenceChangeNotification(this.director, this.employeeSecretary, this.director
.getSecretary(), newEmployee);
instances = computeAffectedInstances(this.getSecretaryOlderThanBossAST(), noti);
compareInstances(instances, new EObject[] { this.director });
}
@Test
public void testSecretaryOlderThanBossSecretaryAgeChange() {
// context Employee \n"
// inv secretaryOlderThanBoss: \n"
// if self.directed->notEmpty() and \n"
// not self.secretary.oclIsUndefined() then \n"
// self.age < self.secretary.age \n"
// else true \n"
// endif";
debugPrintln("Testing secretaryOlderThanBossSecretaryAgeChange\n");
Notification noti;
Collection<EObject> instances;
// change age of secretary
noti = NotificationHelper.createAttributeChangeNotification(this.secretary, this.employeeAge, this.secretary
.getAge(), this.secretary.getAge()+1);
instances = computeAffectedInstances(this.getSecretaryOlderThanBossAST(), noti);
if (OptimizationActivation.getOption().isUnusedDetectionActive()) {
compareInstances(instances, new EObject[] {} ); // change is in unused if-branch
} else {
compareInstances(instances, new EObject[] { this.director, this.secretary });
}
}
@Test
public void testSecretaryOlderThanBossDirectorAgeChange() {
// context Employee \n"
// inv secretaryOlderThanBoss: \n"
// if self.directed->notEmpty() and \n"
// not self.secretary.oclIsUndefined() then \n"
// self.age < self.secretary.age \n"
// else true \n"
// endif";
debugPrintln("Testing secretaryOlderThanBossDirectorAgeChange\n");
Notification noti;
Collection<EObject> instances;
// change age of director
noti = NotificationHelper.createAttributeChangeNotification(this.director, this.employeeAge, this.director
.getAge(), this.director.getAge()+1);
instances = computeAffectedInstances(this.getSecretaryOlderThanBossAST(), noti);
compareInstances(instances, new EObject[] { this.director });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testBoss10YearsOlderThanJuniorEmployeeAgeChange() {
// context Department \n"
// inv boss10YearsOlderThanJunior: \n"
// let t:Tuple(boss:Employee,junior:Employee)="
// Tuple{boss=self.boss, junior=self.employee->sortedBy(age)->first()} in \n"
// t.boss.age > t.junior.age + 10";
debugPrintln("Testing boss10YearsOlderThanJuniorEmployeeAgeChange\n");
Notification noti;
Collection<EObject> instances;
// change age of employee
noti = NotificationHelper.createAttributeChangeNotification(this.e1, this.employeeAge, 42, 1);
instances = computeAffectedInstances(this.getBoss10YearsOlderThanJuniorAST(), noti);
compareInstances(instances, new EObject[] { this.e1.getEmployer() });
}
@Test
public void testBoss10YearsOlderThanJuniorBossAgeChange() {
// context Department \n"
// inv boss10YearsOlderThanJunior: \n"
// let t:Tuple(boss:Employee,junior:Employee)="
// Tuple{boss=self.boss, junior=self.employee->sortedBy(age)->first()} in \n"
// t.boss.age > t.junior.age + 10";
debugPrintln("Testing boss10YearsOlderThanJuniorBossAgeChange\n");
Notification noti;
Collection<EObject> instances;
// change age of boss
noti = NotificationHelper.createAttributeChangeNotification(this.boss1, this.employeeAge, 42, 52);
instances = computeAffectedInstances(this.getBoss10YearsOlderThanJuniorAST(), noti);
compareInstances(instances, new EObject[] { this.e1.getEmployer() });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testCompareBossSalaryToJuniorSalaryBossChange() {
// context Department \n"
// inv compareBossSalaryToJuniorSalary: \n"
// let t:Tuple(boss:Tuple(person:Employee, salary:Integer), junior:Tuple(person:Employee, salary:Integer))="
// Tuple{Tuple{self.boss, self.boss.salary}, Tuple{self.employee->sortedBy(age)->first(),
// self.employee->sortedBy(age)->first().salary}} in \n"
// t.boss.person <> t.junior.person implies t.boss.salary > t.junior.salary + 100";
debugPrintln("Testing compareBossSalaryToJuniorSalaryBossChange\n");
Notification noti;
Collection<EObject> instances;
// change boss of department
noti = NotificationHelper.createReferenceChangeNotification(this.dep1, this.bossRef, CompanyFactory.eINSTANCE
.createEmployee(), this.e1);
instances = computeAffectedInstances(this.getCompareBossSalaryToJuniorSalaryAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testCompareBossSalaryToJuniorSalaryEmployeeSalaryChange() {
// context Department \n"
// inv compareBossSalaryToJuniorSalary: \n"
// let t:Tuple(boss:Tuple(person:Employee, salary:Integer), junior:Tuple(person:Employee, salary:Integer))="
// Tuple{Tuple{self.boss, self.boss.salary}, Tuple{self.employee->sortedBy(age)->first(),
// self.employee->sortedBy(age)->first().salary}} in \n"
// t.boss.person <> t.junior.person implies t.boss.salary > t.junior.salary + 100";
debugPrintln("Testing compareBossSalaryToJuniorSalaryEmployeeSalaryChange\n");
Notification noti;
Collection<EObject> instances;
// change salary of employee
noti = NotificationHelper
.createAttributeChangeNotification(this.e1, this.employeeSalary, 1234, 12345);
instances = computeAffectedInstances(this.getCompareBossSalaryToJuniorSalaryAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testCompareBossSalaryToJuniorSalaryEmployeeAgeChange() {
// context Department \n"
// inv compareBossSalaryToJuniorSalary: \n"
// let t:Tuple(boss:Tuple(person:Employee, salary:Integer), junior:Tuple(person:Employee, salary:Integer))="
// Tuple{Tuple{self.boss, self.boss.salary}, Tuple{self.employee->sortedBy(age)->first(),
// self.employee->sortedBy(age)->first().salary}} in \n"
// t.boss.person <> t.junior.person implies t.boss.salary > t.junior.salary + 100";
debugPrintln("Testing compareBossSalaryToJuniorSalaryEmployeeAgeChange\n");
Notification noti;
Collection<EObject> instances;
// change age of employee
noti = NotificationHelper.createAttributeChangeNotification(this.e1, this.employeeAge, 23, 34);
instances = computeAffectedInstances(this.getCompareBossSalaryToJuniorSalaryAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testCompareBossSalaryToJuniorSalaryEmployeeAdd() {
// context Department \n"
// inv compareBossSalaryToJuniorSalary: \n"
// let t:Tuple(boss:Tuple(person:Employee, salary:Integer), junior:Tuple(person:Employee, salary:Integer))="
// Tuple{Tuple{self.boss, self.boss.salary}, Tuple{self.employee->sortedBy(age)->first(),
// self.employee->sortedBy(age)->first().salary}} in \n"
// t.boss.person <> t.junior.person implies t.boss.salary > t.junior.salary + 100";
debugPrintln("Testing compareBossSalaryToJuniorSalaryEmployeeAdd\n");
Notification noti;
Collection<EObject> instances;
// add new employee
noti = NotificationHelper.createReferenceChangeNotification(this.dep1, this.employeeRef, null, this.e3);
instances = computeAffectedInstances(this.getCompareBossSalaryToJuniorSalaryAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
}
@Test
public void testCompareBossSalaryToJuniorSalaryEmployeeRemove() {
// context Department \n"
// inv compareBossSalaryToJuniorSalary: \n"
// let t:Tuple(boss:Tuple(person:Employee, salary:Integer), junior:Tuple(person:Employee, salary:Integer))="
// Tuple{Tuple{self.boss, self.boss.salary}, Tuple{self.employee->sortedBy(age)->first(),
// self.employee->sortedBy(age)->first().salary}} in \n"
// t.boss.person <> t.junior.person implies t.boss.salary > t.junior.salary + 100";
debugPrintln("Testing compareBossSalaryToJuniorSalaryEmployeeRemove\n");
Notification noti;
Collection<EObject> instances;
// remove employee
noti = NotificationHelper.createReferenceChangeNotification(this.dep1, this.employeeRef, this.e1, null);
instances = computeAffectedInstances(this.getCompareBossSalaryToJuniorSalaryAST(), noti);
compareInstances(instances, new EObject[] { this.dep1 });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testEmployeeInSameDepartmentAsInternEmployeeAdd() {
// context Employee \n"
// inv employeeInSameDepartmentAsIntern: \n"
// self.employer = self.intern.employer";
debugPrintln("Testing employeeInSameDepartmentAsInternEmployeeAdd\n");
// add Employee
final Employee newEmployee = CompanyFactory.eINSTANCE.createEmployee();
final boolean[] result = new boolean[1];
newEmployee.setIntern(this.stud2);
newEmployee.eAdapters().add(new AdapterImpl() {
@Override
public void notifyChanged(Notification notification) {
Collection<EObject> instances = computeAffectedInstances(getEmployeeInSameDepartmentAsInternAST(), notification);
try {
compareInstances(instances, new EObject[] { newEmployee });
result[0] = true;
} catch (AssertionFailedError e) {
result[0] = false;
}
}
});
this.dep1.getEmployee().add(newEmployee);
assertTrue(result[0]);
// this notification is actually an ElementLifeCycleEvent which is not handled correctly atm
// noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.employeeRef, newEmployee);
}
@Test
public void testEmployeeInSameDepartmentAsInternEmployeeInternChange() {
// context Employee \n"
// inv employeeInSameDepartmentAsIntern: \n"
// self.employer = self.intern.employer";
debugPrintln("Testing employeeInSameDepartmentAsInternEmployeeInternChange\n");
Notification noti;
Collection<EObject> instances;
// change intern reference
Student newStudent = CompanyFactory.eINSTANCE.createStudent();
newStudent.setEmployer(dep2);
noti = NotificationHelper.createReferenceChangeNotification(this.e1, this.internRef, this.stud1, newStudent);
instances = computeAffectedInstances(this.getEmployeeInSameDepartmentAsInternAST(), noti);
compareInstances(instances, new EObject[] { this.e1 });
}
@Test
public void testEmployeeInSameDepartmentAsInternEmployeeEmployerChange() {
// context Employee \n"
// inv employeeInSameDepartmentAsIntern: \n"
// self.employer = self.intern.employer";
debugPrintln("Testing employeeInSameDepartmentAsInternEmployeeEmployerChange\n");
Notification noti;
Collection<EObject> instances;
// change employer reference
noti = NotificationHelper.createReferenceChangeNotification(this.e1, this.employerRef, this.dep1, this.dep2);
instances = computeAffectedInstances(this.getEmployeeInSameDepartmentAsInternAST(), noti);
compareInstances(instances, new EObject[] { this.e1 });
}
@Test
public void testEmployeeInSameDepartmentAsInternStudentEmployerChange() {
// context Employee \n"
// inv employeeInSameDepartmentAsIntern: \n"
// self.employer = self.intern.employer";
debugPrintln("Testing employeeInSameDepartmentAsInternStudentEmployerChange\n");
Notification noti;
Collection<EObject> instances;
// change employer reference
noti = NotificationHelper.createReferenceChangeNotification(this.stud1, this.employerRef, this.dep1, this.dep2);
instances = computeAffectedInstances(this.getEmployeeInSameDepartmentAsInternAST(), noti);
// since student is a subclass of employee (and therefore could have own interns), the impact of the above change also
// includes stud1
compareInstances(instances, new EObject[] { this.e1, this.stud1 });
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testCheckForBob() {
debugPrintln("Testing checkForBob\n");
Notification noti;
Collection<EObject> instances;
// change employee name
noti = NotificationHelper.createAttributeChangeNotification(this.e1, this.employeeName, "e1", "Bob");
instances = computeAffectedInstances(this.getCheckForBobAST(), noti);
compareInstances(instances, new EObject[] { this.e1 , this.e2, this.e3, this.e4, this.secretary, this.boss1, this.boss2, this.director, this.stud1, this.stud2});
debugPrintln("--------------------------------------------------\n");
}
@Test
public void testDerivedPropertyHandlingIndirect(){
debugPrintln("Testing derivedPropertyHandling\n");
Notification noti;
Collection<EObject> instances;
// Make e1 the employee of the month of div by making him the employee of the month of dep1.
// That should influence the derived property Department.employeesOfTheMonth but this feature isn't implemented by default.
noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.departmentEmployeeOfTheMonth, this.e1);
instances = computeAffectedInstances(this.getLimitEmployeesOfTheMonthAST(), noti);
compareInstances(instances, new EObject[] {this.div});
}
@Test
public void testDerivedPropertyHandlingDirect() {
Notification noti;
// Make e1 the employee of the month of div by directly manipulating the derived property.
// Since the derived property is unmodifiable, this should return null.
debugPrintln("The following warning is intended.");
noti = NotificationHelper.createReferenceAddNotification(this.div, this.divisionEmployeesOfTheMonth, this.e1);
assertTrue(noti == null);
}
@Test
public void testNestedDerivation() {
Notification noti;
Collection<EObject> instances;
// Make e1 the employee of the month of div by making him the employee of the month of dep1.
// That should influence the derived property Department.employeesOfTheMonth but this feature isn't implemented by default.
noti = NotificationHelper.createReferenceAddNotification(this.dep1, this.departmentEmployeeOfTheMonth, this.e1);
instances = computeAffectedInstances(this.getNestedDerivationAST(), noti);
compareInstances(instances, new EObject[] {this.div});
}
@Test
public void testNonLinearDerivationPositive() {
Notification noti;
Collection<EObject> instances;
//Use a derived property with a derivation expression that contains a branch (Department.biggestNumberOfStudentsOrFreelancers)
//and see if a change in the unused branch causes an impact.
//After the instance creation dep2 has 1 freelance.
//We add another one which will influence the biggestNumberOfStudentsOrFreelancers attribute of dep2 since it has only 1 student.
noti = NotificationHelper.createReferenceAddNotification(this.dep2, this.employeeRef, this.e2);
instances = computeAffectedInstances(this.getNonLinearDerivationAST(), noti);
compareInstances(instances, new EObject[] {this.dep2});
}
@Test
public void testNonLinearDerivationNegative() {
Notification noti;
Collection<EObject> instances;
//Use a derived property with a derivation expression that contains a branch (Department.biggestNumberOfStudentsOrFreelancers)
//and see if a change in the unused branch causes an impact.
//After the instance creation dep2 has 1 freelance.
//We add two more and afterwards we add 1 student which will not influence the biggestNumberOfStudentsOrFreelancers
//attribute of dep2 since it has more freelancers than students.
e2.setEmployer(dep2);
boss1.setEmployer(dep2);
noti = NotificationHelper.createReferenceAddNotification(this.dep2, this.employeeRef, this.stud1);
instances = computeAffectedInstances(this.getNonLinearDerivationAST(), noti);
compareInstances(instances, new EObject[] {/*this.dep2 should not be in the impact since the derived property didn't and couldn't change but this can only be determined if unusedChecks are enabled*/});
debugPrintln("Enable unusedChecks to get rid of this extra context instance.");
}
@Test
public void testlongNavigationWithDerivation() {
// derived property handling has so far only been implemented for the traceback-step approach
if (OptimizationActivation.getOption().isTracebackStepISAActive()) {
Notification noti;
Collection<EObject> instances;
// The tested constraint makes sure, the context of the constraint and of the derivation expression differ.
// The constraints sorts all departments of all divisions of a company by their biggestNumberOfStudentsOrFreelancers
// attribute and checks if the last one in the collection has less than 5 students and freelancers.
// Dep2 initially has 2 freelancers, resulting in the highest value for the biggestNumberOfStudentsOrFreelancers attribute.
// We add another freelancer to generate an impact for this constraint.
noti = NotificationHelper.createReferenceAddNotification(this.dep2, this.employeeRef, this.e2);
instances = computeAffectedInstances(this.getlongNavigationWithDerivationAST(), noti);
compareInstances(instances, new EObject[] {this.company});
debugPrintln("--------------------------------------------------\n");
}
}
// @Test
// public void testDepartmentAlwaysInDivision(){
//
// // context Department \n"
// // inv departmentMustHaveDivision: \n"
// // self.department2division->notEmpty()";
// debugPrintln("Testing departmentAlwaysInDivision\n");
// Set<OCLExpression> stmts = new HashSet<OCLExpression>();
// stmts.add(this.getdepartmentMustHaveDivisionAST());
//
//
//
// Notification noti;
// Collection<EObject> instances;
//
// // create new department
// EObject newElem = this.comp.getEFactoryInstance().create(this.department);
// noti = NotificationHelper.createNewElementAddToResourceNotification(newElem, rs.getResources().iterator().next());
// instances = computeAffectedInstances(TODO, noti);
// compareInstances( instances, new EObject[] { newElem } );
// // add department to division
// // remove department from division
// }
/**
* Creates an instance of the company model ie 2 instances of Department with e employees and one boss each.
*/
private void createInstances() {
this.rs = new ResourceSetImpl();
Resource r = this.rs.createResource(URI.createURI("http://rev/path/computation/test"));
r.eAdapters().add(new ECrossReferenceAdapter());
this.rs.getResources().add(r);
this.company = CompanyFactory.eINSTANCE.createCompany();
r.getContents().add(this.company);
this.div = CompanyFactory.eINSTANCE.createDivision();
this.div.setBudget(1234567);
this.div.setName("Div1");
this.div.setCompany(this.company);
r.getContents().add(this.div);
this.director = CompanyFactory.eINSTANCE.createEmployee();
this.director.setAge(42);
this.director.setName("Director");
this.director.setDirected(this.div);
this.director.setSalary(1234);
this.div.setDirector(this.director);
this.secretary = CompanyFactory.eINSTANCE.createEmployee();
this.secretary.setAge(55);
this.secretary.setName("Secretary");
this.secretary.setSalary(1234);
this.secretary.setEmployer(this.dep1);
this.director.setSecretary(this.secretary);
this.dep1 = CompanyFactory.eINSTANCE.createDepartment();
this.dep1.setName("Dep1");
this.dep1.setBudget(12345567);
this.dep1.setMaxJuniors(5);
this.e1 = CompanyFactory.eINSTANCE.createEmployee();
this.e1.setAge(42);
this.e1.setName("e1");
this.e1.setEmployer(this.dep1);
this.e1.setSalary(1234);
this.e2 = CompanyFactory.eINSTANCE.createFreelance();
this.e2.setAge(42);
this.e2.setName("e2");
this.e2.setAssignment(9);
this.e2.setEmployer(this.dep1);
this.e2.setSalary(1234);
this.boss1 = CompanyFactory.eINSTANCE.createFreelance();
this.boss1.setAge(43);
this.boss1.setName("boss1");
this.boss1.setEmployer(this.dep1);
this.boss1.setManaged(this.dep1);
this.boss1.setSalary(1234);
this.dep1.setBoss(this.boss1);
this.stud1 = CompanyFactory.eINSTANCE.createStudent();
this.stud1.setAge(22);
this.stud1.setName("stud1");
this.stud1.setSalary(234);
this.stud1.setEmployer(this.dep1);
this.e1.setIntern(this.stud1);
this.dep2 = CompanyFactory.eINSTANCE.createDepartment();
this.dep2.setName("Dep2");
this.dep2.setBudget(12345567);
this.dep2.setMaxJuniors(5);
this.e3 = CompanyFactory.eINSTANCE.createEmployee();
this.e3.setAge(42);
this.e3.setName("e3");
this.e3.setEmployer(this.dep2);
this.e3.setSalary(1234);
this.e4 = CompanyFactory.eINSTANCE.createFreelance();
this.e4.setAge(42);
this.e4.setName("e4");
this.e2.setAssignment(9);
this.e4.setEmployer(this.dep2);
this.e4.setSalary(1234);
this.boss2 = CompanyFactory.eINSTANCE.createEmployee();
this.boss2.setAge(44);
this.boss2.setName("boss2");
this.boss2.setEmployer(this.dep2);
this.boss2.setManaged(this.dep2);
this.boss2.setSalary(2345);
this.dep2.setBoss(this.boss2);
this.stud2 = CompanyFactory.eINSTANCE.createStudent();
this.stud2.setAge(23);
this.stud2.setName("stud2");
this.stud2.setSalary(234);
this.stud2.setEmployer(this.dep2);
this.e3.setIntern(this.stud2);
this.div.getDepartment().add(this.dep1);
this.div.getDepartment().add(this.dep2);
}
/**
* Computes the set of affected context instances for event <tt>evt</tt>.
*
* @param expressions
* list of the effected {@link OCLExpression}s
* @param noti
* the event
* @param context
* @return a Collection of {@link EObject}s representing the affected context instances.
*/
private Collection<EObject> computeAffectedInstances(ExpressionInOCL eiocl, Notification noti) {
return ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer((OCLExpression) eiocl.getBodyExpression(),
(EClass) eiocl.getContextVariable().getType(), /* notifyOnNewContextElements */ false,
OCLFactory.getInstance())
.getContextObjects(noti);
}
/**
* @param instances
* @param expectedInstances
*/
private void compareInstances(Collection<EObject> instances, EObject[] expectedInstances) {
Set<EObject> expected = new HashSet<EObject>();
for (int i = 0; i < expectedInstances.length; i++) {
expected.add(expectedInstances[i]);
}
if (instances.containsAll(expected) && instances.size() == expected.size()) {
debugPrintln(">> SUCCESS exact match\n");
} else if (instances.containsAll(expected) && instances.size() != expected.size()) {
debugPrintln(">> SUCCESS \n excess context instances:\n");
instances.removeAll(expected);
for (Iterator<EObject> i = instances.iterator(); i.hasNext();) {
debugPrintln(i.next() + "\n");
}
} else {
debugPrintln(">> FAILURE\n");
expected.removeAll(instances);
for (EObject o : expected) {
debugPrint(o + " not in result");
}
debugPrintln("");
fail("Returned instances does not match expected instances!");
}
}
// /**
// * Unfortunately not all features can be tested with the department model
// */
// private void extendModel( ) {
//
// for some tests we need some additional classes
// MofClass a = this.mofPackage.getModel().getMofClass().createMofClass();
// a.setName("A");
// MofClass b = this.mofPackage.getModel().getMofClass().createMofClass();
// a.setName("B");
// MofClass c = this.mofPackage.getModel().getMofClass().createMofClass();
// a.setName("C");
// MofClass d = this.mofPackage.getModel().getMofClass().createMofClass();
// a.setName("D");
// // B is a subtype of A
// b.getSupertypes().add(a);
// // D-B-Association
// Association db = this.mofPackage.getModel().getAssociation().createAssociation();
// db.setName("DB-Assocation");
// AssociationEnd toB = this.mofPackage.getModel().getAssociationEnd().createAssociationEnd();
// toB.setName("toB");
// toB.setType(b);
// toB.setMultiplicity(this.mofPackage.getModel().createMultiplicityType(0,-1,true,true));
// db.getContents().add(toB);
// AssociationEnd toD = this.mofPackage.getModel().getAssociationEnd().createAssociationEnd();
// toB.setName("toD");
// toB.setType(d);
// toB.setMultiplicity(this.mofPackage.getModel().createMultiplicityType(0,-1,true,true));
// db.getContents().add(toD);
// // A-C-Association
// Association ac = this.mofPackage.getModel().getAssociation().createAssociation();
// ac.setName("DB-Assocation");
// AssociationEnd toC = this.mofPackage.getModel().getAssociationEnd().createAssociationEnd();
// toC.setName("toC");
// toC.setType(c);
// toC.setMultiplicity(this.mofPackage.getModel().createMultiplicityType(0,-1,true,true));
// ac.getContents().add(toC);
// AssociationEnd toA = this.mofPackage.getModel().getAssociationEnd().createAssociationEnd();
// toA.setName("toA");
// toA.setType(a);
// toA.setMultiplicity(this.mofPackage.getModel().createMultiplicityType(0,-1,true,true));
// ac.getContents().add(toA);
// this.companyPackage.getContents().add(a);
// this.companyPackage.getContents().add(b);
// this.companyPackage.getContents().add(c);
// this.companyPackage.getContents().add(d);
// this.companyPackage.getContents().add(ac);
// this.companyPackage.getContents().add(db);
// }
}