1 package org.jetbrains.plugins.groovy.lang
3 import com.intellij.codeInsight.generation.OverrideImplementUtil
4 import com.intellij.codeInsight.lookup.LookupManager
5 import com.intellij.codeInsight.navigation.GotoImplementationHandler
6 import com.intellij.openapi.module.Module
7 import com.intellij.openapi.roots.ContentEntry
8 import com.intellij.openapi.roots.ModifiableRootModel
9 import com.intellij.openapi.roots.OrderRootType
10 import com.intellij.openapi.roots.libraries.Library
11 import com.intellij.openapi.vfs.JarFileSystem
12 import com.intellij.testFramework.LightProjectDescriptor
13 import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor
14 import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
15 import junit.framework.ComparisonFailure
16 import org.jetbrains.annotations.NotNull
17 import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection
18 import org.jetbrains.plugins.groovy.codeInspection.unassignedVariable.UnassignedVariableAccessInspection
19 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition
20 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod
21 import org.jetbrains.plugins.groovy.util.TestUtils
22 import com.intellij.psi.*
27 class GppFunctionalTest extends LightCodeInsightFixtureTestCase {
31 protected LightProjectDescriptor getProjectDescriptor() {
32 return GppProjectDescriptor.instance;
35 protected void setUp() {
39 public void testCastListToIterable() throws Exception {
40 myFixture.addClass("class X extends java.util.ArrayList<Integer> {}")
46 public void testCastListToAnything() throws Exception {
49 File f2 = <warning descr="Constructor 'File' in 'java.io.File' cannot be applied to '(java.lang.String, java.lang.Integer, java.lang.Boolean, java.lang.Integer)'">['path', 2, true, 42]</warning>
53 public void testCastMapToAnotherMap() throws Exception {
54 myFixture.addClass """
55 public class Y extends java.util.HashMap<String, String> {
56 public Y(int initialCapacity) {
57 super(initialCapacity);
63 HashMap<String, File> m1 = ['a':['b']]
64 Y y = <warning descr="Constructor 'Y' in 'Y' cannot be applied to '(['a':java.lang.String])'">[a:'b']</warning>
68 public void testAnonymousClass() throws Exception {
69 myFixture.enableInspections new GroovyAssignabilityCheckInspection()
71 def x = new Object() {
73 HashMap<String, File> m1 = ['a':['b']]
74 HashMap<String, File> m2 = <warning descr="Cannot assign 'File' to 'HashMap<String, File>'">new File('aaa')</warning>
80 public void testCastMapToObject() throws Exception {
81 myFixture.addClass("class Foo { String name; void foo() {} }")
83 Foo f = [name: 'aaa', foo: { println 'hi' }, anotherProperty: 42 ]
87 void testAssignability(String text) {
88 myFixture.enableInspections new GroovyAssignabilityCheckInspection()
89 PsiFile file = configureGppScript(text)
90 myFixture.testHighlighting(true, false, false, file.virtualFile)
93 private PsiFile configureScript(String text) {
94 return myFixture.configureByText("a.groovy", text)
96 private PsiFile configureGppScript(String text) {
97 return myFixture.configureByText("a.gpp", text)
100 public void testDeclaredVariableTypeIsMoreImportantThanTheInitializerOne() throws Exception {
105 myFixture.completeBasic()
106 assertSameElements myFixture.lookupElementStrings, "mkdir", "mkdirs"
109 public void testDeclaredVariableTypeIsMoreImportantThanTheInitializerOne2() throws Exception {
110 myFixture.addClass """
114 public void f_foo() {}
115 public void f_bar() {}
123 myFixture.completeBasic()
124 assertSameElements myFixture.lookupElementStrings, "f_foo", "f_bar"
127 public void testResolveMethod() throws Exception {
128 myFixture.configureByText("a.groovy", """
134 def reference = findReference()
135 def target = reference.resolve()
136 assertEquals "foo", ((GrMethod)target).name
139 private PsiReference findReference() {
140 return myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset)
143 public void testOverloadingWithConversion() throws Exception {
144 myFixture.configureByText("a.groovy", """
151 def reference = findReference()
152 def target = reference.resolve()
154 assert target.text.contains("List l")
157 public void testWrongProperty() throws Exception {
158 myFixture.configureByText 'a.gpp', '''
166 assert !findReference().resolve()
169 public void testCastClosureToOneMethodClass() throws Exception {
170 myFixture.addClass """
171 public abstract class Foo {
172 public abstract void foo(String s);
173 public abstract void bar(String s);
175 public interface Action {
180 testAssignability """
181 Foo f = <warning descr="Cannot assign 'Closure' to 'Foo'">{ println it }</warning>
182 Function1<String, Object> f1 = { println it }
183 Function1<String, Object> f2 = { x=42 -> println x }
184 Function1<String, Object> f3 = <warning descr="Cannot assign 'Closure' to 'Function1<String, Object>'">{ int x -> println x }</warning>
185 Runnable r = { println it }
186 Action a = { println it }
187 Action a1 = { a2 = 2 -> println a2 }
191 public void testClosureParameterTypesInAssignment() throws Exception {
192 configureScript "Function1<String, Object> f = { it.subs<caret> }"
193 myFixture.completeBasic()
194 assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
197 public void testClosureParameterTypesInMethodInvocation() throws Exception {
198 myFixture.configureByText "a.groovy", """
199 def foo(int a = 1, Function1<String, Object> f) {}
201 def foo(Function2<Integer, String, Object> f) {}
205 foo(1, { it.subsREF })
206 foo 1, { it.subsREF }
207 foo(1) { it.subsREF }
208 foo { a -> a.subsREF }
209 foo { a, int b=2 -> a.subsREF }
210 foo { a, b -> b.subsREF }
213 def text = myFixture.file.text
216 pos = text.indexOf("REF", pos+1)
220 myFixture.editor.caretModel.moveToOffset pos
221 myFixture.completeBasic()
223 assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
225 catch (ComparisonFailure ex) {
226 println "at: " + text[0..<pos] + "<caret>" + text[pos..<text.size()]
229 LookupManager.getInstance(project).hideActiveLookup()
233 public void testReturnTypeOneMethodInterface() throws Exception {
234 myFixture.configureByText "a.groovy", """
235 @Typed Function1<String, Integer> bar() {
239 myFixture.completeBasic()
240 assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
243 public void testClosureInMapInstantiation() throws Exception {
244 myFixture.configureByText "a.groovy", """
249 @Typed Foo<String> bar() {
250 return [foo: { it.subs<caret> }]
253 myFixture.completeBasic()
254 assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
257 public void testClosureInMapInstantiationBoxPrimitives() throws Exception {
258 myFixture.configureByText "a.groovy", """
264 return [foo: { it.intV<caret>V }]
267 myFixture.completeBasic()
268 assertSameElements myFixture.lookupElementStrings, "intValue"
271 public void testClosureInListInstantiation() throws Exception {
272 myFixture.configureByText "a.groovy", """
274 def Foo(int a, Function1<String, Integer> f) {}
278 [239, { s -> s.subs<caret> }]
281 myFixture.completeBasic()
282 assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
285 public void testTraitHighlighting() throws Exception {
286 myFixture.configureByText "a.groovy", """
288 abstract class Intf {
292 <error descr="Method 'foo' is not implemented">class Foo implements Intf</error> {}
293 <error descr="Method 'foo' is not implemented">class Wrong extends Foo</error> {}
294 class Bar implements Intf {
298 myFixture.testHighlighting(true, false, false, myFixture.file.virtualFile)
301 public void testTraitImplementingAndNavigation() throws Exception {
302 myFixture.configureByText "a.groovy", """
304 abstract class <caret>Intf {
308 class Foo implements Intf {}
309 class Bar implements Intf {
312 class BarImpl extends Bar {}
314 def facade = JavaPsiFacade.getInstance(getProject())
315 assertOneElement(OverrideImplementUtil.getMethodsToOverrideImplement(facade.findClass("Foo"), true))
317 GrTypeDefinition barClass = facade.findClass("Bar")
318 assertEmpty(OverrideImplementUtil.getMethodsToOverrideImplement(barClass, true))
319 assertTrue "bar" in OverrideImplementUtil.getMethodsToOverrideImplement(barClass, false).collect { ((PsiMethod) it.element).name }
321 assertEmpty(OverrideImplementUtil.getMethodsToOverrideImplement(facade.findClass("BarImpl"), true))
323 def implementations = new GotoImplementationHandler().getSourceAndTargetElements(myFixture.editor, myFixture.file).targets
324 assertEquals Arrays.toString(implementations), 3, implementations.size()
327 public void testResolveToStdLib() throws Exception {
329 @Typed def foo(List<String> l) {
330 l.ea<caret>ch { it.substring(1) }
333 PsiMethod method = resolveReference().navigationElement
334 assertEquals "each", method.name
335 assertEquals "groovypp.util.Iterations", method.containingClass.qualifiedName
338 public void testResolveToStdLibWithArrayQualifier() throws Exception {
339 configureGppScript """
341 a.fol<caret>dLeft(2, { a, b -> a+b })
343 PsiMethod method = resolveReference().navigationElement
344 assertEquals "foldLeft", method.name
345 assertEquals "groovypp.util.Iterations", method.containingClass.qualifiedName
348 private PsiElement resolveReference() {
349 return findReference().resolve()
352 public void testResolveToSuperMethodClosureSyntax() {
354 abstract class Super implements Runnable {
355 def method(int bar) {}
358 Super s = { <caret>method(2) } as Super
360 assert resolveReference() instanceof GrMethod
363 public void testMethodTypeParameterInference() throws Exception {
367 java.util.concurrent.atomic.AtomicReference<Integer> r = [2]
368 r.apply { it.intV<caret>i }
370 myFixture.completeBasic()
371 assertSameElements myFixture.getLookupElementStrings(), "intValue"
374 public void testMethodTypeParameterInference2() throws Exception {
378 java.util.concurrent.atomic.AtomicReference<Integer> r = [2]
379 r.apply { it.intV<caret>i } {}
381 myFixture.completeBasic()
382 assertSameElements myFixture.getLookupElementStrings(), "intValue"
385 public void testGotoSuperMethodFromMapLiterals() throws Exception {
386 PsiClass point = myFixture.addClass("""
392 void move(int x, int y) {}
396 configureScript "Point p = [<caret>y:2]"
397 assertEquals point.findFieldByName("y", false), resolveReference()
399 configureScript "Point p = [<caret>x:2]"
400 assertEquals point.findMethodsByName("setX", false)[0], resolveReference()
402 configureScript "Point p = [mo<caret>ve: { x, y -> z }]"
403 assertEquals point.findMethodsByName("move", false)[0], resolveReference()
405 configureScript "Point p = [mo<caret>ve: ]"
406 def resolveResults = multiResolveReference()
407 assertSameElements resolveResults.collect { it.element }, point.findMethodsByName("move", false)
410 ResolveResult[] multiResolveReference() {
411 return ((PsiPolyVariantReference) myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset)).multiResolve(true)
414 public void testGotoSuperConstructorFromMapLiterals() throws Exception {
415 PsiClass point = myFixture.addClass("""
421 configureGppScript "Point p = [su<caret>per: 2]"
422 assertEquals point.constructors[1], resolveReference()
424 configureGppScript "Point p = [su<caret>per: [2]]"
425 assertEquals point.constructors[1], resolveReference()
427 configureGppScript "Point p = ['su<caret>per': []]"
428 assertEquals point.constructors[0], resolveReference()
430 configureGppScript "Point p = ['su<caret>per': 'a']"
431 assertEquals 1, multiResolveReference().size()
434 public void testGotoSuperConstructorFromLiteralOnsets() throws Exception {
435 PsiClass point = myFixture.addClass("""
441 configureGppScript "Point p = <caret>[super: 2]"
442 assertEquals point.constructors[1], resolveReference()
444 configureGppScript "Point p = <caret>[2]"
445 assertEquals point.constructors[1], resolveReference()
447 configureGppScript "Point p = <caret>[]"
448 assertEquals point.constructors[0], resolveReference()
450 configureGppScript "Point p = <caret>[:]"
451 assertEquals point.constructors[0], resolveReference()
453 configureGppScript "Point p = <caret>[239, 42]"
454 assertEquals 2, multiResolveReference().size()
456 configureGppScript """
460 assertEquals 2, multiResolveReference().size()
462 configureGppScript """
463 def foo(Point... p) {}
464 foo(<caret>['super':[2, 3]])
466 assertEquals 2, multiResolveReference().size()
469 public void testGotoClassFromLiteralOnsetsWhenNoConstructorsPresent() throws Exception {
470 PsiClass point = myFixture.addClass(""" class Point { }""")
471 configureGppScript "Point p = <caret>[super: 2]"
472 assertEquals point, resolveReference()
474 configureGppScript "Point p = <caret>[]"
475 assertEquals point, resolveReference()
478 public void testNoGotoObjectFromLiteral() throws Exception {
479 myFixture.addClass(""" class Point { }""")
481 configureGppScript "def p = <caret>[]"
482 assertNull findReference()
485 public void testHighlightInapplicableLiteralConstructor() throws Exception {
486 myFixture.addClass("""
491 configureGppScript """
494 Point p2 = [super:warning descr="Cannot find constructor of 'Point'">[4, 2]</warning>]
495 foo(<warning descr="Cannot find constructor of 'Point'">[4, 2]</warning>)
499 public void testResolveTraitMethod() throws Exception {
503 public void doSmth() { println "hello" }
508 assertEquals "doSmth", ((PsiMethod) findReference().resolve()).name
511 public void testBaseConstructorCallInMapLiteras() throws Exception {
513 @Typed File foo() { <warning descr="Constructor 'File' in 'java.io.File' cannot be applied to '(['super':[java.lang.String]])'">['super':['a']]</warning> }
514 @Typed File goo() { <warning descr="Constructor 'File' in 'java.io.File' cannot be applied to '([:])'">[:]</warning> }
515 File bar() { <warning descr="Constructor 'File' in 'java.io.File' cannot be applied to '([:])'">[:]</warning> }
517 myFixture.enableInspections new GroovyAssignabilityCheckInspection()
518 myFixture.checkHighlighting(true, false, false)
521 public void testNestedLiteralConstructors() throws Exception {
522 configureGppScript """
531 Foo x = <warning descr="Constructor 'Foo' in 'Foo' cannot be applied to '([java.lang.Integer])'">[[2]]</warning>
534 myFixture.enableInspections new GroovyAssignabilityCheckInspection()
535 myFixture.checkHighlighting(true, false, false)
538 public void testNoReturnTypeInferenceInTypedContext() throws Exception {
539 configureGppScript """
543 new Foo().foo().substr<caret>a
545 assertEmpty myFixture.completeBasic()
548 public void testDeclaredReturnTypeInTypedContext() throws Exception {
549 configureGppScript """
551 String getFoo() { "aaa" }
553 new Foo().foo.substr<caret>a
555 myFixture.completeBasic()
556 assertOrderedEquals myFixture.lookupElementStrings, "substring", "substring"
559 public void testNonInitializedVariable() throws Exception {
570 return <warning descr="Variable 'a' might not be assigned">a</warning>
572 myFixture.enableInspections new UnassignedVariableAccessInspection()
573 myFixture.checkHighlighting(true, false, false)
576 public void testExternalizable() throws Exception {
578 @Typed class Foo implements Externalizable {}
579 <error descr="Method 'writeExternal' is not implemented">class Bar implements Externalizable</error> {}
581 myFixture.checkHighlighting(true, false, false)
586 class GppProjectDescriptor extends DefaultLightProjectDescriptor {
587 static def instance = new GppProjectDescriptor()
590 public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
591 final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary("GROOVY++").getModifiableModel();
592 modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.absoluteTestDataPath + "mockGroovypp/groovypp-0.9.0_1.8.2.jar!/"), OrderRootType.CLASSES)
593 modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.mockGroovy1_7LibraryName + "!/"), OrderRootType.CLASSES);
594 modifiableModel.commit();