792af508a0a2e409a324982f053bc7b753e550c2
[idea/community.git] / java / java-tests / testSrc / com / intellij / codeInsight / template / LiveTemplateTest.groovy
1 /*
2  * Copyright 2000-2016 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 package com.intellij.codeInsight.template
17
18 import com.intellij.JavaTestUtil
19 import com.intellij.codeInsight.CodeInsightSettings
20 import com.intellij.codeInsight.completion.CompletionType
21 import com.intellij.codeInsight.daemon.impl.quickfix.EmptyExpression
22 import com.intellij.codeInsight.lookup.Lookup
23 import com.intellij.codeInsight.lookup.LookupManager
24 import com.intellij.codeInsight.template.impl.*
25 import com.intellij.codeInsight.template.macro.*
26 import com.intellij.openapi.actionSystem.IdeActions
27 import com.intellij.openapi.command.WriteCommandAction
28 import com.intellij.openapi.editor.Editor
29 import com.intellij.openapi.editor.impl.DocumentImpl
30 import com.intellij.openapi.util.JDOMUtil
31 import com.intellij.openapi.util.text.StringUtil
32 import com.intellij.psi.PsiDocumentManager
33 import com.intellij.psi.codeStyle.CodeStyleSettingsManager
34 import com.intellij.psi.codeStyle.CommonCodeStyleSettings
35 import com.intellij.testFramework.LightPlatformCodeInsightTestCase
36 import com.intellij.testFramework.fixtures.CodeInsightTestUtil
37 import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
38 import com.intellij.util.containers.ContainerUtil
39 import com.intellij.util.ui.UIUtil
40 import org.jdom.Element
41 import org.jetbrains.annotations.NotNull
42
43 import static com.intellij.codeInsight.template.Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE
44 import static com.intellij.testFramework.EdtTestUtil.runInEdtAndWait
45 /**
46  * @author spleaner
47  */
48 @SuppressWarnings("SpellCheckingInspection")
49 class LiveTemplateTest extends LightCodeInsightFixtureTestCase {
50   @Override
51   protected String getBasePath() {
52     return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/template/"
53   }
54
55   @Override
56   protected void setUp() {
57     super.setUp()
58     TemplateManagerImpl.setTemplateTesting(getProject(), getTestRootDisposable())
59   }
60
61   @Override
62   protected void tearDown() {
63     CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.FIRST_LETTER
64     CodeInsightSettings.instance.SELECT_AUTOPOPUP_SUGGESTIONS_BY_CHARS = false
65     if (state != null) {
66       WriteCommandAction.runWriteCommandAction project, {
67         state.gotoEnd()
68       }
69     }
70     super.tearDown()
71   }
72
73   private void doTestTemplateWithArg(@NotNull String templateName,
74                                      @NotNull String templateText,
75                                      @NotNull String fileText,
76                                      @NotNull String expected) throws IOException {
77     configureFromFileText("dummy.java", fileText)
78     final TemplateManager manager = TemplateManager.getInstance(getProject())
79     String group = "user"
80     final Template template = manager.createTemplate(templateName, group, templateText)
81     template.addVariable("ARG", "", "", false)
82     TemplateContextType contextType = contextType(JavaCodeContextType.class)
83     ((TemplateImpl)template).getTemplateContext().setEnabled(contextType, true)
84     CodeInsightTestUtil.addTemplate(template, testRootDisposable)
85
86     writeCommand { manager.startTemplate(editor, (char)'\t') }
87     UIUtil.dispatchAllInvocationEvents()
88     checkResultByText(expected)
89   }
90
91   void testDependentSegmentsAtTheSamePosition() {
92     configureFromFileText("dummy.java", "class A { void test() { <caret> } }")
93     TemplateManager manager = TemplateManager.getInstance(getProject())
94     final Template template = manager.createTemplate("test_template", "user_group", '$A$$B$ then "$A$.$B$"')
95     template.addVariable("A", "", "", true)
96     template.addVariable("B", "", "", true)
97     startTemplate(template)
98     myFixture.type("HELLO")
99     myFixture.type("\t")
100     myFixture.type("THERE")
101     myFixture.type("\t")
102     assert state == null
103     checkResultByText("class A { void test() { HELLOTHERE then \"HELLO.THERE\" } }")
104   }
105
106   void testTemplateWithSegmentsAtTheSamePosition_1() {
107     doTestTemplateWithThreeVariables("", "", "", "class A { void test() { for(TestValue1TestValue2TestValue3) {} } }")
108   }
109
110   void testTemplateWithSegmentsAtTheSamePosition_2() {
111     doTestTemplateWithThreeVariables("Def1", "Def2", "DefaultValue", "class A { void test() { for(Def1Def2DefaultValue) {} } }")
112   }
113
114   void testTemplateWithSegmentsAtTheSamePosition_3() {
115     doTestTemplateWithThreeVariables("", "DefaultValue", "", "class A { void test() { for(TestValue1DefaultValueTestValue3) {} } }")
116   }
117
118   private void doTestTemplateWithThreeVariables(String firstDefaultValue, String secondDefaultValue, String thirdDefaultValue,
119                                                 String expectedText) {
120     configureFromFileText("dummy.java", "class A { void test() { <caret> } }")
121
122     TemplateManager manager = TemplateManager.getInstance(getProject())
123     def templateName = "tst_template"
124     def templateGroup = "user"
125     final Template template = manager.createTemplate(templateName, templateGroup, 'for($TEST1$$TEST2$$TEST3$) {}')
126     template.addVariable("TEST1", "", StringUtil.wrapWithDoubleQuote(firstDefaultValue), true)
127     template.addVariable("TEST2", "", StringUtil.wrapWithDoubleQuote(secondDefaultValue), true)
128     template.addVariable("TEST3", "", StringUtil.wrapWithDoubleQuote(thirdDefaultValue), true)
129     startTemplate(template)
130
131     if (firstDefaultValue.empty) myFixture.type("TestValue1")
132     myFixture.type("\t")
133     if (secondDefaultValue.empty) myFixture.type("TestValue2")
134     myFixture.type("\t")
135     if (thirdDefaultValue.empty) myFixture.type("TestValue3")
136     myFixture.type("\t")
137     assert state == null
138     checkResultByText(expectedText)
139   }
140
141   void testTemplateWithArg1() throws IOException {
142     doTestTemplateWithArg("tst", 'wrap($ARG$)', "tst arg<caret>", "wrap(arg)")
143   }
144
145   void testTemplateWithArg2() throws IOException {
146     doTestTemplateWithArg("tst#", 'wrap($ARG$)', "tst#arg<caret>", "wrap(arg)")
147   }
148
149   void testTemplateWithArg3() throws IOException {
150     doTestTemplateWithArg("tst#", 'wrap($ARG$)', "tst# arg<caret>", "tst# arg")
151   }
152
153   void testTemplateAtEndOfFile() {
154     configureFromFileText("empty.java", "")
155     final TemplateManager manager = TemplateManager.getInstance(getProject())
156     final Template template = manager.createTemplate("empty", "user", '$VAR$')
157     template.addVariable("VAR", "", "", false)
158
159     startTemplate(template)
160     checkResultByText("")
161   }
162
163   void testTemplateWithEnd() {
164     configureFromFileText("empty.java", "")
165     final TemplateManager manager = TemplateManager.getInstance(getProject())
166     final Template template = manager.createTemplate("empty", "user", '$VAR$$END$')
167     template.addVariable("VAR", "bar", "bar", true)
168     template.setToReformat(true)
169
170     startTemplate(template)
171     myFixture.type("foo")
172     checkResultByText("foo")
173   }
174
175   void testTemplateWithIndentedEnd() {
176     configureFromFileText("empty.java", "class C {\n" +
177                                         "  bar() {\n" +
178                                         "    <caret>\n" +
179                                         "  }\n" +
180                                         "}")
181     TemplateManager manager = TemplateManager.getInstance(getProject())
182     Template template = manager.createTemplate("empty", "user", 'foo();\n' +
183                                                                 'int i = 0;    $END$\n' +
184                                                                 'foo()')
185     template.setToReformat(true)
186     startTemplate(template)
187     checkResultByText("class C {\n" +
188                       "  bar() {\n" +
189                       "      foo();\n" +
190                       "      int i = 0;    <caret>\n" +
191                       "      foo()\n" +
192                       "  }\n" +
193                       "}")
194   }
195
196
197   void testTemplateWithEndOnEmptyLine() {
198     configureFromFileText("empty.java", "class C {\n" +
199                                         "  bar() {\n" +
200                                         "    <caret>\n" +
201                                         "  }\n" +
202                                         "}")
203     TemplateManager manager = TemplateManager.getInstance(getProject())
204     Template template = manager.createTemplate("empty", "user", 'foo()\n' +
205                                                                 '  $END$\n' +
206                                                                 'foo()')
207     template.setToReformat(true)
208     startTemplate(template)
209     checkResultByText("class C {\n" +
210                       "  bar() {\n" +
211                       "      foo()\n" +
212                       "              <caret>\n" +
213                       "      foo()\n" +
214                       "  }\n" +
215                       "}")
216   }
217
218   private void checkResultByText(String text) {
219     myFixture.checkResult(text)
220   }
221
222   private void configureFromFileText(String name, String text) {
223     myFixture.configureByText(name, text)
224   }
225
226   void testEndInTheMiddle() {
227     configure()
228     final TemplateManager manager = TemplateManager.getInstance(getProject())
229     final Template template = manager.createTemplate("frm", "user", "javax.swing.JFrame frame = new javax.swing.JFrame();\n" +
230                                                                     '$END$\n' +
231                                                                     "frame.setVisible(true);\n" +
232                                                                     "frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);\n" +
233                                                                     "frame.pack();")
234     template.setToShortenLongNames(false)
235     template.setToReformat(true)
236     startTemplate(template)
237     checkResult()
238   }
239
240   void "test honor custom completion caret placement"() {
241     myFixture.configureByText 'a.java', '''
242 class Foo {
243   void foo(int a) {}
244   { <caret> }
245 }
246 '''
247     final TemplateManager manager = TemplateManager.getInstance(getProject())
248     final Template template = manager.createTemplate("frm", "user", '$VAR$')
249     template.addVariable('VAR', new MacroCallNode(new CompleteMacro()), new EmptyNode(), true)
250     startTemplate(template)
251     myFixture.type('fo\n')
252     myFixture.checkResult '''
253 class Foo {
254   void foo(int a) {}
255   { foo(<caret>); }
256 }
257 '''
258     assert !state.finished
259   }
260
261   void "test cancel template when completion placed caret outside the variable"() {
262     myFixture.configureByText 'a.java', '''
263 class Foo {
264   void foo(int a) {}
265   { <caret>() }
266 }
267 '''
268     final TemplateManager manager = TemplateManager.getInstance(getProject())
269     final Template template = manager.createTemplate("frm", "user", '$VAR$')
270     template.addVariable('VAR', new MacroCallNode(new CompleteMacro()), new EmptyNode(), true)
271     startTemplate(template)
272     myFixture.type('fo\n')
273     myFixture.checkResult '''
274 class Foo {
275   void foo(int a) {}
276   { foo(<caret>); }
277 }
278 '''
279     assert !state
280   }
281
282   void "test not to go to next tab after insert if element is a psi package"() {
283     myFixture.configureByText 'a.java', '''
284 <caret>
285 '''
286     final TemplateManager manager = TemplateManager.getInstance(getProject())
287     final Template template = manager.createTemplate("imp", "user", 'import $MODIFIER$ java.$NAME$;')
288     template.addVariable('NAME', new MacroCallNode(new CompleteMacro(true)), new EmptyNode(), true)
289     template.addVariable('MODIFIER', new EmptyExpression(), true)
290     startTemplate(template)
291     myFixture.type('uti\n')
292     myFixture.checkResult '''
293 import  java.util.<caret>;
294 '''
295     assert !state.finished
296   }
297
298   void "test not to go to next tab after insert if element has call arguments"() {
299     myFixture.configureByText 'a.java', '''
300 import  java.util.*;
301 public class Main {
302     List<String> getStringList(int i){
303         List<String> ints = null;
304         <caret>
305         return new ArrayList<>(i);
306     }
307 }
308 '''
309     final TemplateManager manager = TemplateManager.getInstance(getProject())
310     final Template template = manager.createTemplate("for", "user", 'for ($ELEMENT_TYPE$ $VAR$ : $ITERABLE_TYPE$) {\n' +
311                                                                     '$END$;\n' +
312                                                                     '}')
313     template.addVariable('ITERABLE_TYPE', new MacroCallNode(new CompleteSmartMacro()), new EmptyNode(), true)
314     template.addVariable('VAR', new TextExpression("item"), true)
315     template.addVariable('ELEMENT_TYPE', new TextExpression("String"), true)
316     template.setToReformat(true)
317     startTemplate(template)
318     myFixture.type('get\n')
319     myFixture.checkResult """
320 import  java.util.*;
321 public class Main {
322     List<String> getStringList(int i){
323         List<String> ints = null;
324         for (String item : getStringList(<caret>)) {
325             ;
326         }
327         return new ArrayList<>(i);
328     }
329 }
330 """
331     assert !state.finished
332   }
333
334   void "test go to next tab after insert if element does not have call arguments"() {
335     myFixture.configureByText 'a.java', '''
336 import  java.util.*;
337 public class Main {
338     List<String> getStringList(int i){
339         List<String> ints = null;
340         <caret>
341         return new ArrayList<>(i);
342     }
343 }
344 '''
345     final TemplateManager manager = TemplateManager.getInstance(getProject())
346     final Template template = manager.createTemplate("for", "user", 'for ($ELEMENT_TYPE$ $VAR$ : $ITERABLE_TYPE$) {\n' +
347                                                                     '$END$;\n' +
348                                                                     '}')
349     template.addVariable('ITERABLE_TYPE', new MacroCallNode(new CompleteSmartMacro()), new EmptyNode(), true)
350     template.addVariable('VAR', new TextExpression("item"), true)
351     template.addVariable('ELEMENT_TYPE', new TextExpression("String"), true)
352     template.setToReformat(true)
353     startTemplate(template)
354     myFixture.type('in\n')
355     myFixture.checkResult """
356 import  java.util.*;
357 public class Main {
358     List<String> getStringList(int i){
359         List<String> ints = null;
360         for (String <selection>item</selection> : ints) {
361             ;
362         }
363         return new ArrayList<>(i);
364     }
365 }
366 """
367     assert !state.finished
368   }
369
370   void "test non-imported classes in className macro"() {
371     myFixture.addClass('package bar; public class Bar {}')
372     myFixture.configureByText 'a.java', '''
373 class Foo {
374   void foo(int a) {}
375   { <caret> }
376 }
377 '''
378     final TemplateManager manager = TemplateManager.getInstance(getProject())
379     final Template template = manager.createTemplate("frm", "user", '$VAR$')
380     template.addVariable('VAR', new MacroCallNode(new ClassNameCompleteMacro()), new EmptyNode(), true)
381     startTemplate(template)
382     assert !state.finished
383     assert 'Bar' in myFixture.lookupElementStrings
384   }
385
386   void "test variableOfType suggests inner static classes"() {
387     myFixture.addClass('public interface MyCallback {}')
388     myFixture.addClass('''
389 class MyUtils {
390   public static void doSomethingWithCallback(MyCallback cb) { }
391 }
392 ''')
393     myFixture.configureByText 'a.java', '''
394 class Outer {
395   static class Inner implements MyCallback {
396     void aMethod() {
397       <caret>
398     }
399   }
400 }
401 '''
402
403     TemplateManager manager = TemplateManager.getInstance(getProject())
404     Template template = manager.createTemplate("myCbDo", "user", 'MyUtils.doSomethingWithCallback($CB$)')
405
406     MacroCallNode call = new MacroCallNode(new VariableOfTypeMacro())
407     call.addParameter(new ConstantNode("MyCallback"))
408     template.addVariable('CB', call, new EmptyNode(), false)
409     startTemplate(template)
410
411     checkResultByText '''
412 class Outer {
413   static class Inner implements MyCallback {
414     void aMethod() {
415       MyUtils.doSomethingWithCallback(this)
416     }
417   }
418 }
419 '''
420   }
421
422   private void checkResult() {
423     checkResultByFile(getTestName(false) + "-out.java")
424   }
425
426   private void checkResultByFile(String s) {
427     myFixture.checkResultByFile(s)
428   }
429
430   void testToar() throws Throwable {
431     configure()
432     startTemplate("toar", "other")
433     state.gotoEnd(false)
434     checkResult()
435   }
436
437   def startTemplate(String name, char expandKey) {
438     myFixture.type(name)
439     myFixture.type(expandKey)
440   }
441
442   def startTemplate(String name, String group) {
443     startTemplate(TemplateSettings.getInstance().getTemplate(name, group))
444   }
445
446   def startTemplate(Template template) {
447     TemplateManager.getInstance(getProject()).startTemplate(getEditor(), template)
448     UIUtil.dispatchAllInvocationEvents()
449   }
450
451   private static <T extends TemplateContextType> T contextType(Class<T> clazz) {
452     ContainerUtil.findInstance(TemplateContextType.EP_NAME.getExtensions(), clazz)
453   }
454
455   private void configure() {
456     myFixture.configureByFile(getTestName(false) + ".java")
457   }
458
459   void testIter() throws Throwable {
460     configure()
461     startTemplate("iter", "iterations")
462     writeCommand { state.nextTab() }
463     myFixture.finishLookup(Lookup.AUTO_INSERT_SELECT_CHAR)
464     checkResult()
465   }
466
467   void testPreferStartMatchesInLookups() throws Throwable {
468     configure()
469     startTemplate("iter", "iterations")
470     myFixture.type('ese\n') //for entrySet
471     assert myFixture.lookupElementStrings == ['barGooStringBuilderEntry', 'gooStringBuilderEntry', 'stringBuilderEntry', 'builderEntry', 'entry']
472     myFixture.type('e')
473     assert myFixture.lookupElementStrings == ['entry', 'barGooStringBuilderEntry', 'gooStringBuilderEntry', 'stringBuilderEntry', 'builderEntry']
474     assert LookupManager.getActiveLookup(editor).currentItem.lookupString == 'entry'
475   }
476
477   void testClassNameDotInTemplate() {
478     CodeInsightSettings.instance.COMPLETION_CASE_SENSITIVE = CodeInsightSettings.NONE
479     configure()
480     startTemplate("soutv", "output")
481     myFixture.type('File')
482     assert myFixture.lookupElementStrings == ['file']
483     myFixture.type('.')
484     checkResult()
485     assert !state.finished
486   }
487
488   void testFinishTemplateVariantWithDot() {
489     CodeInsightSettings.instance.SELECT_AUTOPOPUP_SUGGESTIONS_BY_CHARS = true
490     configure()
491     startTemplate("soutv", "output")
492     myFixture.type('fil')
493     assert myFixture.lookupElementStrings == ['file']
494     myFixture.type('.')
495     checkResult()
496     assert !state.finished
497   }
498
499   void testAllowTypingRandomExpressionsWithLookupOpen() {
500     configure()
501     startTemplate("iter", "iterations")
502     myFixture.type('file.')
503     checkResult()
504     assert !state.finished
505   }
506
507   private TemplateState getState() {
508     editor?.with { TemplateManagerImpl.getTemplateState(it) }
509   }
510
511   void testIter1() throws Throwable {
512     configure()
513     startTemplate("iter", "iterations")
514     myFixture.performEditorAction("NextTemplateVariable")
515     checkResult()
516   }
517
518   void "_testIterForceBraces"() {
519     CodeStyleSettingsManager.getSettings(getProject()).IF_BRACE_FORCE = CommonCodeStyleSettings.FORCE_BRACES_ALWAYS
520
521     try {
522       configure()
523       startTemplate("iter", "iterations")
524       stripTrailingSpaces()
525       checkResult()
526     }
527     finally {
528       CodeStyleSettingsManager.getSettings(getProject()).IF_BRACE_FORCE = CommonCodeStyleSettings.DO_NOT_FORCE
529     }
530   }
531
532   private void stripTrailingSpaces() {
533     DocumentImpl document = (DocumentImpl)getEditor().getDocument()
534     document.setStripTrailingSpacesEnabled(true)
535     document.stripTrailingSpaces(getProject())
536     PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
537   }
538
539   void testIterParameterizedInner() {
540     configure()
541     startTemplate("iter", "iterations")
542     stripTrailingSpaces()
543     checkResult()
544   }
545
546   void testIterParameterizedInnerInMethod() {
547     configure()
548     startTemplate("iter", "iterations")
549     stripTrailingSpaces()
550     checkResult()
551   }
552
553   void testAsListToar() {
554     configure()
555     startTemplate("toar", "other")
556     myFixture.type('\n\t')
557     checkResult()
558   }
559
560   void testVarargToar() {
561     configure()
562     startTemplate("toar", "other")
563     checkResult()
564   }
565
566   void testSoutp() {
567     configure()
568     startTemplate("soutp", "output")
569     checkResult()
570   }
571
572   void testJavaStatementContext() {
573     final TemplateImpl template = TemplateSettings.getInstance().getTemplate("inst", "other")
574     assertFalse(isApplicable("class Foo {{ if (a inst<caret>) }}", template))
575     assertTrue(isApplicable("class Foo {{ <caret>inst }}", template))
576     assertTrue(isApplicable("class Foo {{ <caret>inst\n a=b; }}", template))
577     assertFalse(isApplicable("class Foo {{ return (<caret>inst) }}", template))
578     assertFalse(isApplicable("class Foo {{ return a <caret>inst) }}", template))
579     assertFalse(isApplicable("class Foo {{ \"<caret>\" }}", template))
580     assertTrue(isApplicable("class Foo {{ <caret>a.b(); ) }}", template))
581     assertTrue(isApplicable("class Foo {{ <caret>a(); ) }}", template))
582     assertTrue(isApplicable("class Foo {{ Runnable r = () -> { <caret>System.out.println(\"foo\"); }; ) }}", template))
583     assertTrue(isApplicable("class Foo {{ Runnable r = () -> <caret>System.out.println(\"foo\"); ) }}", template))
584   }
585
586   void testJavaExpressionContext() {
587     final TemplateImpl template = TemplateSettings.getInstance().getTemplate("toar", "other")
588     assertFalse(isApplicable("class Foo {{ if (a <caret>toar) }}", template))
589     assertTrue(isApplicable("class Foo {{ <caret>toar }}", template))
590     assertTrue(isApplicable("class Foo {{ return (<caret>toar) }}", template))
591     assertFalse(isApplicable("class Foo {{ return (aaa <caret>toar) }}", template))
592     assertTrue(isApplicable("class Foo {{ Runnable r = () -> { <caret>System.out.println(\"foo\"); }; ) }}", template))
593     assertTrue(isApplicable("class Foo {{ Runnable r = () -> <caret>System.out.println(\"foo\"); ) }}", template))
594   }
595
596   void testJavaDeclarationContext() {
597     final TemplateImpl template = TemplateSettings.getInstance().getTemplate("psvm", "other")
598     assertFalse(isApplicable("class Foo {{ <caret>xxx }}", template))
599     assertFalse(isApplicable("class Foo {{ <caret>xxx }}", template))
600     assertFalse(isApplicable("class Foo {{ if (a <caret>xxx) }}", template))
601     assertFalse(isApplicable("class Foo {{ return (<caret>xxx) }}", template))
602     assertTrue(isApplicable("class Foo { <caret>xxx }", template))
603     assertFalse(isApplicable("class Foo { int <caret>xxx }", template))
604     assertTrue(isApplicable("class Foo {} <caret>xxx", template))
605
606     assertTrue(isApplicable("class Foo { void foo(<caret>xxx) {} }", template))
607     assertTrue(isApplicable("class Foo { void foo(<caret>xxx String bar ) {} }", template))
608     assertTrue(isApplicable("class Foo { void foo(<caret>xxx String bar, int goo ) {} }", template))
609     assertTrue(isApplicable("class Foo { void foo(String bar, <caret>xxx int goo ) {} }", template))
610     assertTrue(isApplicable("class Foo { void foo(String bar, <caret>xxx goo ) {} }", template))
611     assertTrue(isApplicable("class Foo { <caret>xxx void foo(String bar, xxx goo ) {} }", template))
612     assertTrue(isApplicable("class Foo { void foo(<caret>String[] bar) {} }", template))
613     assertTrue(isApplicable("class Foo { <caret>xxx String[] foo(String[] bar) {} }", template))
614
615     assertTrue(isApplicable("class Foo { /**\nfoo **/ <caret>xxx String[] foo(String[] bar) {} }", template))
616
617     assertTrue(isApplicable("<caret>xxx package foo; class Foo {}", template))
618   }
619
620   void testOtherContext() throws IOException {
621     configureFromFileText("a.java", "class Foo { <caret>xxx }")
622     assertInstanceOf(
623       assertOneElement(TemplateManagerImpl.getApplicableContextTypes(myFixture.getFile(), getEditor().getCaretModel().getOffset())),
624       JavaCodeContextType.Declaration.class)
625
626     configureFromFileText("a.txt", "class Foo { <caret>xxx }")
627     assertInstanceOf(
628       assertOneElement(TemplateManagerImpl.getApplicableContextTypes(myFixture.getFile(), getEditor().getCaretModel().getOffset())),
629       EverywhereContextType.class)
630   }
631
632   void testJavaOtherContext() throws IOException {
633     def manager = (TemplateManagerImpl)TemplateManager.getInstance(project)
634     def stmtContext = TemplateContextType.EP_NAME.findExtension(JavaCodeContextType.Statement)
635
636     configureFromFileText("a.java", "class Foo {{ iter<caret>  }}")
637
638     TemplateImpl template = TemplateSettings.instance.getTemplate("iter", "iterations")
639     assert (template in manager.findMatchingTemplates(myFixture.file, editor, Lookup.REPLACE_SELECT_CHAR, TemplateSettings.instance)?.keySet())
640
641     assert template.templateContext.getOwnValue(stmtContext)
642     assert !template.templateContext.getOwnValue(stmtContext.baseContextType)
643     template.templateContext.setEnabled(stmtContext, false)
644     template.templateContext.setEnabled(stmtContext.baseContextType, true)
645     try {
646       assert !(template in manager.findMatchingTemplates(myFixture.file, editor, Lookup.REPLACE_SELECT_CHAR, TemplateSettings.instance)?.keySet())
647     } finally {
648       template.templateContext.setEnabled(stmtContext, true)
649       template.templateContext.setEnabled(stmtContext.baseContextType, false)
650     }
651   }
652
653   void testDontSaveDefaultContexts() {
654     def defElement = JDOMUtil.loadDocument('''\
655 <context>
656   <option name="JAVA_STATEMENT" value="false"/>
657   <option name="JAVA_CODE" value="true"/>
658 </context>''').rootElement
659     def defContext = new TemplateContext()
660     defContext.readTemplateContext(defElement)
661
662     assert !defContext.isEnabled(TemplateContextType.EP_NAME.findExtension(JavaCodeContextType.Statement))
663     assert defContext.isEnabled(TemplateContextType.EP_NAME.findExtension(JavaCodeContextType.Declaration))
664     assert defContext.isEnabled(TemplateContextType.EP_NAME.findExtension(JavaCodeContextType.Generic))
665
666     def copy = defContext.createCopy()
667
668     def write = new Element("context")
669     copy.writeTemplateContext(write)
670     assert write.children.size() == 2 : JDOMUtil.writeElement(write)
671
672     copy.setEnabled(TemplateContextType.EP_NAME.findExtension(JavaCommentContextType), false)
673
674     write = new Element("context")
675     copy.writeTemplateContext(write)
676     assert write.children.size() == 3 : JDOMUtil.writeElement(write)
677   }
678
679   void "test use default context when empty"() {
680     def context = new TemplateContext()
681     context.readTemplateContext(new Element("context"))
682
683     def defContext = new TemplateContext()
684     def commentContext = TemplateContextType.EP_NAME.findExtension(JavaCommentContextType)
685     defContext.setEnabled(commentContext, true)
686
687     context.setDefaultContext(defContext)
688     assert context.isEnabled(commentContext)
689     assert !context.isEnabled(TemplateContextType.EP_NAME.findExtension(JavaCodeContextType.Generic))
690   }
691
692   void "test adding new context to Other"() {
693     def defElement = JDOMUtil.loadDocument('''\
694 <context>
695   <option name="OTHER" value="true"/>
696 </context>''').rootElement
697     def context = new TemplateContext()
698     context.readTemplateContext(defElement)
699
700     def javaContext = TemplateContextType.EP_NAME.findExtension(JavaCodeContextType.Generic)
701     context.setEnabled(javaContext, true)
702
703     def saved = new Element('context')
704     context.writeTemplateContext(saved)
705
706     context = new TemplateContext()
707     context.readTemplateContext(saved)
708
709     assert context.isEnabled(javaContext)
710     assert context.isEnabled(TemplateContextType.EP_NAME.findExtension(EverywhereContextType))
711   }
712
713   private boolean isApplicable(String text, TemplateImpl inst) throws IOException {
714     configureFromFileText("a.java", text)
715     return TemplateManagerImpl.isApplicable(myFixture.getFile(), getEditor().getCaretModel().getOffset(), inst)
716   }
717
718   private static writeCommand(Runnable runnable) {
719     WriteCommandAction.runWriteCommandAction(null, runnable)
720   }
721
722   void testSearchByDescriptionWhenTemplatesListed() {
723     myFixture.configureByText("a.java", "class A {{ <caret> }}")
724
725     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
726     myFixture.type('array')
727     assert 'itar' in myFixture.lookupElementStrings
728   }
729
730   void testListTemplatesSearchesPrefixInDescription() {
731     myFixture.configureByText("a.java", "class A { main<caret> }")
732
733     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
734     assert myFixture.lookupElementStrings == ['psvm']
735   }
736
737   void testListTemplatesAction() {
738     myFixture.configureByText("a.java", "class A {{ <caret> }}")
739
740     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
741     assert myFixture.lookupElementStrings.containsAll(['iter', 'itco', 'toar'])
742
743     myFixture.type('it')
744     assert myFixture.lookupElementStrings[0].startsWith('it')
745     assert LookupManager.getInstance(project).activeLookup.currentItem == myFixture.getLookupElements()[0]
746
747     myFixture.type('e')
748     assert myFixture.lookupElementStrings[0].startsWith('ite')
749     assert LookupManager.getInstance(project).activeLookup.currentItem == myFixture.getLookupElements()[0]
750     LookupManager.getInstance(project).hideActiveLookup()
751
752     myFixture.type('\b\b')
753     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
754     assert myFixture.lookupElementStrings.containsAll(['iter', 'itco'])
755     LookupManager.getInstance(project).hideActiveLookup()
756
757     myFixture.type('xxxxx')
758     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
759     assert myFixture.lookupElementStrings.containsAll(['iter', 'itco', 'toar'])
760     LookupManager.getInstance(project).hideActiveLookup()
761   }
762
763   void testSelectionFromLookupBySpace() {
764     myFixture.configureByText("a.java", "class A {{ itc<caret> }}")
765
766     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
767     myFixture.type ' '
768     myFixture.checkResult """\
769 import java.util.Iterator;
770
771 class A {{
772     for (Iterator <selection>iterator</selection> = collection.iterator(); iterator.hasNext(); ) {
773         Object next =  iterator.next();
774         \n\
775     }
776 }}"""
777   }
778
779   void testNavigationActionsDontTerminateTemplate() throws Throwable {
780     configureFromFileText("a.txt", "")
781
782     final TemplateManager manager = TemplateManager.getInstance(getProject())
783     final Template template = manager.createTemplate("vn", "user", 'Hello $V1$ World $V1$\nHello $V2$ World $V2$\nHello $V3$ World $V3$')
784     template.addVariable("V1", "", "", true)
785     template.addVariable("V2", "", "", true)
786     template.addVariable("V3", "", "", true)
787     final Editor editor = getEditor()
788
789     startTemplate(template)
790
791     final TemplateState state = getState()
792
793     for (int i = 0; i < 3; i++) {
794       assertFalse(String.valueOf(i), state.isFinished())
795       myFixture.type('H')
796       final String docText = editor.getDocument().getText()
797       assertTrue(docText, docText.startsWith("Hello H World H\n"))
798       final int offset = editor.getCaretModel().getOffset()
799
800       moveCaret(offset + 1)
801       moveCaret(offset)
802
803       myFixture.completeBasic()
804       myFixture.type(' ')
805
806       assertEquals(offset + 1, editor.getCaretModel().getOffset())
807       assertFalse(state.isFinished())
808
809       myFixture.type('\b')
810       assertFalse(state.isFinished())
811       writeCommand { state.nextTab() }
812     }
813     assertTrue(state.isFinished())
814     checkResultByFile(getTestName(false) + "-out.txt")
815   }
816
817   private void moveCaret(final int offset) {
818     runInEdtAndWait {
819       getEditor().getCaretModel().moveToOffset(offset)
820     }
821   }
822
823   void testUseDefaultValueForQuickResultCalculation() {
824     myFixture.configureByText 'a.txt', '<caret>'
825
826     final TemplateManager manager = TemplateManager.getInstance(getProject())
827     final Template template = manager.createTemplate("vn", "user", '$V1$ var = $V2$;')
828     template.addVariable("V1", "", "", true)
829     template.addVariable("V2", "", '"239"', true)
830
831     startTemplate(template)
832
833     myFixture.checkResult '<caret> var = 239;'
834
835     myFixture.type 'O'
836     myFixture.checkResult 'O<caret> var = 239;'
837
838     myFixture.type '\t'
839     myFixture.checkResult 'O var = <selection>239</selection>;'
840   }
841
842   void testTemplateExpandingWithSelection() {
843     final TemplateManager manager = TemplateManager.getInstance(getProject())
844     final Template template = manager.createTemplate("tpl", "user", 'expanded')
845     final JavaStringContextType contextType = contextType(JavaStringContextType.class)
846     ((TemplateImpl)template).getTemplateContext().setEnabled(contextType, true)
847
848     myFixture.configureByText("a.java", "class A { void f() { Stri<selection>ng s = \"tpl</selection><caret>\"; } }")
849
850     CodeInsightTestUtil.addTemplate(template, testRootDisposable)
851     myFixture.type '\t'
852     myFixture.checkResult 'class A { void f() { Stri   "; } }'
853   }
854
855   void "test expand current live template on no suggestions in lookup"() {
856     myFixture.configureByText "a.java", "class Foo {{ <caret> }}"
857     myFixture.completeBasic()
858     assert myFixture.lookup
859     myFixture.type("sout")
860     assert myFixture.lookup
861     assert myFixture.lookupElementStrings == []
862     myFixture.type('\t')
863     myFixture.checkResult "class Foo {{\n    System.out.println(<caret>);\n}}"
864   }
865
866   void "_test multi-dimensional toar"() {
867     myFixture.configureByText "a.java", '''
868 class Foo {{
869   java.util.List<String[]> list;
870   String[][] s = toar<caret>
871 }}'''
872     myFixture.type('\t')
873     //state.gotoEnd()
874     myFixture.checkResult '''
875 class Foo {{
876   java.util.List<String[]> list;
877   String[][] s = list.toArray(new String[list.size()][])<caret>
878 }}'''
879   }
880
881   void "test inner class name"() {
882     myFixture.configureByText "a.java", '''
883 class Outer {
884     class Inner {
885         void foo() {
886             soutm<caret>
887         }
888     }
889 }'''
890     myFixture.type('\t')
891     assert myFixture.editor.document.text.contains("\"Inner.foo")
892   }
893
894   void "test do not strip type argument containing class"() {
895     myFixture.configureByText 'a.java', '''
896 import java.util.*;
897 class Foo {
898   List<Map.Entry<String, Integer>> foo() {
899     <caret>
900   }
901 }
902 '''
903
904     final TemplateManager manager = TemplateManager.getInstance(getProject())
905     final Template template = manager.createTemplate("result", "user", '$T$ result;')
906     template.addVariable('T', new MacroCallNode(new MethodReturnTypeMacro()), new EmptyNode(), false)
907     template.toReformat = true
908
909     startTemplate(template)
910     assert myFixture.editor.document.text.contains('List<Map.Entry<String, Integer>> result;')
911   }
912
913   void "test name shadowing"() {
914     myFixture.configureByText "a.java", """class LiveTemplateVarSuggestion {
915     private Object value;
916     public void setValue(Object value, Object value1){
917       inn<caret>
918     }
919 }"""
920     myFixture.type('\t')
921     assert myFixture.lookupElementStrings == ['value', 'value1']
922   }
923
924   void "test invoke surround template by tab"() {
925     myFixture.configureByText "a.txt", "B<caret>"
926     myFixture.type('\t')
927     myFixture.checkResult("{<caret>}")
928   }
929
930   void "test escape string characters in soutv"() {
931     myFixture.configureByText "a.java", """
932 class Foo {
933   {
934     soutv<caret>
935   }
936 }
937 """
938     myFixture.type('\t"a"')
939     myFixture.checkResult """
940 class Foo {
941   {
942       System.out.println("\\"a\\" = " + "a"<caret>);
943   }
944 }
945 """
946   }
947
948   void "test stop at SELECTION when invoked surround template by tab"() {
949     myFixture.configureByText "a.txt", "<caret>"
950
951     final TemplateManager manager = TemplateManager.getInstance(getProject())
952     final Template template = manager.createTemplate("xxx", "user", 'foo $ARG$ bar $END$ goo $SELECTION$ after')
953     template.addVariable("ARG", "", "", true)
954
955     startTemplate(template)
956     myFixture.type('arg')
957     state.nextTab()
958     assert !state
959     checkResultByText 'foo arg bar  goo <caret> after'
960   }
961
962   void "test reuse static import"() {
963     myFixture.addClass("""package foo;
964 public class Bar {
965   public static void someMethod() {}
966   public static void someMethod(int a) {}
967 }""")
968     myFixture.configureByText "a.java", """
969 import static foo.Bar.someMethod;
970
971 class Foo {
972   {
973     <caret>
974   }
975 }
976 """
977     final TemplateManager manager = TemplateManager.getInstance(getProject())
978     final Template template = manager.createTemplate("xxx", "user", 'foo.Bar.someMethod($END$)')
979     template.setValue(USE_STATIC_IMPORT_IF_POSSIBLE, true)
980
981     startTemplate(template)
982     myFixture.checkResult """
983 import static foo.Bar.someMethod;
984
985 class Foo {
986   {
987     someMethod(<caret>)
988   }
989 }
990 """
991   }
992
993   void "test concat macro"() {
994     final TemplateManager manager = TemplateManager.getInstance(getProject())
995     final Template template = manager.createTemplate("result", "user", '$A$ $B$ c')
996     template.addVariable('A', new EmptyNode(), true)
997     
998     def macroCallNode = new MacroCallNode(new ConcatMacro())
999     macroCallNode.addParameter(new VariableNode('A', null))
1000     macroCallNode.addParameter(new TextExpression("ID"))
1001     template.addVariable('B', macroCallNode, false)
1002
1003     myFixture.configureByText "a.txt", "<caret>"
1004     startTemplate(template)
1005     myFixture.type('tableName')
1006     state.nextTab()
1007     assert !state
1008     myFixture.checkResult('tableName tableNameID c')
1009   }
1010
1011   void "test snakeCase should convert hyphens to underscores"() {
1012     final TemplateManager manager = TemplateManager.getInstance(getProject())
1013     final Template template = manager.createTemplate("result", "user", '$A$ $B$ c')
1014     template.addVariable('A', new EmptyNode(), true)
1015
1016     def macroCallNode = new MacroCallNode(new SplitWordsMacro.SnakeCaseMacro())
1017     macroCallNode.addParameter(new VariableNode('A', null))
1018     template.addVariable('B', macroCallNode, false)
1019
1020     myFixture.configureByText "a.txt", "<caret>"
1021     startTemplate(template)
1022     myFixture.type('-foo-bar_goo-')
1023     state.nextTab()
1024     assert !state
1025     myFixture.checkResult('-foo-bar_goo- _foo_bar_goo_ c<caret>')
1026   }
1027
1028   void "test use single member static import first"() {
1029     myFixture.addClass("""package foo;
1030 public class Bar {
1031   public static void someMethod() {}
1032   public static void someMethod(int a) {}
1033 }""")
1034     myFixture.configureByText "a.java", """
1035
1036 class Foo {
1037   {
1038     <caret>
1039   }
1040 }
1041 """
1042     final TemplateManager manager = TemplateManager.getInstance(getProject())
1043     final Template template = manager.createTemplate("xxx", "user", 'foo.Bar.someMethod($END$)')
1044     template.setValue(USE_STATIC_IMPORT_IF_POSSIBLE, true)
1045
1046     startTemplate(template)
1047     myFixture.checkResult """import static foo.Bar.someMethod;
1048
1049 class Foo {
1050   {
1051     someMethod(<caret>)
1052   }
1053 }
1054 """
1055   }
1056
1057   void "test two static imports"() {
1058     myFixture.configureByText "a.java", """
1059
1060 class Foo {
1061   {
1062     <caret>
1063   }
1064 }
1065 """
1066     final TemplateManager manager = TemplateManager.getInstance(getProject())
1067     final Template template = manager.createTemplate("xxx", "user", 'java.lang.Math.abs(java.lang.Math.PI);')
1068     template.setValue(USE_STATIC_IMPORT_IF_POSSIBLE, true)
1069
1070     startTemplate(template)
1071     myFixture.checkResult """\
1072 import static java.lang.Math.PI;
1073 import static java.lang.Math.abs;
1074
1075 class Foo {
1076   {
1077     abs(PI);<caret>
1078   }
1079 }
1080 """
1081   }
1082
1083   void "test do not replace macro value with null result"() {
1084     myFixture.configureByText "a.java", """\
1085 class Foo {
1086   {
1087     <caret>
1088   }
1089 }
1090 """
1091     final TemplateManager manager = TemplateManager.getInstance(getProject())
1092     final Template template = manager.createTemplate("xxx", "user", '$VAR1$ $VAR2$ $VAR1$')
1093     template.addVariable("VAR1", "", "", true)
1094     template.addVariable("VAR2", new MacroCallNode(new FileNameMacro()), new ConstantNode("default"), true)
1095     ((TemplateImpl)template).templateContext.setEnabled(contextType(JavaCodeContextType.class), true)
1096     CodeInsightTestUtil.addTemplate(template, testRootDisposable)
1097
1098     startTemplate(template)
1099     myFixture.checkResult """\
1100 class Foo {
1101   {
1102     <caret> a.java """ + """
1103   }
1104 }
1105 """
1106     myFixture.type 'test'
1107
1108     myFixture.checkResult """\
1109 class Foo {
1110   {
1111     test<caret> a.java test
1112   }
1113 }
1114 """
1115   }
1116
1117   void "test do replace macro value with empty result"() {
1118     myFixture.configureByText "a.java", """\
1119 class Foo {
1120   {
1121     <caret>
1122   }
1123 }
1124 """
1125     final TemplateManager manager = TemplateManager.getInstance(getProject())
1126     final Template template = manager.createTemplate("xxx", "user", '$VAR1$ $VAR2$')
1127     template.addVariable("VAR1", "", "", true)
1128     template.addVariable("VAR2", new MacroCallNode(new MyMirrorMacro("VAR1")), null, true)
1129     ((TemplateImpl)template).templateContext.setEnabled(contextType(JavaCodeContextType.class), true)
1130     CodeInsightTestUtil.addTemplate(template, testRootDisposable)
1131
1132     startTemplate(template)
1133     myFixture.checkResult """\
1134 class Foo {
1135   {
1136     <caret> """ + """
1137   }
1138 }
1139 """
1140     myFixture.type '42'
1141     myFixture.checkResult """\
1142 class Foo {
1143   {
1144     42<caret> 42
1145   }
1146 }
1147 """
1148
1149     myFixture.type '\b\b'
1150     myFixture.checkResult """\
1151 class Foo {
1152   {
1153     <caret> """ + """
1154   }
1155 }
1156 """
1157   }
1158
1159   private static class MyMirrorMacro extends Macro {
1160     private final String myVariableName
1161
1162     MyMirrorMacro(String variableName) {
1163       this.myVariableName = variableName
1164     }
1165
1166     @Override
1167     String getName() {
1168       return "mirror"
1169     }
1170
1171     @Override
1172     String getPresentableName() {
1173       return getName()
1174     }
1175
1176     @Override
1177     Result calculateResult(@NotNull Expression[] params, ExpressionContext context) {
1178       def state = TemplateManagerImpl.getTemplateState(context.editor)
1179       return state != null ? state.getVariableValue(myVariableName) : null
1180     }
1181
1182     @Override
1183     Result calculateQuickResult(@NotNull Expression[] params, ExpressionContext context) {
1184       return calculateResult(params, context)
1185     }
1186   }
1187
1188   void "test escape shouldn't move caret to the end marker"() {
1189     myFixture.configureByText 'a.java', """
1190 class Foo {{
1191   itar<caret>
1192 }}
1193 """
1194     myFixture.type '\ta'
1195     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1196     myFixture.checkResult """
1197 class Foo {{
1198     for (int a<caret> = 0; a < array.length; a++) {
1199          = array[a];
1200         
1201     }
1202 }}
1203 """
1204   }
1205
1206   void "test add new line on enter outside editing variable"() {
1207     myFixture.configureByText 'a.java', """
1208 class Foo {{
1209   <caret>
1210 }}
1211 """
1212     myFixture.type 'soutv\tabc'
1213     myFixture.editor.caretModel.moveCaretRelatively(3, 0, false, false, false)
1214     myFixture.type '\n'
1215     myFixture.checkResult """
1216 class Foo {{
1217     System.out.println("abc = " + abc);
1218     <caret>
1219 }}
1220 """
1221   }
1222
1223   void "test type tab character on tab outside editing variable"() {
1224     myFixture.configureByText 'a.java', """
1225 class Foo {{
1226   <caret>
1227 }}
1228 """
1229     myFixture.type 'soutv\tabc'
1230     myFixture.editor.caretModel.moveCaretRelatively(2, 0, false, false, false)
1231     myFixture.type '\t'
1232     myFixture.checkResult """
1233 class Foo {{
1234     System.out.println("abc = " + abc); <caret>
1235 }}
1236 """
1237   }
1238
1239   void "test delete at the last template position"() {
1240     myFixture.configureByText 'a.java', """
1241 class Foo {{
1242   <caret>
1243 }}
1244 """
1245     myFixture.type 'iter\t'
1246     LightPlatformCodeInsightTestCase.delete(myFixture.editor, myFixture.project)
1247     myFixture.checkResult """
1248 class Foo {{
1249     for (Object o : <caret> {
1250         
1251     }
1252 }}
1253 """
1254   }
1255
1256
1257
1258   void "test multicaret expanding with space"() {
1259     myFixture.configureByText "a.java", """\
1260 class Foo {
1261   {
1262     <caret>
1263     <caret>
1264     <caret>
1265   }
1266 }
1267 """
1268     def defaultShortcutChar = TemplateSettings.instance.defaultShortcutChar
1269     try {
1270       TemplateSettings.instance.defaultShortcutChar = TemplateSettings.SPACE_CHAR
1271       startTemplate("sout", TemplateSettings.SPACE_CHAR)
1272     }
1273     finally {
1274       TemplateSettings.instance.defaultShortcutChar = defaultShortcutChar
1275     }
1276     myFixture.checkResult("""\
1277 class Foo {
1278   {
1279       System.out.println();
1280       System.out.println();
1281       System.out.println();
1282   }
1283 }
1284 """)
1285   }
1286
1287   void "test multicaret expanding with enter"() {
1288     myFixture.configureByText "a.java", """\
1289 class Foo {
1290   {
1291     <caret>
1292     <caret>
1293     <caret>
1294   }
1295 }
1296 """
1297     def defaultShortcutChar = TemplateSettings.instance.defaultShortcutChar
1298     try {
1299       TemplateSettings.instance.defaultShortcutChar = TemplateSettings.ENTER_CHAR
1300       startTemplate("sout", TemplateSettings.ENTER_CHAR)
1301     }
1302     finally {
1303       TemplateSettings.instance.defaultShortcutChar = defaultShortcutChar
1304     }
1305     myFixture.checkResult("""\
1306 class Foo {
1307   {
1308       System.out.println();
1309       System.out.println();
1310       System.out.println();
1311   }
1312 }
1313 """)
1314   }
1315
1316   void "test multicaret expanding with tab"() {
1317     myFixture.configureByText "a.java", """\
1318 class Foo {
1319   {
1320     <caret>
1321     <caret>
1322     <caret>
1323   }
1324 }
1325 """
1326     def defaultShortcutChar = TemplateSettings.instance.defaultShortcutChar
1327     try {
1328       TemplateSettings.instance.defaultShortcutChar = TemplateSettings.TAB_CHAR
1329       startTemplate("sout", TemplateSettings.TAB_CHAR)
1330     }
1331     finally {
1332       TemplateSettings.instance.defaultShortcutChar = defaultShortcutChar
1333     }
1334
1335     myFixture.checkResult("""\
1336 class Foo {
1337   {
1338       System.out.println();
1339       System.out.println();
1340       System.out.println();
1341   }
1342 }
1343 """)
1344   }
1345
1346   void "test sout template in expression lambda"() {
1347     myFixture.configureByText 'a.java', '''class Foo {{
1348   strings.stream().forEach(o -> sout<caret>);
1349 }}
1350 '''
1351     myFixture.type('\t')
1352     myFixture.checkResult '''class Foo {{
1353   strings.stream().forEach(o -> System.out.println(<caret>));
1354 }}
1355 '''
1356   }
1357
1358   void "test finish template on moving caret by completion insert handler"() {
1359     TemplateManagerImpl templateManager = TemplateManager.getInstance(project) as TemplateManagerImpl
1360     myFixture.configureByText('a.html', '<selection><p></p></selection>')
1361     def template = TemplateSettings.instance.getTemplate("T2", "html/xml")
1362     myFixture.testAction(new InvokeTemplateAction(template, myFixture.editor, myFixture.project, ContainerUtil.newHashSet()))
1363     myFixture.complete(CompletionType.BASIC)
1364     myFixture.type("nofra")
1365     myFixture.finishLookup(Lookup.REPLACE_SELECT_CHAR)
1366     myFixture.checkResult("<noframes><caret><p></p></noframes>")
1367     assertNull(templateManager.getActiveTemplate(myFixture.editor))
1368   }
1369
1370   void "test escape with selection"() {
1371     myFixture.configureByText "a.java", """
1372 class Foo {
1373   {
1374       soutv<caret>
1375   }
1376 }
1377 """
1378     myFixture.type('\tfoo')
1379     myFixture.editor.selectionModel.setSelection(myFixture.caretOffset - 3, myFixture.caretOffset)
1380     assert myFixture.editor.selectionModel.hasSelection()
1381
1382     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1383     assert !myFixture.editor.selectionModel.hasSelection()
1384     assert TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1385
1386     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1387     assert !TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1388
1389     myFixture.checkResult """
1390 class Foo {
1391   {
1392       System.out.println("foo = " + foo<caret>);
1393   }
1394 }
1395 """
1396   }
1397
1398   void "test escape with lookup"() {
1399     myFixture.configureByText "a.java", """
1400 class Foo {
1401   {
1402       int foo_1, foo_2;
1403       soutv<caret>
1404   }
1405 }
1406 """
1407     myFixture.type('\t')
1408     assert myFixture.lookup
1409
1410     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1411     assert !myFixture.lookup
1412     assert TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1413
1414     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1415     assert !TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1416
1417     myFixture.checkResult """
1418 class Foo {
1419   {
1420       int foo_1, foo_2;
1421       System.out.println("foo_1 = " + foo_1);
1422   }
1423 }
1424 """
1425   }
1426
1427   void "test escape with lookup and selection"() {
1428     myFixture.configureByText "a.java", """
1429 class Foo {
1430   {
1431       int foo_1, foo_2;
1432       soutv<caret>
1433   }
1434 }
1435 """
1436     myFixture.type('\tfoo')
1437     myFixture.editor.selectionModel.setSelection(myFixture.caretOffset - 3, myFixture.caretOffset)
1438     myFixture.completeBasic()
1439     assert myFixture.editor.selectionModel.hasSelection()
1440     assert myFixture.lookup
1441
1442     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1443     assert !myFixture.editor.selectionModel.hasSelection()
1444     assert !myFixture.lookup
1445     assert TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1446
1447     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1448     assert !TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1449
1450     myFixture.checkResult """
1451 class Foo {
1452   {
1453       int foo_1, foo_2;
1454       System.out.println("foo = " + foo<caret>);
1455   }
1456 }
1457 """
1458   }
1459
1460   void "test escape with empty lookup"() {
1461     myFixture.configureByText "a.java", """
1462 class Foo {
1463   {
1464       int foo_1, foo_2;
1465       soutv<caret>
1466   }
1467 }
1468 """
1469     myFixture.type('\tfoobar')
1470     assert myFixture.lookup
1471     assert !myFixture.lookup.currentItem
1472
1473     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1474     assert !myFixture.lookup
1475     assert !TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1476
1477     myFixture.checkResult """
1478 class Foo {
1479   {
1480       int foo_1, foo_2;
1481       System.out.println("foobar = " + foobar);
1482   }
1483 }
1484 """
1485   }
1486
1487   void "test iterate over list with wildcard component type"() {
1488     myFixture.configureByText 'a.java', '''class C {{
1489 java.util.List<? extends Integer> list;
1490 <caret>
1491 }}'''
1492     myFixture.type('itli\t')
1493     myFixture.checkResult '''class C {{
1494 java.util.List<? extends Integer> list;
1495     for (int i = 0; i < list.size(); i++) {
1496         Integer integer =  list.get(i);
1497         
1498     }
1499 }}'''
1500   }
1501
1502   void "test home end go outside template fragments if already on their bounds"() {
1503     myFixture.configureByText 'a.txt', ' <caret> g'
1504
1505     TemplateManager manager = TemplateManager.getInstance(getProject())
1506     Template template = manager.createTemplate("empty", "user", '$VAR$')
1507     template.addVariable("VAR", "", '"foo"', true)
1508     manager.startTemplate(myFixture.editor, template)
1509
1510     myFixture.checkResult ' <selection>foo<caret></selection> g'
1511
1512     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_LINE_START)
1513     myFixture.checkResult ' <caret>foo g'
1514
1515     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_LINE_START)
1516     myFixture.checkResult '<caret> foo g'
1517
1518     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_RIGHT)
1519     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_LINE_END)
1520     myFixture.checkResult ' foo<caret> g'
1521
1522     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_LINE_END)
1523     myFixture.checkResult ' foo g<caret>'
1524   }
1525 }