/******************************************************************************* * Copyright (c) 2007, 2015 Borland Software Corporation 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: * Borland Software Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.m2m.tests.qvt.oml; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.URIUtil; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.m2m.internal.qvt.oml.QvtMessage; import org.eclipse.m2m.internal.qvt.oml.common.MDAConstants; import org.eclipse.m2m.internal.qvt.oml.common.io.FileUtil; import org.eclipse.m2m.internal.qvt.oml.compiler.CompiledUnit; import org.eclipse.m2m.internal.qvt.oml.compiler.QVTOCompiler; import org.eclipse.m2m.internal.qvt.oml.compiler.QvtCompilerOptions; import org.eclipse.m2m.internal.qvt.oml.compiler.UnitProxy; import org.eclipse.m2m.internal.qvt.oml.project.builder.WorkspaceUnitResolver; import org.eclipse.m2m.internal.qvt.oml.runtime.project.TransformationUtil; import org.eclipse.m2m.tests.qvt.oml.ParserTests.TestData; import org.eclipse.m2m.tests.qvt.oml.util.ProblemSourceAnnotationHelper; import org.eclipse.m2m.tests.qvt.oml.util.TestUtil; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import junit.framework.TestCase; /** * @author pkobiakov */ @RunWith(Parameterized.class) public class TestQvtParser extends TestCase { public TestQvtParser(TestData data) { super(data.getDir()); myData = data; } @Parameters(name="{0}") public static Iterable<TestData> data() { return Arrays.asList( new TestData[] { TestData.createSourceChecked("abstractout", 3, 0), //$NON-NLS-1$ TestData.createSourceChecked("collectionAssignment", 4, 0), //$NON-NLS-1$ TestData.createSourceChecked("overload_multipleParams", 0, 19), //$NON-NLS-1$ TestData.createSourceChecked("overload_singleParam", 0, 0), //$NON-NLS-1$ TestData.createSourceChecked("mainInLibrary", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("dynamicpackage", 0, 0), //$NON-NLS-1$ TestData.createSourceChecked("importedInstances", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("moduleElementErrorRecovery_265452", 7, 0), //$NON-NLS-1$ TestData.createSourceChecked("unitElementErrorRecovery_264517_1", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("unitElementErrorRecovery_264517_2", 3, 0), //$NON-NLS-1$ TestData.createSourceChecked("unitElementErrorRecovery_264675", 3, 0), //$NON-NLS-1$ TestData.createSourceChecked("nestedPropertiesAssignment_262757", 7, 0), //$NON-NLS-1$ TestData.createSourceChecked("collectionOperationNotFound_224093", 3, 0), //$NON-NLS-1$ TestData.createSourceChecked("deprecated_importLocation", 0, 1), //$NON-NLS-1$ TestData.createSourceChecked("misplacedTopElements", 0, 4), //$NON-NLS-1$ TestData.createSourceChecked("escape_sequences_250630", 4, 0), //$NON-NLS-1$ TestData.createSourceChecked("multiline_strings_262733", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("deprecated_rename", 0, 1), //$NON-NLS-1$ TestData.createSourceChecked("varInitExpWithResult_261623", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("_while_261024", 4, 0), //$NON-NLS-1$ TestData.createSourceChecked("listtype", 7, 0), //$NON-NLS-1$ TestData.createSourceChecked("listtype2", 7, 0), //$NON-NLS-1$ //new TestData("orderedsetdoesnotconformtoset", 1), //$NON-NLS-1$ TestData.createSourceChecked("computeExp_252269", 3, 1), //$NON-NLS-1$ new TestData("implicitsource_ocl_234354", 7, 0), //$NON-NLS-1$ TestData.createSourceChecked("duplicateModelTypeDef", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("blackboxlib_annotation_java", 1, 2), //$NON-NLS-1$ TestData.createSourceChecked("dupImportFileUnit", 0, 1), //$NON-NLS-1$ TestData.createSourceChecked("dupImportLibrary", 0, 1), //$NON-NLS-1$ TestData.createSourceChecked("testmodelparamtype", 3, 0), //$NON-NLS-1$ TestData.createSourceChecked("resolvecond", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("intermPropClash", 9, 0), //$NON-NLS-1$ TestData.createSourceChecked("noClassInImplicitPopulate", 3, 1), //$NON-NLS-1$ TestData.createSourceChecked("parmnamesclash", 22, 1), //$NON-NLS-1$ TestData.createSourceChecked("stdlibElementAsOut", 7, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug2732_wrongcondition", 1, 1), //$NON-NLS-1$ TestData.createSourceChecked("varscope", 10, 0), //$NON-NLS-1$ TestData.createSourceChecked("_while", 12, 0), //$NON-NLS-1$ TestData.createSourceChecked("implicitCallSrc", 16, 6), //$NON-NLS-1$ TestData.createSourceChecked("libraryWithModuleElements", 2, 0), //$NON-NLS-1$ new TestData("assert_log", 0), //$NON-NLS-1$ new TestData("opersignatureparamclash", 1), //$NON-NLS-1$ new TestData("collectreturntype", 0), //$NON-NLS-1$ new TestData("nocollectoncollection", 0), //$NON-NLS-1$ ///Commented out, due to migration to OCL 1.2, TODO - clarify the current error reporting with MDT, seems to be incorrect // new TestData("nonstaticcallinstaticcontext", 1), //$NON-NLS-1$ new TestData("virtrettypemismatch", 1), //$NON-NLS-1$ new TestData("missinglibmmimport", 1), //$NON-NLS-1$ new TestData("noglobalallinstances", 0), //$NON-NLS-1$ new TestData("imp", 0), //$NON-NLS-1$ // TODO: independent parsing for imports new TestData("imp2", 0), //$NON-NLS-1$ new TestData("imp3", 0), //$NON-NLS-1$ TestData.createSourceChecked("impError", 2, 0), //$NON-NLS-1$ new TestData("assignereadonlyprop", 1), //$NON-NLS-1$ new TestData("nonbooleanguard", 1), //$NON-NLS-1$ TestData.createSourceChecked("sameparamname", 2, 0), //$NON-NLS-1$ new TestData("badtype", 1), //$NON-NLS-1$ new TestData("simple", 0), //$NON-NLS-1$ new TestData("selfimport", 1), //$NON-NLS-1$ new TestData("normalimport", 0), //$NON-NLS-1$ new TestData("missingmappingcall", 1), //$NON-NLS-1$ new TestData("missingfeature", 1), //$NON-NLS-1$ new TestData("featuretypemismatch", 1), //$NON-NLS-1$ new TestData("initvariable", 1), //$NON-NLS-1$ new TestData("missingvariablereference", 1), //$NON-NLS-1$ new TestData("optionalout", 0), //$NON-NLS-1$ new TestData("nonassignableout", 1), //$NON-NLS-1$ TestData.createSourceChecked("wrongout", 3, 0), //$NON-NLS-1$ new TestData("outininitvar", 0), //$NON-NLS-1$ new TestData("modifyfeature", 0), //$NON-NLS-1$ new TestData("missingout", 2), //$NON-NLS-1$ new TestData("modifyfeatureerror", 2), //$NON-NLS-1$ new TestData("bodywithsemicolon", 0), //$NON-NLS-1$ new TestData("modifyparam", 0), //$NON-NLS-1$ TestData.createSourceChecked("wrongparamnameinout", 2, 0), //$NON-NLS-1$ new TestData("modifyfeatureininiterror", 2), //$NON-NLS-1$ TestData.createSourceChecked("voidout", 2, 0), //$NON-NLS-1$ new TestData("modifyinparam", 1), //$NON-NLS-1$ new TestData("modifyresult", 0), //$NON-NLS-1$ new TestData("wrongorderininit", 1), //$NON-NLS-1$ new TestData("duplicateinitvariable", 1), //$NON-NLS-1$ TestData.createSourceChecked("missingObjectType", 1, 0), // replaced former 'nestedouterror' //$NON-NLS-1$ new TestData("emptyinit", 0), //$NON-NLS-1$ new TestData("assignresultininit", 0), //$NON-NLS-1$ new TestData("assign_inoutParam", 2), //$NON-NLS-1$ new TestData("assign_inParam", 2), //$NON-NLS-1$ new TestData("assign_varThis", 1), //$NON-NLS-1$ new TestData("errorinexpressionlist", 1), //$NON-NLS-1$ new TestData("largefile", 0), //$NON-NLS-1$ new TestData("calldump", 0), //$NON-NLS-1$ new TestData("missingparamname", 2), //$NON-NLS-1$ new TestData("nameclash", 1), //$NON-NLS-1$ new TestData("emptymodule", 0), //$NON-NLS-1$ new TestData("props", 0), //$NON-NLS-1$ new TestData("duplicatelocalproperty", 1), //$NON-NLS-1$ new TestData("wrongorderinproperty", 1), //$NON-NLS-1$ new TestData("implicitpopulation", 0), //$NON-NLS-1$ new TestData("implicitpopulationwithinit", 0), //$NON-NLS-1$ new TestData("mapkeyword", 0), //$NON-NLS-1$ new TestData("endsectfull", 0), //$NON-NLS-1$ new TestData("endsectimplicitpopulation", 0), //$NON-NLS-1$ new TestData("endsectimplicitpopulationnoinit", 0), //$NON-NLS-1$ new TestData("endsectinitnopopulation", 0), //$NON-NLS-1$ new TestData("endsectonly", 0), //$NON-NLS-1$ new TestData("endsectpopulationnoinit", 0), //$NON-NLS-1$ new TestData("configpropstype", 0), //$NON-NLS-1$ new TestData("mm_header1", 1), //$NON-NLS-1$ new TestData("mm_header2", 1), //$NON-NLS-1$ new TestData("mm_header3", 1), //$NON-NLS-1$ new TestData("mm_header4", 1), //$NON-NLS-1$ new TestData("mm_header5", 2), //$NON-NLS-1$ new TestData("mm_header6", 1), //$NON-NLS-1$ new TestData("mm_header7", 1), //$NON-NLS-1$ new TestData("entryOpDupl", 1), //$NON-NLS-1$ new TestData("resolveIn_ambiguity", 1), //$NON-NLS-1$ new TestData("bug205303_2", 0), //$NON-NLS-1$ TestData.createSourceChecked("bug325192", 8, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug268636", 5, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug272869", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug413130", 0, 1), //$NON-NLS-1$ TestData.createSourceChecked("bug404647_2", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug414363", 0, 28), //$NON-NLS-1$ TestData.createSourceChecked("bug401521", 2, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug414616", 2, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug419299", 8, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug414619", 0, 5), //$NON-NLS-1$ TestData.createSourceChecked("bug415024", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug413391", 10, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug424912", 0, 6), //$NON-NLS-1$ TestData.createSourceChecked("bug289982_ambiguousLib", 0, 1), //$NON-NLS-1$ TestData.createSourceChecked("bug289982_undefinedLib", 0, 1), //$NON-NLS-1$ TestData.createSourceChecked("bug289982_validation", 7, 7), //$NON-NLS-1$ TestData.createSourceChecked("bug424584", 11, 0), //$NON-NLS-1$ new TestData("bug428028", 0), //$NON-NLS-1$ TestData.createSourceChecked("bug425634", 0, 6), //$NON-NLS-1$ new TestData("bug433585", 0), //$NON-NLS-1$ new TestData("bug438038", 0), //$NON-NLS-1$ TestData.createSourceChecked("bug446375", 2, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug468303", 0, 1), //$NON-NLS-1$ TestData.createSourceChecked("bug477331", 2, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug483290", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug487299", 0, 2), //$NON-NLS-1$ new TestData("bug486810", 0), //$NON-NLS-1$ TestData.createSourceChecked("bug475907", 1, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug484020", 14, 0), //$NON-NLS-1$ TestData.createSourceChecked("bug473151", 0, 5), //$NON-NLS-1$ new TestData("bug488742", 0), //$NON-NLS-1$ TestData.createSourceChecked("bug490424", 4, 0).includeMetamodel("test1.ecore"), //$NON-NLS-1$ //$NON-NLS-2$ TestData.createSourceChecked("bug496181", 0, 3), //$NON-NLS-1$ } ); } protected CompiledUnit[] getCompiledResults() { return myCompiled; } @Override @Before public void setUp() throws Exception { TestUtil.turnOffAutoBuilding(); String name = "ParserTest"; //$NON-NLS-1$ myProject = TestProject.getExistingProject(name); if(myProject == null) { myProject = new TestProject(name, new String[] {}, 0); } } @Override @After public void tearDown() throws Exception { myCompiled = null; File destinationFolder = getDestinationFolder(); if (destinationFolder.exists()) { FileUtil.delete(destinationFolder); } } public TestProject getTestProject() { return myProject; } @Override @Test public void runTest() throws Exception { copyData("sources/" + myData.getDir(), "parserTestData/sources/" + myData.getDir()); //$NON-NLS-1$ //$NON-NLS-2$ final File folder = getDestinationFolder(); assertTrue("Invalid folder " + folder, folder.exists() && folder.isDirectory()); //$NON-NLS-1$ resSet = TestUtil.getMetamodelResolutionRS(new ResourceSetImpl(), myData.getMetamodels(), new TestUtil.UriProvider() { public URI getModelUri(String model) { String absolutePath = getFile(folder, model).getAbsolutePath(); return URI.createFileURI(absolutePath); } }); myCompiled = compile(folder); assertTrue("No results", myCompiled.length > 0); //$NON-NLS-1$ boolean collectOnlyCSTProblems = myData.usesSourceAnnotations(); List<QvtMessage> allErrors = getAllErrors(myCompiled, collectOnlyCSTProblems); assertEquals("Wrong error count for '" + folder.getName() + "', error(s)=" + allErrors, myData.getErrCount(), allErrors.size()); //$NON-NLS-1$ //$NON-NLS-2$ if (myData.getWarnCount() != -1) { List<QvtMessage> allWarnings = getAllWarnings(myCompiled, collectOnlyCSTProblems); assertEquals("Wrong warning count for '" + folder.getName() + "', warning(s)=" + allWarnings, myData.getWarnCount(), allWarnings.size()); //$NON-NLS-1$ //$NON-NLS-2$ } // check the AST is consistent for (CompiledUnit compilationResult : myCompiled) { if(compilationResult.getErrors().size() == 0) { TestUtil.assertAllPersistableAST(compilationResult); } } // if(myData.usesSourceAnnotations()) { Set<ProblemSourceAnnotationHelper> helpers = new HashSet<ProblemSourceAnnotationHelper>(); for (CompiledUnit compilationResult : myCompiled) { doCompiledUnitCheck(compilationResult, helpers); } // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=458233 // // int expectedProblemCount = myData.getAllProblemsCount(); // int foundProblemCount = 0; // for (ProblemSourceAnnotationHelper nextHelper : helpers) { // foundProblemCount += nextHelper.getProblemsMap().size(); // } // // if (expectedProblemCount >= 0) { // TestCase.assertEquals(expectedProblemCount, foundProblemCount); // } } } protected File getDestinationFolder() { return new File(myProject.getProject().getLocation().toString() + "/sources/" + myData.getDir()); } private void doCompiledUnitCheck(CompiledUnit module, Set<ProblemSourceAnnotationHelper> annotationCollector) { if(!MDAConstants.QVTO_FILE_EXTENSION.equals(module.getURI().fileExtension())) { // check only .qvto file as these have CST stream return; } ProblemSourceAnnotationHelper helper = ProblemSourceAnnotationHelper .assertCompilationProblemMatchExpectedAnnotations(module); annotationCollector.add(helper); for (CompiledUnit importedModule : module.getCompiledImports()) { if (!annotationCollector.contains(importedModule)) { doCompiledUnitCheck(importedModule, annotationCollector); } } } static class CompositeException extends Exception { private static final long serialVersionUID = -1045874581781288741L; public CompositeException(String message, List<Throwable> exceptions) { super(message); myExceptions = exceptions; } @Override public String toString() { StringBuffer s = new StringBuffer(); s.append(super.toString()); for(Throwable t : myExceptions) { StringWriter trace = new StringWriter(); t.printStackTrace(new PrintWriter(trace)); s.append("\n" + trace.toString()); //$NON-NLS-1$ } return s.toString(); } private final List<Throwable> myExceptions; } private List<QvtMessage> getAllErrors(CompiledUnit[] compiled, boolean concreteSyntaxOnly) { List<QvtMessage> errors = new ArrayList<QvtMessage>(); for (CompiledUnit compilationResult : compiled) { TransformationUtil.getErrors(compilationResult, errors, concreteSyntaxOnly); } return errors; } private List<QvtMessage> getAllWarnings(CompiledUnit[] compiled, boolean concreteSyntaxOnly) { List<QvtMessage> warnings = new ArrayList<QvtMessage>(); for (CompiledUnit compilationResult : compiled) { TransformationUtil.getWarnings(compilationResult, warnings, concreteSyntaxOnly); } return warnings; } private CompiledUnit[] compile(File folder) throws Exception { final String topName = folder.getName() + MDAConstants.QVTO_FILE_EXTENSION_WITH_DOT; getFile(folder, topName); WorkspaceUnitResolver resolver = new WorkspaceUnitResolver(Collections.singletonList(getIFolder(folder))); QVTOCompiler compiler = QVTOCompiler.createCompiler(resSet.getPackageRegistry()); QvtCompilerOptions options = new QvtCompilerOptions(); options.setGenerateCompletionData(false); UnitProxy unit = resolver.resolveUnit(folder.getName()); return new CompiledUnit[] { compiler.compile(unit, options, null) }; } private static File getFile(File folder, final String expectedName) { File file = new File(folder, expectedName); assertTrue("Invalid file: " + file, file.exists() && file.isFile()); //$NON-NLS-1$ return file; } private IContainer getIFolder(File folderUnderWorkspace) throws MalformedURLException, URISyntaxException { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IPath location = new Path(folderUnderWorkspace.getAbsolutePath()); IContainer[] containers = workspace.getRoot().findContainersForLocationURI(URIUtil.toURI(location.makeAbsolute().toFile().toURI().toURL())); if(containers == null || containers.length != 1 || containers[0] instanceof IFolder == false) { throw new RuntimeException("Folder not found: " + folderUnderWorkspace); //$NON-NLS-1$ } return (IFolder)containers[0]; } private void copyData(String destPath, String srcPath) throws Exception { File sourceFolder = TestUtil.getPluginRelativeFolder(srcPath); File destFolder = new File(myProject.getProject().getLocation().toString() + "/" + destPath); //$NON-NLS-1$ destFolder.mkdirs(); FileUtil.copyFolder(sourceFolder, destFolder); myProject.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); } private final TestData myData; private TestProject myProject; private CompiledUnit[] myCompiled; private ResourceSet resSet; }