/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GppFunctionalTest.groovy

https://bitbucket.org/nbargnesi/idea · Groovy · 616 lines · 539 code · 74 blank · 3 comment · 2 complexity · a735a8bcfe77180df1928d3540b35ce6 MD5 · raw file

  1. package org.jetbrains.plugins.groovy.lang
  2. import com.intellij.codeInsight.generation.OverrideImplementUtil
  3. import com.intellij.codeInsight.lookup.LookupManager
  4. import com.intellij.codeInsight.navigation.GotoImplementationHandler
  5. import com.intellij.codeInspection.deadCode.UnusedDeclarationInspection
  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.psi.search.GlobalSearchScope
  13. import com.intellij.testFramework.LightProjectDescriptor
  14. import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor
  15. import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
  16. import junit.framework.ComparisonFailure
  17. import org.jetbrains.annotations.NotNull
  18. import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection
  19. import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection
  20. import org.jetbrains.plugins.groovy.codeInspection.unassignedVariable.UnassignedVariableAccessInspection
  21. import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition
  22. import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod
  23. import org.jetbrains.plugins.groovy.util.TestUtils
  24. import com.intellij.psi.*
  25. /**
  26. * @author peter
  27. */
  28. class GppFunctionalTest extends LightCodeInsightFixtureTestCase {
  29. @NotNull
  30. @Override
  31. protected LightProjectDescriptor getProjectDescriptor() {
  32. return GppProjectDescriptor.instance;
  33. }
  34. protected void setUp() {
  35. super.setUp()
  36. }
  37. public void testCastListToIterable() throws Exception {
  38. myFixture.addClass("class X extends java.util.ArrayList<Integer> {}")
  39. testAssignability """
  40. X ints = [239, 4.2d]
  41. """
  42. }
  43. public void testCastListToAnything() throws Exception {
  44. testAssignability """
  45. File f1 = ['path']
  46. 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>
  47. """
  48. }
  49. public void testCastMapToAnotherMap() throws Exception {
  50. myFixture.addClass """
  51. public class Y extends java.util.HashMap<String, String> {
  52. public Y(int initialCapacity) {
  53. super(initialCapacity);
  54. }
  55. }
  56. """
  57. testAssignability """
  58. HashMap<String, File> m1 = ['a':['b']]
  59. Y y = <warning descr="Constructor 'Y' in 'Y' cannot be applied to '(['a':java.lang.String])'">[a:'b']</warning>
  60. """
  61. }
  62. public void testAnonymousClass() throws Exception {
  63. myFixture.enableInspections new GroovyAssignabilityCheckInspection()
  64. testAssignability """
  65. def x = new Object() {
  66. def foo() {
  67. HashMap<String, File> m1 = ['a':['b']]
  68. HashMap<String, File> m2 = <warning descr="Cannot assign 'File' to 'HashMap<String, File>'">new File('aaa')</warning>
  69. }
  70. }
  71. """
  72. }
  73. public void testCastMapToObject() throws Exception {
  74. myFixture.addClass("class Foo { String name; void foo() {} }")
  75. testAssignability """
  76. Foo f = [name: 'aaa', foo: { println 'hi' }, anotherProperty: 42 ]
  77. """
  78. }
  79. void testAssignability(String text) {
  80. myFixture.enableInspections new GroovyAssignabilityCheckInspection()
  81. PsiFile file = configureGppScript(text)
  82. myFixture.testHighlighting(true, false, false, file.virtualFile)
  83. }
  84. private PsiFile configureScript(String text) {
  85. return myFixture.configureByText("a.groovy", text)
  86. }
  87. private PsiFile configureGppScript(String text) {
  88. return myFixture.configureByText("a.gpp", text)
  89. }
  90. public void testDeclaredVariableTypeIsMoreImportantThanTheInitializerOne() throws Exception {
  91. configureScript("""
  92. File f = ['path']
  93. f.mk<caret>
  94. """)
  95. myFixture.completeBasic()
  96. assertSameElements myFixture.lookupElementStrings, "mkdir", "mkdirs"
  97. }
  98. public void testDeclaredVariableTypeIsMoreImportantThanTheInitializerOne2() throws Exception {
  99. myFixture.addClass """
  100. public class Some {
  101. public int prop
  102. public void f_foo() {}
  103. public void f_bar() {}
  104. }
  105. """
  106. configureScript("""
  107. Some s = [prop: 239]
  108. s.f_<caret>
  109. """)
  110. myFixture.completeBasic()
  111. assertSameElements myFixture.lookupElementStrings, "f_foo", "f_bar"
  112. }
  113. public void testResolveMethod() throws Exception {
  114. myFixture.configureByText("a.groovy", """
  115. def foo(File f) {}
  116. @Typed def bar() {
  117. fo<caret>o(['path'])
  118. }
  119. """)
  120. def reference = findReference()
  121. def target = reference.resolve()
  122. assertEquals "foo", ((GrMethod)target).name
  123. }
  124. private PsiReference findReference() {
  125. return myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset)
  126. }
  127. public void testOverloadingWithConversion() throws Exception {
  128. myFixture.configureByText("a.groovy", """
  129. def foo(List l) {}
  130. def foo(File f) {}
  131. @Typed def bar() {
  132. fo<caret>o(['path'])
  133. }
  134. """)
  135. def reference = findReference()
  136. def target = reference.resolve()
  137. assertNotNull target
  138. assert target.text.contains("List l")
  139. }
  140. public void testWrongProperty() throws Exception {
  141. myFixture.configureByText 'a.gpp', '''
  142. class ClassA {
  143. def prop = 2
  144. def bar() {
  145. def t = new Object()
  146. t.pr<caret>op
  147. }
  148. }'''
  149. assert !findReference().resolve()
  150. }
  151. public void testCastClosureToOneMethodClass() throws Exception {
  152. myFixture.addClass """
  153. public abstract class Foo {
  154. public abstract void foo(String s);
  155. public abstract void bar(String s);
  156. }
  157. public interface Action {
  158. void act();
  159. }
  160. """
  161. testAssignability """
  162. Foo f = <warning descr="Cannot assign 'Closure' to 'Foo'">{ println it }</warning>
  163. Function1<String, Object> f1 = { println it }
  164. Function1<String, Object> f2 = { x=42 -> println x }
  165. Function1<String, Object> f3 = <warning descr="Cannot assign 'Closure' to 'Function1<String, Object>'">{ int x -> println x }</warning>
  166. Runnable r = { println it }
  167. Action a = { println it }
  168. Action a1 = { a2 = 2 -> println a2 }
  169. """
  170. }
  171. public void testClosureParameterTypesInAssignment() throws Exception {
  172. configureScript "Function1<String, Object> f = { it.subs<caret> }"
  173. myFixture.completeBasic()
  174. assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
  175. }
  176. public void testClosureParameterTypesInMethodInvocation() throws Exception {
  177. myFixture.configureByText "a.groovy", """
  178. def foo(int a = 1, Function1<String, Object> f) {}
  179. def foo(String s) {}
  180. def foo(Function2<Integer, String, Object> f) {}
  181. @Typed def bar() {
  182. foo { it.subsREF }
  183. foo(1, { it.subsREF })
  184. foo 1, { it.subsREF }
  185. foo(1) { it.subsREF }
  186. foo { a -> a.subsREF }
  187. foo { a, int b=2 -> a.subsREF }
  188. foo { a, b -> b.subsREF }
  189. }
  190. """
  191. def text = myFixture.file.text
  192. def pos = 0
  193. while (true) {
  194. pos = text.indexOf("REF", pos+1)
  195. if (pos < 0) {
  196. break
  197. }
  198. myFixture.editor.caretModel.moveToOffset pos
  199. myFixture.completeBasic()
  200. try {
  201. assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
  202. }
  203. catch (ComparisonFailure ex) {
  204. println "at: " + text[0..<pos] + "<caret>" + text[pos..<text.size()]
  205. throw ex
  206. }
  207. LookupManager.getInstance(project).hideActiveLookup()
  208. }
  209. }
  210. public void testReturnTypeOneMethodInterface() throws Exception {
  211. myFixture.configureByText "a.groovy", """
  212. @Typed Function1<String, Integer> bar() {
  213. { it.subs<caret> }
  214. }
  215. """
  216. myFixture.completeBasic()
  217. assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
  218. }
  219. public void testClosureInMapInstantiation() throws Exception {
  220. myFixture.configureByText "a.groovy", """
  221. class Foo<T> {
  222. int foo(T a) {}
  223. }
  224. @Typed Foo<String> bar() {
  225. return [foo: { it.subs<caret> }]
  226. }
  227. """
  228. myFixture.completeBasic()
  229. assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
  230. }
  231. public void testClosureInMapInstantiationBoxPrimitives() throws Exception {
  232. myFixture.configureByText "a.groovy", """
  233. class Foo {
  234. int foo(int a) {}
  235. }
  236. @Typed Foo bar() {
  237. return [foo: { it.intV<caret>V }]
  238. }
  239. """
  240. myFixture.completeBasic()
  241. assertSameElements myFixture.lookupElementStrings, "intValue"
  242. }
  243. public void testClosureInListInstantiation() throws Exception {
  244. myFixture.configureByText "a.groovy", """
  245. class Foo {
  246. def Foo(int a, Function1<String, Integer> f) {}
  247. }
  248. @Typed Foo foo() {
  249. [239, { s -> s.subs<caret> }]
  250. }
  251. """
  252. myFixture.completeBasic()
  253. assertSameElements myFixture.lookupElementStrings, "subSequence", "substring", "substring"
  254. }
  255. public void testTraitHighlighting() throws Exception {
  256. myFixture.configureByText "a.groovy", """
  257. @Trait
  258. abstract class Intf {
  259. abstract void foo()
  260. void bar() {}
  261. }
  262. <error descr="Method 'foo' is not implemented">class Foo implements Intf</error> {}
  263. <error descr="Method 'foo' is not implemented">class Wrong extends Foo</error> {}
  264. class Bar implements Intf {
  265. void foo() {}
  266. }
  267. """
  268. myFixture.testHighlighting(true, false, false, myFixture.file.virtualFile)
  269. }
  270. public void testTraitImplementingAndNavigation() throws Exception {
  271. myFixture.configureByText "a.groovy", """
  272. @Trait
  273. abstract class <caret>Intf {
  274. abstract void foo()
  275. void bar() {}
  276. }
  277. class Foo implements Intf {}
  278. class Bar implements Intf {
  279. void foo() {}
  280. }
  281. class BarImpl extends Bar {}
  282. """
  283. def facade = JavaPsiFacade.getInstance(getProject())
  284. def allScope = GlobalSearchScope.allScope(project)
  285. assertOneElement(OverrideImplementUtil.getMethodsToOverrideImplement(facade.findClass("Foo", allScope), true))
  286. GrTypeDefinition barClass = facade.findClass("Bar", allScope) as GrTypeDefinition
  287. assertEmpty(OverrideImplementUtil.getMethodsToOverrideImplement(barClass, true))
  288. assertTrue "bar" in OverrideImplementUtil.getMethodsToOverrideImplement(barClass, false).collect { ((PsiMethod) it.element).name }
  289. assertEmpty(OverrideImplementUtil.getMethodsToOverrideImplement(facade.findClass("BarImpl", allScope), true))
  290. def implementations = new GotoImplementationHandler().getSourceAndTargetElements(myFixture.editor, myFixture.file).targets
  291. assertEquals Arrays.toString(implementations), 3, implementations.size()
  292. }
  293. public void testResolveToStdLib() throws Exception {
  294. configureScript """
  295. @Typed def foo(List<String> l) {
  296. l.ea<caret>ch { it.substring(1) }
  297. }
  298. """
  299. PsiMethod method = resolveReference().navigationElement as PsiMethod
  300. assertEquals "each", method.name
  301. assertEquals "groovypp.util.Iterations", method.containingClass.qualifiedName
  302. }
  303. public void testResolveToStdLibWithArrayQualifier() throws Exception {
  304. configureGppScript """
  305. Integer[] a = []
  306. a.fol<caret>dLeft(2, { a, b -> a+b })
  307. """
  308. PsiMethod method = resolveReference().navigationElement as PsiMethod
  309. assertEquals "foldLeft", method.name
  310. assertEquals "groovypp.util.Iterations", method.containingClass.qualifiedName
  311. }
  312. private PsiElement resolveReference() {
  313. return findReference().resolve()
  314. }
  315. public void testResolveToSuperMethodClosureSyntax() {
  316. configureScript """
  317. abstract class Super implements Runnable {
  318. def method(int bar) {}
  319. }
  320. Super s = { <caret>method(2) } as Super
  321. """
  322. assert resolveReference() instanceof GrMethod
  323. }
  324. public void testMethodTypeParameterInference() throws Exception {
  325. configureScript """
  326. @Typed package aaa
  327. java.util.concurrent.atomic.AtomicReference<Integer> r = [2]
  328. r.apply { it.intV<caret>i }
  329. """
  330. myFixture.completeBasic()
  331. assertSameElements myFixture.getLookupElementStrings(), "intValue"
  332. }
  333. public void testMethodTypeParameterInference2() throws Exception {
  334. configureScript """
  335. @Typed package aaa
  336. java.util.concurrent.atomic.AtomicReference<Integer> r = [2]
  337. r.apply { it.intV<caret>i } {}
  338. """
  339. myFixture.completeBasic()
  340. assertSameElements myFixture.getLookupElementStrings(), "intValue"
  341. }
  342. public void testGotoSuperMethodFromMapLiterals() throws Exception {
  343. PsiClass point = myFixture.addClass("""
  344. class Point {
  345. Point() {}
  346. Point(int y) {}
  347. int y;
  348. void setX(int x) {}
  349. void move(int x, int y) {}
  350. void move(int y) {}
  351. }""")
  352. configureScript "Point p = [<caret>y:2]"
  353. assertEquals point.findFieldByName("y", false), resolveReference()
  354. configureScript "Point p = [<caret>x:2]"
  355. assertEquals point.findMethodsByName("setX", false)[0], resolveReference()
  356. configureScript "Point p = [mo<caret>ve: { x, y -> z }]"
  357. assertEquals point.findMethodsByName("move", false)[0], resolveReference()
  358. configureScript "Point p = [mo<caret>ve: ]"
  359. def resolveResults = multiResolveReference()
  360. assertSameElements resolveResults.collect { it.element }, point.findMethodsByName("move", false)
  361. }
  362. ResolveResult[] multiResolveReference() {
  363. return ((PsiPolyVariantReference) myFixture.file.findReferenceAt(myFixture.editor.caretModel.offset)).multiResolve(true)
  364. }
  365. public void testGotoSuperConstructorFromMapLiterals() throws Exception {
  366. PsiClass point = myFixture.addClass("""
  367. class Point {
  368. Point() {}
  369. Point(int y) {}
  370. }""")
  371. configureGppScript "Point p = [su<caret>per: 2]"
  372. assertEquals point.constructors[1], resolveReference()
  373. configureGppScript "Point p = [su<caret>per: [2]]"
  374. assertEquals point.constructors[1], resolveReference()
  375. configureGppScript "Point p = ['su<caret>per': []]"
  376. assertEquals point.constructors[0], resolveReference()
  377. configureGppScript "Point p = ['su<caret>per': 'a']"
  378. assertEquals 1, multiResolveReference().size()
  379. }
  380. public void testGotoSuperConstructorFromLiteralOnsets() throws Exception {
  381. PsiClass point = myFixture.addClass("""
  382. class Point {
  383. Point() {}
  384. Point(int y) {}
  385. }""")
  386. configureGppScript "Point p = <caret>[super: 2]"
  387. assertEquals point.constructors[1], resolveReference()
  388. configureGppScript "Point p = <caret>[2]"
  389. assertEquals point.constructors[1], resolveReference()
  390. configureGppScript "Point p = <caret>[]"
  391. assertEquals point.constructors[0], resolveReference()
  392. configureGppScript "Point p = <caret>[:]"
  393. assertEquals point.constructors[0], resolveReference()
  394. configureGppScript "Point p = <caret>[239, 42]"
  395. assertEquals 2, multiResolveReference().size()
  396. configureGppScript """
  397. def foo(Point p) {}
  398. foo(<caret>[2, 3])
  399. """
  400. assertEquals 2, multiResolveReference().size()
  401. configureGppScript """
  402. def foo(Point... p) {}
  403. foo(<caret>['super':[2, 3]])
  404. """
  405. assertEquals 2, multiResolveReference().size()
  406. }
  407. public void testGotoClassFromLiteralOnsetsWhenNoConstructorsPresent() throws Exception {
  408. PsiClass point = myFixture.addClass(""" class Point { }""")
  409. configureGppScript "Point p = <caret>[super: 2]"
  410. assertEquals point, resolveReference()
  411. configureGppScript "Point p = <caret>[]"
  412. assertEquals point, resolveReference()
  413. }
  414. public void testNoGotoObjectFromLiteral() throws Exception {
  415. myFixture.addClass(""" class Point { }""")
  416. configureGppScript "def p = <caret>[]"
  417. assertNull findReference()
  418. }
  419. public void testHighlightInapplicableLiteralConstructor() throws Exception {
  420. myFixture.addClass("""
  421. class Point {
  422. Point() {}
  423. }""")
  424. configureGppScript """
  425. def foo(Point p) {}
  426. Point p = [:]
  427. Point p2 = [super:warning descr="Cannot find constructor of 'Point'">[4, 2]</warning>]
  428. foo(<warning descr="Cannot find constructor of 'Point'">[4, 2]</warning>)
  429. """
  430. }
  431. public void testResolveTraitMethod() throws Exception {
  432. configureScript """
  433. @Trait
  434. class Some {
  435. public void doSmth() { println "hello" }
  436. }
  437. Some s
  438. s.do<caret>Smth()
  439. """
  440. assertEquals "doSmth", ((PsiMethod) findReference().resolve()).name
  441. }
  442. public void testBaseConstructorCallInMapLiteras() throws Exception {
  443. configureScript """
  444. @Typed File foo() { <warning descr="Constructor 'File' in 'java.io.File' cannot be applied to '(['super':[java.lang.String]])'">['super':['a']]</warning> }
  445. @Typed File goo() { <warning descr="Constructor 'File' in 'java.io.File' cannot be applied to '([:])'">[:]</warning> }
  446. File bar() { <warning descr="Constructor 'File' in 'java.io.File' cannot be applied to '([:])'">[:]</warning> }
  447. """
  448. myFixture.enableInspections new GroovyAssignabilityCheckInspection()
  449. myFixture.checkHighlighting(true, false, false)
  450. }
  451. public void testNestedLiteralConstructors() throws Exception {
  452. configureGppScript """
  453. class Foo {
  454. def Foo(Bar b) { }
  455. }
  456. class Bar {
  457. def Bar(int i) { }
  458. }
  459. Foo x = <warning descr="Constructor 'Foo' in 'Foo' cannot be applied to '([java.lang.Integer])'">[[2]]</warning>
  460. println x
  461. """
  462. myFixture.enableInspections new GroovyAssignabilityCheckInspection()
  463. myFixture.checkHighlighting(true, false, false)
  464. }
  465. public void testNoReturnTypeInferenceInTypedContext() throws Exception {
  466. configureGppScript """
  467. class Foo {
  468. def foo() { "aaa" }
  469. }
  470. new Foo().foo().substr<caret>a
  471. """
  472. assertEmpty myFixture.completeBasic()
  473. }
  474. public void testDeclaredReturnTypeInTypedContext() throws Exception {
  475. configureGppScript """
  476. class Foo {
  477. String getFoo() { "aaa" }
  478. }
  479. new Foo().foo.substr<caret>a
  480. """
  481. myFixture.completeBasic()
  482. assertOrderedEquals myFixture.lookupElementStrings, "substring", "substring"
  483. }
  484. public void testNonInitializedVariable() throws Exception {
  485. configureScript """
  486. @Typed
  487. def foo() {
  488. int a
  489. return a
  490. }
  491. def bar() {
  492. int a
  493. return <warning descr="Variable 'a' might not be assigned">a</warning>
  494. }"""
  495. myFixture.enableInspections new UnassignedVariableAccessInspection()
  496. myFixture.checkHighlighting(true, false, false)
  497. }
  498. public void testExternalizable() throws Exception {
  499. configureScript '''
  500. @Typed class Foo implements Externalizable {}
  501. <error descr="Method 'writeExternal' is not implemented">class Bar implements Externalizable</error> {}
  502. '''
  503. myFixture.checkHighlighting(true, false, false)
  504. }
  505. public void testUsedInterceptors() {
  506. configureGppScript '''
  507. class Bar {
  508. Object getUnresolvedProperty(String <warning descr="Parameter name is unused">name</warning>) {}
  509. Object <warning descr="Method getUnresolvedProperty is unused">getUnresolvedProperty</warning>(int <warning descr="Parameter name is unused">name</warning>) {}
  510. void setUnresolvedProperty(String <warning descr="Parameter name is unused">name</warning>, String <warning descr="Parameter value is unused">value</warning>) {}
  511. int invokeUnresolvedMethod(String <warning descr="Parameter name is unused">name</warning>, String <warning descr="Parameter arg1 is unused">arg1</warning>, boolean <warning descr="Parameter arg2 is unused">arg2</warning>, Object... <warning descr="Parameter args is unused">args</warning>) {}
  512. int invokeUnresolvedMethod(String <warning descr="Parameter name is unused">name</warning>, Object... <warning descr="Parameter args is unused">args</warning>) {}
  513. int <warning descr="Method invokeUnresolvedMethod is unused">invokeUnresolvedMethod</warning>(Object... <warning descr="Parameter args is unused">args</warning>) {}
  514. }
  515. println new Bar().zzz
  516. '''
  517. myFixture.enableInspections(new GroovyUnusedDeclarationInspection(), new UnusedDeclarationInspection())
  518. myFixture.checkHighlighting(true, false, false)
  519. }
  520. }
  521. class GppProjectDescriptor extends DefaultLightProjectDescriptor {
  522. public static final instance = new GppProjectDescriptor()
  523. @Override
  524. public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
  525. final Library.ModifiableModel modifiableModel = model.moduleLibraryTable.createLibrary("GROOVY++").modifiableModel;
  526. modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.absoluteTestDataPath + "mockGroovypp/groovypp-0.9.0_1.8.2.jar!/"), OrderRootType.CLASSES)
  527. modifiableModel.addRoot(JarFileSystem.instance.refreshAndFindFileByPath(TestUtils.mockGroovy1_7LibraryName + "!/"), OrderRootType.CLASSES);
  528. modifiableModel.commit();
  529. }
  530. }