blob: d6363fb560db86c77c250b4b291b1b318edd55ee [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* 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.jetbrains.plugins.groovy.compiler
import com.intellij.compiler.CompilerConfiguration
import com.intellij.compiler.CompilerConfigurationImpl
import com.intellij.execution.executors.DefaultRunExecutor
import com.intellij.execution.impl.DefaultJavaProgramRunner
import com.intellij.execution.process.ProcessAdapter
import com.intellij.execution.process.ProcessEvent
import com.intellij.execution.process.ProcessHandler
import com.intellij.execution.process.ProcessOutputTypes
import com.intellij.execution.runners.ProgramRunner
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.compiler.CompilerMessage
import com.intellij.openapi.compiler.CompilerMessageCategory
import com.intellij.openapi.compiler.options.ExcludeEntryDescription
import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.Ref
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.testFramework.PsiTestUtil
import com.intellij.testFramework.TestLoggerFactory
import org.jetbrains.annotations.NotNull
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
/**
* @author peter
*/
public class GroovyCompilerTest extends GroovyCompilerTestCase {
@Override protected void setUp() {
super.setUp();
addGroovyLibrary(myModule);
}
public void testPlainGroovy() throws Throwable {
myFixture.addFileToProject("A.groovy", "println '239'");
assertEmpty(make());
assertOutput("A", "239");
}
public void testJavaDependsOnGroovy() throws Throwable {
myFixture.addClass("public class Foo {" +
"public static void main(String[] args) { " +
" System.out.println(new Bar().foo());" +
"}" +
"}");
myFixture.addFileToProject("Bar.groovy", "class Bar {" +
" def foo() {" +
" 239" +
" }" +
"}");
make();
assertOutput("Foo", "239");
}
public void testCorrectFailAndCorrect() throws Exception {
myFixture.addClass("public class Foo {" +
"public static void main(String[] args) { " +
" System.out.println(new Bar().foo());" +
"}" +
"}");
final String barText = "class Bar {" + " def foo() { 239 }" + "}";
final PsiFile file = myFixture.addFileToProject("Bar.groovy", barText);
make()
assertOutput("Foo", "239");
setFileText(file, "class Bar {}");
shouldFail { make() }
setFileText(file, barText);
make();
assertOutput("Foo", "239");
}
private void shouldFail(Closure action) {
List<CompilerMessage> messages = action()
assert messages.find { it.category == CompilerMessageCategory.ERROR }
}
public void testRenameToJava() throws Throwable {
myFixture.addClass("public class Foo {" +
"public static void main(String[] args) { " +
" System.out.println(new Bar().foo());" +
"}" +
"}");
final PsiFile bar =
myFixture.addFileToProject("Bar.groovy", "public class Bar {" + "public int foo() { " + " return 239;" + "}" + "}");
make();
assertOutput("Foo", "239");
setFileName bar, "Bar.java"
make();
assertOutput("Foo", "239");
}
public void testTransitiveJavaDependency() throws Throwable {
final VirtualFile ifoo = myFixture.addClass("public interface IFoo { int foo(); }").getContainingFile().getVirtualFile();
myFixture.addClass("public class Foo implements IFoo {" +
" public int foo() { return 239; }" +
"}");
final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar {" +
"Foo foo\n" +
"public static void main(String[] args) { " +
" System.out.println(new Foo().foo());" +
"}" +
"}");
assertEmpty(make());
assertOutput("Bar", "239");
touch(ifoo);
touch(bar.getVirtualFile());
//assertTrue(assertOneElement(make()).contains("WARNING: Groovyc stub generation failed"));
assertEmpty make()
assertOutput("Bar", "239");
}
public void testTransitiveJavaDependencyThroughGroovy() throws Throwable {
myFixture.addClass("public class IFoo { void foo() {} }").getContainingFile().getVirtualFile();
myFixture.addFileToProject("Foo.groovy", "class Foo {\n" +
" static IFoo f\n" +
" public int foo() { return 239; }\n" +
"}");
final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar extends Foo {" +
"public static void main(String[] args) { " +
" System.out.println(new Foo().foo());" +
"}" +
"}");
assertEmpty(make());
assertOutput("Bar", "239");
deleteClassFile("IFoo");
touch(bar.getVirtualFile());
//assertTrue(assertOneElement(make()).contains("WARNING: Groovyc error"));
assertEmpty make()
assertOutput("Bar", "239");
}
public void testTransitiveGroovyDependency() throws Throwable {
def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {} ')
def bar = myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo {}')
def goo = myFixture.addFileToProject('Goo.groovy', 'class Goo extends Bar {}')
assertEmpty(make());
touch(foo.virtualFile)
touch(goo.virtualFile)
assertEmpty(make());
}
public void testJavaDependsOnGroovyEnum() throws Throwable {
myFixture.addFileToProject("Foo.groovy", "enum Foo { FOO }")
myFixture.addClass("class Bar { Foo f; }")
assertEmpty(make())
}
public void testDeleteTransitiveJavaClass() throws Throwable {
myFixture.addClass("public interface IFoo { int foo(); }");
myFixture.addClass("public class Foo implements IFoo {" +
" public int foo() { return 239; }" +
"}");
final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar {" +
"Foo foo\n" +
"public static void main(String[] args) { " +
" System.out.println(new Foo().foo());" +
"}" +
"}");
assertEmpty(make());
assertOutput("Bar", "239");
deleteClassFile("IFoo");
touch(bar.getVirtualFile());
//assertTrue(assertOneElement(make()).contains("WARNING: Groovyc stub generation failed"));
assertEmpty make()
assertOutput("Bar", "239");
}
public void testGroovyDependsOnGroovy() throws Throwable {
myFixture.addClass("public class JustToMakeGroovyGenerateStubs {}");
myFixture.addFileToProject("Foo.groovy", "class Foo { }");
final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar {" +
"def foo(Foo f) {}\n" +
"public static void main(String[] args) { " +
" System.out.println(239);" +
"}" +
"}");
assertEmpty(make());
assertOutput("Bar", "239");
touch(bar.getVirtualFile());
assertEmpty(make());
assertOutput("Bar", "239");
}
@Override
void runBare() {
new File(TestLoggerFactory.testLogDir, "../log/build-log/build.log").delete()
super.runBare()
}
@Override
void runTest() {
try {
super.runTest()
}
catch (Throwable e) {
printLogs()
throw e
}
}
private static void printLogs() {
def ideaLog = new File(TestLoggerFactory.testLogDir, "idea.log")
if (ideaLog.exists()) {
println "\n\nIdea Log:"
def limit = 20000
def logText = ideaLog.text
println(logText.size() < limit ? logText : logText.substring(logText.size() - limit))
}
def makeLog = new File(TestLoggerFactory.testLogDir, "../log/build-log/build.log")
if (makeLog.exists()) {
println "\n\nServer Log:"
println makeLog.text
}
System.out.flush()
}
public void testMakeInTests() throws Throwable {
setupTestSources();
myFixture.addFileToProject("tests/Super.groovy", "class Super {}");
assertEmpty(make());
def sub = myFixture.addFileToProject("tests/Sub.groovy", "class Sub {\n" +
" Super xxx() {}\n" +
" static void main(String[] args) {" +
" println 'hello'" +
" }" +
"}");
def javaFile = myFixture.addFileToProject("tests/Java.java", "public class Java {}");
assertEmpty(make());
assertOutput("Sub", "hello");
}
public void testTestsDependOnProduction() throws Throwable {
setupTestSources();
myFixture.addFileToProject("src/com/Bar.groovy", "package com\n" +
"class Bar {}");
myFixture.addFileToProject("src/com/ToGenerateStubs.java", "package com;\n" +
"public class ToGenerateStubs {}");
myFixture.addFileToProject("tests/com/BarTest.groovy", "package com\n" +
"class BarTest extends Bar {}");
assertEmpty(make());
}
public void testStubForGroovyExtendingJava() throws Exception {
def foo = myFixture.addFileToProject("Foo.groovy", "class Foo extends Goo { }");
myFixture.addFileToProject("Goo.groovy", "class Goo extends Main { void bar() { println 'hello' } }");
def main = myFixture.addClass("public class Main { public static void main(String[] args) { new Goo().bar(); } }");
assertEmpty(make());
assertOutput 'Main', 'hello'
touch(foo.virtualFile)
touch(main.containingFile.virtualFile)
assertEmpty(make());
assertOutput 'Main', 'hello'
}
public void testDontApplyTransformsFromSameModule() throws Exception {
addTransform();
myFixture.addClass("public class JavaClassToGenerateStubs {}");
assertEmpty(make());
}
private void addTransform() throws IOException {
myFixture.addFileToProject("Transf.groovy", """
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.control.*
import org.codehaus.groovy.transform.*
@GroovyASTTransformation(phase = CompilePhase.CONVERSION)
public class Transf implements ASTTransformation {
void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
ModuleNode module = nodes[0]
for (clazz in module.classes) {
if (clazz.name.contains('Bar')) {
module.addStaticStarImport('Foo', ClassHelper.makeWithoutCaching(Foo.class))
}
}
}
}""");
myFixture.addFileToProject("Foo.groovy", "class Foo {\n" +
"static def autoImported() { 239 }\n" +
"}");
CompilerConfiguration.getInstance(getProject()).addResourceFilePattern("*.ASTTransformation");
myFixture.addFileToProject("META-INF/services/org.codehaus.groovy.transform.ASTTransformation", "Transf");
}
public void testApplyTransformsFromDependencies() throws Exception {
addTransform();
myFixture.addFileToProject("dependent/Bar.groovy", "class Bar {\n" +
" static Object zzz = autoImported()\n" +
" static void main(String[] args) {\n" +
" println zzz\n" +
" }\n" +
"}");
myFixture.addFileToProject("dependent/AJavaClass.java", "class AJavaClass {}");
Module dep = addDependentModule();
addGroovyLibrary(dep);
assertEmpty(make());
assertOutput("Bar", "239", dep);
}
public void testIndirectDependencies() throws Exception {
myFixture.addFileToProject("dependent1/Bar1.groovy", "class Bar1 {}");
myFixture.addFileToProject("dependent2/Bar2.groovy", "class Bar2 extends Bar1 {}");
PsiFile main = myFixture.addFileToProject("Main.groovy", "class Main extends Bar2 {}");
Module dep1 = addModule('dependent1', true)
Module dep2 = addModule('dependent2', true)
ModuleRootModificationUtil.addDependency dep2, dep1
ModuleRootModificationUtil.addDependency myModule, dep2
addGroovyLibrary(dep1);
addGroovyLibrary(dep2);
assertEmpty(make())
touch(main.virtualFile)
assertEmpty(make())
}
public void testExtendFromGroovyAbstractClass() throws Exception {
myFixture.addFileToProject "Super.groovy", "abstract class Super {}"
myFixture.addFileToProject "AJava.java", "public class AJava {}"
assertEmpty make()
myFixture.addFileToProject "Sub.groovy", "class Sub extends Super {}"
assertEmpty make()
}
public void test1_7InnerClass() throws Exception {
myFixture.addFileToProject "Foo.groovy", """
class Foo {
static class Bar {}
}"""
def javaFile = myFixture.addFileToProject("AJava.java", "public class AJava extends Foo.Bar {}")
assertEmpty make()
touch(javaFile.virtualFile)
assertEmpty make()
}
public void testRecompileDependentClass() throws Exception {
def cloud = myFixture.addFileToProject("Cloud.groovy", """
class Cloud {
def accessFooProperty(Foo c) {
c.prop = 2
}
}
""")
myFixture.addFileToProject "Foo.groovy", """
class Foo {
def withGooParameter(Goo x) {}
}"""
def goo = myFixture.addFileToProject("Goo.groovy", "class Goo {}")
assertEmpty make()
touch(cloud.virtualFile)
touch(goo.virtualFile)
assertEmpty make()
}
public void testRecompileExpressionReferences() throws Exception {
def rusCon = myFixture.addFileToProject('RusCon.groovy', '''
interface RusCon {
Closure foo = { Seq.foo() }
}''')
myFixture.addFileToProject "Seq.groovy", """
class Seq implements RusCon {
static def foo() { }
}"""
assertEmpty make()
touch(rusCon.virtualFile)
assertEmpty make()
}
public void testRecompileImportedClass() throws Exception {
def bar = myFixture.addFileToProject("pack/Bar.groovy", """
package pack
import pack.Foo
class Bar {}
""")
myFixture.addFileToProject "pack/Foo.groovy", """
package pack
class Foo extends Goo {
}"""
def goo = myFixture.addFileToProject("pack/Goo.groovy", """
package pack
class Goo {}""")
assertEmpty make()
touch(bar.virtualFile)
touch(goo.virtualFile)
assertEmpty make()
}
public void testRecompileDependentClassesWithOnlyOneChanged() throws Exception {
def bar = myFixture.addFileToProject("Bar.groovy", """
class Bar {
Foo f
}
""")
myFixture.addFileToProject "Foo.groovy", """
class Foo extends Bar {
}"""
assertEmpty make()
touch(bar.virtualFile)
assertEmpty make()
}
public void testDollarGroovyInnerClassUsagesInStubs() throws Exception {
def javaFile = myFixture.addClass("""
public class JavaClass {
public static class InnerJavaClass {}
}
""")
myFixture.addFileToProject("WithInner.groovy", """
class WithInner {
static class Inner {}
}
""")
assertEmpty make()
myFixture.addFileToProject("Usage.groovy", """
class Usage {
def foo(WithInner.Inner i) {}
def foo(JavaClass.InnerJavaClass i) {}
}
""")
touch(javaFile.containingFile.virtualFile)
assertEmpty make()
}
public void testDollarGroovyInnerClassUsagesInStubs2() throws Exception {
myFixture.addClass(""" public class JavaClass { } """)
myFixture.addFileToProject("WithInner.groovy", """
class WithInner {
static class Inner {}
}
""")
myFixture.addFileToProject("Usage.groovy", """
class Usage {
def foo(WithInner.Inner i) {}
}
""")
assertEmpty make()
}
public void testGroovyAnnotations() {
myFixture.addClass 'public @interface Anno { Class[] value(); }'
myFixture.addFileToProject 'Foo.groovy', '@Anno([String]) class Foo {}'
myFixture.addFileToProject 'Bar.java', 'class Bar extends Foo {}'
assertEmpty make()
}
public void testGenericStubs() {
myFixture.addFileToProject 'Foo.groovy', 'class Foo { List<String> list }'
myFixture.addFileToProject 'Bar.java', 'class Bar {{ for (String s : new Foo().getList()) {} }}'
assertEmpty make()
}
public void testDuplicateClassDuringCompilation() throws Exception {
def base = myFixture.addFileToProject('p/Base.groovy', 'package p; class Base { }').virtualFile
myFixture.addFileToProject('p/Indirect.groovy', '''package p
class Indirect {
private static class Inner { Base b }
private Indirect.Inner foo(Indirect.Inner g1, Inner g2, Base b) {}
}''').virtualFile
def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { p.Indirect foo() {} }').virtualFile
assertEmpty make()
touch(foo)
touch(base)
assertEmpty make()
}
public void testDontRecompileUnneeded() {
myFixture.addFileToProject('Base.groovy', 'class Base { }')
def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo extends Base { }').virtualFile
myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo { }')
def main = myFixture.addFileToProject('Main.groovy', 'class Main extends Bar { }').virtualFile
assertEmpty make()
long oldBaseStamp = findClassFile("Base").timeStamp
long oldMainStamp = findClassFile("Main").timeStamp
touch(main)
touch(foo)
assertEmpty make()
assert oldMainStamp != findClassFile("Main").timeStamp
assert oldBaseStamp == findClassFile("Base").timeStamp
}
public void testPartialCrossRecompile() {
def used = myFixture.addFileToProject('Used.groovy', 'class Used { }')
def java = myFixture.addFileToProject('Java.java', 'class Java { void foo(Used used) {} }')
def main = myFixture.addFileToProject('Main.groovy', 'class Main extends Java { }').virtualFile
assertEmpty compileModule(myModule)
touch(used.virtualFile)
touch(main)
assertEmpty make()
assertEmpty compileModule(myModule)
assertEmpty compileModule(myModule)
setFileText(used, 'class Used2 {}')
shouldFail { make() }
assert findClassFile('Used') == null
setFileText(used, 'class Used3 {}')
setFileText(java, 'class Java { void foo(Used3 used) {} }')
assertEmpty make()
assert findClassFile('Used2') == null
}
public void testClassLoadingDuringBytecodeGeneration() {
def used = myFixture.addFileToProject('Used.groovy', 'class Used { }')
def java = myFixture.addFileToProject('Java.java', '''
abstract class Java {
Object getProp() { return null; }
abstract void foo(Used used);
}''')
def main = myFixture.addFileToProject('Main.groovy', '''
class Main {
def foo(Java j) {
return j.prop
}
}''').virtualFile
assertEmpty make()
touch(used.virtualFile)
touch(main)
assertEmpty make()
}
public void testMakeInDependentModuleAfterChunkRebuild() {
def used = myFixture.addFileToProject('Used.groovy', 'class Used { }')
def java = myFixture.addFileToProject('Java.java', 'class Java { void foo(Used used) {} }')
def main = myFixture.addFileToProject('Main.groovy', 'class Main extends Java { }').virtualFile
addGroovyLibrary(addDependentModule())
def dep = myFixture.addFileToProject("dependent/Dep.java", "class Dep { }")
assertEmpty make()
setFileText(used, 'class Used { String prop }')
touch(main)
setFileText(dep, 'class Dep { String prop = new Used().getProp(); }')
assertEmpty make()
}
public void "test module cycle"() {
def dep = addDependentModule()
ModuleRootModificationUtil.addDependency(myModule, dep)
addGroovyLibrary(dep)
myFixture.addFileToProject('Foo.groovy', 'class Foo extends Bar { static void main(String[] args) { println "Hello from Foo" } }')
myFixture.addFileToProject('FooX.java', 'class FooX extends Bar { }')
myFixture.addFileToProject("dependent/Bar.groovy", "class Bar { Foo f; static void main(String[] args) { println 'Hello from Bar' } }")
myFixture.addFileToProject("dependent/BarX.java", "class BarX { Foo f; }")
def checkClassFiles = {
assert findClassFile('Foo', myModule)
assert findClassFile('FooX', myModule)
assert findClassFile('Bar', dep)
assert findClassFile('BarX', dep)
assert !findClassFile('Bar', myModule)
assert !findClassFile('BarX', myModule)
assert !findClassFile('Foo', dep)
assert !findClassFile('FooX', dep)
}
assertEmpty(make())
checkClassFiles()
assertEmpty(make())
checkClassFiles()
assertOutput('Foo', 'Hello from Foo', myModule)
assertOutput('Bar', 'Hello from Bar', dep)
checkClassFiles()
}
public void testCompileTimeConstants() {
myFixture.addFileToProject 'Gr.groovy', '''
interface Gr {
String HELLO = "Hello"
int MAGIC = 239
Boolean BOOL = true
boolean bool = true
}'''
myFixture.addFileToProject 'Main.java', '''
public class Main {
public static void main(String[] args) {
System.out.println(Gr.HELLO + ", " + Gr.BOOL + Gr.bool + Gr.MAGIC);
}
}
'''
make()
assertOutput 'Main', 'Hello, truetrue239'
}
public void "test reporting rebuild errors caused by missing files excluded from compilation"() {
def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {}')
myFixture.addFileToProject 'Bar.groovy', 'class Bar extends Foo {}'
make()
excludeFromCompilation(foo)
shouldFail { rebuild() }
}
private void excludeFromCompilation(PsiFile foo) {
final ExcludedEntriesConfiguration configuration =
((CompilerConfigurationImpl)CompilerConfiguration.getInstance(project)).getExcludedEntriesConfiguration()
configuration.addExcludeEntryDescription(new ExcludeEntryDescription(foo.virtualFile, false, true, testRootDisposable))
}
public void "test make stub-level error and correct it"() {
def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { }')
myFixture.addFileToProject('Bar.java', 'class Bar extends Foo {}')
assertEmpty make()
setFileText(foo, 'class Foo implements Runnabl {}')
shouldFail { make() }
setFileText(foo, 'class Foo {}')
assertEmpty make()
}
//todo jeka: when recompiling module, delete all class files including those with excluded source
public void "_test reporting module compile errors caused by missing files excluded from compilation"() {
def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {}')
myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo {}')
make()
excludeFromCompilation(foo)
shouldFail { compileModule(myModule) }
}
public void "test stubs generated while processing groovy class file dependencies"() {
def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { }')
def bar = myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo { }')
def client = myFixture.addFileToProject('Client.groovy', 'class Client { Bar bar = new Bar() }')
def java = myFixture.addFileToProject('Java.java', 'class Java extends Client { String getName(Bar bar) { return bar.toString(); } }')
assertEmpty(make())
setFileText(bar, 'class Bar { }')
assertEmpty(make())
assert findClassFile("Client")
}
public void "test navigate from stub to source"() {
GroovyFile groovyFile = (GroovyFile) myFixture.addFileToProject("a.groovy", "class Groovy3 { InvalidType type }")
myFixture.addClass("class Java4 extends Groovy3 {}").containingFile
def msg = make().find { it.message.contains('InvalidType') }
assert msg?.virtualFile
ApplicationManager.application.runWriteAction { msg.virtualFile.delete(this) }
def messages = make()
assert messages
def error = messages.find { it.message.contains('InvalidType') }
assert error?.virtualFile
assert groovyFile.classes[0] == GroovyCompilerLoader.findClassByStub(project, error.virtualFile)
}
public void "test ignore groovy internal non-existent interface helper inner class"() {
myFixture.addFileToProject 'Foo.groovy', '''
interface Foo {}
class Zoo {
Foo foo() {}
static class Inner implements Foo {}
}
'''
def bar = myFixture.addFileToProject('Bar.groovy', 'class Bar { def foo = new Zoo.Inner() {} }')
assertEmpty make()
assertEmpty compileFiles(bar.virtualFile)
}
public void "test multiline strings"() {
myFixture.addFileToProject 'Foo.groovy', '''class Foo {
public static final String s = """
multi
line
string
"""
} '''
myFixture.addFileToProject 'Bar.java', 'class Bar extends Foo {} '
assertEmpty make()
}
public void "test inner java class references with incremental recompilation"() {
def bar1 = myFixture.addFileToProject('bar/Bar1.groovy', 'package bar; class Bar1 extends Bar2 { } ')
myFixture.addFileToProject('bar/Bar2.java', 'package bar; class Bar2 extends Bar3 { } ')
def bar3 = myFixture.addFileToProject('bar/Bar3.groovy', 'package bar; class Bar3 { Bar1 property } ')
myFixture.addClass("package foo; public class Outer { public static class Inner extends bar.Bar1 { } }")
def using = myFixture.addFileToProject('UsingInner.groovy', 'import foo.Outer; class UsingInner extends bar.Bar1 { Outer.Inner property } ')
assertEmpty make()
touch bar1.virtualFile
touch bar3.virtualFile
touch using.virtualFile
assertEmpty make()
}
public void "test rename class to java and touch its usage"() {
def usage = myFixture.addFileToProject('Usage.groovy', 'class Usage { Renamed r } ')
def renamed = myFixture.addFileToProject('Renamed.groovy', 'public class Renamed { } ')
assertEmpty make()
touch usage.virtualFile
setFileName(renamed, 'Renamed.java')
assertEmpty make()
}
public void "test compiling static extension"() {
setupTestSources()
myFixture.addFileToProject "src/extension/Extension.groovy", """
package extension
import groovy.transform.CompileStatic
@CompileStatic class Extension {
static <T> T test2(List<T> self) {
self.first()
}
}"""
myFixture.addFileToProject "src/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule", """
moduleName=extension-verify
moduleVersion=1.0-test
extensionClasses=extension.Extension
staticExtensionClasses=
"""
myFixture.addFileToProject "tests/AppTest.groovy", """
class AppTest {
@groovy.transform.CompileStatic
static main(args) {
List<String> list = new ArrayList<>()
list.add("b")
list.add("c")
println list.test2()
}
}
"""
assertEmpty make()
assertOutput 'AppTest', 'b'
}
public void "test no groovy library"() {
myFixture.addFileToProject("dependent/a.groovy", "");
addModule("dependent", true)
def messages = make()
assert messages.find { it.message.contains("Cannot compile Groovy files: no Groovy library is defined for module 'dependent'") }
}
public void testGroovyOutputIsInstrumented() {
myFixture.addFileToProject("Bar.groovy",
"import org.jetbrains.annotations.NotNull; " +
"public class Bar {" +
"void xxx(@NotNull String param) { println param }\n" +
"static void main(String[] args) { new Bar().xxx(null) }"+
"}"
);
File annotations = new File(PathManager.getJarPathForClass(NotNull.class));
PsiTestUtil.addLibrary(myModule, "annotations", annotations.getParent(), annotations.getName());
assertEmpty(make());
final Ref<Boolean> exceptionFound = Ref.create(Boolean.FALSE);
ProcessHandler process = runProcess("Bar", myModule, DefaultRunExecutor.class, new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
if (ProcessOutputTypes.SYSTEM != outputType) {
if (!exceptionFound.get()) {
exceptionFound.set(event.getText().contains("java.lang.IllegalArgumentException: Argument for @NotNull parameter 'param' of Bar.xxx must not be null"));
}
}
}
}, ProgramRunner.PROGRAM_RUNNER_EP.findExtension(DefaultJavaProgramRunner.class));
process.waitFor();
assertTrue(exceptionFound.get());
}
}