| /******************************************************************************* |
| * Copyright (c) 2011, 2018 Willink Transformations 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: |
| * E.D.Willink - Initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ocl.ecore.tests; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.MalformedURLException; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EOperation; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.EcorePackage; |
| import org.eclipse.emf.ecore.impl.EPackageRegistryImpl; |
| import org.eclipse.ocl.OCLInput; |
| import org.eclipse.ocl.ParserException; |
| import org.eclipse.ocl.ecore.Constraint; |
| import org.eclipse.ocl.ecore.EcoreEnvironment; |
| import org.eclipse.ocl.ecore.EcoreEnvironmentFactory; |
| import org.eclipse.ocl.ecore.OCL; |
| import org.eclipse.ocl.ecore.OCL.Query; |
| import org.eclipse.ocl.ecore.opposites.DefaultOppositeEndFinder; |
| import org.eclipse.ocl.ecore.opposites.EcoreEnvironmentFactoryWithHiddenOpposites; |
| import org.eclipse.ocl.ecore.opposites.OppositeEndFinder; |
| import org.eclipse.ocl.ecore.tests.extlibrary.Book; |
| import org.eclipse.ocl.ecore.tests.extlibrary.BookCategory; |
| import org.eclipse.ocl.ecore.tests.extlibrary.EXTLibraryFactory; |
| import org.eclipse.ocl.ecore.tests.extlibrary.EXTLibraryPackage; |
| import org.eclipse.ocl.ecore.tests.extlibrary.Library; |
| import org.eclipse.ocl.expressions.OCLExpression; |
| import org.eclipse.ocl.helper.OCLHelper; |
| |
| |
| |
| /** |
| * Tests for the OCL delegate implementations. |
| */ |
| @SuppressWarnings("nls") |
| public class DocumentationExamples extends AbstractTestSuite |
| { |
| public InputStream getInputStream(String fileName) throws MalformedURLException, IOException { |
| URI uri = getTestModelURI(fileName); |
| return resourceSet.getURIConverter().createInputStream(uri); |
| } |
| |
| private List<Library> getLibraries() { |
| return Collections.emptyList(); |
| } |
| |
| public Library getLibrary() { |
| Library library = EXTLibraryFactory.eINSTANCE.createLibrary(); |
| Book aBook = EXTLibraryFactory.eINSTANCE.createBook(); |
| aBook.setTitle("Bleak House"); |
| library.getBooks().add(aBook); |
| return library; |
| } |
| |
| /* |
| * This 'test' provides the source text for the 'Parsing OCL Document' example |
| * in org.eclipse.ocl.doc/doc/5120-parsing-constraints.textile |
| */ |
| public void test_parsingConstraintsExample() throws IOException, ParserException { |
| // create an OCL instance for Ecore |
| OCL ocl = OCL.newInstance(EcoreEnvironmentFactory.INSTANCE); |
| |
| // create an OCL helper object |
| OCLHelper<EClassifier, EOperation, EStructuralFeature, Constraint> helper = |
| ocl.createOCLHelper(); |
| |
| // set the OCL context classifier |
| helper.setContext(EXTLibraryPackage.Literals.LIBRARY); |
| |
| Constraint invariant = helper.createInvariant( |
| "books->forAll(b1, b2 | b1 <> b2 implies b1.title <> b2.title)"); |
| |
| OCLExpression<EClassifier> query = helper.createQuery( |
| "books->collect(b : Book | b.category)->asSet()"); |
| |
| EOperation oper = null; |
| for (EOperation next : EcorePackage.Literals.EMODEL_ELEMENT.getEOperations()) { |
| if ("getEAnnotation".equals(next.getName())) { |
| oper = next; |
| break; |
| } |
| } |
| |
| // define a post-condition specifying the value of EModelElement::getEAnnotation(EString). |
| // This operation environment includes variables representing the operation |
| // parameters (in this case, only "source : String") and the operation result |
| helper.setOperationContext(EcorePackage.Literals.ECLASS, oper); |
| Constraint body = helper.createPostcondition( |
| "result = self.eAnnotations->any(ann | ann.source = source)"); |
| |
| // define a derivation constraint for the EReference::eReferenceType property |
| helper.setAttributeContext( |
| EcorePackage.Literals.EREFERENCE, |
| EcorePackage.Literals.EREFERENCE__EREFERENCE_TYPE); |
| Constraint derive = helper.createDerivedValueExpression( |
| "self.eType->any(true).oclAsType(EClass)"); |
| |
| if ((body == derive) && (invariant == query)) { /* the yellow markers go away */ } |
| } |
| |
| |
| /* |
| * This 'test' provides the source text for the 'Parsing OCL Document' example |
| * in org.eclipse.ocl.doc/doc/5115-evaluating-constraints.textile |
| */ |
| public void test_evaluatingConstraintsExample() throws IOException, ParserException { |
| OCL ocl = OCL.newInstance(EcoreEnvironmentFactory.INSTANCE); |
| OCLHelper<EClassifier, ?, ?, Constraint> helper = ocl.createOCLHelper(); |
| |
| helper.setContext(EXTLibraryPackage.Literals.LIBRARY); |
| Constraint invariant = helper.createInvariant( |
| "books->forAll(b1, b2 | b1 <> b2 implies b1.title <> b2.title)"); |
| OCLExpression<EClassifier> query = helper.createQuery( |
| "books->collect(b : Book | b.category)->asSet()"); |
| |
| // create a Query to evaluate our query expression |
| Query queryEval = ocl.createQuery(query); |
| |
| // create another to check our constraint |
| Query constraintEval = ocl.createQuery(invariant); |
| |
| List<Library> libraries = getLibraries(); // hypothetical source of libraries |
| |
| // only print the set of book categories for valid libraries |
| for (Library next : libraries) { |
| if (constraintEval.check(next)) { |
| // the OCL result type of our query expression is Set(BookCategory) |
| @SuppressWarnings("unchecked") |
| Set<BookCategory> categories = (Set<BookCategory>) queryEval.evaluate(next); |
| |
| if (!noDebug) System.out.printf("%s: %s\n", next.getName(), categories); |
| } |
| } |
| |
| // Check one |
| |
| // check a single library |
| Library lib = getLibrary(); // hypothetical source of a library |
| |
| // check whether it satisfies the constraint |
| if (!noDebug) System.out.printf("%s valid: %b\n", lib.getName(), ocl.check(lib, invariant)); |
| |
| // MoreSuccinct |
| |
| // only print the set of book categories for valid libraries |
| for (Library next : constraintEval.select(libraries)) { |
| @SuppressWarnings("unchecked") |
| Set<BookCategory> categories = (Set<BookCategory>) queryEval.evaluate(next); |
| |
| if (!noDebug) System.out.printf("%s: %s%n", next.getName(), categories); |
| } |
| } |
| |
| /* |
| * This 'test' provides the source text for the 'Parsing OCL Document' example |
| * in org.eclipse.ocl.doc/doc/5120-parsing-documents.textile |
| */ |
| public void test_parsingDocumentsExample() throws IOException, ParserException { |
| //------------------------------------------------------------------------- |
| // The OCL Input |
| //------------------------------------------------------------------------- |
| EPackage.Registry registry = new EPackageRegistryImpl(); |
| registry.put(EXTLibraryPackage.eNS_URI, EXTLibraryPackage.eINSTANCE); |
| EcoreEnvironmentFactory environmentFactory = new EcoreEnvironmentFactory(registry); |
| OCL ocl = OCL.newInstance(environmentFactory); |
| |
| // get an OCL text file via some hypothetical API |
| InputStream in = getInputStream("/model/parsingDocumentsExample.ocl"); |
| |
| Map<String, Constraint> constraintMap = new HashMap<String, Constraint>(); |
| |
| // parse the contents as an OCL document |
| try { |
| OCLInput document = new OCLInput(in); |
| |
| List<Constraint> constraints = ocl.parse(document); |
| for (Constraint next : constraints) { |
| constraintMap.put(next.getName(), next); |
| |
| OCLExpression<EClassifier> body = next.getSpecification().getBodyExpression(); |
| if (!noDebug) System.out.printf("%s: %s%n", next.getName(), body); |
| } |
| } finally { |
| in.close(); |
| } |
| //------------------------------------------------------------------------- |
| // Accessing the Constraints |
| //------------------------------------------------------------------------- |
| Library library = getLibrary(); // get library from a hypothetical source |
| |
| OCLHelper<EClassifier, ?, ?, Constraint> helper = ocl.createOCLHelper(); |
| |
| // use the constraints defined in the OCL document |
| |
| // use the getBooks() additional operation to find a book |
| helper.setContext(EXTLibraryPackage.Literals.LIBRARY); |
| OCLExpression<EClassifier> query = helper.createQuery( |
| "getBooks('Bleak House')->asSequence()->first()"); |
| |
| Book book = (Book) ocl.evaluate(library, query); |
| if (!noDebug) System.out.printf("Got book: %s%n", book); |
| |
| // use the unique_title constraint to validate the book |
| if (!noDebug) System.out.printf("Validate book: %b%n", |
| ocl.check(book, constraintMap.get("unique_title"))); |
| } |
| |
| private class MyOppositeEndFinder extends DefaultOppositeEndFinder { |
| public MyOppositeEndFinder() { |
| super(EPackage.Registry.INSTANCE); |
| } |
| } |
| |
| /** |
| * The following is documented in doc/org.eclipse.ocl.doc/doc/5160-customization.textile |
| * in section "Customizing Hidden Opposite Lookup and Navigation" |
| */ |
| public void testCustomizingOppositeEndFinder() { |
| OppositeEndFinder oef = new MyOppositeEndFinder(); |
| OCL ocl = OCL.newInstance(new EcoreEnvironmentFactoryWithHiddenOpposites( |
| EPackage.Registry.INSTANCE, oef)); |
| assertSame(oef, ((EcoreEnvironment) ocl.getEnvironment()).getOppositeEndFinder()); |
| } |
| } |