allow to verify both caret and inlays position simultaneously in tests

This commit is contained in:
Dmitry Batrak
2017-07-17 19:51:16 +03:00
parent 6336d4840c
commit f615f12336
3 changed files with 114 additions and 132 deletions
@@ -26,7 +26,6 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.editor.VisualPosition;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.registry.RegistryValue;
import com.intellij.util.ui.UIUtil;
@@ -61,28 +60,24 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
// check hints appearance on completion
configureJava("class C { void m() { System.setPro<caret> } }");
complete("setProperty");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
// check that hints don't disappear after daemon highlighting passes
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
// test Tab/Shift+Tab navigation
checkResult("class C { void m() { System.setProperty(<caret>, ) } }");
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
next();
checkResult("class C { void m() { System.setProperty(, <caret>) } }");
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/><caret>) } }");
prev();
checkResult("class C { void m() { System.setProperty(<caret>, ) } }");
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
// test hints remain shown while entering parameter values
myFixture.type("\"a");
next();
myFixture.type("\"b");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>\"a\", <hint text=\"value:\"/>\"b\") } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>\"a\", <hint text=\"value:\"/>\"b<caret>\") } }");
// test hints disappearance when caret moves out of parameter list
right();
@@ -90,35 +85,31 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
right();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(\"a\", \"b\") } }");
checkResultWithInlays("class C { void m() { System.setProperty(\"a\", \"b\") <caret>} }");
}
public void testBasicScenarioWithHintsEnabledForMethod() throws Exception {
// check hints appearance on completion
configureJava("class C { void m() { Character.for<caret> } }");
complete("forDigit");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
// check that hints don't disappear after daemon highlighting passes
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
// test Tab/Shift+Tab navigation
checkResult("class C { void m() { Character.forDigit(<caret>, ) } }");
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
next();
checkResult("class C { void m() { Character.forDigit(, <caret>) } }");
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>, <hint text=\"radix:\"/><caret>) } }");
prev();
checkResult("class C { void m() { Character.forDigit(<caret>, ) } }");
assertTrue(myFixture.getEditor().getCaretModel().getLogicalPosition().leansForward);
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
// test hints remain shown while entering parameter values
myFixture.type("1");
next();
myFixture.type("2");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1, <hint text=\"radix:\"/>2) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1, <hint text=\"radix:\"/>2<caret>) } }");
// test hints don't disappear when caret moves out of parameter list
right();
@@ -126,7 +117,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
right();
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1, <hint text=\"radix:\"/>2) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1, <hint text=\"radix:\"/>2) }<caret> }");
}
public void testWithHintsEnabledForNonLiterals() throws Exception {
@@ -137,10 +128,10 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
configureJava("class C { void m() { Character.for<caret> } }");
complete("forDigit");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
}
finally {
option.set(savedValue);
@@ -150,23 +141,21 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
public void testSwitchingOverloads() {
configureJava("class C { void m() { Character.to<caret> } }");
complete("toChars(int codePoint)");
checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/><caret>) } }");
showParameterInfo();
myFixture.performEditorAction("MethodOverloadSwitchDown");
checkResultWithInlays(
"class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>, <hint text=\"dst:\"/>, <hint text=\"dstIndex:\"/>) } }");
"class C { void m() { Character.toChars(<hint text=\"codePoint:\"/><caret>, <hint text=\"dst:\"/>, <hint text=\"dstIndex:\"/>) } }");
}
public void testSwitchingOverloadsWithParameterFilled() {
configureJava("class C { void m() { Character.to<caret> } }");
complete("toChars(int codePoint)");
type("123");
checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>123) } }");
checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>123<caret>) } }");
showParameterInfo();
myFixture.performEditorAction("MethodOverloadSwitchDown");
checkResultWithInlays(
"class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>123, <hint text=\"dst:\"/>, <hint text=\"dstIndex:\"/>) } }");
checkResult("class C { void m() { Character.toChars(123, <caret>, ) } }");
checkResultWithInlays("class C { void m() { Character.toChars(<hint text=\"codePoint:\"/>123, <hint text=\"dst:\"/><caret>, <hint text=\"dstIndex:\"/>) } }");
}
public void testSwitchingOverloadsForMethodWithDisabledHints() throws Exception {
@@ -179,7 +168,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
checkResultWithInlays("class C {\n" +
" int some(int from, int to) { return 0; }\n" +
" int some(int from, int to, int other) { return 0; }\n" +
" void m() { some(<hint text=\"from:\"/>, <hint text=\"to:\"/>, <hint text=\"other:\"/>) }\n" +
" void m() { some(<hint text=\"from:\"/><caret>, <hint text=\"to:\"/>, <hint text=\"other:\"/>) }\n" +
"}");
showParameterInfo();
myFixture.performEditorAction("MethodOverloadSwitchDown");
@@ -187,23 +176,23 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
checkResultWithInlays("class C {\n" +
" int some(int from, int to) { return 0; }\n" +
" int some(int from, int to, int other) { return 0; }\n" +
" void m() { some(<hint text=\"from:\"/>, <hint text=\"to:\"/>) }\n" +
" void m() { some(<hint text=\"from:\"/><caret>, <hint text=\"to:\"/>) }\n" +
"}");
}
public void testNoHintsForMethodReference() {
configureJava("class C {\n" +
" interface I { void i(int p); }\n" +
" void referenced(int a) {}\n" +
" void m(I lambda) {}\n" +
" void m2() { m(this::<caret>) }\n" +
"}");
" interface I { void i(int p); }\n" +
" void referenced(int a) {}\n" +
" void m(I lambda) {}\n" +
" void m2() { m(this::<caret>) }\n" +
"}");
complete("referenced");
checkResultWithInlays("class C {\n" +
" interface I { void i(int p); }\n" +
" void referenced(int a) {}\n" +
" void m(I lambda) {}\n" +
" void m2() { m(this::referenced) }\n" +
" void m2() { m(this::referenced<caret>) }\n" +
"}");
}
@@ -211,13 +200,11 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
configureJava("class C { void m() { System.setPro<caret> } }");
complete("setProperty");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
myFixture.type("System.getPro");
complete("getProperty(String key, String def)");
waitForAllAsyncStuff();
checkResultWithInlays(
"class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>), <hint text=\"value:\"/>) } }");
checkResult("class C { void m() { System.setProperty(System.getProperty(<caret>, ), ) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/><caret>, <hint text=\"def:\"/>), <hint text=\"value:\"/>) } }");
}
public void testTabWithNestedCompletion() throws Exception {
@@ -227,40 +214,39 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
myFixture.type("System.getPro");
complete("getProperty(String key, String def)");
waitForAllAsyncStuff();
checkResult("class C { void m() { System.setProperty(System.getProperty(<caret>, ), ) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/><caret>, <hint text=\"def:\"/>), <hint text=\"value:\"/>) } }");
next();
checkResult("class C { void m() { System.setProperty(System.getProperty(, <caret>), ) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/><caret>), <hint text=\"value:\"/>) } }");
next();
checkResult("class C { void m() { System.setProperty(System.getProperty(, )<caret>, ) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>)<caret>, <hint text=\"value:\"/>) } }");
next();
checkResult("class C { void m() { System.setProperty(System.getProperty(, ), <caret>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>), <hint text=\"value:\"/><caret>) } }");
next();
checkResult("class C { void m() { System.setProperty(System.getProperty(, ), )<caret> } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>), <hint text=\"value:\"/>)<caret> } }");
}
public void testNoHintsForMethodWithOneParameterFromBlackList() {
configureJava("class C { void m() { System.getPro<caret> } }");
complete("getProperty(String key)");
checkResult("class C { void m() { System.getProperty(<caret>) } }");
checkResultWithInlays("class C { void m() { System.getProperty() } }");
checkResultWithInlays("class C { void m() { System.getProperty(<caret>) } }");
}
public void testHintsDisappearWhenNumberOfParametersIsChangedDirectly() throws Exception {
configureJava("class C { void m() { System.getPro<caret> } }");
complete("getProperty(String key, String def)");
checkResultWithInlays("class C { void m() { System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>) } }");
checkResultWithInlays("class C { void m() { System.getProperty(<hint text=\"key:\"/><caret>, <hint text=\"def:\"/>) } }");
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE);
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.getProperty( ) } }");
checkResultWithInlays("class C { void m() { System.getProperty(<caret> ) } }");
}
public void testHintsDisappearWhenNumberOfParametersIsChangedDirectlyWithNoOverloads() throws Exception {
configureJava("class C { void m() { Character.for<caret> } }");
complete("forDigit");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>, <hint text=\"radix:\"/>) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/><caret>, <hint text=\"radix:\"/>) } }");
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE);
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit( ) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<caret> ) } }");
}
public void testCaretIsToTheRightOfHintAfterSmartInnerCompletion() throws Exception {
@@ -268,10 +254,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
complete("setProperty");
type("new String().trim");
myFixture.complete(CompletionType.SMART);
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>new String().trim(), <hint text=\"value:\"/>) } }");
checkResult("class C { void m() { System.setProperty(new String().trim(), <caret>) } }");
assertEquals(getEditor().offsetToVisualPosition(getEditor().getCaretModel().getOffset(), true, false),
getEditor().getCaretModel().getVisualPosition());
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>new String().trim(), <hint text=\"value:\"/><caret>) } }");
}
public void testNoHintsDuplicationWhenTypingToTheLeftOfHint() throws Exception {
@@ -282,10 +265,10 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
right();
type("2");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1,<hint text=\"radix:\"/>2 ) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1,<hint text=\"radix:\"/>2<caret> ) } }");
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_LINE_END);
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1,<hint text=\"radix:\"/>2 ) } }");
checkResultWithInlays("class C { void m() { Character.forDigit(<hint text=\"digit:\"/>1,<hint text=\"radix:\"/>2 ) } }<caret>");
}
public void testIntroduceVariableIntention() throws Exception {
@@ -334,9 +317,7 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
next();
next();
prev();
checkResult("class C { void m() { System.getProperty(, <caret>) } }");
checkResultWithInlays("class C { void m() { System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/>) } }");
assertFalse(getEditor().getInlayModel().hasInlineElementAt(getEditor().getCaretModel().getVisualPosition()));
checkResultWithInlays("class C { void m() { System.getProperty(<hint text=\"key:\"/>, <hint text=\"def:\"/><caret>) } }");
}
public void testPrevParameterFromOutsideWhenParametersAreNotEmpty() throws Exception {
@@ -348,104 +329,66 @@ public class CompletionHintsTest extends LightFixtureCompletionTestCase {
next();
waitForAllAsyncStuff();
prev();
checkResult("class C { void m() { System.getProperty(\"a\", <caret>\"b\") } }");
checkResultWithInlays("class C { void m() { System.getProperty(<hint text=\"key:\"/>\"a\", <hint text=\"def:\"/>\"b\") } }");
checkResultWithInlays("class C { void m() { System.getProperty(<hint text=\"key:\"/>\"a\", <hint text=\"def:\"/><caret>\"b\") } }");
}
public void testVararg() throws Exception {
configureJava("class C { void m() { String.for<caret> } }");
complete();
checkResult("class C { void m() { String.format(<caret>) } }");
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/><hint text=\", args:\"/>) } }");
assertCaretAfterInlay();
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/><caret><hint text=\", args:\"/>) } }");
type("\"a");
next();
checkResult("class C { void m() { String.format(\"a\", <caret>) } }");
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\", <hint text=\"args:\"/>) } }");
assertCaretAfterInlay();
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\", <hint text=\"args:\"/><caret>) } }");
next();
checkResult("class C { void m() { String.format(\"a\")<caret> } }");
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\"<hint text=\", args:\"/>) } }");
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\"<hint text=\", args:\"/>)<caret> } }");
prev();
checkResult("class C { void m() { String.format(\"a\", <caret>) } }");
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\", <hint text=\"args:\"/>) } }");
assertCaretAfterInlay();
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\", <hint text=\"args:\"/><caret>) } }");
prev();
checkResult("class C { void m() { String.format(\"a\"<caret>) } }");
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\"<hint text=\", args:\"/>) } }");
assertCaretBeforeInlay();
checkResultWithInlays("class C { void m() { String.format(<hint text=\"format:\"/>\"a\"<caret><hint text=\", args:\"/>) } }");
}
public void testVarargWithNoMandatoryArguments() throws Exception {
configureJava("class C { int vararg(int... args){ return 0; } void m() { varar<caret> } }");
complete();
checkResult("class C { int vararg(int... args){ return 0; } void m() { vararg(<caret>) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>) } }");
assertCaretAfterInlay();
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/><caret>) } }");
type("1");
next();
checkResult("class C { int vararg(int... args){ return 0; } void m() { vararg(1, <caret>) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1, ) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1, <caret>) } }");
next();
checkResult("class C { int vararg(int... args){ return 0; } void m() { vararg(1)<caret> } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1)<caret> } }");
prev();
checkResult("class C { int vararg(int... args){ return 0; } void m() { vararg(1, <caret>) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1, ) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1, <caret>) } }");
prev();
checkResult("class C { int vararg(int... args){ return 0; } void m() { vararg(1<caret>) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1) } }");
checkResultWithInlays("class C { int vararg(int... args){ return 0; } void m() { vararg(<hint text=\"args:\"/>1<caret>) } }");
}
public void testVarargWithTwoMandatoryArguments() throws Exception {
configureJava("class C { int vararg(int a, int b, int... args){ return 0; } void m() { varar<caret> } }");
complete();
checkResult("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<caret>, ) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>, <hint text=\"b:\"/><hint text=\", args:\"/>) } }");
assertCaretAfterInlay();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/><caret>, <hint text=\"b:\"/><hint text=\", args:\"/>) } }");
type("1");
next();
checkResult("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(1, <caret>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/><hint text=\", args:\"/>) } }");
assertCaretAfterInlay();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/><caret><hint text=\", args:\"/>) } }");
type("2");
next();
checkResult("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(1, 2, <caret>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2, <hint text=\"args:\"/>) } }");
assertCaretAfterInlay();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2, <hint text=\"args:\"/><caret>) } }");
next();
checkResult("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(1, 2)<caret> } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2<hint text=\", args:\"/>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2<hint text=\", args:\"/>)<caret> } }");
prev();
checkResult("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(1, 2, <caret>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2, <hint text=\"args:\"/>) } }");
assertCaretAfterInlay();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2, <hint text=\"args:\"/><caret>) } }");
prev();
checkResult("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(1, 2<caret>) } }");
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2<hint text=\", args:\"/>) } }");
assertCaretBeforeInlay();
checkResultWithInlays("class C { int vararg(int a, int b, int... args){ return 0; } void m() { vararg(<hint text=\"a:\"/>1, <hint text=\"b:\"/>2<caret><hint text=\", args:\"/>) } }");
}
public void testHintsDontDisappearWhenNavigatingAwayFromUncompletedInvocation() throws Exception {
configureJava("class C { void m() { System.setPro<caret> } }");
complete("setProperty");
waitForAllAsyncStuff();
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
checkResultWithInlays("class C { void m() { System.setProperty(<hint text=\"key:\"/><caret>, <hint text=\"value:\"/>) } }");
myFixture.getEditor().getCaretModel().moveToOffset(0);
type(' ');
waitForAllAsyncStuff();
checkResultWithInlays(" class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
}
private void assertCaretBeforeInlay() {
VisualPosition posFromOffset = myFixture.getEditor().offsetToVisualPosition(myFixture.getEditor().getCaretModel().getOffset());
assertEquals(posFromOffset, myFixture.getEditor().getCaretModel().getVisualPosition());
}
private void assertCaretAfterInlay() {
VisualPosition posFromOffset = myFixture.getEditor().offsetToVisualPosition(myFixture.getEditor().getCaretModel().getOffset());
assertEquals(new VisualPosition(posFromOffset.line, posFromOffset.column + 1),
myFixture.getEditor().getCaretModel().getVisualPosition());
checkResultWithInlays(" <caret>class C { void m() { System.setProperty(<hint text=\"key:\"/>, <hint text=\"value:\"/>) } }");
}
private void checkResult(String text) {
@@ -27,7 +27,6 @@ import com.intellij.codeInsight.daemon.GutterMark;
import com.intellij.codeInsight.daemon.impl.*;
import com.intellij.codeInsight.folding.CodeFoldingManager;
import com.intellij.codeInsight.highlighting.actions.HighlightUsagesAction;
import com.intellij.codeInsight.hints.InlayInfo;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.IntentionListStep;
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
@@ -115,6 +114,7 @@ import com.intellij.refactoring.rename.*;
import com.intellij.rt.execution.junit.FileComparisonFailure;
import com.intellij.testFramework.*;
import com.intellij.testFramework.fixtures.*;
import com.intellij.testFramework.utils.inlays.CaretAndInlaysInfo;
import com.intellij.testFramework.utils.inlays.InlayHintsChecker;
import com.intellij.ui.breadcrumbs.BreadcrumbsProvider;
import com.intellij.ui.breadcrumbs.BreadcrumbsUtil;
@@ -1760,9 +1760,9 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
public void checkResultWithInlays(String text) {
Document checkDocument = new DocumentImpl(text);
InlayHintsChecker checker = new InlayHintsChecker(this);
List<InlayInfo> inlayInfos = checker.extractInlays(checkDocument);
CaretAndInlaysInfo inlaysAndCaretInfo = checker.extractInlaysAndCaretInfo(checkDocument);
checkResult(checkDocument.getText());
checker.verifyInlays(inlayInfos, text);
checker.verifyInlaysAndCaretInfo(inlaysAndCaretInfo, text);
}
@Override
@@ -20,11 +20,15 @@ import com.intellij.codeInsight.hints.InlayInfo
import com.intellij.codeInsight.hints.settings.ParameterNameHintsSettings
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.VisualPosition
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
import com.intellij.openapi.util.TextRange
import com.intellij.rt.execution.junit.FileComparisonFailure
import com.intellij.testFramework.VfsTestUtil
import com.intellij.testFramework.fixtures.CodeInsightTestFixture
import junit.framework.ComparisonFailure
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import java.util.regex.Pattern
@@ -33,7 +37,7 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
private var isParamHintsEnabledBefore = false
companion object {
val pattern: Pattern = Pattern.compile("<hint\\s+text=\"([^\"\n\r]+)\"\\s*/>")
val pattern: Pattern = Pattern.compile("(<caret>)|(<selection>)|(</selection>)|<hint\\s+text=\"([^\"\n\r]+)\"\\s*/>")
private val default = ParameterNameHintsSettings()
}
@@ -55,19 +59,19 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
val file = myFixture.file
val document = myFixture.getDocument(file)
val originalText = document.text
val expectedInlays: List<InlayInfo> = extractInlays(document)
myFixture.doHighlighting();
verifyInlays(expectedInlays, originalText)
val expectedInlaysAndCaret = extractInlaysAndCaretInfo(document)
myFixture.doHighlighting()
verifyInlaysAndCaretInfo(expectedInlaysAndCaret, originalText)
}
fun verifyInlays(expectedInlays : List<InlayInfo>, originalText: String) {
fun verifyInlaysAndCaretInfo(expectedInlaysAndCaret: CaretAndInlaysInfo, originalText: String) {
val file = myFixture.file
val document = myFixture.getDocument(file)
val actual: List<Pair<Int, String>> = getActualInlays()
val expected = expectedInlays.map { Pair(it.offset, it.text) }
val expected = expectedInlaysAndCaret.inlays.map { Pair(it.offset, it.text) }
if (expectedInlays.size != actual.size || actual.zip(expected).any { it.first != it.second }) {
if (expectedInlaysAndCaret.inlays.size != actual.size || actual.zip(expected).any { it.first != it.second }) {
val proposedText = StringBuilder(document.text)
actual.asReversed().forEach { proposedText.insert(it.first, "<hint text=\"${it.second}\" />") }
@@ -75,6 +79,19 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
throw FileComparisonFailure("Hints differ", originalText, proposedText.toString(), originalPath)
} ?: throw ComparisonFailure("Hints differ", originalText, proposedText.toString())
}
if (expectedInlaysAndCaret.caretOffset != null) {
assertEquals("Unexpected caret offset", expectedInlaysAndCaret.caretOffset, myFixture.editor.caretModel.offset)
val position = myFixture.editor.offsetToVisualPosition(expectedInlaysAndCaret.caretOffset)
assertEquals("Unexpected caret visual position",
VisualPosition(position.line, position.column + expectedInlaysAndCaret.inlaysBeforeCaret),
myFixture.editor.caretModel.visualPosition)
val selectionModel = myFixture.editor.selectionModel
if (expectedInlaysAndCaret.selection == null) assertFalse(selectionModel.hasSelection())
else assertEquals("Unexpected selection",
expectedInlaysAndCaret.selection,
TextRange(selectionModel.selectionStart, selectionModel.selectionEnd))
}
}
private fun getActualInlays(): List<Pair<Int, String>> {
@@ -88,25 +105,45 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
.sortedBy { it.first }
}
fun extractInlays(document: Document): List<InlayInfo> {
fun extractInlaysAndCaretInfo(document: Document): CaretAndInlaysInfo {
val text = document.text
val matcher = pattern.matcher(text)
val inlays = mutableListOf<InlayInfo>()
var extractedLength = 0
var caretOffset : Int? = null
var inlaysBeforeCaret = 0
var selectionStart : Int? = null
var selectionEnd : Int? = null
while (matcher.find()) {
val start = matcher.start()
val matchedLength = matcher.end() - start
val realStartOffset = start - extractedLength
inlays += InlayInfo(matcher.group(1), realStartOffset)
if (matcher.group(1) != null) {
caretOffset = realStartOffset
inlays.asReversed()
.takeWhile { it.offset == caretOffset }
.forEach { inlaysBeforeCaret++ }
}
else if (matcher.group(2) != null) {
selectionStart = realStartOffset
}
else if (matcher.group(3) != null) {
selectionEnd = realStartOffset
}
else {
inlays += InlayInfo(matcher.group(4), realStartOffset)
}
removeText(document, realStartOffset, matchedLength)
extractedLength += (matcher.end() - start)
}
return inlays
return CaretAndInlaysInfo(caretOffset, inlaysBeforeCaret,
if (selectionStart == null || selectionEnd == null) null else TextRange(selectionStart, selectionEnd),
inlays)
}
private fun removeText(document: Document, realStartOffset: Int, matchedLength: Int) {
@@ -116,4 +153,6 @@ class InlayHintsChecker(private val myFixture: CodeInsightTestFixture) {
}
}
}
class CaretAndInlaysInfo (val caretOffset: Int?, val inlaysBeforeCaret: Int, val selection: TextRange?, val inlays: List<InlayInfo>)