bd9aff7377659bc0fc5d61180aa56391c908cf00
[idea/community.git] / plugins / groovy / test / org / jetbrains / plugins / groovy / compiler / GroovyCompilerTest.groovy
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *  http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16
17 package org.jetbrains.plugins.groovy.compiler
18 import com.intellij.compiler.CompilerConfiguration
19 import com.intellij.compiler.CompilerConfigurationImpl
20 import com.intellij.compiler.CompilerWorkspaceConfiguration
21 import com.intellij.compiler.server.BuildManager
22 import com.intellij.execution.executors.DefaultRunExecutor
23 import com.intellij.execution.impl.DefaultJavaProgramRunner
24 import com.intellij.execution.process.ProcessAdapter
25 import com.intellij.execution.process.ProcessEvent
26 import com.intellij.execution.process.ProcessHandler
27 import com.intellij.execution.process.ProcessOutputTypes
28 import com.intellij.execution.runners.ProgramRunner
29 import com.intellij.openapi.application.ApplicationManager
30 import com.intellij.openapi.application.PathManager
31 import com.intellij.openapi.application.PluginPathManager
32 import com.intellij.openapi.compiler.CompilerMessage
33 import com.intellij.openapi.compiler.CompilerMessageCategory
34 import com.intellij.openapi.compiler.options.ExcludeEntryDescription
35 import com.intellij.openapi.compiler.options.ExcludesConfiguration
36 import com.intellij.openapi.module.Module
37 import com.intellij.openapi.roots.ModuleRootModificationUtil
38 import com.intellij.openapi.util.Key
39 import com.intellij.openapi.util.Ref
40 import com.intellij.openapi.util.io.FileUtil
41 import com.intellij.openapi.vfs.VirtualFile
42 import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
43 import com.intellij.psi.PsiFile
44 import com.intellij.testFramework.PsiTestUtil
45 import com.intellij.testFramework.TestLoggerFactory
46 import org.jetbrains.annotations.NotNull
47 import org.jetbrains.plugins.groovy.config.GroovyFacetUtil
48 import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
49 /**
50  * @author peter
51  */
52 public abstract class GroovyCompilerTest extends GroovyCompilerTestCase {
53   @Override protected void setUp() {
54     super.setUp();
55     addGroovyLibrary(myModule);
56   }
57
58   public void testPlainGroovy() throws Throwable {
59     myFixture.addFileToProject("A.groovy", "println '239'");
60     assertEmpty(make());
61     assertOutput("A", "239");
62   }
63
64   public void testJavaDependsOnGroovy() throws Throwable {
65     myFixture.addClass("public class Foo {" +
66                        "public static void main(String[] args) { " +
67                        "  System.out.println(new Bar().foo());" +
68                        "}" +
69                        "}");
70     myFixture.addFileToProject("Bar.groovy", "class Bar {" +
71                                              "  def foo() {" +
72                                              "    239" +
73                                              "  }" +
74                                              "}");
75     make();
76     assertOutput("Foo", "239");
77   }
78
79   public void testCorrectFailAndCorrect() throws Exception {
80     myFixture.addClass("public class Foo {" +
81                        "public static void main(String[] args) { " +
82                        "  System.out.println(new Bar().foo());" +
83                        "}" +
84                        "}");
85     final String barText = "class Bar {" + "  def foo() { 239  }" + "}";
86     final PsiFile file = myFixture.addFileToProject("Bar.groovy", barText);
87     make()
88     assertOutput("Foo", "239");
89
90     setFileText(file, "class Bar {}");
91     shouldFail { make() }
92
93     setFileText(file, barText);
94     make();
95     assertOutput("Foo", "239");
96   }
97
98   protected static void shouldFail(Closure action) {
99     List<CompilerMessage> messages = action()
100     assert messages.find { it.category == CompilerMessageCategory.ERROR }
101   }
102
103   public void testRenameToJava() throws Throwable {
104     myFixture.addClass("public class Foo {" +
105                        "public static void main(String[] args) { " +
106                        "  System.out.println(new Bar().foo());" +
107                        "}" +
108                        "}");
109
110     final PsiFile bar =
111       myFixture.addFileToProject("Bar.groovy", "public class Bar {" + "public int foo() { " + "  return 239;" + "}" + "}");
112
113     make();
114     assertOutput("Foo", "239");
115
116     setFileName bar, "Bar.java"
117
118     make();
119     assertOutput("Foo", "239");
120   }
121
122   public void testTransitiveJavaDependency() throws Throwable {
123     final VirtualFile ifoo = myFixture.addClass("public interface IFoo { int foo(); }").getContainingFile().getVirtualFile();
124     myFixture.addClass("public class Foo implements IFoo {" +
125                        "  public int foo() { return 239; }" +
126                        "}");
127     final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar {" +
128                                                                  "Foo foo\n" +
129                                                                  "public static void main(String[] args) { " +
130                                                                  "  System.out.println(new Foo().foo());" +
131                                                                  "}" +
132                                                                  "}");
133     assertEmpty(make());
134     assertOutput("Bar", "239");
135
136     touch(ifoo);
137     touch(bar.getVirtualFile());
138
139     //assertTrue(assertOneElement(make()).contains("WARNING: Groovyc stub generation failed"));
140     assertEmpty make()
141     assertOutput("Bar", "239");
142   }
143
144   public void testTransitiveJavaDependencyThroughGroovy() throws Throwable {
145     myFixture.addClass("public class IFoo { void foo() {} }").getContainingFile().getVirtualFile();
146     myFixture.addFileToProject("Foo.groovy", "class Foo {\n" +
147                                              "  static IFoo f\n" +
148                                              "  public int foo() { return 239; }\n" +
149                                              "}");
150     final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar extends Foo {" +
151                                                                  "public static void main(String[] args) { " +
152                                                                  "  System.out.println(new Foo().foo());" +
153                                                                  "}" +
154                                                                  "}");
155     assertEmpty(make());
156     assertOutput("Bar", "239");
157
158     deleteClassFile("IFoo");
159     touch(bar.getVirtualFile());
160
161     //assertTrue(assertOneElement(make()).contains("WARNING: Groovyc error"));
162     assertEmpty make()
163     assertOutput("Bar", "239");
164   }
165
166   public void testTransitiveGroovyDependency() throws Throwable {
167     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {} ')
168     def bar = myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo {}')
169     def goo = myFixture.addFileToProject('Goo.groovy', 'class Goo extends Bar {}')
170     assertEmpty(make());
171
172     touch(foo.virtualFile)
173     touch(goo.virtualFile)
174     assertEmpty(make());
175   }
176
177   public void testJavaDependsOnGroovyEnum() throws Throwable {
178     myFixture.addFileToProject("Foo.groovy", "enum Foo { FOO }")
179     myFixture.addClass("class Bar { Foo f; }")
180     assertEmpty(make())
181   }
182
183   public void testDeleteTransitiveJavaClass() throws Throwable {
184     myFixture.addClass("public interface IFoo { int foo(); }");
185     myFixture.addClass("public class Foo implements IFoo {" +
186                        "  public int foo() { return 239; }" +
187                        "}");
188     final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar {" +
189                                                                  "Foo foo\n" +
190                                                                  "public static void main(String[] args) { " +
191                                                                  "  System.out.println(new Foo().foo());" +
192                                                                  "}" +
193                                                                  "}");
194     assertEmpty(make());
195     assertOutput("Bar", "239");
196
197     deleteClassFile("IFoo");
198     touch(bar.getVirtualFile());
199
200     //assertTrue(assertOneElement(make()).contains("WARNING: Groovyc stub generation failed"));
201     assertEmpty make()
202     assertOutput("Bar", "239");
203   }
204
205   public void testGroovyDependsOnGroovy() throws Throwable {
206     myFixture.addClass("public class JustToMakeGroovyGenerateStubs {}");
207     myFixture.addFileToProject("Foo.groovy", "class Foo { }");
208     final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar {" +
209                                                                  "def foo(Foo f) {}\n" +
210                                                                  "public static void main(String[] args) { " +
211                                                                  "  System.out.println(239);" +
212                                                                  "}" +
213                                                                  "}");
214     assertEmpty(make());
215     assertOutput("Bar", "239");
216
217     touch(bar.getVirtualFile());
218
219     assertEmpty(make());
220     assertOutput("Bar", "239");
221   }
222
223   @Override
224   void runBare() {
225     new File(TestLoggerFactory.testLogDir, "../log/build-log/build.log").delete()
226     super.runBare()
227   }
228
229   @Override
230   void runTest() {
231     try {
232       super.runTest()
233     }
234     catch (Throwable e) {
235       printLogs()
236       throw e
237     }
238   }
239
240   private static void printLogs() {
241     def ideaLog = new File(TestLoggerFactory.testLogDir, "idea.log")
242     if (ideaLog.exists()) {
243       println "\n\nIdea Log:"
244       def limit = 20000
245       def logText = ideaLog.text
246       println(logText.size() < limit ? logText : logText.substring(logText.size() - limit))
247     }
248     def makeLog = new File(TestLoggerFactory.testLogDir, "../log/build-log/build.log")
249     if (makeLog.exists()) {
250       println "\n\nServer Log:"
251       println makeLog.text
252     }
253     System.out.flush()
254   }
255
256   public void testMakeInTests() throws Throwable {
257     setupTestSources();
258     myFixture.addFileToProject("tests/Super.groovy", "class Super {}");
259     assertEmpty(make());
260
261     def sub = myFixture.addFileToProject("tests/Sub.groovy", "class Sub {\n" +
262       "  Super xxx() {}\n" +
263       "  static void main(String[] args) {" +
264       "    println 'hello'" +
265       "  }" +
266       "}");
267
268     def javaFile = myFixture.addFileToProject("tests/Java.java", "public class Java {}");
269
270     assertEmpty(make());
271     assertOutput("Sub", "hello");
272   }
273
274   public void testTestsDependOnProduction() throws Throwable {
275     setupTestSources();
276     myFixture.addFileToProject("src/com/Bar.groovy", "package com\n" +
277                                                      "class Bar {}");
278     myFixture.addFileToProject("src/com/ToGenerateStubs.java", "package com;\n" +
279                                                                "public class ToGenerateStubs {}");
280     myFixture.addFileToProject("tests/com/BarTest.groovy", "package com\n" +
281                                                            "class BarTest extends Bar {}");
282     assertEmpty(make());
283   }
284
285   public void testStubForGroovyExtendingJava() throws Exception {
286     def foo = myFixture.addFileToProject("Foo.groovy", "class Foo extends Goo { }");
287     myFixture.addFileToProject("Goo.groovy", "class Goo extends Main { void bar() { println 'hello' } }");
288     def main = myFixture.addClass("public class Main { public static void main(String[] args) { new Goo().bar(); } }");
289
290     assertEmpty(make());
291     assertOutput 'Main', 'hello'
292
293     touch(foo.virtualFile)
294     touch(main.containingFile.virtualFile)
295     assertEmpty(make());
296
297     assertOutput 'Main', 'hello'
298   }
299
300   public void testDontApplyTransformsFromSameModule() throws Exception {
301     addTransform();
302
303     myFixture.addClass("public class JavaClassToGenerateStubs {}");
304
305     assertEmpty(make());
306
307   }
308
309   private void addTransform() throws IOException {
310     myFixture.addFileToProject("Transf.java", """
311 import org.codehaus.groovy.ast.*;
312 import org.codehaus.groovy.control.*;
313 import org.codehaus.groovy.transform.*;
314 @GroovyASTTransformation(phase = CompilePhase.CONVERSION)
315 public class Transf implements ASTTransformation {
316   public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
317     ModuleNode module = (ModuleNode)nodes[0];
318     for (ClassNode clazz : module.getClasses()) {
319
320       if (clazz.getName().contains("Bar")) {
321         module.addStaticStarImport("Foo", ClassHelper.makeWithoutCaching(Foo.class));
322       }
323     }
324       //throw new RuntimeException("In class " + nodes[0]);
325   }
326 }""");
327
328     myFixture.addFileToProject("Foo.java", "public class Foo {\n" +
329                                              "public static int autoImported() { return 239; }\n" +
330                                              "}");
331
332     CompilerConfiguration.getInstance(getProject()).addResourceFilePattern("*.ASTTransformation");
333
334     myFixture.addFileToProject("META-INF/services/org.codehaus.groovy.transform.ASTTransformation", "Transf");
335   }
336
337   public void testApplyTransformsFromDependencies() throws Exception {
338     addTransform();
339
340     myFixture.addFileToProject("dependent/Bar.groovy", "class Bar {\n" +
341                                                        "  static Object zzz = autoImported()\n" +
342                                                        "  static void main(String[] args) {\n" +
343                                                        "    println zzz\n" +
344                                                        "  }\n" +
345                                                        "}");
346
347     myFixture.addFileToProject("dependent/AJavaClass.java", "class AJavaClass {}");
348
349     Module dep = addDependentModule();
350
351     addGroovyLibrary(dep);
352
353     assertEmpty(make());
354     assertOutput("Bar", "239", dep);
355   }
356
357   public void testIndirectDependencies() throws Exception {
358     myFixture.addFileToProject("dependent1/Bar1.groovy", "class Bar1 {}");
359     myFixture.addFileToProject("dependent2/Bar2.groovy", "class Bar2 extends Bar1 {}");
360     PsiFile main = myFixture.addFileToProject("Main.groovy", "class Main extends Bar2 {}");
361
362     Module dep1 = addModule('dependent1', true)
363     Module dep2 = addModule('dependent2', true)
364     ModuleRootModificationUtil.addDependency dep2, dep1
365     ModuleRootModificationUtil.addDependency myModule, dep2
366
367     addGroovyLibrary(dep1);
368     addGroovyLibrary(dep2);
369
370     assertEmpty(make())
371
372     touch(main.virtualFile)
373     assertEmpty(make())
374   }
375
376   public void testExtendFromGroovyAbstractClass() throws Exception {
377     myFixture.addFileToProject "Super.groovy", "abstract class Super {}"
378     myFixture.addFileToProject "AJava.java", "public class AJava {}"
379     assertEmpty make()
380
381     myFixture.addFileToProject "Sub.groovy", "class Sub extends Super {}"
382     assertEmpty make()
383   }
384
385   public void test1_7InnerClass() throws Exception {
386     myFixture.addFileToProject "Foo.groovy", """
387 class Foo {
388   static class Bar {}
389 }"""
390     def javaFile = myFixture.addFileToProject("AJava.java", "public class AJava extends Foo.Bar {}")
391     assertEmpty make()
392
393     touch(javaFile.virtualFile)
394     assertEmpty make()
395   }
396
397   public void testRecompileDependentClass() throws Exception {
398     def cloud = myFixture.addFileToProject("Cloud.groovy", """
399 class Cloud {
400   def accessFooProperty(Foo c) {
401     c.prop = 2
402   }
403 }
404 """)
405     myFixture.addFileToProject "Foo.groovy", """
406 class Foo {
407   def withGooParameter(Goo x) {}
408 }"""
409     def goo = myFixture.addFileToProject("Goo.groovy", "class Goo {}")
410
411     assertEmpty make()
412
413     touch(cloud.virtualFile)
414     touch(goo.virtualFile)
415     assertEmpty make()
416   }
417
418   public void testRecompileExpressionReferences() throws Exception {
419     def rusCon = myFixture.addFileToProject('RusCon.groovy', '''
420 interface RusCon {
421   Closure foo = { Seq.foo() }
422 }''')
423     myFixture.addFileToProject "Seq.groovy", """
424 class Seq implements RusCon {
425   static def foo() { }
426 }"""
427     assertEmpty make()
428
429     touch(rusCon.virtualFile)
430     assertEmpty make()
431   }
432
433   public void testRecompileImportedClass() throws Exception {
434     def bar = myFixture.addFileToProject("pack/Bar.groovy", """
435 package pack
436 import pack.Foo
437 class Bar {}
438 """)
439     myFixture.addFileToProject "pack/Foo.groovy", """
440 package pack
441 class Foo extends Goo {
442 }"""
443     def goo = myFixture.addFileToProject("pack/Goo.groovy", """
444 package pack
445 class Goo {}""")
446
447     assertEmpty make()
448
449     touch(bar.virtualFile)
450     touch(goo.virtualFile)
451     assertEmpty make()
452   }
453
454   public void testRecompileDependentClassesWithOnlyOneChanged() throws Exception {
455     def bar = myFixture.addFileToProject("Bar.groovy", """
456 class Bar {
457   Foo f
458 }
459 """)
460     myFixture.addFileToProject "Foo.groovy", """
461 class Foo extends Bar {
462 }"""
463
464     assertEmpty make()
465
466     touch(bar.virtualFile)
467     assertEmpty make()
468   }
469
470   public void testDollarGroovyInnerClassUsagesInStubs() throws Exception {
471     def javaFile = myFixture.addClass("""
472       public class JavaClass {
473         public static class InnerJavaClass {}
474       }
475 """)
476     myFixture.addFileToProject("WithInner.groovy", """
477 class WithInner {
478   static class Inner {}
479 }
480 """)
481     assertEmpty make()
482
483     myFixture.addFileToProject("Usage.groovy", """
484 class Usage {
485   def foo(WithInner.Inner i) {}
486   def foo(JavaClass.InnerJavaClass i) {}
487 }
488 """)
489
490     touch(javaFile.containingFile.virtualFile)
491     assertEmpty make()
492   }
493
494   public void testDollarGroovyInnerClassUsagesInStubs2() throws Exception {
495     myFixture.addClass(""" public class JavaClass { } """)
496     myFixture.addFileToProject("WithInner.groovy", """
497 class WithInner {
498   static class Inner {}
499 }
500 """)
501
502     myFixture.addFileToProject("Usage.groovy", """
503 class Usage {
504   def foo(WithInner.Inner i) {}
505 }
506 """)
507
508     assertEmpty make()
509   }
510
511   public void testGroovyAnnotations() {
512     myFixture.addClass 'public @interface Anno { Class<?>[] value(); }'
513     myFixture.addFileToProject 'Foo.groovy', '@Anno([String]) class Foo {}'
514     myFixture.addFileToProject 'Bar.java', 'class Bar extends Foo {}'
515
516     assertEmpty make()
517   }
518
519   public void testGenericStubs() {
520     myFixture.addFileToProject 'Foo.groovy', 'class Foo { List<String> list }'
521     myFixture.addFileToProject 'Bar.java', 'class Bar {{ for (String s : new Foo().getList()) { s.hashCode(); } }}'
522     assertEmpty make()
523   }
524
525   public void testDuplicateClassDuringCompilation() throws Exception {
526     def base = myFixture.addFileToProject('p/Base.groovy', 'package p; class Base { }').virtualFile
527     myFixture.addFileToProject('p/Indirect.groovy', '''package p
528 class Indirect {
529   private static class Inner { Base b }
530
531   private Indirect.Inner foo(Indirect.Inner g1, Inner g2, Base b) {}
532  }''').virtualFile
533     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { p.Indirect foo() {} }').virtualFile
534     assertEmpty make()
535
536     touch(foo)
537     touch(base)
538     assertEmpty make()
539   }
540
541   public void testDontRecompileUnneeded() {
542     myFixture.addFileToProject('Base.groovy', 'class Base { }')
543     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo extends Base { }').virtualFile
544     myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo { }')
545     def main = myFixture.addFileToProject('Main.groovy', 'class Main extends Bar { }').virtualFile
546     assertEmpty make()
547     long oldBaseStamp = findClassFile("Base").timeStamp
548     long oldMainStamp = findClassFile("Main").timeStamp
549
550     touch(main)
551     touch(foo)
552     assertEmpty make()
553     assert oldMainStamp != findClassFile("Main").timeStamp
554     assert oldBaseStamp == findClassFile("Base").timeStamp
555   }
556
557   public void testPartialCrossRecompile() {
558     def used = myFixture.addFileToProject('Used.groovy', 'class Used { }')
559     def java = myFixture.addFileToProject('Java.java', 'class Java { void foo(Used used) {} }')
560     def main = myFixture.addFileToProject('Main.groovy', 'class Main extends Java {  }').virtualFile
561
562     assertEmpty compileModule(myModule)
563
564     touch(used.virtualFile)
565     touch(main)
566     assertEmpty make()
567
568     assertEmpty compileModule(myModule)
569     assertEmpty compileModule(myModule)
570
571     setFileText(used, 'class Used2 {}')
572     shouldFail { make() }
573     assert findClassFile('Used') == null
574
575     setFileText(used, 'class Used3 {}')
576     setFileText(java, 'class Java { void foo(Used3 used) {} }')
577     assertEmpty make()
578
579     assert findClassFile('Used2') == null
580   }
581
582   public void testClassLoadingDuringBytecodeGeneration() {
583     def used = myFixture.addFileToProject('Used.groovy', 'class Used { }')
584     def java = myFixture.addFileToProject('Java.java', '''
585 abstract class Java {
586   Object getProp() { return null; }
587   abstract void foo(Used used);
588 }''')
589     def main = myFixture.addFileToProject('Main.groovy', '''
590 class Main {
591   def foo(Java j) {
592     return j.prop
593   }
594 }''').virtualFile
595
596     assertEmpty make()
597
598     touch(used.virtualFile)
599     touch(main)
600     assertEmpty make()
601   }
602
603   public void testMakeInDependentModuleAfterChunkRebuild() {
604     def used = myFixture.addFileToProject('Used.groovy', 'class Used { }')
605     def java = myFixture.addFileToProject('Java.java', 'class Java { void foo(Used used) {} }')
606     def main = myFixture.addFileToProject('Main.groovy', 'class Main extends Java {  }').virtualFile
607
608     addGroovyLibrary(addDependentModule())
609
610     def dep = myFixture.addFileToProject("dependent/Dep.java", "class Dep { }")
611
612     assertEmpty make()
613
614     setFileText(used, 'class Used { String prop }')
615     touch(main)
616     setFileText(dep, 'class Dep { String prop = new Used().getProp(); }')
617
618     assertEmpty make()
619   }
620
621   public void "test extend package-local class from another module"() {
622     addGroovyLibrary(addDependentModule())
623
624     myFixture.addClass("package foo; class Foo {}")
625     myFixture.addFileToProject("dependent/foo/Bar.java", "package foo; class Bar extends Foo {}")
626     myFixture.addFileToProject("dependent/foo/Goo.groovy", "package foo; class Goo extends Bar {}")
627
628     assertEmpty make()
629   }
630
631   public void "test module cycle"() {
632     def dep = addDependentModule()
633     ModuleRootModificationUtil.addDependency(myModule, dep)
634     addGroovyLibrary(dep)
635
636     myFixture.addFileToProject('Foo.groovy', 'class Foo extends Bar { static void main(String[] args) { println "Hello from Foo" } }')
637     myFixture.addFileToProject('FooX.java', 'class FooX extends Bar { }')
638     myFixture.addFileToProject('FooY.groovy', 'class FooY extends BarX { }')
639     myFixture.addFileToProject("dependent/Bar.groovy", "class Bar { Foo f; static void main(String[] args) { println 'Hello from Bar' } }")
640     myFixture.addFileToProject("dependent/BarX.java", "class BarX { Foo f; }")
641     myFixture.addFileToProject("dependent/BarY.groovy", "class BarY extends FooX { }")
642
643     def checkClassFiles = {
644       assert findClassFile('Foo', myModule)
645       assert findClassFile('FooX', myModule)
646       assert findClassFile('Bar', dep)
647       assert findClassFile('BarX', dep)
648
649       assert !findClassFile('Bar', myModule)
650       assert !findClassFile('BarX', myModule)
651       assert !findClassFile('Foo', dep)
652       assert !findClassFile('FooX', dep)
653     }
654
655     assertEmpty(make())
656     checkClassFiles()
657
658     assertEmpty(make())
659     checkClassFiles()
660
661     assertOutput('Foo', 'Hello from Foo', myModule)
662     assertOutput('Bar', 'Hello from Bar', dep)
663
664     checkClassFiles()
665   }
666
667   public void testCompileTimeConstants() {
668     myFixture.addFileToProject 'Gr.groovy', '''
669 interface Gr {
670   String HELLO = "Hello"
671   int MAGIC = 239
672   Boolean BOOL = true
673   boolean bool = true
674 }'''
675     myFixture.addFileToProject 'Main.java', '''
676 public class Main {
677   public static void main(String[] args) {
678     System.out.println(Gr.HELLO + ", " + Gr.BOOL + Gr.bool + Gr.MAGIC);
679   }
680 }
681 '''
682     make()
683     assertOutput 'Main', 'Hello, truetrue239'
684   }
685
686   public void "test reporting rebuild errors caused by missing files excluded from compilation"() {
687     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {}')
688     myFixture.addFileToProject 'Bar.groovy', 'class Bar extends Foo {}'
689
690     make()
691
692     excludeFromCompilation(foo)
693
694     shouldFail { rebuild() }
695   }
696
697   public void "test compile groovy excluded from stub generation"() {
698     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {}')
699     myFixture.addFileToProject 'Bar.groovy', 'class Bar extends Foo {}'
700
701     excludeFromCompilation(GroovyCompilerConfiguration.getInstance(project).excludeFromStubGeneration, foo)
702
703     assertEmpty make()
704   }
705
706   private void excludeFromCompilation(PsiFile foo) {
707     excludeFromCompilation(CompilerConfiguration.getInstance(project).getExcludedEntriesConfiguration(), foo)
708   }
709
710   private excludeFromCompilation(ExcludesConfiguration configuration, PsiFile foo) {
711     configuration.addExcludeEntryDescription(new ExcludeEntryDescription(foo.virtualFile, false, true, testRootDisposable))
712   }
713
714   public void "test make stub-level error and correct it"() {
715     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { }')
716     myFixture.addFileToProject('Bar.java', 'class Bar extends Foo {}')
717
718     assertEmpty make()
719
720     setFileText(foo, 'class Foo implements Runnabl {}')
721
722     def compilerTempRoot = BuildManager.instance.getProjectSystemDirectory(project).absolutePath
723     try {
724       VfsRootAccess.allowRootAccess(compilerTempRoot) //because compilation error points to file under 'groovyStubs' directory
725       shouldFail { make() }
726     }
727     finally {
728       VfsRootAccess.disallowRootAccess(compilerTempRoot)
729     }
730
731     setFileText(foo, 'class Foo {}')
732
733     assertEmpty make()
734   }
735
736   public void "test reporting module compile errors caused by missing files excluded from compilation"() {
737     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {}')
738     myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo {}')
739
740     make()
741
742     excludeFromCompilation(foo)
743
744     shouldFail { compileModule(myModule) }
745   }
746
747   public void "test stubs generated while processing groovy class file dependencies"() {
748     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { }')
749     def bar = myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo { }')
750     def client = myFixture.addFileToProject('Client.groovy', 'class Client { Bar bar = new Bar() }')
751     def java = myFixture.addFileToProject('Java.java', 'class Java extends Client { String getName(Bar bar) { return bar.toString();  } }')
752
753     assertEmpty(make())
754
755     setFileText(bar, 'class Bar { }')
756
757     assertEmpty(make())
758     assert findClassFile("Client")
759   }
760
761   public void "test ignore groovy internal non-existent interface helper inner class"() {
762     myFixture.addFileToProject 'Foo.groovy', '''
763 interface Foo {}
764
765 class Zoo {
766   Foo foo() {}
767   static class Inner implements Foo {}
768 }
769
770 '''
771     def bar = myFixture.addFileToProject('Bar.groovy', 'class Bar { def foo = new Zoo.Inner() {}  }')
772
773     assertEmpty make()
774     assertEmpty compileFiles(bar.virtualFile)
775   }
776
777   public void "test multiline strings"() {
778     myFixture.addFileToProject 'Foo.groovy', '''class Foo {
779   public static final String s = """
780 multi
781 line
782 string
783 """
784  } '''
785     myFixture.addFileToProject 'Bar.java', 'class Bar extends Foo {} '
786
787     assertEmpty make()
788   }
789
790   public void "test inner java class references with incremental recompilation"() {
791     def bar1 = myFixture.addFileToProject('bar/Bar1.groovy', 'package bar; class Bar1 extends Bar2 { } ')
792     myFixture.addFileToProject('bar/Bar2.java', 'package bar; class Bar2 extends Bar3 { } ')
793     def bar3 = myFixture.addFileToProject('bar/Bar3.groovy', 'package bar; class Bar3 { Bar1 property } ')
794
795     myFixture.addClass("package foo; public class Outer { public static class Inner extends bar.Bar1 { } }")
796     def using = myFixture.addFileToProject('UsingInner.groovy', 'import foo.Outer; class UsingInner extends bar.Bar1 { Outer.Inner property } ')
797
798     assertEmpty make()
799
800     touch bar1.virtualFile
801     touch bar3.virtualFile
802     touch using.virtualFile
803
804     assertEmpty make()
805   }
806
807   public void "test rename class to java and touch its usage"() {
808     def usage = myFixture.addFileToProject('Usage.groovy', 'class Usage { Renamed r } ')
809     def renamed = myFixture.addFileToProject('Renamed.groovy', 'public class Renamed { } ')
810     assertEmpty make()
811
812     touch usage.virtualFile
813     setFileName(renamed, 'Renamed.java')
814     assertEmpty make()
815   }
816
817   public void "test compiling static extension"() {
818     setupTestSources()
819     myFixture.addFileToProject "src/extension/Extension.groovy", """
820 package extension
821 import groovy.transform.CompileStatic
822
823 @CompileStatic class Extension {
824     static <T> T test2(List<T> self) {
825         self.first()
826     }
827 }"""
828     myFixture.addFileToProject "src/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule", """
829 moduleName=extension-verify
830 moduleVersion=1.0-test
831 extensionClasses=extension.Extension
832 staticExtensionClasses=
833 """
834     myFixture.addFileToProject "tests/AppTest.groovy", """
835 class AppTest {
836     @groovy.transform.CompileStatic
837     static main(args) {
838         List<String> list = new ArrayList<>()
839         list.add("b")
840         list.add("c")
841         println list.test2()
842     }
843 }
844 """
845     assertEmpty make()
846     assertOutput 'AppTest', 'b'
847   }
848
849   public void "test no groovy library"() {
850     myFixture.addFileToProject("dependent/a.groovy", "");
851     addModule("dependent", true)
852
853     def messages = make()
854     assert messages.find { it.message.contains("Cannot compile Groovy files: no Groovy library is defined for module 'dependent'") }
855   }
856
857   public void testGroovyOutputIsInstrumented() {
858     myFixture.addFileToProject("Bar.groovy",
859        "import org.jetbrains.annotations.NotNull; " +
860        "public class Bar {" +
861          "void xxx(@NotNull String param) { println param }\n" +
862          "static void main(String[] args) { new Bar().xxx(null) }"+
863        "}"
864     );
865
866     File annotations = new File(PathManager.getJarPathForClass(NotNull.class));
867     PsiTestUtil.addLibrary(myModule, "annotations", annotations.getParent(), annotations.getName());
868
869     assertEmpty(make());
870
871     final Ref<Boolean> exceptionFound = Ref.create(Boolean.FALSE);
872     ProcessHandler process = runProcess("Bar", myModule, DefaultRunExecutor.class, new ProcessAdapter() {
873       @Override
874       public void onTextAvailable(ProcessEvent event, Key outputType) {
875         if (ProcessOutputTypes.SYSTEM != outputType) {
876           if (!exceptionFound.get()) {
877             exceptionFound.set(event.getText().contains("java.lang.IllegalArgumentException: Argument for @NotNull parameter 'param' of Bar.xxx must not be null"));
878           }
879         }
880       }
881     }, ProgramRunner.PROGRAM_RUNNER_EP.findExtension(DefaultJavaProgramRunner.class));
882     process.waitFor();
883
884     assertTrue(exceptionFound.get());
885   }
886
887   public void "test extend groovy classes with additional dependencies"() {
888     PsiTestUtil.addLibrary(myModule, "junit", GroovyFacetUtil.libDirectory, "junit.jar");
889     PsiTestUtil.addLibrary(myModule, "cli", FileUtil.toCanonicalPath(PluginPathManager.getPluginHomePath("groovy") + "/../../build/lib"), "commons-cli-1.2.jar");
890
891     myFixture.addFileToProject("a.groovy", "class Foo extends GroovyTestCase {}")
892     myFixture.addFileToProject("b.groovy", "class Bar extends CliBuilder {}")
893     assertEmpty(make())
894   }
895
896   static class GroovycTest extends GroovyCompilerTest {
897     public void "test navigate from stub to source"() {
898       GroovyFile groovyFile = (GroovyFile) myFixture.addFileToProject("a.groovy", "class Groovy3 { InvalidType type }")
899       myFixture.addClass("class Java4 extends Groovy3 {}").containingFile
900
901       def msg = make().find { it.message.contains('InvalidType') }
902       assert msg?.virtualFile
903       ApplicationManager.application.runWriteAction { msg.virtualFile.delete(this) }
904
905       def messages = make()
906       assert messages
907       def error = messages.find { it.message.contains('InvalidType') }
908       assert error?.virtualFile
909       assert groovyFile.classes[0] == GroovyCompilerLoader.findClassByStub(project, error.virtualFile)
910     }
911
912     public void "test config script"() {
913       def script = FileUtil.createTempFile("configScriptTest", ".groovy", true)
914       FileUtil.writeToFile(script, "import groovy.transform.*; withConfig(configuration) { ast(CompileStatic) }")
915
916       CompilerWorkspaceConfiguration.getInstance(project).COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS = "-Dgroovyc.config.script=" + script.path
917
918       myFixture.addFileToProject("a.groovy", "class A { int s = 'foo' }")
919       shouldFail { make() }
920     }
921     
922   }
923
924   static class EclipseTest extends GroovyCompilerTest {
925     @Override
926     protected void setUp() {
927       super.setUp()
928
929       ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(project)).defaultCompiler = new GreclipseIdeaCompiler(project)
930
931       def jarName = "groovy-eclipse-batch-2.3.4-01.jar"
932       def jarPath = FileUtil.toCanonicalPath(PluginPathManager.getPluginHomePath("groovy") + "/lib/" + jarName)
933
934       GreclipseIdeaCompilerSettings.getSettings(project).greclipsePath = jarPath
935     }
936
937   }
938
939 }