blob: b95cefd2ce48d2ea86eba5ebda80c51689131357 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2019 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.examples.test.xtext;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EObjectValidator;
import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
import org.eclipse.emf.examples.extlibrary.Book;
import org.eclipse.emf.examples.extlibrary.BookCategory;
import org.eclipse.emf.examples.extlibrary.EXTLibraryFactory;
import org.eclipse.emf.examples.extlibrary.EXTLibraryPackage;
import org.eclipse.emf.examples.extlibrary.Library;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.examples.xtext.tests.XtextTestCase;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.internal.labels.LabelSubstitutionLabelProvider;
import org.eclipse.ocl.pivot.resource.ProjectManager;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.OCL;
import org.eclipse.ocl.pivot.utilities.ParserException;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.ocl.pivot.utilities.Query;
import org.eclipse.ocl.pivot.validation.ComposedEValidator;
import org.eclipse.ocl.xtext.completeocl.validation.CompleteOCLEObjectValidator;
/**
* Tests for the OCL delegate implementations.
*/
@SuppressWarnings("null")
public class PivotDocumentationExamples extends XtextTestCase
{
public void debugPrintf(String format, Object... args) {
// System.out.printf(format, args);
}
public InputStream getInputStream(String fileName) throws MalformedURLException, IOException {
URI uri = getTestModelURI(fileName);
URL url = new URL(uri.toString());
return url.openStream();
}
public URI getInputURI(String fileName) throws MalformedURLException, IOException {
return getTestModelURI(fileName);
}
private @NonNull List<Library> getLibraries(ResourceSet resourceSet) {
URI uri = getTestModelURI("models/documentation/PivotDocumentationExamples.extlibrary");
resourceSet.getPackageRegistry().put(EXTLibraryPackage.eNS_URI, EXTLibraryPackage.eINSTANCE);
Resource resource = resourceSet.getResource(uri, true);
@SuppressWarnings("unchecked") List<Library> libraries = (List<Library>)(List<?>)resource.getContents();
return libraries;
}
public Library getLibrary(ResourceSet resourceSet) {
Resource resource = resourceSet.createResource(URI.createURI("test.xmi"));
Library library = EXTLibraryFactory.eINSTANCE.createLibrary();
resource.getContents().add(library);
Book aBook = EXTLibraryFactory.eINSTANCE.createBook();
aBook.setTitle("Bleak House");
library.getBooks().add(aBook);
Book bBook = EXTLibraryFactory.eINSTANCE.createBook();
bBook.setTitle("Bleak House");
library.getBooks().add(bBook);
return library;
}
/*
* This 'test' provides the source text for the 'Parsing Constraints and Queries' example
* in org.eclipse.ocl.doc/doc/6310-pivot-parsing-constraints.textile
*/
public void test_parsingConstraintsExample() throws IOException, ParserException {
{
// create an OCL instance exploiting an externally supplied ResourceSet
ResourceSet myResourceSet = new ResourceSetImpl();
/* ... */
OCL ocl = OCL.newInstance(myResourceSet);
assert (ocl != null) && (myResourceSet != null); /* Suppress the unused variable markers */
}
// create an OCL instance exploiting registered models on the Java classpath
OCL ocl = OCL.newInstance(ProjectManager.CLASS_PATH);
ResourceSet resourceSet = ocl.getResourceSet();
EClass contextEClass = EXTLibraryPackage.Literals.LIBRARY;
ExpressionInOCL invariant = ocl.createInvariant(contextEClass,
"books->forAll(b1, b2 | b1 <> b2 implies b1.title <> b2.title)");
ExpressionInOCL query = ocl.createQuery(contextEClass,
"books->collect(b : Book | b.category)->asSet()");
// 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
EOperation contextEOperation = NameUtil.getENamedElement(
EcorePackage.Literals.EMODEL_ELEMENT.getEOperations(), "getEAnnotation");
ExpressionInOCL body = ocl.createPostcondition(contextEOperation,
"result = self.eAnnotations->any(ann | ann.source = source)");
// define a derivation constraint for the EReference::eReferenceType property
EReference contextEReference = EcorePackage.Literals.EREFERENCE__EREFERENCE_TYPE;
ExpressionInOCL derive = ocl.createQuery(contextEReference,
"self.eType->any(true).oclAsType(EClass)");
// syntax errors such as bad text or semantic errors such as bad names throw a ParserException
try {
ocl.createInvariant(contextEClass, "books->forall(true)");
}
catch (ParserException e) {
/*e.printStackTrace();*/
}
// ensure that resources are released
ocl.dispose();
if ((body == derive) && (invariant == query) && (resourceSet != null)) { /* Suppress the unused variable markers */ }
}
/*
* This 'test' provides the source text for the 'Evaluating Constraints and Queries' example
* in org.eclipse.ocl.doc/doc/6315-pivot-evaluating-constraints.textile
*/
public void test_evaluatingConstraintsExample() throws IOException, ParserException {
OCL ocl = OCL.newInstance(OCL.CLASS_PATH);
ResourceSet resourceSet = ocl.getResourceSet();
ExpressionInOCL invariant = ocl.createInvariant(EXTLibraryPackage.Literals.LIBRARY,
"books->forAll(b1, b2 | b1 <> b2 implies b1.title <> b2.title)");
ExpressionInOCL query = ocl.createQuery(EXTLibraryPackage.Literals.LIBRARY,
"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(resourceSet); // hypothetical source of libraries
// only print the set of book categories for valid libraries
for (Library next : libraries) {
if (constraintEval.checkEcore(next)) {
// the OCL result type of our query expression is Set(BookCategory)
@SuppressWarnings("unchecked")
Set<BookCategory> categories = (Set<BookCategory>) queryEval.evaluateUnboxed(next);
debugPrintf("%s: %s%n\n", next.getName(), categories);
}
}
// Check one
// check a single library
Library lib = getLibrary(resourceSet); // hypothetical source of a library
// check whether it satisfies the constraint
debugPrintf("%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.selectEcore(libraries)) {
@SuppressWarnings("unchecked")
Set<BookCategory> categories = (Set<BookCategory>) queryEval.evaluateUnboxed(next);
debugPrintf("%s: %s%n\n", next.getName(), categories);
}
ocl.dispose();
}
/*
* This 'test' provides the source text for the 'Parsing OCL Document' example
* in org.eclipse.ocl.doc/doc/6320-pivot-parsing-documents.textile
*/
public void test_parsingDocumentsExample() throws IOException, ParserException {
OCL ocl1 = OCL.newInstance(OCL.CLASS_PATH);
//-------------------------------------------------------------------------
// The OCL Input
//-------------------------------------------------------------------------
// Create an EPackage.Registry for just the EXTLibraryPackage
EPackage.Registry registry = new EPackageRegistryImpl();
registry.put(EXTLibraryPackage.eNS_URI, EXTLibraryPackage.eINSTANCE);
// Create an OCL that creates a ResourceSet using the minimal EPackage.Registry
OCL ocl = OCL.newInstance(registry);
ResourceSet resourceSet = ocl.getResourceSet();
// get an OCL text file via some hypothetical API
URI uri = getInputURI("/models/documentation/parsingDocumentsExample.ocl");
// parse the contents as an OCL document
Resource asResource = ocl.parse(uri);
// accumulate the document constraints in constraintMap and print all constraints
Map<String, ExpressionInOCL> constraintMap = new HashMap<String, ExpressionInOCL>();
for (TreeIterator<EObject> tit = asResource.getAllContents(); tit.hasNext(); ) {
EObject next = tit.next();
if (next instanceof Constraint) {
Constraint constraint = (Constraint)next;
ExpressionInOCL expressionInOCL = ocl.getSpecification(constraint);
if (expressionInOCL != null) {
String name = constraint.getName();
if (name != null) {
constraintMap.put(name, expressionInOCL);
debugPrintf("%s: %s%n\n", name,
expressionInOCL.getOwnedBody());
}
}
}
}
//-------------------------------------------------------------------------
// Accessing the Constraints
//-------------------------------------------------------------------------
Library library = getLibrary(resourceSet); // get library from a hypothetical source
// use the constraints defined in the OCL document
// use getBooks() from the document in another query to find a book
ExpressionInOCL expression = ocl.createQuery(EXTLibraryPackage.Literals.LIBRARY,
"getBooks('Bleak House')->asSequence()->first()");
Book book = (Book) ocl.evaluate(library, expression);
debugPrintf("Got book: %s%n\n", book);
// use the unique_title constraint to validate the book
boolean isValid = ocl.check(book, constraintMap.get("unique_title"));
debugPrintf("Validate book: %b%n\n", isValid);
//-------------------------------------------------------------------------
// Using all the Constraints to validate a model
//-------------------------------------------------------------------------
// Register an additional EValidator for the Complete OCL document constraints
ComposedEValidator newEValidator = ComposedEValidator.install(EXTLibraryPackage.eINSTANCE);
newEValidator.addChild(new CompleteOCLEObjectValidator(
EXTLibraryPackage.eINSTANCE, uri, ocl.getEnvironmentFactory()));
// Validate the entire Resource containing the library
Resource resource = library.eResource();
MyDiagnostician diagnostician = new MyDiagnostician();
Diagnostic diagnostics = diagnostician.validate(resource);
// Print the diagnostics
if (diagnostics.getSeverity() != Diagnostic.OK) {
String formattedDiagnostics = PivotUtil.formatDiagnostics(diagnostics, "\n");
debugPrintf("Validation: %s\n", formattedDiagnostics);
}
assertEquals(Diagnostic.ERROR, diagnostics.getSeverity());
assertEquals(4, diagnostics.getChildren().size()); // 2 ObjectEValiador missing authors, 2 CompleteOCLEObjectValidator non-unique titles
ocl.dispose();
ocl1.dispose();
}
public class MyDiagnostician extends Diagnostician
{
@Override
public Map<Object, Object> createDefaultContext() {
Map<Object, Object> context = super.createDefaultContext();
context.put(EValidator.SubstitutionLabelProvider.class,
new LabelSubstitutionLabelProvider());
return context;
}
public BasicDiagnostic createDefaultDiagnostic(Resource resource) {
return new BasicDiagnostic(EObjectValidator.DIAGNOSTIC_SOURCE, 0,
EMFEditUIPlugin.INSTANCE.getString(
"_UI_DiagnosisOfNObjects_message", new String[]{"1"}),
new Object[]{resource});
}
public Diagnostic validate(Resource resource) {
BasicDiagnostic diagnostics = createDefaultDiagnostic(resource);
Map<Object, Object> context = createDefaultContext();
for (EObject eObject : resource.getContents()) {
validate(eObject, diagnostics, context);
}
return diagnostics;
}
}
}