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