package org.dresdenocl.tracer.test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.custommonkey.xmlunit.Diff; import org.dresdenocl.facade.Ocl2ForEclipseFacade; import org.dresdenocl.model.IModel; import org.dresdenocl.model.ModelAccessException; import org.dresdenocl.modelinstance.IModelInstance; import org.dresdenocl.modelinstancetype.types.IModelInstanceObject; import org.dresdenocl.parser.ParseException; import org.dresdenocl.pivotmodel.Constraint; import org.dresdenocl.pivotmodel.Type; import org.dresdenocl.testsuite._abstract.AbstractDresdenOclTest; import org.dresdenocl.tracer.tracermodel.TracerItem; import org.dresdenocl.tracer.tracermodel.TracerRoot; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; /** * Abstract test class for Dresden OCL Tracer tests. * * @author Lars Schuetze * */ public class AbstractTracerTest extends AbstractDresdenOclTest { /** The name of a test {@link IModelInstance} for this test suite. */ protected static final String INSTANCE1_PATH = "bin/package1/Instance1.class"; /** The name of a test {@link IModelInstance} for this test suite. */ protected static final String INSTANCE2_PATH = "bin/package1/Instance2.class"; /** The name of a test {@link IModelInstance} for this test suite. */ protected static final String INSTANCE3_PATH = "bin/package1/Instance3.class"; /** The name of a test {@link IModelInstance} for this test suite. */ protected static final String INSTANCE4_PATH = "bin/package1/Instance4.class"; /** The name of a test {@link IModelInstance} for this test suite. */ protected static final String INSTANCE5_PATH = "bin/package1/Instance5.class"; /** The name of a test {@link IModel} for this test suite. */ protected static final String MODEL1_PATH = "bin/package1/Model1.class"; /** The name of a test {@link IModel} for this test suite. */ protected static final String MODEL2_PATH = "bin/package1/Model2.class"; /** The {@link IModel} under test. */ private static IModel modelUnderTest; /** This cache maps the path of a model instance file to a model instance. */ private static Map<String, IModelInstance> modelInstanceCache; /** This cache maps the path of a model file to a model. */ private static Map<String, IModel> modelCache; /** This cache maps the path of a constraint file to a list of constraints. */ private static Map<String, List<Constraint>> constraintCache; /** This is the {@link DocumentBuilder} for the XMLs processed. */ private static DocumentBuilder db; /** The {@link File} where the regression XMLs are loaded into. */ protected static File regressionFile; /** The {@link Document} where the temporary XMLs are stored in. */ protected static Document temporaryDocument; /** Setup method that should be called by concrete test classes. */ public static void setUp() throws Exception { AbstractDresdenOclTest.setUp(); /* Activate the Tracer */ /* TODO: make the tests work again * org.junit.Assert.assertNotNull(org.dresdenocl.tracer.TracerPlugin .getInterpreterTraceListener()); */ /* Set up all caches */ modelInstanceCache = new WeakHashMap<String, IModelInstance>(); modelCache = new WeakHashMap<String, IModel>(); constraintCache = new WeakHashMap<String, List<Constraint>>(); db = getDocumentBuilder(); } protected static DocumentBuilder getDocumentBuilder() throws ParserConfigurationException { if (db == null) { /* Set up the builder for the XML documents */ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); dbf.setCoalescing(true); dbf.setIgnoringComments(true); dbf.setIgnoringElementContentWhitespace(true); db = dbf.newDocumentBuilder(); } return db; } /** TeardDown method that should be called by concrete test classes. */ public static void tearDown() { /* nullify all class variables */ modelUnderTest = null; db = null; regressionFile = null; temporaryDocument = null; /* nullify all caches */ modelInstanceCache = null; modelCache = null; constraintCache = null; } /** * <p> * Saves the given {@link TracerRoot} into a file with the given * filename * </p> * * @param root * the {@link TracerRoot} to be serialized * @return * @throws ParserConfigurationException * @throws TransformerException * @throws IOException */ protected static Document serializeTracerRoot(TracerRoot root) throws ParserConfigurationException, TransformerException { Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); /* Process the root into XML */ Element rootElement = document.createElement("TracerItems"); document.appendChild(rootElement); for (TracerItem rootItem : root.getRootItems()) { processAllChilds(rootElement, rootItem, document); } return document; } /** * <p> * Process all children of a given TracerItem to be serialized into a XML * file. * </p> * * @param rootElement * the root Element of the XML document * @param item * the {@link TracerItem} to be processed. * @param document * the {@link Document} to be written. */ private static void processAllChilds(Element rootElement, TracerItem item, Document document) { Element e = document.createElement("TracerItem"); rootElement.appendChild(e); e.setAttribute("expression", item.getExpression().toString()); e.setAttribute("result", item.getResult().toString()); /* Call this function for all children recursively */ for (TracerItem child : item.getChildren()) { processAllChilds(e, child, document); } } /** * <p> * Compares two given XML files * </p> * * @param regressionFile * the regression XML file * @param testDocument * the {@link Document} to be compared * @return whether the regression file and the test document are the same * @throws SAXException * @throws IOException */ protected static boolean compareXmlFiles(File regressionFile, Document testDocument) throws SAXException, IOException { org.junit.Assert.assertTrue(regressionFile != null); org.junit.Assert.assertTrue(testDocument != null); org.junit.Assert.assertTrue(regressionFile.exists()); Document regressionDocument; regressionDocument = db.parse(regressionFile); Diff diff = new Diff(regressionDocument, testDocument); //System.out.println(diff.toString()); return diff.similar(); } /** * <p> * Load and interpret the constraints on the model instances of the model and * returns the trace. * </p> * * @param modelFilePath * the path to the model file. * @param modelInstanceFilePath * the path to the model instance file. * @param constraintFilePath * the path to the constraint file. * @param objectTypeNames * the names of the object types in the model instance. * @param modelType * the type of the model * @param modelInstanceType * the type of the model instance * @return the resulting trace * @throws Exception */ protected static TracerRoot getTraceFromInterpretation(String modelFilePath, String modelInstanceFilePath, String constraintFilePath, String bundleId, String[] objectTypeNames, String modelType, String modelInstanceType) throws Exception { assertNotNull(modelFilePath); assertNotNull(modelInstanceFilePath); assertNotNull(constraintFilePath); assertNotNull(bundleId); assertTrue(objectTypeNames.length >= 1); assertNotNull(modelType); assertNotNull(modelInstanceType); /* Clear the tracer */ //TODO: rework //TracerPlugin.getInterpreterTraceListener().interpretationCleared(); modelUnderTest = getModel(modelFilePath, modelType, bundleId); assertNotNull(modelUnderTest); /* Find the type for the IMIObjects to test. */ Type objectType; objectType = modelUnderTest.findType(Arrays.asList(objectTypeNames)); assertNotNull(objectType); /* Get all constraints */ List<Constraint> constraints; constraints = getConstraints(constraintFilePath, bundleId); /* Load or get the instance. */ IModelInstance modelInstance; modelInstance = getModelInstance(modelInstanceFilePath, modelInstanceType, bundleId); /* Find the IMIObject(s) to test. */ Set<IModelInstanceObject> imiObjects; imiObjects = modelInstance.getAllInstances(objectType); assertNotNull(imiObjects); /* Send the constraints to the interpreter */ for (IModelInstanceObject imiObject : imiObjects) { Ocl2ForEclipseFacade.interpretConstraints(constraints, modelInstance, imiObject); } // end for. modelUnderTest.removeConstraints(constraints); TracerRoot tracedRoot = null; //TODO: rework //tracedRoot = TracerPlugin.getInterpreterTraceListener().getCurrentRoot(); assertNotNull(tracedRoot); //TODO: rework //assertTrue(tracedRoot.getRootItems().size() >= 1); return tracedRoot; } private static IModel getModel(String modelFilePath, String modelType, String bundleId) throws ModelAccessException { IModel model = modelCache.get(modelFilePath); /* check if the model has been cached before */ if (model != null) { return model; } File modelFile; /* Load the model */ try { modelFile = AbstractTracerTest.getFile(modelFilePath, bundleId); } catch (IOException e) { throw new ModelAccessException(e.getMessage(), e); } model = Ocl2ForEclipseFacade.getModel(modelFile, modelType); /* cache the model */ modelCache.put(modelFilePath, model); return model; } private static IModelInstance getModelInstance(String modelInstanceFilePath, String modelInstanceType, String bundleId) throws IllegalArgumentException, ModelAccessException { IModelInstance modelInstance = modelInstanceCache.get(modelInstanceFilePath); /* check if the model has been cached before */ if (modelInstance != null) { return modelInstance; } File modelInstanceFile; try { modelInstanceFile = AbstractTracerTest.getFile(modelInstanceFilePath, bundleId); } catch (IOException e) { throw new ModelAccessException(e.getMessage(), e); } modelInstance = Ocl2ForEclipseFacade.getModelInstance(modelInstanceFile, modelUnderTest, modelInstanceType); assertNotNull(modelInstance); /* Cache the model instance */ modelInstanceCache.put(modelInstanceFilePath, modelInstance); return modelInstance; } private static List<Constraint> getConstraints(String constraintFilePath, String bundleId) throws ModelAccessException, IllegalArgumentException, ParseException { List<Constraint> constraints = constraintCache.get(constraintFilePath); /* check if the constraints has been cached before */ if (constraints != null) { return constraints; } File constraintFile; try { constraintFile = AbstractTracerTest.getFile(constraintFilePath, bundleId); } catch (IOException e) { throw new ModelAccessException(e.getMessage(), e); } assertNotNull(constraintFile); assertTrue(constraintFile.canRead()); constraints = Ocl2ForEclipseFacade.parseConstraints(constraintFile, modelUnderTest, true); assertNotNull(constraints); assertTrue(constraints.size() >= 1); /* cache the constraints */ constraintCache.put(constraintFilePath, constraints); return constraints; } }