| /******************************************************************************* |
| * Copyright (c) 2009, 2013 SAP AG and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * SAP AG - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.ocl.examples.impactanalyzer.tests.instanceScope; |
| |
| import java.util.Collection; |
| |
| import modelmanagement.ModelmanagementFactory; |
| import modelmanagement.ModelmanagementPackage; |
| |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.emf.ecore.EAttribute; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EReference; |
| 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.ocl.common.OCLConstants; |
| import org.eclipse.ocl.common.internal.options.CommonOptions; |
| import org.eclipse.ocl.ecore.OCL; |
| import org.eclipse.ocl.ecore.OCLExpression; |
| import org.eclipse.ocl.examples.impactanalyzer.ImpactAnalyzer; |
| 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.Test; |
| |
| import behavioral.actions.ActionsFactory; |
| import data.classes.Association; |
| import data.classes.AssociationEnd; |
| import data.classes.ClassTypeDefinition; |
| import data.classes.ClassesFactory; |
| import data.classes.ClassesPackage; |
| import data.classes.MethodSignature; |
| import data.classes.Parameter; |
| import data.classes.SapClass; |
| import data.classes.SignatureImplementation; |
| import data.classes.TypeAdapter; |
| import dataaccess.expressions.ExpressionsFactory; |
| import dataaccess.expressions.ExpressionsPackage; |
| import dataaccess.expressions.MethodCallExpression; |
| import dataaccess.expressions.ObjectCreationExpression; |
| import dataaccess.expressions.VariableExpression; |
| import dataaccess.expressions.literals.LiteralsFactory; |
| import dataaccess.expressions.literals.LiteralsPackage; |
| import dataaccess.expressions.literals.ObjectLiteral; |
| import dataaccess.expressions.literals.StringLiteral; |
| |
| public class OclIaTest extends BaseDepartmentTestWithOCL { |
| |
| private static final String testAnalysisOfRecursiveOperationWithSelf = "context dataaccess::expressions::MethodCallExpression \n" |
| + "inv testAnalysisOfRecursiveOperationWithSelf: \n" |
| + "self.object.getType().getInnermost().oclAsType(data::classes::ClassTypeDefinition).clazz.allSignatures() \n" |
| + "->select(s | s.name = 'testMethod')"; |
| |
| private static final String testAllInstancesSelectClassName = "context data::classes::ClassTypeDefinition \n" |
| + "inv testAllInstancesSelectClassName:\n" + "data::classes::SapClass.allInstances()->select(c | c.name = 'Bob')"; |
| |
| private static final String testVerySimpleTracerBasedInstanceScopeAnalysisWithNewClassScopeAnalysis = "context data::classes::SapClass \n" |
| + "inv testVerySimpleTracerBasedInstanceScopeAnalysisWithNewClassScopeAnalysis: \n" |
| + "self.oclAsType(data::classes::SapClass).name"; |
| |
| private static final String testLongRunningNavigationPathExpression = "context data::classes::AssociationEnd inv LongRunningNavigationPath: \n " |
| + "'.'.concat(self.oclAsType(data::classes::AssociationEnd).name)"; |
| |
| private static final String testLowerMultiplicityPropagationForMethodCall = "context data::classes::ClassTypeDefinition \n" |
| + "inv testLowerMultiplicityPropagationForMethodCallOnParameterUsage: \n" |
| + "self.ownerTypedElement.oclAsType(dataaccess::expressions::MethodCallExpression).methodSignature.output.lowerMultiplicity * \n" |
| + "self.ownerTypedElement.oclAsType(dataaccess::expressions::MethodCallExpression).object.getType().lowerMultiplicity"; |
| |
| private static final String testInstanceScopeAnalysisForRecursiveOperation = "context data::classes::SapClass \n" |
| + "inv testInstanceScopeAnalysisForRecursiveOperation: \n" + "self.adapters->forAll(a | self.conformsTo(a.to))"; |
| |
| private static final String testVerySimpleInstanceScopeAnalysisWithTupleUsingSelf = "context data::classes::SapClass \n" |
| + "inv testVerySimpleInstanceScopeAnalysisWithTupleUsingSelf: \n" + "Tuple{cls=self}.cls.name"; |
| |
| private static final String testVerySimpleInstanceScopeAnalysisWithTuple = "context data::classes::SapClass \n" |
| + "inv testVerySimpleInstanceScopeAnalysisWithTuple: \n" + "Tuple{name=self.name}.name"; |
| |
| private static final String testForIA2 = "context dataaccess::expressions::literals::ObjectLiteral \n" + "inv testForIA2: \n" |
| + "self.oclAsType(dataaccess::expressions::literals::ObjectLiteral).valueClass.getAssociationEnds().otherEnd()" |
| + "->select(ae|ae.name='Assoc_to_Bob_changed')"; |
| |
| private EPackage cp; |
| private ResourceSetImpl rs; |
| |
| @Override |
| public void setUp() { |
| CommonOptions.DEFAULT_DELEGATION_MODE.setDefaultValue(OCLConstants.OCL_DELEGATE_URI_LPG); |
| this.cp = ClassesPackage.eINSTANCE; |
| this.rs = new ResourceSetImpl(); |
| this.rs.eAdapters().add(new ECrossReferenceAdapter()); |
| this.rs.getResources().add(this.cp.eResource()); |
| } |
| |
| @Override |
| public void tearDown() { |
| this.rs = null; |
| this.cp = null; |
| } |
| |
| @Test |
| public void testSelectByType() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testSelectByType:\n" + |
| "self.ownedSignatures.implementation->selectByType(data::classes::LinkSetting).implements_.output"+ |
| ".oclAsType(data::classes::ClassTypeDefinition).clazz.name", |
| this.cp).iterator().next().getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c1 = ClassesFactory.eINSTANCE.createSapClass(); |
| c1.setName("c1"); |
| MethodSignature ms1 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms1.setName("ms1"); |
| c1.getOwnedSignatures().add(ms1); |
| SapClass c2 = ClassesFactory.eINSTANCE.createSapClass(); |
| c2.setName("c2"); |
| MethodSignature ms2 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms2.setName("ms2"); |
| c2.getOwnedSignatures().add(ms2); |
| SignatureImplementation ms1Impl = ActionsFactory.eINSTANCE.createBlock(); |
| ms1.setImplementation(ms1Impl); |
| SignatureImplementation ms2Impl = ClassesFactory.eINSTANCE.createLinkSetting(); |
| ms2.setImplementation(ms2Impl); |
| SapClass output = ClassesFactory.eINSTANCE.createSapClass(); |
| output.setName("Output"); |
| ClassTypeDefinition outputCtdForMs1 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ClassTypeDefinition outputCtdForMs2 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| outputCtdForMs1.setClazz(output); |
| outputCtdForMs2.setClazz(output); |
| ms1.setOutput(outputCtdForMs1); |
| ms2.setOutput(outputCtdForMs2); |
| |
| Collection<?> resultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertTrue(resultOnC1.isEmpty()); |
| Collection<?> resultOnC2 = (Collection<?>) OCL.newInstance().evaluate(c2, expression); |
| assertEquals(1, resultOnC2.size()); |
| assertTrue(resultOnC2.contains("Output")); |
| |
| final Notification[] noti = new Notification[1]; |
| Adapter adapter = new AdapterImpl() { |
| @Override |
| public void notifyChanged(Notification msg) { |
| noti[0] = msg; |
| } |
| }; |
| output.eAdapters().add(adapter); |
| |
| output.setName("NewOutput"); |
| Collection<?> newResultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertTrue(newResultOnC1.isEmpty()); |
| Collection<?> newResultOnC2 = (Collection<?>) OCL.newInstance().evaluate(c2, expression); |
| assertEquals(1, newResultOnC2.size()); |
| assertTrue(newResultOnC2.contains("NewOutput")); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti[0]); |
| assertEquals(1, impact.size()); // expecting only c2 to be impacted because c1's ms1 implementation has the wrong type |
| assertFalse(impact.contains(c1)); |
| assertTrue(impact.contains(c2)); |
| } |
| |
| @Test |
| public void testSelectByTypeForSubclass() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testSelectByTypeForSubclass:\n" + |
| "self.ownedSignatures.implementation->selectByType(data::classes::SignatureImplementation).implements_.output"+ |
| ".oclAsType(data::classes::ClassTypeDefinition).clazz.name", |
| this.cp).iterator().next().getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c1 = ClassesFactory.eINSTANCE.createSapClass(); |
| c1.setName("c1"); |
| MethodSignature ms1 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms1.setName("ms1"); |
| c1.getOwnedSignatures().add(ms1); |
| SapClass c2 = ClassesFactory.eINSTANCE.createSapClass(); |
| c2.setName("c2"); |
| MethodSignature ms2 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms2.setName("ms2"); |
| c2.getOwnedSignatures().add(ms2); |
| SignatureImplementation ms1Impl = ActionsFactory.eINSTANCE.createBlock(); |
| ms1.setImplementation(ms1Impl); |
| SignatureImplementation ms2Impl = ClassesFactory.eINSTANCE.createLinkSetting(); |
| ms2.setImplementation(ms2Impl); |
| SapClass output = ClassesFactory.eINSTANCE.createSapClass(); |
| output.setName("Output"); |
| ClassTypeDefinition outputCtdForMs1 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ClassTypeDefinition outputCtdForMs2 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| outputCtdForMs1.setClazz(output); |
| outputCtdForMs2.setClazz(output); |
| ms1.setOutput(outputCtdForMs1); |
| ms2.setOutput(outputCtdForMs2); |
| |
| Collection<?> resultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertTrue(resultOnC1.isEmpty()); |
| Collection<?> resultOnC2 = (Collection<?>) OCL.newInstance().evaluate(c2, expression); |
| assertTrue(resultOnC2.isEmpty()); |
| |
| final Notification[] noti = new Notification[1]; |
| Adapter adapter = new AdapterImpl() { |
| @Override |
| public void notifyChanged(Notification msg) { |
| noti[0] = msg; |
| } |
| }; |
| output.eAdapters().add(adapter); |
| |
| output.setName("NewOutput"); |
| Collection<?> newResultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertTrue(newResultOnC1.isEmpty()); |
| Collection<?> newResultOnC2 = (Collection<?>) OCL.newInstance().evaluate(c2, expression); |
| assertTrue(newResultOnC2.isEmpty()); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti[0]); |
| assertTrue(impact.isEmpty()); // expecting neither c1 nor c2 to be in |
| // the result because neither Block nor |
| // LinkSetting has exactly type |
| // SignatureImplementation |
| } |
| |
| @Test |
| public void testSelectByKind() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testSelectByKind:\n" + |
| "self.ownedSignatures.implementation->selectByKind(data::classes::LinkSetting).implements_.output"+ |
| ".oclAsType(data::classes::ClassTypeDefinition).clazz.name", |
| this.cp).iterator().next().getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c1 = ClassesFactory.eINSTANCE.createSapClass(); |
| c1.setName("c1"); |
| MethodSignature ms1 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms1.setName("ms1"); |
| c1.getOwnedSignatures().add(ms1); |
| SapClass c2 = ClassesFactory.eINSTANCE.createSapClass(); |
| c2.setName("c2"); |
| MethodSignature ms2 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms2.setName("ms2"); |
| c2.getOwnedSignatures().add(ms2); |
| SignatureImplementation ms1Impl = ActionsFactory.eINSTANCE.createBlock(); |
| ms1.setImplementation(ms1Impl); |
| SignatureImplementation ms2Impl = ClassesFactory.eINSTANCE.createLinkSetting(); |
| ms2.setImplementation(ms2Impl); |
| SapClass output = ClassesFactory.eINSTANCE.createSapClass(); |
| output.setName("Output"); |
| ClassTypeDefinition outputCtdForMs1 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ClassTypeDefinition outputCtdForMs2 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| outputCtdForMs1.setClazz(output); |
| outputCtdForMs2.setClazz(output); |
| ms1.setOutput(outputCtdForMs1); |
| ms2.setOutput(outputCtdForMs2); |
| |
| Collection<?> resultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertTrue(resultOnC1.isEmpty()); |
| Collection<?> resultOnC2 = (Collection<?>) OCL.newInstance().evaluate(c2, expression); |
| assertEquals(1, resultOnC2.size()); |
| assertTrue(resultOnC2.contains("Output")); |
| |
| final Notification[] noti = new Notification[1]; |
| Adapter adapter = new AdapterImpl() { |
| @Override |
| public void notifyChanged(Notification msg) { |
| noti[0] = msg; |
| } |
| }; |
| output.eAdapters().add(adapter); |
| |
| output.setName("NewOutput"); |
| Collection<?> newResultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertTrue(newResultOnC1.isEmpty()); |
| Collection<?> newResultOnC2 = (Collection<?>) OCL.newInstance().evaluate(c2, expression); |
| assertEquals(1, newResultOnC2.size()); |
| assertTrue(newResultOnC2.contains("NewOutput")); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti[0]); |
| assertEquals(1, impact.size()); // expecting only c2 to be impacted because c1's ms1's implementation's type doesn't match |
| assertTrue(impact.contains(c2)); |
| } |
| |
| @Test |
| public void testSelectByKindForSubclass() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testSelectByKindForSubclass:\n" + |
| "self.ownedSignatures.implementation->selectByKind(data::classes::SignatureImplementation).implements_.output"+ |
| ".oclAsType(data::classes::ClassTypeDefinition).clazz.name", |
| this.cp).iterator().next().getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c1 = ClassesFactory.eINSTANCE.createSapClass(); |
| c1.setName("c1"); |
| MethodSignature ms1 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms1.setName("ms1"); |
| c1.getOwnedSignatures().add(ms1); |
| SapClass c2 = ClassesFactory.eINSTANCE.createSapClass(); |
| c2.setName("c2"); |
| MethodSignature ms2 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms2.setName("ms2"); |
| c2.getOwnedSignatures().add(ms2); |
| SignatureImplementation ms1Impl = ActionsFactory.eINSTANCE.createBlock(); |
| ms1.setImplementation(ms1Impl); |
| SignatureImplementation ms2Impl = ClassesFactory.eINSTANCE.createLinkSetting(); |
| ms2.setImplementation(ms2Impl); |
| SapClass output = ClassesFactory.eINSTANCE.createSapClass(); |
| output.setName("Output"); |
| ClassTypeDefinition outputCtdForMs1 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ClassTypeDefinition outputCtdForMs2 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| outputCtdForMs1.setClazz(output); |
| outputCtdForMs2.setClazz(output); |
| ms1.setOutput(outputCtdForMs1); |
| ms2.setOutput(outputCtdForMs2); |
| |
| Collection<?> resultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertEquals(1, resultOnC1.size()); |
| assertTrue(resultOnC1.contains("Output")); |
| Collection<?> resultOnC2 = (Collection<?>) OCL.newInstance().evaluate(c2, expression); |
| assertEquals(1, resultOnC2.size()); |
| assertTrue(resultOnC2.contains("Output")); |
| |
| final Notification[] noti = new Notification[1]; |
| Adapter adapter = new AdapterImpl() { |
| @Override |
| public void notifyChanged(Notification msg) { |
| noti[0] = msg; |
| } |
| }; |
| output.eAdapters().add(adapter); |
| |
| output.setName("NewOutput"); |
| Collection<?> newResultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertEquals(1, newResultOnC1.size()); |
| assertTrue(newResultOnC1.contains("NewOutput")); |
| Collection<?> newResultOnC2 = (Collection<?>) OCL.newInstance().evaluate(c2, expression); |
| assertEquals(1, newResultOnC2.size()); |
| assertTrue(newResultOnC2.contains("NewOutput")); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti[0]); |
| assertEquals(2, impact.size()); // expecting both, c1 and c2, to be impacted |
| assertTrue(impact.contains(c1)); |
| assertTrue(impact.contains(c2)); |
| } |
| |
| @Test |
| public void testSimpleClosure() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testSimpleClosure:\n" + |
| "self->closure(i | i.ownedSignatures.input.ownedTypeDefinition." + |
| "oclAsType(data::classes::ClassTypeDefinition).clazz)", |
| this.cp).iterator().next().getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c1 = ClassesFactory.eINSTANCE.createSapClass(); |
| c1.setName("c1"); |
| MethodSignature ms1 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms1.setName("ms1"); |
| c1.getOwnedSignatures().add(ms1); |
| Parameter p1 = ClassesFactory.eINSTANCE.createParameter(); |
| p1.setName("p1"); |
| ms1.getInput().add(p1); |
| ClassTypeDefinition ctd1 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| p1.setOwnedTypeDefinition(ctd1); |
| |
| SapClass c2 = ClassesFactory.eINSTANCE.createSapClass(); |
| ctd1.setClazz(c2); |
| c2.setName("c2"); |
| MethodSignature ms2 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms2.setName("ms2"); |
| c2.getOwnedSignatures().add(ms2); |
| Parameter p2 = ClassesFactory.eINSTANCE.createParameter(); |
| p2.setName("p2"); |
| ms2.getInput().add(p2); |
| ClassTypeDefinition ctd2 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| p2.setOwnedTypeDefinition(ctd2); |
| |
| SapClass c3 = ClassesFactory.eINSTANCE.createSapClass(); |
| ctd2.setClazz(c3); |
| c3.setName("c3"); |
| MethodSignature ms3 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms3.setName("ms3"); |
| c3.getOwnedSignatures().add(ms3); |
| Parameter p3 = ClassesFactory.eINSTANCE.createParameter(); |
| p3.setName("p3"); |
| ms3.getInput().add(p3); |
| ClassTypeDefinition ctd3 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| p3.setOwnedTypeDefinition(ctd3); |
| |
| SapClass c4 = ClassesFactory.eINSTANCE.createSapClass(); |
| ctd3.setClazz(c4); |
| c4.setName("c4"); |
| MethodSignature ms4 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms3.setName("ms4"); |
| c4.getOwnedSignatures().add(ms4); |
| |
| Collection<?> resultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertTrue(resultOnC1.contains(c2)); |
| assertTrue(resultOnC1.contains(c3)); |
| assertTrue(resultOnC1.contains(c4)); |
| |
| final Notification[] noti = new Notification[1]; |
| Adapter adapter = new AdapterImpl() { |
| @Override |
| public void notifyChanged(Notification msg) { |
| noti[0] = msg; |
| } |
| }; |
| ms2.eAdapters().add(adapter); |
| |
| // now add another parameter p22 with new type c5 to ms2; this should change expression |
| // for c2 and c1 whose ms1 argument p1 is using c2 |
| SapClass c5 = ClassesFactory.eINSTANCE.createSapClass(); |
| c5.setName("c5"); |
| Parameter p22 = ClassesFactory.eINSTANCE.createParameter(); |
| p22.setName("p22"); |
| ClassTypeDefinition ctd22 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| p22.setOwnedTypeDefinition(ctd22); |
| ctd22.setClazz(c5); |
| ms2.getInput().add(p22); |
| Collection<?> newResultOnC1 = (Collection<?>) OCL.newInstance().evaluate(c1, expression); |
| assertTrue(newResultOnC1.contains(c2)); |
| assertTrue(newResultOnC1.contains(c3)); |
| assertTrue(newResultOnC1.contains(c4)); |
| assertTrue(newResultOnC1.contains(c5)); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti[0]); |
| assertEquals(2, impact.size()); // expecting c1 and c2 to be impacted |
| assertTrue(impact.contains(c1)); |
| assertTrue(impact.contains(c2)); |
| } |
| |
| @Test |
| public void testResultUseInIterate() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testMoveWithoutImpact:\n" + |
| "Sequence{1, 2, 3}->iterate(i; result:Set(data::classes::SapClass)=Set{self} | result.ownedSignatures.output.oclAsType(data::classes::ClassTypeDefinition).clazz)", |
| this.cp).iterator().next().getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c1 = ClassesFactory.eINSTANCE.createSapClass(); |
| c1.setName("c1"); |
| SapClass c2 = ClassesFactory.eINSTANCE.createSapClass(); |
| c2.setName("c2"); |
| SapClass c3 = ClassesFactory.eINSTANCE.createSapClass(); |
| c3.setName("c3"); |
| SapClass c4 = ClassesFactory.eINSTANCE.createSapClass(); |
| c4.setName("c4"); |
| SapClass c5 = ClassesFactory.eINSTANCE.createSapClass(); |
| c5.setName("c5"); |
| SapClass c6 = ClassesFactory.eINSTANCE.createSapClass(); |
| c6.setName("c6"); |
| |
| connectWithMethodOutput(c1, c2); |
| connectWithMethodOutput(c2, c3); |
| connectWithMethodOutput(c3, c4); |
| connectWithMethodOutput(c4, c5); |
| |
| this.cp.eResource().getContents().add(c1); |
| this.cp.eResource().getContents().add(c2); |
| this.cp.eResource().getContents().add(c3); |
| this.cp.eResource().getContents().add(c4); |
| this.cp.eResource().getContents().add(c5); |
| final Notification[] noti = new Notification[1]; |
| Adapter adapter = new AdapterImpl() { |
| @Override |
| public void notifyChanged(Notification msg) { |
| noti[0] = msg; |
| } |
| }; |
| c5.eAdapters().add(adapter); |
| connectWithMethodOutput(c5, c6); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti[0]); |
| assertEquals(5, impact.size()); // expecting all c1..c6 to be impacted |
| assertFalse(impact.contains(c6)); |
| } |
| |
| private void connectWithMethodOutput(SapClass c1, SapClass c2) { |
| MethodSignature m1 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| m1.setName("m1"); |
| ClassTypeDefinition ctd1 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ctd1.setClazz(c2); |
| m1.setOutput(ctd1); |
| c1.getOwnedSignatures().add(m1); |
| } |
| |
| @Test |
| public void testMoveWithoutImpact() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testMoveWithoutImpact:\n" + "self.ownedSignatures->at(3).name = 'm3'", |
| this.cp).iterator().next().getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c = ClassesFactory.eINSTANCE.createSapClass(); |
| MethodSignature m1 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| m1.setName("m1"); |
| c.getOwnedSignatures().add(m1); |
| MethodSignature m2 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| m2.setName("m2"); |
| c.getOwnedSignatures().add(m2); |
| MethodSignature m3 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| m1.setName("m3"); |
| c.getOwnedSignatures().add(m3); |
| this.cp.eResource().getContents().add(c); |
| c.setName("C"); |
| final Notification[] noti = new Notification[1]; |
| Adapter adapter = new AdapterImpl() { |
| @Override |
| public void notifyChanged(Notification msg) { |
| noti[0] = msg; |
| } |
| }; |
| c.eAdapters().add(adapter); |
| c.getOwnedSignatures().move(0, 1); // swap first two signatures |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti[0]); |
| assertEquals(0, impact.size()); |
| c.getOwnedSignatures().move(1, 2); // not the name of the element at position 3 should have changed |
| Collection<EObject> impact2 = ia.getContextObjects(noti[0]); |
| assertEquals(1, impact2.size()); |
| assertTrue(impact2.contains(c)); |
| } |
| |
| @Test |
| public void testTupleLiteralUsedTwice() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testTupleLiteralUsedTwice:\n" |
| + "let t:Tuple(c:data::classes::SapClass, d:data::classes::SapClass) = Tuple{c=self, d=self.adapters.to->first()} in\n" |
| + "Set{t.c.name, t.d.name}", this.cp).iterator().next().getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c = ClassesFactory.eINSTANCE.createSapClass(); |
| SapClass d = ClassesFactory.eINSTANCE.createSapClass(); |
| d.setName("D"); |
| this.cp.eResource().getContents().add(c); |
| c.setName("oldName"); |
| TypeAdapter ta = ClassesFactory.eINSTANCE.createTypeAdapter(); |
| ta.setAdapted(c); |
| ta.setTo(d); |
| EAttribute att = (EAttribute) c.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(c, att, "oldName", "newName"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(c)); |
| Notification noti2 = NotificationHelper.createAttributeChangeNotification(d, att, "D", "newD"); |
| Collection<EObject> impact2 = ia.getContextObjects(noti2); |
| assertTrue(impact2.size() == 2 && impact2.contains(c) && impact2.contains(d)); |
| } |
| |
| @Test |
| public void testTupleLiteralWithImmediatePropertyCall() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testTupleLiteralWithImmediatePropertyCall:\n" + "Tuple{c=self}.c.name", |
| this.cp).iterator().next().getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c = ClassesFactory.eINSTANCE.createSapClass(); |
| this.cp.eResource().getContents().add(c); |
| c.setName("oldName"); |
| EAttribute att = (EAttribute) c.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(c, att, "oldName", "newName"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(c)); |
| } |
| |
| @Test |
| public void testTupleLiteralPassedThroughLetVariable() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testTupleLiteralPassedThroughLetVariable:\n" |
| + "let t:Tuple(c:data::classes::SapClass) = Tuple{c=self} in\n" + "t.c.name", this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c = ClassesFactory.eINSTANCE.createSapClass(); |
| this.cp.eResource().getContents().add(c); |
| c.setName("oldName"); |
| EAttribute att = (EAttribute) c.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(c, att, "oldName", "newName"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(c)); |
| } |
| |
| @Test |
| public void testTupleLiteralPassedThroughTwoLetVariables() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testTupleLiteralPassedThroughLetVariable:\n" |
| + "let t1:Tuple(c:data::classes::SapClass) = Tuple{c=self} in\n" |
| + "let t2:Tuple(c:data::classes::SapClass) = t1 in\n" + "t2.c.name", this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c = ClassesFactory.eINSTANCE.createSapClass(); |
| this.cp.eResource().getContents().add(c); |
| c.setName("oldName"); |
| EAttribute att = (EAttribute) c.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(c, att, "oldName", "newName"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(c)); |
| } |
| |
| @Test |
| public void testNestedTupleLiteral() { |
| OCLExpression expression = (OCLExpression) parse( |
| "context data::classes::SapClass inv testNestedTupleLiteral:\n" |
| + "Tuple{c:Tuple(d:data::classes::SapClass)=Tuple{d=self}}.c.d.name", this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| SapClass c = ClassesFactory.eINSTANCE.createSapClass(); |
| this.cp.eResource().getContents().add(c); |
| c.setName("oldName"); |
| EAttribute att = (EAttribute) c.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(c, att, "oldName", "newName"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(c)); |
| } |
| |
| @Test |
| public void testLongRunningNavigationPathConstruction() { |
| OCLExpression expression = (OCLExpression) parse(testLongRunningNavigationPathExpression, this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(expression); |
| AssociationEnd ae = ClassesFactory.eINSTANCE.createAssociationEnd(); |
| this.cp.eResource().getContents().add(ae); |
| EAttribute att = (EAttribute) ae.eClass().getEStructuralFeature(ClassesPackage.ASSOCIATION_END__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(ae, att, "oldName", "newName"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(expression, ClassesPackage.eINSTANCE |
| .getAssociationEnd(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertTrue(impact.size() == 1 && impact.contains(ae)); |
| } |
| |
| /** |
| * self.ownerTypedElement.oclAsType(MethodCallExpression).methodSignature.output.lowerMultiplicity * |
| * self.ownerTypedElement.oclAsType(MethodCallExpression).object.getType().lowerMultiplicity |
| */ |
| |
| @Test |
| public void testLowerMultiplicityPropagationForMethodCallOnParameterUsage() { |
| OCLExpression exp = (OCLExpression) parse(testLowerMultiplicityPropagationForMethodCall, this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| Resource r = this.cp.eResource(); |
| r.eAdapters().add(new ECrossReferenceAdapter()); |
| r.getContents().add(exp); |
| // construct something like "abc".length(), then change multiplicity of "abc" from 1..1 to 0..1 |
| MethodSignature length = ClassesFactory.eINSTANCE.createMethodSignature(); |
| r.getContents().add(length); |
| length.setName("length"); |
| SapClass numberClass = ClassesFactory.eINSTANCE.createSapClass(); |
| r.getContents().add(numberClass); |
| numberClass.setName("Number"); |
| ClassTypeDefinition msOutput = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| msOutput.setClazz(numberClass); |
| msOutput.setLowerMultiplicity(1); |
| msOutput.setUpperMultiplicity(1); |
| length.setOutput(msOutput); |
| ClassTypeDefinition ctd = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ctd.setClazz(numberClass); |
| ctd.setLowerMultiplicity(1); |
| ctd.setUpperMultiplicity(1); |
| MethodCallExpression mce = ExpressionsFactory.eINSTANCE.createMethodCallExpression(); |
| r.getContents().add(mce); |
| mce.setOwnedTypeDefinition(ctd); |
| mce.setMethodSignature(length); |
| Parameter p = ClassesFactory.eINSTANCE.createParameter(); |
| r.getContents().add(p); |
| p.setName("p"); |
| SapClass stringClass = ClassesFactory.eINSTANCE.createSapClass(); |
| r.getContents().add(stringClass); |
| stringClass.setName("String"); |
| ClassTypeDefinition otDef = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| otDef.setClazz(stringClass); |
| otDef.setUpperMultiplicity(1); |
| otDef.setLowerMultiplicity(1); |
| p.setOwnedTypeDefinition(otDef); |
| VariableExpression ve = ExpressionsFactory.eINSTANCE.createVariableExpression(); |
| ve.setVariable(p); // this should infer the variable expression's multiplicity to that of p |
| mce.setObject(ve); |
| |
| assertEquals(1, ve.getType().getLowerMultiplicity()); |
| |
| OCL ocl = org.eclipse.ocl.examples.impactanalyzer.util.OCL.newInstance(); |
| Object oldResult = ocl.evaluate(ctd, exp); |
| Notification noti = NotificationHelper.createChangeLowerMultiplicityNotification(p.getOwnedTypeDefinition(), 0); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE |
| .getClassTypeDefinition(), /* notifyOnNewContextElements */ false, |
| OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| Object newResult = ocl.evaluate(ctd, exp); |
| |
| assertEquals(0, p.getOwnedTypeDefinition().getLowerMultiplicity()); |
| assertFalse("expected " + oldResult + " and " + newResult + " to be different but were equal", oldResult |
| .equals(newResult)); |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(ctd)); |
| |
| } |
| |
| /** |
| * self.ownerTypedElement.oclAsType(MethodCallExpression).methodSignature.output.lowerMultiplicity * |
| * self.ownerTypedElement.oclAsType(MethodCallExpression).object.getType().lowerMultiplicity |
| */ |
| @Test |
| public void testLowerMultiplicityPropagationForMethodCall() { |
| OCLExpression exp = (OCLExpression) parse(testLowerMultiplicityPropagationForMethodCall, this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| Resource r = this.cp.eResource(); |
| r.getContents().add(exp); |
| // construct something like "abc".length(), then change multiplicity of "abc" from 1..1 to 0..1 |
| MethodSignature length = ClassesFactory.eINSTANCE.createMethodSignature(); |
| length.setName("length"); |
| SapClass numberClass = ClassesFactory.eINSTANCE.createSapClass(); |
| numberClass.setName("Number"); |
| ClassTypeDefinition msOutput = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| msOutput.setClazz(numberClass); |
| msOutput.setLowerMultiplicity(1); |
| msOutput.setUpperMultiplicity(1); |
| length.setOutput(msOutput); |
| ClassTypeDefinition ctd1 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ctd1.setClazz(numberClass); |
| ctd1.setLowerMultiplicity(1); |
| ctd1.setUpperMultiplicity(1); |
| MethodCallExpression mce = ExpressionsFactory.eINSTANCE.createMethodCallExpression(); |
| mce.setOwnedTypeDefinition(ctd1); |
| mce.setMethodSignature(length); |
| StringLiteral sl = LiteralsFactory.eINSTANCE.createStringLiteral(); |
| sl.setLiteral("abc"); |
| SapClass stringClass = ClassesFactory.eINSTANCE.createSapClass(); |
| ClassTypeDefinition ctd2 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ctd2.setClazz(stringClass); |
| ctd2.setLowerMultiplicity(1); |
| ctd2.setUpperMultiplicity(1); |
| sl.setOwnedTypeDefinition(ctd2); |
| mce.setObject(sl); |
| |
| r.getContents().add(mce); |
| r.getContents().add(length); |
| r.getContents().add(numberClass); |
| r.getContents().add(stringClass); |
| |
| assertEquals(1, sl.getOwnedTypeDefinition().getLowerMultiplicity()); |
| |
| Notification noti = NotificationHelper.createChangeLowerMultiplicityNotification(sl.getOwnedTypeDefinition(), 0); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE |
| .getClassTypeDefinition(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| |
| assertEquals(0, sl.getOwnedTypeDefinition().getLowerMultiplicity()); |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(ctd1)); |
| |
| } |
| |
| /** |
| * data::classes::SapClass.allInstances()->select(c | c.name = 'something' |
| */ |
| @Test |
| public void testAnalysisOfRecursiveOperationWithSelf() { |
| OCLExpression exp = (OCLExpression) parse(testAnalysisOfRecursiveOperationWithSelf, this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| Resource r = this.cp.eResource(); |
| |
| r.eAdapters().add(new ECrossReferenceAdapter()); |
| r.getContents().add(exp); |
| |
| // construct something like "new HumbaClass1().m()" |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setName("Alice"); |
| MethodSignature ms = ClassesFactory.eINSTANCE.createMethodSignature(); |
| ms.setName("testMethod"); |
| cl1.getOwnedSignatures().add(ms); |
| final ClassTypeDefinition ctd = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ctd.setLowerMultiplicity(1); |
| ctd.setUpperMultiplicity(1); |
| ctd.setClazz(null); |
| final MethodCallExpression mce = ExpressionsFactory.eINSTANCE.createMethodCallExpression(); |
| final ObjectCreationExpression oce = ExpressionsFactory.eINSTANCE.createObjectCreationExpression(); |
| oce.setClassToInstantiate(cl1); |
| oce.setOwnedTypeDefinition(ctd); |
| mce.setObject(oce); |
| |
| r.getContents().add(cl1); |
| r.getContents().add(mce); |
| |
| Notification noti = NotificationHelper.createChangeClazzNotification(ctd, cl1); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ExpressionsPackage.eINSTANCE |
| .getMethodCallExpression(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(mce) && !impact.contains(ctd)); |
| |
| } |
| |
| /** |
| * data::classes::SapClass.allInstances()->select(c | c.name = 'something' |
| */ |
| @Test |
| public void testAllInstancesSelectClassName() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse(testAllInstancesSelectClassName, this.cp).iterator().next().getSpecification() |
| .getBodyExpression(); |
| r.getContents().add(exp); |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setName("Alice"); |
| r.getContents().add(cl1); |
| final ClassTypeDefinition ctd = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ctd.setClazz(cl1); |
| r.getContents().add(ctd); |
| |
| EAttribute att = (EAttribute) cl1.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(cl1, att, "Alice", "Bob"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, |
| ClassesPackage.eINSTANCE.getClassTypeDefinition(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| // The expression has as its context ClassTypeDefinition. Therefore, the SapClass must not be returned |
| // as impacted object. However, the change affects the ->select clause after allInstances(), so |
| // all context objects of type ClassTypeDefinition are affected. That's what we want to assert now: |
| assertTrue(impact.size() > 0 && impact.contains(ctd) && !impact.contains(cl1)); |
| } |
| |
| /** |
| * The ->select lets only classes pass whose name is 'Bob'. Therefore, a class named 'Alice' |
| * should not be produced by any context. |
| */ |
| @Test |
| public void testFindContextElementsForResultForAllInstances() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse(testAllInstancesSelectClassName, this.cp).iterator().next().getSpecification() |
| .getBodyExpression(); |
| r.getContents().add(exp); |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setName("Alice"); |
| r.getContents().add(cl1); |
| final ClassTypeDefinition ctd = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ctd.setClazz(cl1); |
| r.getContents().add(ctd); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, |
| ClassesPackage.eINSTANCE.getClassTypeDefinition(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> contexts = ia.getContextObjects(cl1); |
| assertTrue(contexts.isEmpty()); |
| } |
| |
| /** |
| * The ->select lets only classes pass whose name is 'Bob'. Therefore, a class named 'Bob' |
| * should be produced by all possible contexts |
| */ |
| @Test |
| public void testFindAllContextElementsForResultForAllInstances() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse(testAllInstancesSelectClassName, this.cp).iterator().next().getSpecification() |
| .getBodyExpression(); |
| r.getContents().add(exp); |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setName("Bob"); |
| r.getContents().add(cl1); |
| final ClassTypeDefinition ctd = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| ctd.setClazz(cl1); |
| r.getContents().add(ctd); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, |
| ClassesPackage.eINSTANCE.getClassTypeDefinition(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> contexts = ia.getContextObjects(cl1); |
| assertTrue(!contexts.isEmpty()); |
| assertTrue(contexts.contains(ctd)); |
| } |
| |
| /** |
| * data::classes::SapClass.allInstances()->select(c | c.name = 'something' |
| */ |
| @Test |
| public void testTriggeringAllInstancesByDirectResourceContainment() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse(testAllInstancesSelectClassName, this.cp).iterator().next().getSpecification() |
| .getBodyExpression(); |
| r.getContents().add(exp); |
| final ClassTypeDefinition ctd = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| r.getContents().add(ctd); |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setName("Bob"); |
| final Notification[] notifications = new Notification[1]; |
| Adapter a = new AdapterImpl() { |
| @Override |
| public void notifyChanged(Notification n) { |
| if (n.getEventType() != Notification.REMOVING_ADAPTER) { |
| if (notifications[0] != null) { |
| fail("didn't expect to receive two notifications"); |
| } |
| notifications[0] = n; |
| } |
| } |
| }; |
| r.eAdapters().add(a); |
| cl1.eAdapters().add(a); |
| r.getContents().add(cl1); |
| assertNotNull("Expected to receive one notification", notifications[0]); |
| r.eAdapters().remove(a); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE.getClassTypeDefinition(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(notifications[0]); |
| // The expression has as its context ClassTypeDefinition. Therefore, the SapClass must not be returned |
| // as impacted object. However, the change affects the ->select clause after allInstances(), so |
| // all context objects of type ClassTypeDefinition are affected. That's what we want to assert now: |
| assertTrue(impact.size() > 0 && impact.contains(ctd) && !impact.contains(cl1)); |
| } |
| |
| @Test |
| public void testVerySimpleTracerBasedInstanceScopeAnalysisWithNewClassScopeAnalysis() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse(testVerySimpleTracerBasedInstanceScopeAnalysisWithNewClassScopeAnalysis, |
| this.cp).iterator().next().getSpecification().getBodyExpression(); |
| r.getContents().add(exp); |
| |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setName("Alice"); |
| r.getContents().add(cl1); |
| |
| EAttribute att = (EAttribute) cl1.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(cl1, att, "Alice", "Bob"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE.getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| |
| assertTrue(impact.size() == 1 && impact.contains(cl1)); |
| } |
| |
| @Test |
| public void testInstanceScopeAnalysisForRecursiveOperation() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse(testInstanceScopeAnalysisForRecursiveOperation, this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| r.getContents().add(exp); |
| |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setName("Alice"); |
| r.getContents().add(cl1); |
| SapClass cl2 = ClassesFactory.eINSTANCE.createSapClass(); |
| ; |
| cl2.setName("Bob"); |
| r.getContents().add(cl2); |
| TypeAdapter adapter = ClassesFactory.eINSTANCE.createTypeAdapter(); |
| adapter.setName("Alice_to_Bob_Adapter"); |
| adapter.setAdapted(cl1); |
| // the adapted reference already is a container |
| // r.getContents().add(adapter); |
| |
| EReference ref1 = (EReference) adapter.eClass().getEStructuralFeature(ClassesPackage.TYPE_ADAPTER__TO); |
| Notification noti1 = NotificationHelper.createReferenceChangeNotification(adapter, ref1, null, cl2); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE.getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact1 = ia.getContextObjects(noti1); |
| |
| assertTrue(impact1.size() == 1 && impact1.contains(cl1)); |
| } |
| |
| @Test |
| public void testVerySimpleInstanceScopeAnalysisWithTupleUsingSelf() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse(testVerySimpleInstanceScopeAnalysisWithTupleUsingSelf, this.cp).iterator() |
| .next().getSpecification().getBodyExpression(); |
| r.getContents().add(exp); |
| |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setName("Alice"); |
| r.getContents().add(cl1); |
| |
| EAttribute att = (EAttribute) cl1.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(cl1, att, "Alice", "Bob"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE.getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(cl1)); |
| } |
| |
| @Test |
| public void testVerySimpleInstanceScopeAnalysisWithTuple() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse(testVerySimpleInstanceScopeAnalysisWithTuple, this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| r.getContents().add(exp); |
| |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setName("Alice"); |
| r.getContents().add(cl1); |
| |
| EAttribute att = (EAttribute) cl1.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(cl1, att, "Alice", "Bob"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE.getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| |
| assertTrue(impact.size() == 1 && impact.contains(cl1)); |
| } |
| |
| @Test |
| public void testGetFloorTokenNull() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse(testForIA2, this.cp).iterator().next().getSpecification().getBodyExpression(); |
| |
| SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| r.getContents().add(cl1); |
| cl1.setName("Alice"); |
| cl1.setValueType(true); |
| |
| ClassTypeDefinition ctd1 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| r.getContents().add(ctd1); |
| ctd1.setClazz(cl1); |
| ctd1.setLowerMultiplicity(1); |
| ctd1.setUpperMultiplicity(1); |
| ctd1.setOrdered(false); |
| ctd1.setUnique(false); |
| |
| SapClass cl2 = ClassesFactory.eINSTANCE.createSapClass(); |
| r.getContents().add(cl2); |
| cl2.setName("Bob"); |
| |
| ClassTypeDefinition ctd2 = ClassesFactory.eINSTANCE.createClassTypeDefinition(); |
| r.getContents().add(ctd2); |
| ctd2.setClazz(cl2); |
| ctd2.setLowerMultiplicity(1); |
| ctd2.setUpperMultiplicity(1); |
| ctd2.setOrdered(false); |
| ctd2.setUnique(false); |
| |
| ObjectLiteral ol1 = LiteralsFactory.eINSTANCE.createObjectLiteral(); |
| r.getContents().add(ol1); |
| ol1.setValueClass(cl1); |
| |
| AssociationEnd ae1 = ClassesFactory.eINSTANCE.createAssociationEnd(); |
| r.getContents().add(ae1); |
| ae1.setName("Assoc_to_Alice"); |
| ae1.setType(ctd1); |
| |
| AssociationEnd ae2 = ClassesFactory.eINSTANCE.createAssociationEnd(); |
| r.getContents().add(ae2); |
| ae2.setName("Assoc_to_Bob"); |
| ae2.setType(ctd2); |
| |
| Association a = ClassesFactory.eINSTANCE.createAssociation(); |
| r.getContents().add(a); |
| a.setName("Assoc"); |
| a.getEnds().add(ae1); |
| a.getEnds().add(ae2); |
| |
| EAttribute att = (EAttribute) ae1.eClass().getEStructuralFeature(ClassesPackage.ASSOCIATION_END__NAME); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(ae2, att, "Assoc_to_Bob", |
| "Assoc_to_Bob_changed"); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE |
| .createImpactAnalyzer(exp, LiteralsPackage.eINSTANCE.getObjectLiteral(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertEquals(1, impact.size()); |
| assertTrue(impact.contains(ol1)); |
| } |
| |
| @Test |
| public void testPredicateEvaluation() { |
| OCLExpression exp = (OCLExpression) parse( |
| "context data::classes::SapClass inv testPredicateEvaluation:\n" |
| + "self.ownedSignatures->select(s|s.sideEffectFree)->size() > 1", this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(exp); |
| SapClass c1 = ClassesFactory.eINSTANCE.createSapClass(); |
| c1.setName("c1"); |
| SapClass c2 = ClassesFactory.eINSTANCE.createSapClass(); |
| c2.setName("c2"); |
| SapClass c3 = ClassesFactory.eINSTANCE.createSapClass(); |
| c3.setName("c3"); |
| MethodSignature m1 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| m1.setName("Signature 1"); |
| m1.setSideEffectFree(true); |
| MethodSignature m2 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| m2.setName("Signature 2"); |
| m2.setSideEffectFree(false); |
| MethodSignature m3 = ClassesFactory.eINSTANCE.createMethodSignature(); |
| m3.setName("Signature 3"); |
| m3.setSideEffectFree(true); |
| |
| c1.getOwnedSignatures().add(m1); |
| c2.getOwnedSignatures().add(m2); |
| c3.getOwnedSignatures().add(m3); |
| |
| EAttribute att = (EAttribute) m3.eClass().getEStructuralFeature(ClassesPackage.METHOD_SIGNATURE__SIDE_EFFECT_FREE); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(m3, att, true, false); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertTrue(impact.size() == 1 && impact.contains(c3)); |
| |
| noti = NotificationHelper.createAttributeChangeNotification(m3, att, false, true); |
| impact = ia.getContextObjects(noti); |
| assertTrue(impact.size() == 1 && impact.contains(c3)); |
| |
| noti = NotificationHelper.createAttributeChangeNotification(m3, att, false, false); |
| impact = ia.getContextObjects(noti); |
| assertTrue(impact.size() == 0); |
| |
| noti = NotificationHelper.createAttributeChangeNotification(m3, att, true, true); |
| impact = ia.getContextObjects(noti); |
| assertTrue(impact.size() == 0); |
| } |
| |
| @Test |
| public void testDeltaPropagationForAllInstances() { |
| OCLExpression exp = (OCLExpression) parse( |
| "context data::classes::SapClass inv testDeltaPropagationForAllInstances:\n" |
| + "data::classes::SapClass.allInstances()->select(name='Humba')->size() = 0", this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| this.cp.eResource().getContents().add(exp); |
| SapClass c1 = ClassesFactory.eINSTANCE.createSapClass(); |
| c1.setName("Trala"); |
| SapClass c2 = ClassesFactory.eINSTANCE.createSapClass(); |
| c2.setName("Humba"); |
| modelmanagement.Package pkg = ModelmanagementFactory.eINSTANCE.createPackage(); |
| pkg.setName("Pkg"); |
| this.cp.eResource().getContents().add(pkg); |
| Notification noti = NotificationHelper.createReferenceAddNotification(pkg, ModelmanagementPackage.eINSTANCE |
| .getPackage_Classes(), c1); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE.getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| assertEquals(0, impact.size()); |
| |
| noti = NotificationHelper.createReferenceAddNotification(pkg, ModelmanagementPackage.eINSTANCE.getPackage_Classes(), c2); |
| impact = ia.getContextObjects(noti); |
| assertTrue(impact.size() >= 2); // we don't know the exact size because of all the other test elements created for fixture |
| assertTrue(impact.contains(c1) && impact.contains(c2)); |
| } |
| |
| @Test |
| public void testSimpleUnusedCheckWithIfConditionAlwaysFalse() { |
| Resource r = this.cp.eResource(); |
| OCLExpression exp = (OCLExpression) parse("context data::classes::SapClass inv testSimpleUnusedCheckWithIfClause:\n"+ |
| "if false then self.valueType else true endif", this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| r.getContents().add(exp); |
| |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setValueType(false); |
| r.getContents().add(cl1); |
| |
| EAttribute att = (EAttribute) cl1.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__VALUE_TYPE); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(cl1, att, false, true); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE.getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| |
| if (OptimizationActivation.getOption().isTracebackStepISAActive() && OptimizationActivation.getOption().isUnusedDetectionActive()) { |
| // expecting no impact because the then clause affected by the change is unused |
| assertEquals(0, impact.size()); |
| } else { |
| assertEquals(1, impact.size()); |
| assertEquals(cl1, impact.iterator().next()); |
| } |
| } |
| |
| @Test |
| public void testSimpleUnusedCheckWithIteratorSourceAlwaysEmpty() { |
| Resource r = this.cp.eResource(); |
| // the idea: while self.valueType changes for cl1, self.adapters is always empty for the changed object |
| OCLExpression exp = (OCLExpression) parse("context data::classes::SapClass inv testSimpleUnusedCheckWithIfClause:\n"+ |
| "self.adapters->select(a | a.to.valueType = self.valueType)", this.cp).iterator().next() |
| .getSpecification().getBodyExpression(); |
| r.getContents().add(exp); |
| |
| final SapClass cl1 = ClassesFactory.eINSTANCE.createSapClass(); |
| cl1.setValueType(false); |
| r.getContents().add(cl1); |
| |
| EAttribute att = (EAttribute) cl1.eClass().getEStructuralFeature(ClassesPackage.SAP_CLASS__VALUE_TYPE); |
| Notification noti = NotificationHelper.createAttributeChangeNotification(cl1, att, false, true); |
| ImpactAnalyzer ia = ImpactAnalyzerFactory.INSTANCE.createImpactAnalyzer(exp, ClassesPackage.eINSTANCE.getSapClass(), /* notifyOnNewContextElements */ false, OCLFactory.getInstance()); |
| Collection<EObject> impact = ia.getContextObjects(noti); |
| |
| if (OptimizationActivation.getOption().isUnusedDetectionActive()) { |
| // expecting no impact because the then clause affected by the change is unused |
| assertEquals(0, impact.size()); |
| } else { |
| assertEquals(1, impact.size()); |
| assertEquals(cl1, impact.iterator().next()); |
| } |
| } |
| |
| } |