IDEA-CR-15780 do not write default context values
[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 = copy.writeTemplateContext(null)
669     assert write.children.size() == 2 : JDOMUtil.writeElement(write)
670
671     copy.setEnabled(TemplateContextType.EP_NAME.findExtension(JavaCommentContextType), false)
672
673     write = copy.writeTemplateContext(null)
674     assert write.children.size() == 3 : JDOMUtil.writeElement(write)
675   }
676
677   void "test use default context when empty"() {
678     def context = new TemplateContext()
679     context.readTemplateContext(new Element("context"))
680
681     def defContext = new TemplateContext()
682     def commentContext = TemplateContextType.EP_NAME.findExtension(JavaCommentContextType)
683     defContext.setEnabled(commentContext, true)
684
685     context.setDefaultContext(defContext)
686     assert context.isEnabled(commentContext)
687     assert !context.isEnabled(TemplateContextType.EP_NAME.findExtension(JavaCodeContextType.Generic))
688   }
689
690   void "test adding new context to Other"() {
691     def defElement = JDOMUtil.loadDocument('''\
692 <context>
693   <option name="OTHER" value="true"/>
694 </context>''').rootElement
695     def context = new TemplateContext()
696     context.readTemplateContext(defElement)
697
698     def javaContext = TemplateContextType.EP_NAME.findExtension(JavaCodeContextType.Generic)
699     context.setEnabled(javaContext, true)
700
701     def saved = context.writeTemplateContext(null)
702
703     context = new TemplateContext()
704     context.readTemplateContext(saved)
705
706     assert context.isEnabled(javaContext)
707     assert context.isEnabled(TemplateContextType.EP_NAME.findExtension(EverywhereContextType))
708   }
709
710   private boolean isApplicable(String text, TemplateImpl inst) throws IOException {
711     configureFromFileText("a.java", text)
712     return TemplateManagerImpl.isApplicable(myFixture.getFile(), getEditor().getCaretModel().getOffset(), inst)
713   }
714
715   private static writeCommand(Runnable runnable) {
716     WriteCommandAction.runWriteCommandAction(null, runnable)
717   }
718
719   void testSearchByDescriptionWhenTemplatesListed() {
720     myFixture.configureByText("a.java", "class A {{ <caret> }}")
721
722     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
723     myFixture.type('array')
724     assert 'itar' in myFixture.lookupElementStrings
725   }
726
727   void testListTemplatesSearchesPrefixInDescription() {
728     myFixture.configureByText("a.java", "class A { main<caret> }")
729
730     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
731     assert myFixture.lookupElementStrings == ['psvm']
732   }
733
734   void testListTemplatesAction() {
735     myFixture.configureByText("a.java", "class A {{ <caret> }}")
736
737     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
738     assert myFixture.lookupElementStrings.containsAll(['iter', 'itco', 'toar'])
739
740     myFixture.type('it')
741     assert myFixture.lookupElementStrings[0].startsWith('it')
742     assert LookupManager.getInstance(project).activeLookup.currentItem == myFixture.getLookupElements()[0]
743
744     myFixture.type('e')
745     assert myFixture.lookupElementStrings[0].startsWith('ite')
746     assert LookupManager.getInstance(project).activeLookup.currentItem == myFixture.getLookupElements()[0]
747     LookupManager.getInstance(project).hideActiveLookup()
748
749     myFixture.type('\b\b')
750     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
751     assert myFixture.lookupElementStrings.containsAll(['iter', 'itco'])
752     LookupManager.getInstance(project).hideActiveLookup()
753
754     myFixture.type('xxxxx')
755     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
756     assert myFixture.lookupElementStrings.containsAll(['iter', 'itco', 'toar'])
757     LookupManager.getInstance(project).hideActiveLookup()
758   }
759
760   void testSelectionFromLookupBySpace() {
761     myFixture.configureByText("a.java", "class A {{ itc<caret> }}")
762
763     new ListTemplatesHandler().invoke(project, editor, myFixture.file)
764     myFixture.type ' '
765     myFixture.checkResult """\
766 import java.util.Iterator;
767
768 class A {{
769     for (Iterator <selection>iterator</selection> = collection.iterator(); iterator.hasNext(); ) {
770         Object next =  iterator.next();
771         \n\
772     }
773 }}"""
774   }
775
776   void testNavigationActionsDontTerminateTemplate() throws Throwable {
777     configureFromFileText("a.txt", "")
778
779     final TemplateManager manager = TemplateManager.getInstance(getProject())
780     final Template template = manager.createTemplate("vn", "user", 'Hello $V1$ World $V1$\nHello $V2$ World $V2$\nHello $V3$ World $V3$')
781     template.addVariable("V1", "", "", true)
782     template.addVariable("V2", "", "", true)
783     template.addVariable("V3", "", "", true)
784     final Editor editor = getEditor()
785
786     startTemplate(template)
787
788     final TemplateState state = getState()
789
790     for (int i = 0; i < 3; i++) {
791       assertFalse(String.valueOf(i), state.isFinished())
792       myFixture.type('H')
793       final String docText = editor.getDocument().getText()
794       assertTrue(docText, docText.startsWith("Hello H World H\n"))
795       final int offset = editor.getCaretModel().getOffset()
796
797       moveCaret(offset + 1)
798       moveCaret(offset)
799
800       myFixture.completeBasic()
801       myFixture.type(' ')
802
803       assertEquals(offset + 1, editor.getCaretModel().getOffset())
804       assertFalse(state.isFinished())
805
806       myFixture.type('\b')
807       assertFalse(state.isFinished())
808       writeCommand { state.nextTab() }
809     }
810     assertTrue(state.isFinished())
811     checkResultByFile(getTestName(false) + "-out.txt")
812   }
813
814   private void moveCaret(final int offset) {
815     runInEdtAndWait {
816       getEditor().getCaretModel().moveToOffset(offset)
817     }
818   }
819
820   void testUseDefaultValueForQuickResultCalculation() {
821     myFixture.configureByText 'a.txt', '<caret>'
822
823     final TemplateManager manager = TemplateManager.getInstance(getProject())
824     final Template template = manager.createTemplate("vn", "user", '$V1$ var = $V2$;')
825     template.addVariable("V1", "", "", true)
826     template.addVariable("V2", "", '"239"', true)
827
828     startTemplate(template)
829
830     myFixture.checkResult '<caret> var = 239;'
831
832     myFixture.type 'O'
833     myFixture.checkResult 'O<caret> var = 239;'
834
835     myFixture.type '\t'
836     myFixture.checkResult 'O var = <selection>239</selection>;'
837   }
838
839   void testTemplateExpandingWithSelection() {
840     final TemplateManager manager = TemplateManager.getInstance(getProject())
841     final Template template = manager.createTemplate("tpl", "user", 'expanded')
842     final JavaStringContextType contextType = contextType(JavaStringContextType.class)
843     ((TemplateImpl)template).getTemplateContext().setEnabled(contextType, true)
844
845     myFixture.configureByText("a.java", "class A { void f() { Stri<selection>ng s = \"tpl</selection><caret>\"; } }")
846
847     CodeInsightTestUtil.addTemplate(template, testRootDisposable)
848     myFixture.type '\t'
849     myFixture.checkResult 'class A { void f() { Stri   "; } }'
850   }
851
852   void "test expand current live template on no suggestions in lookup"() {
853     myFixture.configureByText "a.java", "class Foo {{ <caret> }}"
854     myFixture.completeBasic()
855     assert myFixture.lookup
856     myFixture.type("sout")
857     assert myFixture.lookup
858     assert myFixture.lookupElementStrings == []
859     myFixture.type('\t')
860     myFixture.checkResult "class Foo {{\n    System.out.println(<caret>);\n}}"
861   }
862
863   void "_test multi-dimensional toar"() {
864     myFixture.configureByText "a.java", '''
865 class Foo {{
866   java.util.List<String[]> list;
867   String[][] s = toar<caret>
868 }}'''
869     myFixture.type('\t')
870     //state.gotoEnd()
871     myFixture.checkResult '''
872 class Foo {{
873   java.util.List<String[]> list;
874   String[][] s = list.toArray(new String[list.size()][])<caret>
875 }}'''
876   }
877
878   void "test inner class name"() {
879     myFixture.configureByText "a.java", '''
880 class Outer {
881     class Inner {
882         void foo() {
883             soutm<caret>
884         }
885     }
886 }'''
887     myFixture.type('\t')
888     assert myFixture.editor.document.text.contains("\"Inner.foo")
889   }
890
891   void "test do not strip type argument containing class"() {
892     myFixture.configureByText 'a.java', '''
893 import java.util.*;
894 class Foo {
895   List<Map.Entry<String, Integer>> foo() {
896     <caret>
897   }
898 }
899 '''
900
901     final TemplateManager manager = TemplateManager.getInstance(getProject())
902     final Template template = manager.createTemplate("result", "user", '$T$ result;')
903     template.addVariable('T', new MacroCallNode(new MethodReturnTypeMacro()), new EmptyNode(), false)
904     template.toReformat = true
905
906     startTemplate(template)
907     assert myFixture.editor.document.text.contains('List<Map.Entry<String, Integer>> result;')
908   }
909
910   void "test name shadowing"() {
911     myFixture.configureByText "a.java", """class LiveTemplateVarSuggestion {
912     private Object value;
913     public void setValue(Object value, Object value1){
914       inn<caret>
915     }
916 }"""
917     myFixture.type('\t')
918     assert myFixture.lookupElementStrings == ['value', 'value1']
919   }
920
921   void "test invoke surround template by tab"() {
922     myFixture.configureByText "a.txt", "B<caret>"
923     myFixture.type('\t')
924     myFixture.checkResult("{<caret>}")
925   }
926
927   void "test escape string characters in soutv"() {
928     myFixture.configureByText "a.java", """
929 class Foo {
930   {
931     soutv<caret>
932   }
933 }
934 """
935     myFixture.type('\t"a"')
936     myFixture.checkResult """
937 class Foo {
938   {
939       System.out.println("\\"a\\" = " + "a"<caret>);
940   }
941 }
942 """
943   }
944
945   void "test stop at SELECTION when invoked surround template by tab"() {
946     myFixture.configureByText "a.txt", "<caret>"
947
948     final TemplateManager manager = TemplateManager.getInstance(getProject())
949     final Template template = manager.createTemplate("xxx", "user", 'foo $ARG$ bar $END$ goo $SELECTION$ after')
950     template.addVariable("ARG", "", "", true)
951
952     startTemplate(template)
953     myFixture.type('arg')
954     state.nextTab()
955     assert !state
956     checkResultByText 'foo arg bar  goo <caret> after'
957   }
958
959   void "test reuse static import"() {
960     myFixture.addClass("""package foo;
961 public class Bar {
962   public static void someMethod() {}
963   public static void someMethod(int a) {}
964 }""")
965     myFixture.configureByText "a.java", """
966 import static foo.Bar.someMethod;
967
968 class Foo {
969   {
970     <caret>
971   }
972 }
973 """
974     final TemplateManager manager = TemplateManager.getInstance(getProject())
975     final Template template = manager.createTemplate("xxx", "user", 'foo.Bar.someMethod($END$)')
976     template.setValue(USE_STATIC_IMPORT_IF_POSSIBLE, true)
977
978     startTemplate(template)
979     myFixture.checkResult """
980 import static foo.Bar.someMethod;
981
982 class Foo {
983   {
984     someMethod(<caret>)
985   }
986 }
987 """
988   }
989
990   void "test concat macro"() {
991     final TemplateManager manager = TemplateManager.getInstance(getProject())
992     final Template template = manager.createTemplate("result", "user", '$A$ $B$ c')
993     template.addVariable('A', new EmptyNode(), true)
994     
995     def macroCallNode = new MacroCallNode(new ConcatMacro())
996     macroCallNode.addParameter(new VariableNode('A', null))
997     macroCallNode.addParameter(new TextExpression("ID"))
998     template.addVariable('B', macroCallNode, false)
999
1000     myFixture.configureByText "a.txt", "<caret>"
1001     startTemplate(template)
1002     myFixture.type('tableName')
1003     state.nextTab()
1004     assert !state
1005     myFixture.checkResult('tableName tableNameID c')
1006   }
1007
1008   void "test snakeCase should convert hyphens to underscores"() {
1009     final TemplateManager manager = TemplateManager.getInstance(getProject())
1010     final Template template = manager.createTemplate("result", "user", '$A$ $B$ c')
1011     template.addVariable('A', new EmptyNode(), true)
1012
1013     def macroCallNode = new MacroCallNode(new SplitWordsMacro.SnakeCaseMacro())
1014     macroCallNode.addParameter(new VariableNode('A', null))
1015     template.addVariable('B', macroCallNode, false)
1016
1017     myFixture.configureByText "a.txt", "<caret>"
1018     startTemplate(template)
1019     myFixture.type('-foo-bar_goo-')
1020     state.nextTab()
1021     assert !state
1022     myFixture.checkResult('-foo-bar_goo- _foo_bar_goo_ c<caret>')
1023   }
1024
1025   void "test use single member static import first"() {
1026     myFixture.addClass("""package foo;
1027 public class Bar {
1028   public static void someMethod() {}
1029   public static void someMethod(int a) {}
1030 }""")
1031     myFixture.configureByText "a.java", """
1032
1033 class Foo {
1034   {
1035     <caret>
1036   }
1037 }
1038 """
1039     final TemplateManager manager = TemplateManager.getInstance(getProject())
1040     final Template template = manager.createTemplate("xxx", "user", 'foo.Bar.someMethod($END$)')
1041     template.setValue(USE_STATIC_IMPORT_IF_POSSIBLE, true)
1042
1043     startTemplate(template)
1044     myFixture.checkResult """import static foo.Bar.someMethod;
1045
1046 class Foo {
1047   {
1048     someMethod(<caret>)
1049   }
1050 }
1051 """
1052   }
1053
1054   void "test two static imports"() {
1055     myFixture.configureByText "a.java", """
1056
1057 class Foo {
1058   {
1059     <caret>
1060   }
1061 }
1062 """
1063     final TemplateManager manager = TemplateManager.getInstance(getProject())
1064     final Template template = manager.createTemplate("xxx", "user", 'java.lang.Math.abs(java.lang.Math.PI);')
1065     template.setValue(USE_STATIC_IMPORT_IF_POSSIBLE, true)
1066
1067     startTemplate(template)
1068     myFixture.checkResult """\
1069 import static java.lang.Math.PI;
1070 import static java.lang.Math.abs;
1071
1072 class Foo {
1073   {
1074     abs(PI);<caret>
1075   }
1076 }
1077 """
1078   }
1079
1080   void "test do not replace macro value with null result"() {
1081     myFixture.configureByText "a.java", """\
1082 class Foo {
1083   {
1084     <caret>
1085   }
1086 }
1087 """
1088     final TemplateManager manager = TemplateManager.getInstance(getProject())
1089     final Template template = manager.createTemplate("xxx", "user", '$VAR1$ $VAR2$ $VAR1$')
1090     template.addVariable("VAR1", "", "", true)
1091     template.addVariable("VAR2", new MacroCallNode(new FileNameMacro()), new ConstantNode("default"), true)
1092     ((TemplateImpl)template).templateContext.setEnabled(contextType(JavaCodeContextType.class), true)
1093     CodeInsightTestUtil.addTemplate(template, testRootDisposable)
1094
1095     startTemplate(template)
1096     myFixture.checkResult """\
1097 class Foo {
1098   {
1099     <caret> a.java """ + """
1100   }
1101 }
1102 """
1103     myFixture.type 'test'
1104
1105     myFixture.checkResult """\
1106 class Foo {
1107   {
1108     test<caret> a.java test
1109   }
1110 }
1111 """
1112   }
1113
1114   void "test do replace macro value with empty result"() {
1115     myFixture.configureByText "a.java", """\
1116 class Foo {
1117   {
1118     <caret>
1119   }
1120 }
1121 """
1122     final TemplateManager manager = TemplateManager.getInstance(getProject())
1123     final Template template = manager.createTemplate("xxx", "user", '$VAR1$ $VAR2$')
1124     template.addVariable("VAR1", "", "", true)
1125     template.addVariable("VAR2", new MacroCallNode(new MyMirrorMacro("VAR1")), null, true)
1126     ((TemplateImpl)template).templateContext.setEnabled(contextType(JavaCodeContextType.class), true)
1127     CodeInsightTestUtil.addTemplate(template, testRootDisposable)
1128
1129     startTemplate(template)
1130     myFixture.checkResult """\
1131 class Foo {
1132   {
1133     <caret> """ + """
1134   }
1135 }
1136 """
1137     myFixture.type '42'
1138     myFixture.checkResult """\
1139 class Foo {
1140   {
1141     42<caret> 42
1142   }
1143 }
1144 """
1145
1146     myFixture.type '\b\b'
1147     myFixture.checkResult """\
1148 class Foo {
1149   {
1150     <caret> """ + """
1151   }
1152 }
1153 """
1154   }
1155
1156   private static class MyMirrorMacro extends Macro {
1157     private final String myVariableName
1158
1159     MyMirrorMacro(String variableName) {
1160       this.myVariableName = variableName
1161     }
1162
1163     @Override
1164     String getName() {
1165       return "mirror"
1166     }
1167
1168     @Override
1169     String getPresentableName() {
1170       return getName()
1171     }
1172
1173     @Override
1174     Result calculateResult(@NotNull Expression[] params, ExpressionContext context) {
1175       def state = TemplateManagerImpl.getTemplateState(context.editor)
1176       return state != null ? state.getVariableValue(myVariableName) : null
1177     }
1178
1179     @Override
1180     Result calculateQuickResult(@NotNull Expression[] params, ExpressionContext context) {
1181       return calculateResult(params, context)
1182     }
1183   }
1184
1185   void "test escape shouldn't move caret to the end marker"() {
1186     myFixture.configureByText 'a.java', """
1187 class Foo {{
1188   itar<caret>
1189 }}
1190 """
1191     myFixture.type '\ta'
1192     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1193     myFixture.checkResult """
1194 class Foo {{
1195     for (int a<caret> = 0; a < array.length; a++) {
1196          = array[a];
1197         
1198     }
1199 }}
1200 """
1201   }
1202
1203   void "test add new line on enter outside editing variable"() {
1204     myFixture.configureByText 'a.java', """
1205 class Foo {{
1206   <caret>
1207 }}
1208 """
1209     myFixture.type 'soutv\tabc'
1210     myFixture.editor.caretModel.moveCaretRelatively(3, 0, false, false, false)
1211     myFixture.type '\n'
1212     myFixture.checkResult """
1213 class Foo {{
1214     System.out.println("abc = " + abc);
1215     <caret>
1216 }}
1217 """
1218   }
1219
1220   void "test type tab character on tab outside editing variable"() {
1221     myFixture.configureByText 'a.java', """
1222 class Foo {{
1223   <caret>
1224 }}
1225 """
1226     myFixture.type 'soutv\tabc'
1227     myFixture.editor.caretModel.moveCaretRelatively(2, 0, false, false, false)
1228     myFixture.type '\t'
1229     myFixture.checkResult """
1230 class Foo {{
1231     System.out.println("abc = " + abc); <caret>
1232 }}
1233 """
1234   }
1235
1236   void "test delete at the last template position"() {
1237     myFixture.configureByText 'a.java', """
1238 class Foo {{
1239   <caret>
1240 }}
1241 """
1242     myFixture.type 'iter\t'
1243     LightPlatformCodeInsightTestCase.delete(myFixture.editor, myFixture.project)
1244     myFixture.checkResult """
1245 class Foo {{
1246     for (Object o : <caret> {
1247         
1248     }
1249 }}
1250 """
1251   }
1252
1253
1254
1255   void "test multicaret expanding with space"() {
1256     myFixture.configureByText "a.java", """\
1257 class Foo {
1258   {
1259     <caret>
1260     <caret>
1261     <caret>
1262   }
1263 }
1264 """
1265     def defaultShortcutChar = TemplateSettings.instance.defaultShortcutChar
1266     try {
1267       TemplateSettings.instance.defaultShortcutChar = TemplateSettings.SPACE_CHAR
1268       startTemplate("sout", TemplateSettings.SPACE_CHAR)
1269     }
1270     finally {
1271       TemplateSettings.instance.defaultShortcutChar = defaultShortcutChar
1272     }
1273     myFixture.checkResult("""\
1274 class Foo {
1275   {
1276       System.out.println();
1277       System.out.println();
1278       System.out.println();
1279   }
1280 }
1281 """)
1282   }
1283
1284   void "test multicaret expanding with enter"() {
1285     myFixture.configureByText "a.java", """\
1286 class Foo {
1287   {
1288     <caret>
1289     <caret>
1290     <caret>
1291   }
1292 }
1293 """
1294     def defaultShortcutChar = TemplateSettings.instance.defaultShortcutChar
1295     try {
1296       TemplateSettings.instance.defaultShortcutChar = TemplateSettings.ENTER_CHAR
1297       startTemplate("sout", TemplateSettings.ENTER_CHAR)
1298     }
1299     finally {
1300       TemplateSettings.instance.defaultShortcutChar = defaultShortcutChar
1301     }
1302     myFixture.checkResult("""\
1303 class Foo {
1304   {
1305       System.out.println();
1306       System.out.println();
1307       System.out.println();
1308   }
1309 }
1310 """)
1311   }
1312
1313   void "test multicaret expanding with tab"() {
1314     myFixture.configureByText "a.java", """\
1315 class Foo {
1316   {
1317     <caret>
1318     <caret>
1319     <caret>
1320   }
1321 }
1322 """
1323     def defaultShortcutChar = TemplateSettings.instance.defaultShortcutChar
1324     try {
1325       TemplateSettings.instance.defaultShortcutChar = TemplateSettings.TAB_CHAR
1326       startTemplate("sout", TemplateSettings.TAB_CHAR)
1327     }
1328     finally {
1329       TemplateSettings.instance.defaultShortcutChar = defaultShortcutChar
1330     }
1331
1332     myFixture.checkResult("""\
1333 class Foo {
1334   {
1335       System.out.println();
1336       System.out.println();
1337       System.out.println();
1338   }
1339 }
1340 """)
1341   }
1342
1343   void "test sout template in expression lambda"() {
1344     myFixture.configureByText 'a.java', '''class Foo {{
1345   strings.stream().forEach(o -> sout<caret>);
1346 }}
1347 '''
1348     myFixture.type('\t')
1349     myFixture.checkResult '''class Foo {{
1350   strings.stream().forEach(o -> System.out.println(<caret>));
1351 }}
1352 '''
1353   }
1354
1355   void "test finish template on moving caret by completion insert handler"() {
1356     TemplateManagerImpl templateManager = TemplateManager.getInstance(project) as TemplateManagerImpl
1357     myFixture.configureByText('a.html', '<selection><p></p></selection>')
1358     def template = TemplateSettings.instance.getTemplate("T2", "html/xml")
1359     myFixture.testAction(new InvokeTemplateAction(template, myFixture.editor, myFixture.project, ContainerUtil.newHashSet()))
1360     myFixture.complete(CompletionType.BASIC)
1361     myFixture.type("nofra")
1362     myFixture.finishLookup(Lookup.REPLACE_SELECT_CHAR)
1363     myFixture.checkResult("<noframes><caret><p></p></noframes>")
1364     assertNull(templateManager.getActiveTemplate(myFixture.editor))
1365   }
1366
1367   void "test escape with selection"() {
1368     myFixture.configureByText "a.java", """
1369 class Foo {
1370   {
1371       soutv<caret>
1372   }
1373 }
1374 """
1375     myFixture.type('\tfoo')
1376     myFixture.editor.selectionModel.setSelection(myFixture.caretOffset - 3, myFixture.caretOffset)
1377     assert myFixture.editor.selectionModel.hasSelection()
1378
1379     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1380     assert !myFixture.editor.selectionModel.hasSelection()
1381     assert TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1382
1383     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1384     assert !TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1385
1386     myFixture.checkResult """
1387 class Foo {
1388   {
1389       System.out.println("foo = " + foo<caret>);
1390   }
1391 }
1392 """
1393   }
1394
1395   void "test escape with lookup"() {
1396     myFixture.configureByText "a.java", """
1397 class Foo {
1398   {
1399       int foo_1, foo_2;
1400       soutv<caret>
1401   }
1402 }
1403 """
1404     myFixture.type('\t')
1405     assert myFixture.lookup
1406
1407     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1408     assert !myFixture.lookup
1409     assert TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1410
1411     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1412     assert !TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1413
1414     myFixture.checkResult """
1415 class Foo {
1416   {
1417       int foo_1, foo_2;
1418       System.out.println("foo_1 = " + foo_1);
1419   }
1420 }
1421 """
1422   }
1423
1424   void "test escape with lookup and selection"() {
1425     myFixture.configureByText "a.java", """
1426 class Foo {
1427   {
1428       int foo_1, foo_2;
1429       soutv<caret>
1430   }
1431 }
1432 """
1433     myFixture.type('\tfoo')
1434     myFixture.editor.selectionModel.setSelection(myFixture.caretOffset - 3, myFixture.caretOffset)
1435     myFixture.completeBasic()
1436     assert myFixture.editor.selectionModel.hasSelection()
1437     assert myFixture.lookup
1438
1439     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1440     assert !myFixture.editor.selectionModel.hasSelection()
1441     assert !myFixture.lookup
1442     assert TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1443
1444     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1445     assert !TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1446
1447     myFixture.checkResult """
1448 class Foo {
1449   {
1450       int foo_1, foo_2;
1451       System.out.println("foo = " + foo<caret>);
1452   }
1453 }
1454 """
1455   }
1456
1457   void "test escape with empty lookup"() {
1458     myFixture.configureByText "a.java", """
1459 class Foo {
1460   {
1461       int foo_1, foo_2;
1462       soutv<caret>
1463   }
1464 }
1465 """
1466     myFixture.type('\tfoobar')
1467     assert myFixture.lookup
1468     assert !myFixture.lookup.currentItem
1469
1470     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ESCAPE)
1471     assert !myFixture.lookup
1472     assert !TemplateManager.getInstance(project).getActiveTemplate(myFixture.editor)
1473
1474     myFixture.checkResult """
1475 class Foo {
1476   {
1477       int foo_1, foo_2;
1478       System.out.println("foobar = " + foobar);
1479   }
1480 }
1481 """
1482   }
1483
1484   void "test iterate over list with wildcard component type"() {
1485     myFixture.configureByText 'a.java', '''class C {{
1486 java.util.List<? extends Integer> list;
1487 <caret>
1488 }}'''
1489     myFixture.type('itli\t')
1490     myFixture.checkResult '''class C {{
1491 java.util.List<? extends Integer> list;
1492     for (int i = 0; i < list.size(); i++) {
1493         Integer integer =  list.get(i);
1494         
1495     }
1496 }}'''
1497   }
1498
1499   void "test home end go outside template fragments if already on their bounds"() {
1500     myFixture.configureByText 'a.txt', ' <caret> g'
1501
1502     TemplateManager manager = TemplateManager.getInstance(getProject())
1503     Template template = manager.createTemplate("empty", "user", '$VAR$')
1504     template.addVariable("VAR", "", '"foo"', true)
1505     manager.startTemplate(myFixture.editor, template)
1506
1507     myFixture.checkResult ' <selection>foo<caret></selection> g'
1508
1509     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_LINE_START)
1510     myFixture.checkResult ' <caret>foo 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_CARET_RIGHT)
1516     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_LINE_END)
1517     myFixture.checkResult ' foo<caret> g'
1518
1519     myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_LINE_END)
1520     myFixture.checkResult ' foo g<caret>'
1521   }
1522 }