a test for partial groovy-java cross compile
[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
20 import com.intellij.compiler.CompilerConfiguration
21 import com.intellij.openapi.module.Module
22 import com.intellij.openapi.vfs.VirtualFile
23 import com.intellij.psi.PsiFile
24 import junit.framework.AssertionFailedError
25
26 /**
27  * @author peter
28  */
29 public abstract class GroovyCompilerTest extends GroovyCompilerTestCase {
30   @Override protected void setUp() {
31     super.setUp();
32     addGroovyLibrary(myModule);
33   }
34
35   public void testPlainGroovy() throws Throwable {
36     myFixture.addFileToProject("A.groovy", "println '239'");
37     assertEmpty(make());
38     assertOutput("A", "239");
39   }
40
41   public void testJavaDependsOnGroovy() throws Throwable {
42     myFixture.addClass("public class Foo {" +
43                        "public static void main(String[] args) { " +
44                        "  System.out.println(new Bar().foo());" +
45                        "}" +
46                        "}");
47     myFixture.addFileToProject("Bar.groovy", "class Bar {" +
48                                              "  def foo() {" +
49                                              "    239" +
50                                              "  }" +
51                                              "}");
52     make();
53     assertOutput("Foo", "239");
54   }
55
56   public void testCorrectFailAndCorrect() throws Exception {
57     myFixture.addClass("public class Foo {" +
58                        "public static void main(String[] args) { " +
59                        "  System.out.println(new Bar().foo());" +
60                        "}" +
61                        "}");
62     final String barText = "class Bar {" + "  def foo() { 239  }" + "}";
63     final PsiFile file = myFixture.addFileToProject("Bar.groovy", barText);
64     make()
65     assertOutput("Foo", "239");
66
67     setFileText(file, "class Bar {}");
68     makeShouldFail()
69
70     setFileText(file, barText);
71     make();
72     assertOutput("Foo", "239");
73   }
74
75   private void makeShouldFail() {
76     try {
77       make();
78       fail("Make should fail");
79     }
80     catch (RuntimeException e) {
81       if (!(e.getCause() instanceof AssertionFailedError)) {
82         throw e;
83       }
84     }
85   }
86
87   public void testRenameToJava() throws Throwable {
88     myFixture.addClass("public class Foo {" +
89                        "public static void main(String[] args) { " +
90                        "  System.out.println(new Bar().foo());" +
91                        "}" +
92                        "}");
93
94     final PsiFile bar =
95       myFixture.addFileToProject("Bar.groovy", "public class Bar {" + "public int foo() { " + "  return 239;" + "}" + "}");
96
97     make();
98     assertOutput("Foo", "239");
99
100     setFileName bar, "Bar.java"
101
102     make();
103     assertOutput("Foo", "239");
104   }
105
106   public void testTransitiveJavaDependency() throws Throwable {
107     final VirtualFile ifoo = myFixture.addClass("public interface IFoo { int foo(); }").getContainingFile().getVirtualFile();
108     myFixture.addClass("public class Foo implements IFoo {" +
109                        "  public int foo() { return 239; }" +
110                        "}");
111     final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar {" +
112                                                                  "Foo foo\n" +
113                                                                  "public static void main(String[] args) { " +
114                                                                  "  System.out.println(new Foo().foo());" +
115                                                                  "}" +
116                                                                  "}");
117     assertEmpty(make());
118     assertOutput("Bar", "239");
119
120     touch(ifoo);
121     touch(bar.getVirtualFile());
122
123     //assertTrue(assertOneElement(make()).contains("WARNING: Groovyc stub generation failed"));
124     assertEmpty make()
125     assertOutput("Bar", "239");
126   }
127
128   public void testTransitiveJavaDependencyThroughGroovy() throws Throwable {
129     myFixture.addClass("public class IFoo { void foo() {} }").getContainingFile().getVirtualFile();
130     myFixture.addFileToProject("Foo.groovy", "class Foo {\n" +
131                        "  static IFoo f\n" +
132                        "  public int foo() { return 239; }\n" +
133                        "}");
134     final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar extends Foo {" +
135                                                                  "public static void main(String[] args) { " +
136                                                                  "  System.out.println(new Foo().foo());" +
137                                                                  "}" +
138                                                                  "}");
139     assertEmpty(make());
140     assertOutput("Bar", "239");
141
142     deleteClassFile("IFoo");
143     touch(bar.getVirtualFile());
144
145     //assertTrue(assertOneElement(make()).contains("WARNING: Groovyc error"));
146     assertEmpty make()
147     assertOutput("Bar", "239");
148   }
149
150   public void testTransitiveGroovyDependency() throws Throwable {
151     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo {} ')
152     def bar = myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo {}')
153     def goo = myFixture.addFileToProject('Goo.groovy', 'class Goo extends Bar {}')
154     assertEmpty(make());
155
156     touch(foo.virtualFile)
157     touch(goo.virtualFile)
158     assertEmpty(make());
159   }
160
161   public void testJavaDependsOnGroovyEnum() throws Throwable {
162     myFixture.addFileToProject("Foo.groovy", "enum Foo { FOO }")
163     myFixture.addClass("class Bar { Foo f; }")
164     assertEmpty(make())
165   }
166
167   public void testDeleteTransitiveJavaClass() throws Throwable {
168     myFixture.addClass("public interface IFoo { int foo(); }");
169     myFixture.addClass("public class Foo implements IFoo {" +
170                        "  public int foo() { return 239; }" +
171                        "}");
172     final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar {" +
173                                                                  "Foo foo\n" +
174                                                                  "public static void main(String[] args) { " +
175                                                                  "  System.out.println(new Foo().foo());" +
176                                                                  "}" +
177                                                                  "}");
178     assertEmpty(make());
179     assertOutput("Bar", "239");
180
181     deleteClassFile("IFoo");
182     touch(bar.getVirtualFile());
183
184     //assertTrue(assertOneElement(make()).contains("WARNING: Groovyc stub generation failed"));
185     assertEmpty make()
186     assertOutput("Bar", "239");
187   }
188
189   public void testGroovyDependsOnGroovy() throws Throwable {
190     myFixture.addClass("public class JustToMakeGroovyGenerateStubs {}");
191     myFixture.addFileToProject("Foo.groovy", "class Foo { }");
192     final PsiFile bar = myFixture.addFileToProject("Bar.groovy", "class Bar {" +
193                                                                  "def foo(Foo f) {}\n" +
194                                                                  "public static void main(String[] args) { " +
195                                                                  "  System.out.println(239);" +
196                                                                  "}" +
197                                                                  "}");
198     assertEmpty(make());
199     assertOutput("Bar", "239");
200
201     touch(bar.getVirtualFile());
202
203     assertEmpty(make());
204     assertOutput("Bar", "239");
205   }
206
207   public void testMakeInTests() throws Throwable {
208     setupTestSources();
209     myFixture.addFileToProject("tests/Super.groovy", "class Super {}");
210     assertEmpty(make());
211
212     myFixture.addFileToProject("tests/Sub.groovy", "class Sub {\n" +
213                                                                        "  Super xxx() {}\n" +
214                                                                        "  static void main(String[] args) {" +
215                                                                        "    println 'hello'" +
216                                                                        "  }" +
217                                                                        "}");
218     myFixture.addFileToProject("tests/Java.java", "public class Java {}");
219     assertEmpty(make());
220     assertOutput("Sub", "hello");
221   }
222
223   public void testTestsDependOnProduction() throws Throwable {
224     setupTestSources();
225     myFixture.addFileToProject("src/com/Bar.groovy", "package com\n" +
226                                                      "class Bar {}");
227     myFixture.addFileToProject("src/com/ToGenerateStubs.java", "package com;\n" +
228                                                      "public class ToGenerateStubs {}");
229     myFixture.addFileToProject("tests/com/BarTest.groovy", "package com\n" +
230                                                        "class BarTest extends Bar {}");
231     assertEmpty(make());
232   }
233
234   public void testStubForGroovyExtendingJava() throws Exception {
235     myFixture.addClass("public class Foo {}");
236     myFixture.addFileToProject("Bar.groovy", "class Bar extends Foo {}");
237     myFixture.addClass("public class Goo extends Bar {}");
238
239     assertEmpty(make());
240   }
241
242   public void testDontApplyTransformsFromSameModule() throws Exception {
243     addTransform();
244
245     myFixture.addClass("public class JavaClassToGenerateStubs {}");
246
247     assertEmpty(make());
248
249   }
250
251   private void addTransform() throws IOException {
252     myFixture.addFileToProject("Transf.groovy", """
253 import org.codehaus.groovy.ast.*
254 import org.codehaus.groovy.control.*
255 import org.codehaus.groovy.transform.*
256 @GroovyASTTransformation(phase = CompilePhase.CONVERSION)
257 public class Transf implements ASTTransformation {
258   void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
259     ModuleNode module = nodes[0]
260     for (clazz in module.classes) {
261       if (clazz.name.contains('Bar')) {
262         module.addStaticStarImport('Foo', ClassHelper.makeWithoutCaching(Foo.class))
263       }
264     }
265   }
266 }""");
267
268     myFixture.addFileToProject("Foo.groovy", "class Foo {\n" +
269                                              "static def autoImported() { 239 }\n" +
270                                              "}");
271
272     CompilerConfiguration.getInstance(getProject()).addResourceFilePattern("*.ASTTransformation");
273
274     myFixture.addFileToProject("META-INF/services/org.codehaus.groovy.transform.ASTTransformation", "Transf");
275   }
276
277   public void testApplyTransformsFromDependencies() throws Exception {
278     addTransform();
279
280     myFixture.addFileToProject("dependent/Bar.groovy", "class Bar {\n" +
281                                                        "  static Object zzz = autoImported()\n" +
282                                                        "  static void main(String[] args) {\n" +
283                                                        "    println zzz\n" +
284                                                        "  }\n" +
285                                                        "}");
286
287     myFixture.addFileToProject("dependent/AJavaClass.java", "class AJavaClass {}");
288
289     Module dep = addDependentModule();
290
291     addGroovyLibrary(dep);
292
293     assertEmpty(make());
294     assertOutput("Bar", "239", dep);
295   }
296
297   public void testIndirectDependencies() throws Exception {
298     myFixture.addFileToProject("dependent1/Bar1.groovy", "class Bar1 {}");
299     myFixture.addFileToProject("dependent2/Bar2.groovy", "class Bar2 extends Bar1 {}");
300     PsiFile main = myFixture.addFileToProject("Main.groovy", "class Main extends Bar2 {}");
301
302     Module dep1 = addModule('dependent1')
303     Module dep2 = addModule('dependent2')
304     addDependency dep2, dep1
305     addDependency myModule, dep2
306
307     addGroovyLibrary(dep1);
308     addGroovyLibrary(dep2);
309
310     assertEmpty(make())
311
312     touch(main.virtualFile)
313     assertEmpty(make())
314   }
315
316   public void testExtendFromGroovyAbstractClass() throws Exception {
317     myFixture.addFileToProject "Super.groovy", "abstract class Super {}"
318     myFixture.addFileToProject "AJava.java", "public class AJava {}"
319     assertEmpty make()
320
321     myFixture.addFileToProject "Sub.groovy", "class Sub extends Super {}"
322     assertEmpty make()
323   }
324
325   public void test1_7InnerClass() throws Exception {
326     myFixture.addFileToProject "Foo.groovy", """
327 class Foo {
328   static class Bar {}
329 }"""
330     def javaFile = myFixture.addFileToProject("AJava.java", "public class AJava extends Foo.Bar {}")
331     assertEmpty make()
332     
333     touch(javaFile.virtualFile)
334     assertEmpty make()
335   }
336
337   public void testRecompileDependentClass() throws Exception {
338     def cloud = myFixture.addFileToProject("Cloud.groovy", """
339 class Cloud {
340   def accessFooProperty(Foo c) {
341     c.prop = 2
342   }
343 }
344 """)
345     myFixture.addFileToProject "Foo.groovy", """
346 class Foo {
347   def withGooParameter(Goo x) {}
348 }"""
349     def goo = myFixture.addFileToProject("Goo.groovy", "class Goo {}")
350
351     assertEmpty make()
352
353     touch(cloud.virtualFile)
354     touch(goo.virtualFile)
355     assertEmpty make()
356   }
357
358   public void testRecompileExpressionReferences() throws Exception {
359     def rusCon = myFixture.addFileToProject('RusCon.groovy', '''
360 interface RusCon {
361   Closure foo = { Seq.foo() }
362 }''')
363     myFixture.addFileToProject "Seq.groovy", """
364 class Seq implements RusCon {
365   static def foo() { }
366 }"""
367     assertEmpty make()
368
369     touch(rusCon.virtualFile)
370     assertEmpty make()
371   }
372
373   public void testRecompileImportedClass() throws Exception {
374     def bar = myFixture.addFileToProject("pack/Bar.groovy", """
375 package pack
376 import pack.Foo
377 class Bar {}
378 """)
379     myFixture.addFileToProject "pack/Foo.groovy", """
380 package pack
381 class Foo extends Goo {
382 }"""
383     def goo = myFixture.addFileToProject("pack/Goo.groovy", """
384 package pack
385 class Goo {}""")
386
387     assertEmpty make()
388
389     touch(bar.virtualFile)
390     touch(goo.virtualFile)
391     assertEmpty make()
392   }
393
394   public void testRecompileDependentClassesWithOnlyOneChanged() throws Exception {
395     def bar = myFixture.addFileToProject("Bar.groovy", """
396 class Bar {
397   Foo f
398 }
399 """)
400     myFixture.addFileToProject "Foo.groovy", """
401 class Foo extends Bar {
402 }"""
403
404     assertEmpty make()
405
406     touch(bar.virtualFile)
407     assertEmpty make()
408   }
409
410   public void testDollarGroovyInnerClassUsagesInStubs() throws Exception {
411     def javaFile = myFixture.addClass("""
412       public class JavaClass {
413         public static class InnerJavaClass {}
414       }
415 """)
416     myFixture.addFileToProject("WithInner.groovy", """
417 class WithInner {
418   static class Inner {}
419 }
420 """)
421     assertEmpty make()
422
423     myFixture.addFileToProject("Usage.groovy", """
424 class Usage {
425   def foo(WithInner.Inner i) {}
426   def foo(JavaClass.InnerJavaClass i) {}
427 }
428 """)
429
430     touch(javaFile.containingFile.virtualFile)
431     assertEmpty make()
432   }
433
434   public void testDollarGroovyInnerClassUsagesInStubs2() throws Exception {
435     myFixture.addClass(""" public class JavaClass { } """)
436     myFixture.addFileToProject("WithInner.groovy", """
437 class WithInner {
438   static class Inner {}
439 }
440 """)
441
442     myFixture.addFileToProject("Usage.groovy", """
443 class Usage {
444   def foo(WithInner.Inner i) {}
445 }
446 """)
447
448     assertEmpty make()
449   }
450
451   public void testGroovyAnnotations() {
452     myFixture.addClass 'public @interface Anno { Class[] value(); }'
453     myFixture.addFileToProject 'Foo.groovy', '@Anno([String]) class Foo {}'
454     myFixture.addFileToProject 'Bar.java', 'class Bar extends Foo {}'
455
456     assertEmpty make()
457   }
458
459   public void testGenericStubs() {
460     myFixture.addFileToProject 'Foo.groovy', 'class Foo { List<String> list }'
461     myFixture.addFileToProject 'Bar.java', 'class Bar {{ for (String s : new Foo().getList()) {} }}'
462     assertEmpty make()
463   }
464
465   public void testDuplicateClassDuringCompilation() throws Exception {
466     def base = myFixture.addFileToProject('p/Base.groovy', 'package p; class Base { }').virtualFile
467     myFixture.addFileToProject('p/Indirect.groovy', '''package p
468 class Indirect {
469   private static class Inner { Base b }
470
471   private Indirect.Inner foo(Indirect.Inner g1, Inner g2, Base b) {}
472  }''').virtualFile
473     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo { p.Indirect foo() {} }').virtualFile
474     assertEmpty make()
475
476     touch(foo)
477     touch(base)
478     assertEmpty make()
479   }
480
481   public void testDontRecompileUnneeded() {
482     myFixture.addFileToProject('Base.groovy', 'class Base { }')
483     def foo = myFixture.addFileToProject('Foo.groovy', 'class Foo extends Base { }').virtualFile
484     myFixture.addFileToProject('Bar.groovy', 'class Bar extends Foo { }')
485     def main = myFixture.addFileToProject('Main.groovy', 'class Main extends Bar { }').virtualFile
486     assertEmpty make()
487     long oldBaseStamp = findClassFile("Base").modificationStamp
488     long oldMainStamp = findClassFile("Main").modificationStamp
489
490     touch(main)
491     touch(foo)
492     assertEmpty make()
493     assert oldMainStamp != findClassFile("Main").modificationStamp
494     assert oldBaseStamp == findClassFile("Base").modificationStamp
495   }
496
497   public void testPartialCrossRecompile() {
498     def used = myFixture.addFileToProject('Used.groovy', 'class Used { }')
499     def java = myFixture.addFileToProject('Java.java', 'class Java { void foo(Used used) {} }')
500     def main = myFixture.addFileToProject('Main.groovy', 'class Main extends Java {  }').virtualFile
501
502     assertEmpty compileModule(myModule)
503     if (!useJps()) {
504       assertEmpty compileFiles(used.virtualFile, main)
505     }
506     assertEmpty compileModule(myModule)
507     assertEmpty compileModule(myModule)
508     
509     setFileText(used, 'class Used2 {}')
510     makeShouldFail()
511     assert findClassFile('Used') == null
512
513     setFileText(used, 'class Used3 {}')
514     setFileText(java, 'class Java { void foo(Used3 used) {} }')
515     assertEmpty make()
516
517     assert findClassFile('Used2') == null
518   }
519
520   public static class IdeaModeTest extends GroovyCompilerTest {
521     @Override protected boolean useJps() { false }
522   }
523
524   public static class JpsModeTest extends GroovyCompilerTest {
525     @Override protected boolean useJps() { true }
526   }
527
528 }