/******************************************************************************* * Copyright (c) 2009, 2010 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 de.hpi.sam.bp2009.solution.oclToAst.tests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.eclipse.emf.common.util.BasicDiagnostic; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EEnumLiteral; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EParameter; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.util.Diagnostician; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.ocl.Environment; import org.eclipse.ocl.ecore.CallOperationAction; import org.eclipse.ocl.ecore.Constraint; import org.eclipse.ocl.ecore.EcoreEnvironment; import org.eclipse.ocl.ecore.IntegerLiteralExp; import org.eclipse.ocl.ecore.OCL; import org.eclipse.ocl.ecore.OCLExpression; import org.eclipse.ocl.ecore.OperationCallExp; import org.eclipse.ocl.ecore.SendSignalAction; import org.eclipse.ocl.ecore.delegate.OCLDelegateDomain; import org.eclipse.ocl.ecore.delegate.SettingBehavior; import org.eclipse.ocl.ecore.delegate.ValidationBehavior; import org.eclipse.ocl.utilities.UMLReflection; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import behavioral.actions.ActionsPackage; import behavioral.events.EventsPackage; import company.CompanyFactory; import company.CompanyPackage; import company.Department; import company.Division; import company.Employee; import company.util.CompanyValidator; import de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser; import de.hpi.sam.bp2009.solution.oclToAst.ErrorMessage; import de.hpi.sam.bp2009.solution.oclToAst.OclToAstFactory; /** * <!-- begin-user-doc --> A test case for the model object '<em><b>EAnnotation OCL Parser</b></em>'. <!-- end-user-doc --> * <p> * The following operations are tested: * <ul> * <li>{@link de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser#convertOclAnnotation(org.eclipse.emf.ecore.EModelElement) * <em>Convert Ocl Annotation</em>}</li> * </ul> * </p> */ public class EAnnotationOCLParserTest { /** * The fixture for this EAnnotation OCL Parser test case. */ protected EAnnotationOCLParser fixture = null; /** * Sets the fixture for this EAnnotation OCL Parser test case. */ protected void setFixture(EAnnotationOCLParser fixture) { this.fixture = fixture; } /** * Returns the fixture for this EAnnotation OCL Parser test case. * * @generated */ protected EAnnotationOCLParser getFixture() { return fixture; } /** * @see junit.framework.TestCase#setUp() */ @Before public void setUp() { setFixture(OclToAstFactory.eINSTANCE.createEAnnotationOCLParser()); } /** * @see junit.framework.TestCase#tearDown() */ @After public void tearDown() { setFixture(null); } /** * Tests the ' * {@link de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser#convertOclAnnotation(org.eclipse.emf.ecore.EModelElement) * <em>Convert Ocl Annotation</em>}' operation. * * @see de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser#convertOclAnnotation(org.eclipse.emf.ecore.EModelElement) */ @Test public void testConvertOclAnnotation__EModelElement() { EClass placeC = EcoreFactory.eINSTANCE.createEClass(); placeC.setName("Place"); EAttribute token = EcoreFactory.eINSTANCE.createEAttribute(); token.setName("noTokens"); token.setEType(EcorePackage.eINSTANCE.getEInt()); placeC.getEStructuralFeatures().add(token); EAnnotation anno = EcoreFactory.eINSTANCE.createEAnnotation(); anno.setSource(OCLDelegateDomain.OCL_DELEGATE_URI); anno.getDetails().put("someKey", "self.noTokens>4"); placeC.getEAnnotations().add(anno); getFixture().convertOclAnnotation(placeC); // ValidationBehavior.INSTANCE.getInvariant(placeC, "someKey", OCL.newInstance()); assertTrue(placeC.getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI).getContents().get(0) instanceof OCLExpression); assertTrue(((OCLExpression) placeC.getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI).getContents().get(0)) instanceof OperationCallExp); } @Test public void testInvocationDelegate_AST_Usage() { Department dep = CompanyFactory.eINSTANCE.createDepartment(); dep.setBudget(10000); dep.setName("Company"); Employee boss = CompanyFactory.eINSTANCE.createEmployee(); boss.setName("boss"); boss.setAge(40); boss.setManaged(dep); boss.setSalary(1000); Employee e1 = CompanyFactory.eINSTANCE.createEmployee(); e1.setAge(20); e1.setName("employee1"); e1.setSalary(100); dep.setBoss(boss); e1.setEmployer(dep); getFixture().traversalConvertOclAnnotations(CompanyPackage.eINSTANCE); OCL ocl = org.eclipse.ocl.examples.impactanalyzer.util.OCL.newInstance(); // change the annotation string value to proof usage of already parsed ast. Entry<String, String> value = CompanyPackage.eINSTANCE.getDepartment().getEOperations().get(0) .getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI).getDetails().get(0); String v = String.copyValueOf(value.getValue().toCharArray()); value.setValue(null); int result = dep.calcExpenses(); assertEquals("Expected budget: 1100, got: " + result, 1100, result); value.setValue(v); EAnnotation anno = null; anno = CompanyPackage.eINSTANCE.getDepartment().getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI); assertTrue("No annotation found, annotation converting failed.", anno != null); OCLExpression expr = null; // change the annotation string value to proof usage of already parsed ast. Entry<String, String> val = dep.eClass().getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI).getDetails().get(0); String content = String.copyValueOf(val.getValue().toCharArray()); val.setValue(null); expr = ValidationBehavior.INSTANCE.getInvariant(dep.eClass(), "NotBossFreelance", ocl); // expected Expression: // not (self.boss.oclIsTypeOf(Freelance)) assertTrue("No parsed ast found, probably annotation converting failed.", expr != null); assertTrue("The found ast is not the expected one.", expr instanceof OperationCallExp); Object r = ocl.evaluate(dep, expr); assertTrue("Expected value: 'false' , got: " + r.toString(), (Boolean) r); val.setValue(content); } @Test public void testSettingDelegate_AST_Usage() { CompanyFactory compFac = CompanyFactory.eINSTANCE; Division div = compFac.createDivision(); div.setName("Div1"); div.setBudget(2000); Department dep = compFac.createDepartment(); dep.setName("Dep1"); div.getDepartment().add(dep); // create initial expression EAnnotation anno = EcoreFactory.eINSTANCE.createEAnnotation(); anno.setSource(OCLDelegateDomain.OCL_DELEGATE_URI); anno.setEModelElement(CompanyPackage.eINSTANCE.getDepartment_Budget()); anno.getDetails().put(SettingBehavior.INITIAL_CONSTRAINT_KEY, "10000"); getFixture().traversalConvertOclAnnotations(CompanyPackage.eINSTANCE); OCL ocl = org.eclipse.ocl.examples.impactanalyzer.util.OCL.newInstance(); // change the annotation string value to proof usage of already parsed ast. CompanyPackage.eINSTANCE.getDepartment_Budget().getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI).getDetails().get(0) .setValue("-2"); OCLExpression expr = SettingBehavior.INSTANCE.getFeatureBody(ocl, CompanyPackage.eINSTANCE.getDepartment_Budget()); assertTrue("Constraint defining the initial value of department.budget could not be parsed.", expr instanceof IntegerLiteralExp); Object result = ocl.evaluate(dep, expr); assertTrue(result instanceof Integer); assertTrue("The parsed AST was not used.\n" + "Expected value: 10000, got: " + result.toString(), ((Integer) result).equals(new Integer(10000))); // remove annotation, that was only added for test case EcoreUtil.remove(CompanyPackage.eINSTANCE.getDepartment_Budget().getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI)); } @Test public void testValidationDelegate_AST_Usage() { Department dep = CompanyFactory.eINSTANCE.createDepartment(); Division div = CompanyFactory.eINSTANCE.createDivision(); Employee e1 = CompanyFactory.eINSTANCE.createFreelance(); e1.setName("e1"); e1.setEmployer(dep); dep.setBoss(e1); div.setName("div1"); div.getDepartment().add(dep); dep.setName("dep1"); getFixture().traversalConvertOclAnnotations(CompanyPackage.eINSTANCE); Map<Object, Object> context = new HashMap<Object, Object>(); context.put(Environment.SELF_VARIABLE_NAME, dep); // the expression "not (self.boss.oclIsTypeOf(Freelance))" is validated and should be violated assertFalse( "The NotBossFreelance constraint should be violated.", CompanyValidator.INSTANCE.validateDepartment_NotBossFreelance(dep, Diagnostician.INSTANCE.createDefaultDiagnostic(dep), context)); } @Test public void testHiddenOpposite_AST_Usage() { Department dep = CompanyFactory.eINSTANCE.createDepartment(); Division div = CompanyFactory.eINSTANCE.createDivision(); div.setName("div1"); div.getDepartment().add(dep); dep.setName("dep1"); getFixture().traversalConvertOclAnnotations(CompanyPackage.eINSTANCE); Map<Object, Object> context = new HashMap<Object, Object>(); context.put(Environment.SELF_VARIABLE_NAME, CompanyPackage.eINSTANCE.getDepartment()); // the expression "self.department2division->notEmpty()" is validated and should be valid BasicDiagnostic diagnostic = Diagnostician.INSTANCE.createDefaultDiagnostic(dep); assertTrue("The departmentMustHaveDivision constraint is violated.", CompanyValidator.INSTANCE.validateDepartment_BossHighestSalary(dep, diagnostic, context)); assertEquals(diagnostic.toString(), Diagnostic.OK, diagnostic.getSeverity()); } /** * Tests the ' * {@link de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser#convertOclAnnotation(org.eclipse.emf.ecore.EModelElement) * <em>Convert Ocl Annotation</em>}' operation. * * @see de.hpi.sam.bp2009.solution.oclToAst.EAnnotationOCLParser#convertOclAnnotation(org.eclipse.emf.ecore.EModelElement) */ @Test public void testConvertOclAnnotation__EOperation() { EClass aClass = EcoreFactory.eINSTANCE.createEClass(); aClass.setName("aClass"); EOperation operation = EcoreFactory.eINSTANCE.createEOperation(); operation.setName("doSomething"); operation.setEType(EcorePackage.eINSTANCE.getEInt()); aClass.getEOperations().add(operation); EAnnotation anno = EcoreFactory.eINSTANCE.createEAnnotation(); anno.setSource(OCLDelegateDomain.OCL_DELEGATE_URI); anno.getDetails().put("body", "4"); operation.getEAnnotations().add(anno); getFixture().convertOclAnnotation(operation); // change ocl expression string to ensure usage of already parsed ast anno.getDetails().get(0).setValue("null"); EAnnotation annotation = operation.getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI); annotation.getContents(); OCLExpression expr = (OCLExpression) operation.getEAnnotation(OCLDelegateDomain.OCL_DELEGATE_URI) .getContents().get(0); assertTrue(expr instanceof IntegerLiteralExp); OCL ocl = org.eclipse.ocl.examples.impactanalyzer.util.OCL.newInstance(); Object result = ocl.evaluate(operation, expr); assertTrue("Expected value: '4', got: " + result.toString(), "4".equals(result.toString())); } /** * Benchmark test comparing the time consumption using {@link EcoreEnvironment#getDefinition(Object)} to get the body condition * of an operation body defined by an {@link OCLExpression} with stereotype <blockquote>body</blockquote> and if no body expression * is returned, {@link EcoreEnvironment#getBodyCondition(EOperation)} is called to get the body expression instead of * using {@link EcoreEnvironment#getBodyCondition(EOperation)} first. */ @Test @Ignore public void testOperationBodyResolvingPerformance() { EOperation op = CompanyPackage.eINSTANCE.getDepartment().getEAllOperations().get(0); Constraint con = null; Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env = OCL.newInstance().getEnvironment(); //ensure all constraints got already parsed getFixture().traversalConvertOclAnnotations(CompanyPackage.eINSTANCE); for(int j = 10; j > 0; j--){ //looking up a constraint with stereotype body in getDefinition() first and after failing //usage of getBodyCondition() to resolve the operation's body expression. double beforeBody = System.nanoTime(); for(int i = 20; i > 0; i--){ con = getDefinitionOrBodyConstraint(op, env); } double afterBody = System.nanoTime(); assertNotNull(con); con.setStereotype(UMLReflection.DEFINITION); //looking up a constraint with stereotype definition in getDefinition() should be successful. double beforeDef = System.nanoTime(); for(int i = 20; i > 0; i--){ con = getDefinitionOrBodyConstraint(op, env); } double afterDef = System.nanoTime(); assertNotNull(con); con.setStereotype(UMLReflection.BODY); System.out.println("Time using stereotype 'body' : " + (afterBody-beforeBody) + " ns \nTime using stereotype 'definition': " + (afterDef - beforeDef) + " ns"); System.out.println("Using getDefinition() is " + (afterBody-beforeBody)/(afterDef - beforeDef) + "times faster\n"); } } /** * @param op operation the body expression should be returned for * @param env the OCL Environment * @return a {@link Constraint} representing the body of the given operation. */ private Constraint getDefinitionOrBodyConstraint( EOperation op, Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env) { Constraint con = null; con = env.getDefinition(op); if (con == null){ con = env.getBodyCondition(op); } return con; } @Test public void testAnnotationParsingOfNgpmMetaModel() { EAnnotationOCLParser parser = OclToAstFactory.eINSTANCE.createEAnnotationOCLParser(); //FIXME currently parsing of dataaccess.expressions package fails in test case, but is successful in runtime // parser.traversalConvertOclAnnotations(ExpressionsPackage.eINSTANCE); parser.traversalConvertOclAnnotations(EventsPackage.eINSTANCE); parser.traversalConvertOclAnnotations(ActionsPackage.eINSTANCE); // TODO add all packages printParserErrorMessages(parser); System.err.println("Incomplete! Currently not all packages added."); } private void printParserErrorMessages(EAnnotationOCLParser parser) { for (ErrorMessage e : parser.getAllOccurredErrorMessages()) { if (e.getException() != null) { e.getException().printStackTrace(); } } } } // EAnnotationOCLParserTest