2 * Copyright 2000-2014 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.navigation
18 import com.intellij.ide.actions.GotoFileItemProvider
19 import com.intellij.ide.util.gotoByName.*
20 import com.intellij.lang.java.JavaLanguage
21 import com.intellij.openapi.Disposable
22 import com.intellij.openapi.application.ApplicationManager
23 import com.intellij.openapi.application.ModalityState
24 import com.intellij.openapi.util.Computable
25 import com.intellij.openapi.util.Disposer
26 import com.intellij.psi.PsiElement
27 import com.intellij.psi.PsiFile
28 import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
29 import com.intellij.util.Consumer
30 import com.intellij.util.concurrency.Semaphore
31 import org.jetbrains.annotations.NotNull
32 import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
37 class ChooseByNameTest extends LightCodeInsightFixtureTestCase {
38 ChooseByNamePopup myPopup
41 protected void tearDown() throws Exception {
46 public void "test goto class order by matching degree"() {
47 def startMatch = myFixture.addClass("class UiUtil {}")
48 def wordSkipMatch = myFixture.addClass("class UiAbstractUtil {}")
49 def camelMatch = myFixture.addClass("class UberInstructionUxTopicInterface {}")
50 def middleMatch = myFixture.addClass("class BaseUiUtil {}")
51 def elements = getPopupElements(new GotoClassModel2(project), "uiuti")
52 assert elements == [startMatch, wordSkipMatch, camelMatch, ChooseByNameBase.NON_PREFIX_SEPARATOR, middleMatch]
55 public void "test annotation syntax"() {
56 def match = myFixture.addClass("@interface Anno1 {}")
57 myFixture.addClass("class Anno2 {}")
58 def elements = getPopupElements(new GotoClassModel2(project), "@Anno")
59 assert elements == [match]
62 public void "test no result for empty patterns"() {
63 myFixture.addClass("@interface Anno1 {}")
64 myFixture.addClass("class Anno2 {}")
66 def popup = createPopup(new GotoClassModel2(project))
67 assert calcPopupElements(popup, "") == []
70 popup = createPopup(new GotoClassModel2(project))
71 assert calcPopupElements(popup, "@") == []
74 popup = createPopup(new GotoFileModel(project))
75 assert calcPopupElements(popup, "foo/") == []
79 public void "test filter overridden methods from goto symbol"() {
80 def intf = myFixture.addClass("""
85 def impl = myFixture.addClass("""
86 class Impl extends Intf {
92 def elements = getPopupElements(new GotoSymbolModel2(project), "xxx")
94 assert intf.findMethodsByName('xxx1', false)[0] in elements
95 assert intf.findMethodsByName('xxx2', false)[0] in elements
97 assert impl.findMethodsByName('xxx3', false)[0] in elements
98 assert !(impl.findMethodsByName('xxx1', false)[0] in elements)
101 public void "test disprefer underscore"() {
102 def intf = myFixture.addClass("""
108 def elements = getPopupElements(new GotoSymbolModel2(project), "xxx")
113 xxx1 = intf.findMethodsByName('_xxx1', false)
114 xxx2 = intf.findMethodsByName('xxx2', false)
116 assert elements == [xxx2, ChooseByNameBase.NON_PREFIX_SEPARATOR, xxx1]
119 public void "test prefer exact extension matches"() {
120 def m = myFixture.addFileToProject("relaunch.m", "")
121 def mod = myFixture.addFileToProject("reference.mod", "")
122 def elements = getPopupElements(new GotoFileModel(project), "re*.m")
123 assert elements == [m, mod]
126 public void "test consider dot-idea files out of project"() {
127 def outside = myFixture.addFileToProject(".idea/workspace.xml", "")
128 def inside = myFixture.addFileToProject("workspace.txt", "")
129 assert getPopupElements(new GotoFileModel(project), "work", false) == [inside]
130 assert getPopupElements(new GotoFileModel(project), "work", true) == [inside, outside]
133 public void "test prefer better path matches"() {
134 def fooIndex = myFixture.addFileToProject("foo/index.html", "foo")
135 def fooBarIndex = myFixture.addFileToProject("foo/bar/index.html", "foo bar")
136 def barFooIndex = myFixture.addFileToProject("bar/foo/index.html", "bar foo")
137 def elements = getPopupElements(new GotoFileModel(project), "foo/index")
138 assert elements == [fooIndex, barFooIndex, fooBarIndex]
141 public void "test sort same-named items by path"() {
142 def files = (30..10).collect { i -> myFixture.addFileToProject("foo$i/index.html", "foo$i") }.reverse()
143 def elements = getPopupElements(new GotoFileModel(project), "index")
144 assert elements == files
147 public void "test middle matching for directories"() {
148 def fooIndex = myFixture.addFileToProject("foo/index.html", "foo")
149 def ooIndex = myFixture.addFileToProject("oo/index.html", "oo")
150 def fooBarIndex = myFixture.addFileToProject("foo/bar/index.html", "foo bar")
151 def elements = getPopupElements(new GotoFileModel(project), "oo/index")
152 assert elements == [ooIndex, fooIndex, fooBarIndex]
155 public void "test prefer files from current directory"() {
156 def fooIndex = myFixture.addFileToProject("foo/index.html", "foo")
157 def barIndex = myFixture.addFileToProject("bar/index.html", "bar")
158 def fooContext = myFixture.addFileToProject("foo/context.html", "")
159 def barContext = myFixture.addFileToProject("bar/context.html", "")
161 def popup = createPopup(new GotoFileModel(project), fooContext)
162 assert calcPopupElements(popup, "index") == [fooIndex, barIndex]
165 popup = createPopup(new GotoFileModel(project), barContext)
166 assert calcPopupElements(popup, "index") == [barIndex, fooIndex]
170 public void "test accept file paths starting with a dot"() {
171 def file = myFixture.addFileToProject("foo/index.html", "foo")
172 def model = new GotoFileModel(project)
173 def popup = ChooseByNamePopup.createPopup(project, model, new GotoFileItemProvider(project, null, model))
174 assert calcPopupElements(popup, "./foo/in") == [file]
177 public void "test goto file can go to dir"() {
178 PsiFile fooIndex = myFixture.addFileToProject("foo/index.html", "foo")
179 PsiFile barIndex = myFixture.addFileToProject("bar.txt/bar.txt", "foo")
181 def popup = createPopup(new GotoFileModel(project), fooIndex)
186 fooDir = fooIndex.containingDirectory
187 barDir = barIndex.containingDirectory
190 assert calcPopupElements(popup, "foo/") == [fooDir]
191 assert calcPopupElements(popup, "foo\\") == [fooDir]
192 assert calcPopupElements(popup, "/foo") == [fooDir]
193 assert calcPopupElements(popup, "\\foo") == [fooDir]
194 assert calcPopupElements(popup, "foo") == []
195 assert calcPopupElements(popup, "/index.html") == [fooIndex]
196 assert calcPopupElements(popup, "\\index.html") == [fooIndex]
197 assert calcPopupElements(popup, "index.html/") == [fooIndex]
198 assert calcPopupElements(popup, "index.html\\") == [fooIndex]
200 assert calcPopupElements(popup, "bar.txt/") == [barDir]
201 assert calcPopupElements(popup, "bar.txt\\") == [barDir]
202 assert calcPopupElements(popup, "/bar.txt") == [barDir]
203 assert calcPopupElements(popup, "\\bar.txt") == [barDir]
204 assert calcPopupElements(popup, "bar.txt") == [barIndex]
208 public void "test find method by qualified name"() {
209 def clazz = myFixture.addClass("package foo.bar; class Goo { void zzzZzz() {} }")
210 def method = ApplicationManager.application.runReadAction( { clazz.methods[0] } as Computable)
211 assert getPopupElements(new GotoSymbolModel2(project), 'zzzZzz') == [method]
212 assert getPopupElements(new GotoSymbolModel2(project), 'goo.zzzZzz') == [method]
213 assert getPopupElements(new GotoSymbolModel2(project), 'foo.bar.goo.zzzZzz') == [method]
214 assert getPopupElements(new GotoSymbolModel2(project), 'foo.zzzZzz') == [method]
215 assert getPopupElements(new GotoSymbolModel2(project), 'bar.zzzZzz') == [method]
216 assert getPopupElements(new GotoSymbolModel2(project), 'bar.goo.zzzZzz') == [method]
219 public void "test line and column suffix"() {
220 def c = myFixture.addClass("package foo; class Bar {}")
221 assert getPopupElements(new GotoClassModel2(project), 'Bar') == [c]
222 assert getPopupElements(new GotoClassModel2(project), 'Bar:2') == [c]
223 assert getPopupElements(new GotoClassModel2(project), 'Bar:2:3') == [c]
224 assert getPopupElements(new GotoClassModel2(project), 'Bar:[2:3]') == [c]
225 assert getPopupElements(new GotoClassModel2(project), 'Bar:[2,3]') == [c]
228 public void "test custom line suffixes"() {
229 def file = myFixture.addFileToProject("Bar.txt", "")
230 def model = new GotoFileModel(project)
231 assert getPopupElements(model, 'Bar:2') == [file]
232 assert getPopupElements(model, 'Bar(2)') == [file]
233 assert getPopupElements(model, 'Bar on line 2') == [file]
234 assert getPopupElements(model, 'Bar at line 2') == [file]
237 public void "test dollar"() {
238 def bar = myFixture.addClass("package foo; class Bar { class Foo {} }")
239 def foo = ApplicationManager.application.runReadAction( { bar.innerClasses[0] } as Computable)
240 myFixture.addClass("package goo; class Goo { }")
241 assert getPopupElements(new GotoClassModel2(project), 'Bar$Foo') == [foo]
242 assert getPopupElements(new GotoClassModel2(project), 'foo.Bar$Foo') == [foo]
243 assert getPopupElements(new GotoClassModel2(project), 'foo.B$F') == [foo]
244 assert !getPopupElements(new GotoClassModel2(project), 'foo$Foo')
245 assert !getPopupElements(new GotoClassModel2(project), 'foo$Bar')
246 assert !getPopupElements(new GotoClassModel2(project), 'foo$Bar$Foo')
247 assert !getPopupElements(new GotoClassModel2(project), 'foo$Goo')
250 public void "test anonymous classes"() {
251 def goo = myFixture.addClass("package goo; class Goo { Runnable r = new Runnable() {}; }")
252 assert getPopupElements(new GotoClassModel2(project), 'Goo$1') == [goo]
255 public void "test qualified name matching"() {
256 def bar = myFixture.addClass("package foo.bar; class Bar { }")
257 def bar2 = myFixture.addClass("package goo.baz; class Bar { }")
258 assert getPopupElements(new GotoClassModel2(project), 'foo.Bar') == [bar]
259 assert getPopupElements(new GotoClassModel2(project), 'foo.bar.Bar') == [bar]
260 assert getPopupElements(new GotoClassModel2(project), 'goo.Bar') == [bar2]
261 assert getPopupElements(new GotoClassModel2(project), 'goo.baz.Bar') == [bar2]
264 public void "test try lowercase pattern if nothing matches"() {
265 def match = myFixture.addClass("class IPRoi { }")
266 def nonMatch = myFixture.addClass("class InspectionProfileImpl { }")
267 assert getPopupElements(new GotoClassModel2(project), 'IPRoi') == [match]
268 assert getPopupElements(new GotoClassModel2(project), 'IproImpl') == [nonMatch]
271 private static filterJavaItems(List<Object> items) {
272 return ApplicationManager.application.runReadAction ({
273 return items.findAll { it instanceof PsiElement && it.language == JavaLanguage.INSTANCE }
277 public void "test super method in jdk"() {
278 def clazz = myFixture.addClass("package foo.bar; class Goo implements Runnable { public void run() {} }")
282 ourRun = clazz.methods[0]
283 sdkRun = ourRun.containingClass.interfaces[0].methods[0]
286 def withLibs = filterJavaItems(getPopupElements(new GotoSymbolModel2(project), 'run ', true))
287 assert withLibs == [sdkRun]
288 assert !(ourRun in withLibs)
290 def noLibs = filterJavaItems(getPopupElements(new GotoSymbolModel2(project), 'run ', false))
291 assert noLibs == [ourRun]
292 assert !(sdkRun in noLibs)
295 public void "test super method not matching query qualifier"() {
296 def baseClass = myFixture.addClass("class Base { void xpaint() {} }")
297 def subClass = myFixture.addClass("class Sub extends Base { void xpaint() {} }")
302 base = baseClass.methods[0]
303 sub = subClass.methods[0]
306 assert getPopupElements(new GotoSymbolModel2(project), 'Ba.xpai', false) == [base]
307 assert getPopupElements(new GotoSymbolModel2(project), 'Su.xpai', false) == [sub]
310 public void "test groovy script class with non-identifier name"() {
311 GroovyFile file1 = myFixture.addFileToProject('foo.groovy', '')
312 GroovyFile file2 = myFixture.addFileToProject('foo-bar.groovy', '')
314 def variants = getPopupElements(new GotoSymbolModel2(project), 'foo', false)
315 edt { assert variants == [file1.scriptClass, file2.scriptClass] }
318 private List<Object> getPopupElements(ChooseByNameModel model, String text, boolean checkboxState = false) {
319 return calcPopupElements(createPopup(model), text, checkboxState)
322 static ArrayList<Object> calcPopupElements(ChooseByNamePopup popup, String text, boolean checkboxState = false) {
323 List<Object> elements = ['empty']
324 def semaphore = new Semaphore()
327 popup.scheduleCalcElements(text, checkboxState, ModalityState.NON_MODAL, { set ->
328 elements = set as List
330 } as Consumer<Set<?>>)
332 if (!semaphore.waitFor(10000)) {
339 private ChooseByNamePopup createPopup(ChooseByNameModel model, PsiElement context = null) {
345 def popup = myPopup = ChooseByNamePopup.createPopup(project, model, (PsiElement)context, "")
346 Disposer.register(testRootDisposable, { popup.close(false) } as Disposable)
352 protected boolean runInDispatchThread() {
357 protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {