/* * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.eclipse.jdt.core.groovy.tests.builder; import static org.eclipse.jdt.core.tests.util.GroovyUtils.isAtLeastGroovy; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.jdt.groovy.model.GroovyCompilationUnit; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.core.groovy.tests.ReconcilerUtils; import org.eclipse.jdt.core.tests.util.Util; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.junit.Test; /** * These tests are about building and working with complete projects. * <p> * To add a new project: * <ul> * <li>Create a folder named after the project in the testdata folder * <li>In there create a source.zip containing your source code (call it * source.zip) * <li>Create a folder 'lib' and copy all the dependencies the source has into * there (as jar files) * <li>It can be helpful to also create a readme.txt at the project level * describing where the source is from, what commit it is (e.g. git commit tag) * </ul> * <p> * Once setup like that it is usable for testing here. */ public final class FullProjectTests extends BuilderTestSuite { private static void assertDoesNotContainMethod(ClassNode cn, String methodname) { for (MethodNode mn : cn.getMethods()) { if (mn.getName().equals(methodname)) { fail("Found method named '" + methodname + "' in class '" + cn.getName() + "'"); } } } private static void assertContainsMethod(ClassNode cn, String methodname) { for (MethodNode mn : cn.getMethods()) { if (mn.getName().equals(methodname)) { return; } } fail("Did not find method named '" + methodname + "' in class '" + cn.getName() + "'"); } private static void assertContainsProblem(Set<IProblem> problems, String expected) { for (IProblem problem : problems) { if (problem.toString().contains(expected)) { return; } } fail("Expected '" + expected + "' in data '" + problems + "'"); } private static void setTransformsOption(IJavaProject javaproject, String transformsSpec) { Map<String, String> m = new HashMap<String, String>(); m.put(CompilerOptions.OPTIONG_GroovyTransformsToRunOnReconcile, transformsSpec); javaproject.setOptions(m); } //-------------------------------------------------------------------------- @Test // Transforms during reconciling tests public void testReconcilingWithTransforms_notransformallowed() throws Exception { IPath projectPath = env.addProject("Project"); env.addExternalJars(projectPath, Util.getJavaClassLibs()); env.addGroovyJars(projectPath); fullBuild(projectPath); // Slight change in behavior from around groovy 2.1.8/groovy 2.2beta2 onwards. If you don't say anything // they are all on. If you do say something it is obeyed. You can say '*' setTransformsOption(env.getJavaProject(projectPath), "Foo"); // remove old package fragment root so that names don't collide env.removePackageFragmentRoot(projectPath, ""); IPath root = env.addPackageFragmentRoot(projectPath, "src"); env.setOutputFolder(projectPath, "bin"); IPath path = env.addGroovyClass(root, "", "Foo", "@Singleton\n"+ "class Foo {\n"+ " void mone() {}\n"+ "}\n" ); incrementalBuild(projectPath); ICompilationUnit icu = env.getUnit(path); icu.becomeWorkingCopy(null); List<ClassNode> classes = ((GroovyCompilationUnit) icu).getModuleNode().getClasses(); ClassNode cn = classes.get(0); assertDoesNotContainMethod(cn, "getInstance"); } @Test public void testReconcilingWithTransforms_singletonallowed() throws Exception { assumeTrue(isAtLeastGroovy(20)); IPath projectPath = env.addProject("Project"); env.addExternalJars(projectPath, Util.getJavaClassLibs()); env.addGroovyJars(projectPath); setTransformsOption(env.getJavaProject(projectPath), "Singleton"); fullBuild(projectPath); // remove old package fragment root so that names don't collide env.removePackageFragmentRoot(projectPath, ""); IPath root = env.addPackageFragmentRoot(projectPath, "src"); env.setOutputFolder(projectPath, "bin"); IPath path = env.addGroovyClass(root, "", "Foo", "@Singleton\n"+ "class Foo {\n"+ " void mone() {}\n"+ "}\n" ); incrementalBuild(projectPath); ICompilationUnit icu = env.getUnit(path); icu.becomeWorkingCopy(null); List<ClassNode> classes = ((GroovyCompilationUnit) icu).getModuleNode().getClasses(); ClassNode cn = classes.get(0); assertContainsMethod(cn, "getInstance"); } @Test public void testReconcilingWithTransforms_singletonallowedspecialchar() throws Exception { assumeTrue(isAtLeastGroovy(20)); IPath projectPath = env.addProject("Project"); env.addExternalJars(projectPath, Util.getJavaClassLibs()); env.addGroovyJars(projectPath); setTransformsOption(env.getJavaProject(projectPath), "Singleton$"); fullBuild(projectPath); // remove old package fragment root so that names don't collide env.removePackageFragmentRoot(projectPath, ""); IPath root = env.addPackageFragmentRoot(projectPath, "src"); env.setOutputFolder(projectPath, "bin"); IPath path = env.addGroovyClass(root, "", "Foo", "@Singleton\n"+ "class Foo {\n"+ " void mone() {}\n"+ "}\n" ); incrementalBuild(projectPath); ICompilationUnit icu = env.getUnit(path); icu.becomeWorkingCopy(null); List<ClassNode> classes = ((GroovyCompilationUnit) icu).getModuleNode().getClasses(); ClassNode cn = classes.get(0); assertContainsMethod(cn, "getInstance"); } @Test public void testReconcilingWithTransforms_multipleButOnlyOneAllowed() throws Exception { IPath projectPath = env.addProject("Project"); env.addExternalJars(projectPath, Util.getJavaClassLibs()); env.addGroovyJars(projectPath); setTransformsOption(env.getJavaProject(projectPath), "Singleton"); fullBuild(projectPath); // remove old package fragment root so that names don't collide env.removePackageFragmentRoot(projectPath, ""); IPath root = env.addPackageFragmentRoot(projectPath, "src"); env.setOutputFolder(projectPath, "bin"); IPath path = env.addGroovyClass(root, "", "Foo", "@Singleton\n"+ "class Foo {\n"+ " @Delegate Bar b = new BarImpl();\n"+ " void mone() {}\n"+ "}\n"+ "interface Bar { void method(); }\n"+ "class BarImpl implements Bar { void method() {};}\n" ); incrementalBuild(projectPath); ICompilationUnit icu = env.getUnit(path); icu.becomeWorkingCopy(null); List<ClassNode> classes = ((GroovyCompilationUnit) icu).getModuleNode().getClasses(); ClassNode cn = classes.get(0); assertContainsMethod(cn, "getInstance"); assertDoesNotContainMethod(cn, "method"); } @Test public void testReconcilingWithTransforms_multipleAndBothAllowed() throws Exception { IPath projectPath = env.addProject("Project"); env.addExternalJars(projectPath, Util.getJavaClassLibs()); env.addGroovyJars(projectPath); fullBuild(projectPath); setTransformsOption(env.getJavaProject(projectPath), "Singleton,Delegate"); // remove old package fragment root so that names don't collide env.removePackageFragmentRoot(projectPath, ""); IPath root = env.addPackageFragmentRoot(projectPath, "src"); env.setOutputFolder(projectPath, "bin"); IPath path = env.addGroovyClass(root, "", "Foo", "@Singleton\n"+ "class Foo {\n"+ " @Delegate Bar b = new BarImpl();\n"+ " void mone() {}\n"+ "}\n"+ "interface Bar { void method(); }\n"+ "class BarImpl implements Bar { void method() {};}\n" ); incrementalBuild(projectPath); ICompilationUnit icu = env.getUnit(path); icu.becomeWorkingCopy(null); List<ClassNode> classes = ((GroovyCompilationUnit) icu).getModuleNode().getClasses(); ClassNode cn = classes.get(0); assertContainsMethod(cn, "getInstance"); assertContainsMethod(cn, "method"); } @Test public void testReconcilingWithTransforms_compileStatic() throws Exception { assumeTrue(isAtLeastGroovy(20)); IPath projectPath = env.addProject("Project"); env.addExternalJars(projectPath, Util.getJavaClassLibs()); env.addGroovyJars(projectPath); fullBuild(projectPath); // remove old package fragment root so that names don't collide env.removePackageFragmentRoot(projectPath, ""); IPath root = env.addPackageFragmentRoot(projectPath, "src"); env.setOutputFolder(projectPath, "bin"); IPath path = env.addGroovyClass(root, "", "Foo", "@groovy.transform.CompileStatic\n"+ "class Foo {\n"+ " void xxx(int i) { xxx('abc');}\n"+ "}\n" ); incrementalBuild(projectPath); ICompilationUnit icu = env.getUnit(path); Set<IProblem> problems = ReconcilerUtils.reconcile(icu); assertContainsProblem(problems, "Cannot find matching method Foo#xxx"); } @Test public void testReconcilingWithTransforms_typeChecked() throws Exception { assumeTrue(isAtLeastGroovy(20)); IPath projectPath = env.addProject("Project"); env.addExternalJars(projectPath, Util.getJavaClassLibs()); env.addGroovyJars(projectPath); fullBuild(projectPath); // remove old package fragment root so that names don't collide env.removePackageFragmentRoot(projectPath, ""); IPath root = env.addPackageFragmentRoot(projectPath, "src"); env.setOutputFolder(projectPath, "bin"); IPath path = env.addGroovyClass(root, "", "Foo", "@groovy.transform.TypeChecked\n"+ "class Foo {\n"+ " void xxx(int i) { xxx('abc');}\n"+ "}\n" ); incrementalBuild(projectPath); ICompilationUnit icu = env.getUnit(path); Set<IProblem> problems = ReconcilerUtils.reconcile(icu); assertContainsProblem(problems, "Cannot find matching method Foo#xxx"); } @Test public void testReconcilingWithTransforms_multipleAndWildcard() throws Exception { IPath projectPath = env.addProject("Project"); env.addExternalJars(projectPath, Util.getJavaClassLibs()); env.addGroovyJars(projectPath); IJavaProject p = env.getJavaProject(projectPath); setTransformsOption(p, "*"); fullBuild(projectPath); // remove old package fragment root so that names don't collide env.removePackageFragmentRoot(projectPath, ""); IPath root = env.addPackageFragmentRoot(projectPath, "src"); env.setOutputFolder(projectPath, "bin"); IPath path = env.addGroovyClass(root, "", "Foo", "@Singleton\n"+ "class Foo {\n"+ " @Delegate Bar b = new BarImpl();\n"+ " void mone() {}\n"+ "}\n"+ "interface Bar { void method(); }\n"+ "class BarImpl implements Bar { void method() {};}\n" ); incrementalBuild(projectPath); ICompilationUnit icu = env.getUnit(path); icu.becomeWorkingCopy(null); List<ClassNode> classes = ((GroovyCompilationUnit) icu).getModuleNode().getClasses(); ClassNode cn = classes.get(0); assertContainsMethod(cn, "getInstance"); assertContainsMethod(cn, "method"); } }