de.monticore.codegen.GeneratorTest.java Source code

Java tutorial

Introduction

Here is the source code for de.monticore.codegen.GeneratorTest.java

Source

/*
 * ******************************************************************************
 * MontiCore Language Workbench
 * Copyright (c) 2015, MontiCore, All rights reserved.
 *
 * This project is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this project. If not, see <http://www.gnu.org/licenses/>.
 * ******************************************************************************
 */

package de.monticore.codegen;

import static org.junit.Assert.assertTrue;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

import org.apache.commons.io.FileUtils;

import com.google.common.collect.Lists;

import de.monticore.MontiCoreConfiguration;
import de.se_rwth.commons.logging.Log;

/**
 * TODO: Write me!
 *
 * @author (last commit) $Author$
 * @version $Revision$, $Date$
 */
public abstract class GeneratorTest {

    /**
     * Parent folder for the generated code
     */
    protected static final String OUTPUT_FOLDER = "target/generated-sources/monticore/codetocompile";

    protected static final String GRAMMAR_EXTENSION = ".mc4";

    /**
     * Base generator arguments
     */
    private List<String> generatorArguments = Lists.newArrayList(
            getConfigProperty(MontiCoreConfiguration.Options.MODELPATH.toString()), "src/test/resources",
            getConfigProperty(MontiCoreConfiguration.Options.OUT.toString()), OUTPUT_FOLDER,
            getConfigProperty(MontiCoreConfiguration.Options.HANDCODEDPATH.toString()), "src/test/resources");

    protected static final String LOG = "GeneratorTest";

    /**
     * Generated source code using the generator which has to be tested
     * 
     * @param model
     */
    protected abstract void doGenerate(String model);

    /**
     * Gets path to the generated code for the given model
     * 
     * @param model
     * @return path to the generated code
     */
    protected abstract Path getPathToGeneratedCode(String model);

    /**
     * Test generation of code for a correct model 
     * 
     * @param model
     */
    public abstract void testCorrect(String model);

    public void testCorrect(String model, boolean compileGeneratedCode) {
        if (compileGeneratedCode) {
            testCorrect(model);
        } else {
            doGenerate(model);
        }
    }

    public void testCorrect(String model, Path pathToCompile) {
        doGenerate(model);
        doCompile(model, pathToCompile); // TODO: fix compile path of visitor
    }

    /**
     * TODO: extend path to compile
     * 
     * @param model
     * @param pathToCompile
     */
    protected void doCompile(String model, Path pathToCompile) {
        boolean compilationSuccess = compile(pathToCompile);
        assertTrue("There are compile errors in generated code for the model: " + model, compilationSuccess);
    }

    /**
     * Test generation of code for a false model TODO: Write me!
     * 
     * @param model
     * @param errorsNumber expected errors
     */
    protected void testFalse(String model, int errorsNumber) {
        // implement
    }

    /**
     * Compiles the files in the given directory, printing errors to the console
     * if any occur.
     * 
     * @param sourceCodePath the source directory to be compiled
     * @return true if the compilation succeeded
     */
    protected boolean compile(Path sourceCodePath) {
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
        boolean compilationSuccess = false;
        Optional<CompilationTask> task = setupCompilation(sourceCodePath, diagnostics);
        if (!task.isPresent()) {
            return compilationSuccess;
        }
        compilationSuccess = task.get().call();
        if (!compilationSuccess) {
            for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                Log.error(diagnostic.toString());
            }
        }
        return compilationSuccess;
    }

    /**
     * Instantiates all the parameters required for a CompilationTask and returns
     * the finished task.
     * 
     * @param sourceCodePath the source directory to be compiled
     * @param diagnostics a bin for any error messages that may be generated by
     * the compiler
     * @return the compilationtask that will compile any entries in the given
     * directory
     */
    protected Optional<CompilationTask> setupCompilation(Path sourceCodePath,
            DiagnosticCollector<JavaFileObject> diagnostics) {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        if (compiler != null) {
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
            // set compiler's classpath to be same as the runtime's
            String sPath = Paths.get("target/generated-sources/monticore/codetocompile").toAbsolutePath()
                    .toString();
            List<String> optionList = Lists.newArrayList("-classpath",
                    System.getProperty("java.class.path") + File.pathSeparator + sPath, "-sourcepath", sPath);
            // System.out.println("Options" + optionList);
            Iterable<? extends JavaFileObject> javaFileObjects = getJavaFileObjects(sourceCodePath, fileManager);
            // System.out.println("Java files" + javaFileObjects);
            return Optional.of(compiler.getTask(null, fileManager, diagnostics, optionList, null, javaFileObjects));
        }
        return Optional.empty();
    }

    /**
     * Creates an Iterable over all the JavaFileObjects contained in a given
     * directory.
     * 
     * @param sourceCodePath the directory from which JavaFileObjects are to be
     * retrieved
     * @param fileManager the StandardJavaFileManager to be used for the
     * JavaFileObject creation
     * @return the JavaFileObjects contained in the given directory
     */
    protected Iterable<? extends JavaFileObject> getJavaFileObjects(Path sourceCodePath,
            StandardJavaFileManager fileManager) {
        Collection<File> files = FileUtils.listFiles(sourceCodePath.toFile(), new String[] { "java" }, true);
        return fileManager.getJavaFileObjects(files.toArray(new File[files.size()]));
    }

    protected void dependencies(String... dependencies) {
        for (String dependency : dependencies) {
            if (!Files.exists(getPathToGeneratedCode(dependency))) {
                doGenerate(dependency);
                compile(getPathToGeneratedCode(dependency));
            }
        }
    }

    /**
     * @return generatorArguments
     */
    public List<String> getGeneratorArguments() {
        return this.generatorArguments;
    }

    /**
     * @param generatorArguments the generatorArguments to set
     */
    public void setGeneratorArguments(List<String> generatorArguments) {
        this.generatorArguments = generatorArguments;
    }

    public static String getConfigProperty(String property) {
        return new StringBuilder("-").append(property).toString();
    }

}