Groovy-Eclipse compiler support back-end (IDEA-52379)
[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
19 import com.intellij.compiler.CompilerConfiguration
20 import com.intellij.compiler.CompilerConfigurationImpl
21 import com.intellij.compiler.CompilerWorkspaceConfiguration
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.ExcludedEntriesConfiguration
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.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.lang.psi.GroovyFile
47
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   private 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 module cycle"() {
621     def dep = addDependentModule()
622     ModuleRootModificationUtil.addDependency(myModule, dep)
623     addGroovyLibrary(dep)
624
625     myFixture.addFileToProject('Foo.groovy', 'class Foo extends Bar { static void main(String[] args) { println "Hello from Foo" } }')
626     myFixture.addFileToProject('FooX.java', 'class FooX extends Bar { }')
627     myFixture.addFileToProject("dependent/Bar.groovy", "class Bar { Foo f; static void main(String[] args) { println 'Hello from Bar' } }")
628     myFixture.addFileToProject("dependent/BarX.java", "class BarX { Foo f; }")
629
630     def checkClassFiles = {
631       assert findClassFile('Foo', myModule)
632       assert findClassFile('FooX', myModule)
633       assert findClassFile('Bar', dep)
634       assert findClassFile('BarX', dep)
635
636       assert !findClassFile('Bar', myModule)
637       assert !findClassFile('BarX', myModule)
638       assert !findClassFile('Foo', dep)
639       assert !findClassFile('FooX', dep)
640     }
641
642     assertEmpty(make())
643     checkClassFiles()
644
645     assertEmpty(make())
646     checkClassFiles()
647
648     assertOutput('Foo', 'Hello from Foo', myModule)
649     assertOutput('Bar', 'Hello from Bar', dep)
650
651     checkClassFiles()
652   }
653
654   public void testCompileTimeConstants() {
655     myFixture.addFileToProject 'Gr.groovy', '''
656 interface Gr {
657   String HELLO = "Hello"
658   int MAGIC = 239
659   Boolean BOOL = true
660   boolean bool = true
661 }'''
662     myFixture.addFileToProject 'Main.java', '''
663 public class Main {
664   public static void main(String[] args) {
665     System.out.println(Gr.HELLO + ", " + Gr.BOOL + Gr.bool + Gr.MAGIC);
666   }
667 }
668 '''
669     make()
670     assertOutput 'Main', 'Hello, truetrue239'
671   }
672
673   public void "test reporting rebuild errors caused by missing files excluded from compilation"() {
674     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {}')
675     myFixture.addFileToProject 'Bar.groovy', 'class Bar extends Foo {}'
676
677     make()
678
679     excludeFromCompilation(foo)
680
681     shouldFail { rebuild() }
682   }
683
684   private void excludeFromCompilation(PsiFile foo) {
685     final ExcludedEntriesConfiguration configuration =
686       ((CompilerConfigurationImpl)CompilerConfiguration.getInstance(project)).getExcludedEntriesConfiguration()
687     configuration.addExcludeEntryDescription(new ExcludeEntryDescription(foo.virtualFile, false, true, testRootDisposable))
688   }
689
690   public void "test make stub-level error and correct it"() {
691     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { }')
692     myFixture.addFileToProject('Bar.java', 'class Bar extends Foo {}')
693
694     assertEmpty make()
695
696     setFileText(foo, 'class Foo implements Runnabl {}')
697
698     shouldFail { make() }
699
700     setFileText(foo, 'class Foo {}')
701
702     assertEmpty make()
703   }
704
705   public void "test reporting module compile errors caused by missing files excluded from compilation"() {
706     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {}')
707     myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo {}')
708
709     make()
710
711     excludeFromCompilation(foo)
712
713     shouldFail { compileModule(myModule) }
714   }
715
716   public void "test stubs generated while processing groovy class file dependencies"() {
717     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { }')
718     def bar = myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo { }')
719     def client = myFixture.addFileToProject('Client.groovy', 'class Client { Bar bar = new Bar() }')
720     def java = myFixture.addFileToProject('Java.java', 'class Java extends Client { String getName(Bar bar) { return bar.toString();  } }')
721
722     assertEmpty(make())
723
724     setFileText(bar, 'class Bar { }')
725
726     assertEmpty(make())
727     assert findClassFile("Client")
728   }
729
730   public void "test ignore groovy internal non-existent interface helper inner class"() {
731     myFixture.addFileToProject 'Foo.groovy', '''
732 interface Foo {}
733
734 class Zoo {
735   Foo foo() {}
736   static class Inner implements Foo {}
737 }
738
739 '''
740     def bar = myFixture.addFileToProject('Bar.groovy', 'class Bar { def foo = new Zoo.Inner() {}  }')
741
742     assertEmpty make()
743     assertEmpty compileFiles(bar.virtualFile)
744   }
745
746   public void "test multiline strings"() {
747     myFixture.addFileToProject 'Foo.groovy', '''class Foo {
748   public static final String s = """
749 multi
750 line
751 string
752 """
753  } '''
754     myFixture.addFileToProject 'Bar.java', 'class Bar extends Foo {} '
755
756     assertEmpty make()
757   }
758
759   public void "test inner java class references with incremental recompilation"() {
760     def bar1 = myFixture.addFileToProject('bar/Bar1.groovy', 'package bar; class Bar1 extends Bar2 { } ')
761     myFixture.addFileToProject('bar/Bar2.java', 'package bar; class Bar2 extends Bar3 { } ')
762     def bar3 = myFixture.addFileToProject('bar/Bar3.groovy', 'package bar; class Bar3 { Bar1 property } ')
763
764     myFixture.addClass("package foo; public class Outer { public static class Inner extends bar.Bar1 { } }")
765     def using = myFixture.addFileToProject('UsingInner.groovy', 'import foo.Outer; class UsingInner extends bar.Bar1 { Outer.Inner property } ')
766
767     assertEmpty make()
768
769     touch bar1.virtualFile
770     touch bar3.virtualFile
771     touch using.virtualFile
772
773     assertEmpty make()
774   }
775
776   public void "test rename class to java and touch its usage"() {
777     def usage = myFixture.addFileToProject('Usage.groovy', 'class Usage { Renamed r } ')
778     def renamed = myFixture.addFileToProject('Renamed.groovy', 'public class Renamed { } ')
779     assertEmpty make()
780
781     touch usage.virtualFile
782     setFileName(renamed, 'Renamed.java')
783     assertEmpty make()
784   }
785
786   public void "test compiling static extension"() {
787     setupTestSources()
788     myFixture.addFileToProject "src/extension/Extension.groovy", """
789 package extension
790 import groovy.transform.CompileStatic
791
792 @CompileStatic class Extension {
793     static <T> T test2(List<T> self) {
794         self.first()
795     }
796 }"""
797     myFixture.addFileToProject "src/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule", """
798 moduleName=extension-verify
799 moduleVersion=1.0-test
800 extensionClasses=extension.Extension
801 staticExtensionClasses=
802 """
803     myFixture.addFileToProject "tests/AppTest.groovy", """
804 class AppTest {
805     @groovy.transform.CompileStatic
806     static main(args) {
807         List<String> list = new ArrayList<>()
808         list.add("b")
809         list.add("c")
810         println list.test2()
811     }
812 }
813 """
814     assertEmpty make()
815     assertOutput 'AppTest', 'b'
816   }
817
818   public void "test no groovy library"() {
819     myFixture.addFileToProject("dependent/a.groovy", "");
820     addModule("dependent", true)
821
822     def messages = make()
823     assert messages.find { it.message.contains("Cannot compile Groovy files: no Groovy library is defined for module 'dependent'") }
824   }
825
826   public void testGroovyOutputIsInstrumented() {
827     myFixture.addFileToProject("Bar.groovy",
828        "import org.jetbrains.annotations.NotNull; " +
829        "public class Bar {" +
830          "void xxx(@NotNull String param) { println param }\n" +
831          "static void main(String[] args) { new Bar().xxx(null) }"+
832        "}"
833     );
834
835     File annotations = new File(PathManager.getJarPathForClass(NotNull.class));
836     PsiTestUtil.addLibrary(myModule, "annotations", annotations.getParent(), annotations.getName());
837
838     assertEmpty(make());
839
840     final Ref<Boolean> exceptionFound = Ref.create(Boolean.FALSE);
841     ProcessHandler process = runProcess("Bar", myModule, DefaultRunExecutor.class, new ProcessAdapter() {
842       @Override
843       public void onTextAvailable(ProcessEvent event, Key outputType) {
844         if (ProcessOutputTypes.SYSTEM != outputType) {
845           if (!exceptionFound.get()) {
846             exceptionFound.set(event.getText().contains("java.lang.IllegalArgumentException: Argument for @NotNull parameter 'param' of Bar.xxx must not be null"));
847           }
848         }
849       }
850     }, ProgramRunner.PROGRAM_RUNNER_EP.findExtension(DefaultJavaProgramRunner.class));
851     process.waitFor();
852
853     assertTrue(exceptionFound.get());
854   }
855
856   static class GroovycTest extends GroovyCompilerTest {
857     public void "test navigate from stub to source"() {
858       GroovyFile groovyFile = (GroovyFile) myFixture.addFileToProject("a.groovy", "class Groovy3 { InvalidType type }")
859       myFixture.addClass("class Java4 extends Groovy3 {}").containingFile
860
861       def msg = make().find { it.message.contains('InvalidType') }
862       assert msg?.virtualFile
863       ApplicationManager.application.runWriteAction { msg.virtualFile.delete(this) }
864
865       def messages = make()
866       assert messages
867       def error = messages.find { it.message.contains('InvalidType') }
868       assert error?.virtualFile
869       assert groovyFile.classes[0] == GroovyCompilerLoader.findClassByStub(project, error.virtualFile)
870     }
871   }
872
873   static class EclipseTest extends GroovyCompilerTest {
874     @Override
875     protected void setUp() {
876       super.setUp()
877
878       def conf = CompilerWorkspaceConfiguration.getInstance(project)
879       assert conf.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS == CompilerWorkspaceConfiguration.DEFAULT_COMPILE_PROCESS_VM_OPTIONS
880
881       def jarName = "groovy-eclipse-batch-2.3.4-01.jar"
882       def jarPath = FileUtil.toCanonicalPath(PluginPathManager.getPluginHomePath("groovy") + "/lib/" + jarName)
883       conf.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS = "-Dgroovy.eclipse.batch.jar=" + jarPath
884     }
885
886     @Override
887     protected void tearDown() throws Exception {
888       def conf = CompilerWorkspaceConfiguration.getInstance(project)
889       conf.COMPILER_PROCESS_ADDITIONAL_VM_OPTIONS = CompilerWorkspaceConfiguration.DEFAULT_COMPILE_PROCESS_VM_OPTIONS
890
891       super.tearDown()
892     }
893   }
894
895 }