62f7f76454924e3c2a5b9dca79b05b51c05b1bc5
[idea/community.git] / python / testSrc / com / jetbrains / python / PyFormatterTest.java
1 /*
2  * Copyright 2000-2013 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.jetbrains.python;
17
18 import com.intellij.formatting.WrapType;
19 import com.intellij.openapi.command.WriteCommandAction;
20 import com.intellij.psi.PsiElement;
21 import com.intellij.psi.PsiFile;
22 import com.intellij.psi.codeStyle.CodeStyleManager;
23 import com.intellij.psi.util.PsiTreeUtil;
24 import com.jetbrains.python.fixtures.PyTestCase;
25 import com.jetbrains.python.formatter.PyCodeStyleSettings;
26 import com.jetbrains.python.psi.LanguageLevel;
27 import com.jetbrains.python.psi.PyElementGenerator;
28 import com.jetbrains.python.psi.PyStatement;
29 import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
30
31 /**
32  * @author yole
33  */
34 public class PyFormatterTest extends PyTestCase {
35   public void testBlankLineBetweenMethods() {
36     doTest();
37   }
38
39   public void testBlankLineAroundClasses() {
40     getCommonCodeStyleSettings().BLANK_LINES_AROUND_CLASS = 2;
41     doTest();
42   }
43
44   public void testSpaceAfterComma() {
45     doTest();
46   }
47
48   public void testPep8ExtraneousWhitespace() {
49     doTest();
50   }
51
52   public void testPep8Operators() {
53     doTest();
54   }
55
56   public void testPep8KeywordArguments() {
57     doTest();
58   }
59
60   public void testUnaryMinus() {
61     doTest();
62   }
63
64   public void testBlankLineAfterImports() {
65     doTest();
66   }
67
68   // PY-15701
69   public void testNoBlankLinesAfterLocalImports() {
70     doTest();
71   }
72
73   public void testBlankLineBeforeFunction() {
74     doTest();
75   }
76
77   public void testStarArgument() {  // PY-1395
78     doTest();
79   }
80
81   public void testDictLiteral() {  // PY-1461
82     doTest();
83   }
84
85   public void testListAssignment() {  // PY-1522
86     doTest();
87   }
88
89   public void testStarExpression() {  // PY-1523
90     doTestPy3();
91   }
92
93   private void doTestPy3() {
94     PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON30);
95     try {
96       doTest();
97     }
98     finally {
99       PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null);
100     }
101   }
102
103   public void testWrapTuple() {  // PY-1792
104     doTest();
105   }
106
107   public void testSpaceAfterCommaWrappedLine() {  // PY-1065
108     doTest();
109   }
110
111   public void testAlignInBinaryExpression() {
112     doTest();
113   }
114
115   public void testAlignInStringLiteral() {
116     doTest();
117   }
118
119   public void testComment() {  // PY-2108
120     doTest();
121   }
122
123   public void testCommentBetweenClasses() { // PY-1598
124     doTest();
125   }
126
127   public void testCommentInEmptyTuple() { //PY-11904
128     doTest();
129   }
130
131   public void testTwoLinesBetweenTopLevelClasses() { // PY-2765
132     doTest();
133   }
134
135   public void testTwoLinesBetweenTopLevelFunctions() { // PY-2765
136     doTest();
137   }
138
139   // PY-9923
140   public void testTwoLinesBetweenTopLevelDeclarationsWithComment() { // PY-9923
141     doTest();
142   }
143
144   // PY-9923
145   public void testTwoLinesBetweenTopLevelStatementAndDeclarationsWithComment() {
146     doTest();
147   }
148
149   public void testSpecialSlice() {  // PY-1928
150     doTest();
151   }
152
153   public void testNoWrapBeforeParen() {  // PY-3172
154     doTest();
155   }
156
157   public void testTupleAssignment() {  // PY-4034 comment
158     doTest();
159   }
160
161   public void testSpaceInMethodDeclaration() {  // PY-4241
162     getCommonCodeStyleSettings().SPACE_BEFORE_METHOD_PARENTHESES = true;
163     doTest();
164   }
165
166   public void testOptionalAlignForMethodParameters() {  // PY-3995
167     getCommonCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS = false;
168     doTest();
169   }
170
171   public void testNoAlignForMethodArguments() {  // PY-3995
172     getCommonCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = false;
173     doTest();
174   }
175
176   public void testAlignForMethodArguments() {  // PY-3995
177     doTest();
178   }
179
180   public void testLambdaColon() {
181     doTest();
182   }
183
184   public void testInGenerator() {  // PY-5379
185     doTest();
186   }
187
188   public void testIndentInGenerator() {  // PY-6219
189     doTest();
190   }
191
192   public void testSpaceAroundDot() {  // PY-6908
193     doTest();
194   }
195
196   public void testSetLiteralInArgList() {  // PY-6672
197     getCommonCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
198     doTest();
199   }
200
201   public void testLiterals() {  // PY-6751
202     doTest();
203   }
204
205   public void testTupleInArgList() {
206     getCommonCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
207     doTest();
208   }
209
210   public void testAlignInBinaryExpressions() {
211     doTest();
212   }
213
214   public void testFromImportRelative() {
215     doTest();
216   }
217
218   public void testContinuationIndent() {
219     doTest();
220   }
221
222   public void testContinuationIndentInIndentingStatement() { // PY-9573
223     doTest();
224   }
225
226   public void testContinuationIndentInIndentingStatement2() { // PY-11868
227     doTest();
228   }
229
230   public void testBlankLineAfterDecorator() {
231     doTest();
232   }
233
234   public void testSpaceAroundKeywords() {
235     doTest();
236   }
237
238   public void testSpaceAfterReturn() {
239     doTest();
240   }
241
242   public void testSpaceAfterRelativeImport() {  // PY-8112
243     doTest();
244   }
245
246   public void testSpaceWithinBraces() {  // PY-8069
247     getPythonCodeStyleSettings().SPACE_WITHIN_BRACES = true;
248     doTest();
249   }
250
251   public void testTupleClosingParen() {  // PY-7946
252     doTest();
253   }
254
255   public void testBeforeTopLevelClass() {  // PY-7743
256     doTest();
257   }
258
259   public void testPsiFormatting() { // IDEA-69724
260     String initial =
261       "def method_name(\n" +
262       "   desired_impulse_response,\n" +
263       " desired_response_parameters,\n" +
264       " inverse_filter_length, \n" +
265       " observed_impulse_response):\n" +
266       " # Extract from here to ...\n" +
267       "   desired_impulse_response = {'dirac, 'gaussian', logistic_derivative'}\n" +
268       "return desired,                o";
269
270     final PsiFile file = PyElementGenerator.getInstance(myFixture.getProject()).createDummyFile(LanguageLevel.PYTHON30, initial);
271     final PsiElement reformatted = CodeStyleManager.getInstance(myFixture.getProject()).reformat(file);
272
273     String expected =
274       "def method_name(\n" +
275       "        desired_impulse_response,\n" +
276       "        desired_response_parameters,\n" +
277       "        inverse_filter_length,\n" +
278       "        observed_impulse_response):\n" +
279       "    # Extract from here to ...\n" +
280       "    desired_impulse_response = {'dirac, '\n" +
281       "    gaussian\n" +
282       "    ', logistic_derivative'}\n" +
283       "    return desired, o";
284     assertEquals(expected, reformatted.getText());
285   }
286
287   public void testWrapDefinitionWithLongLine() { // IDEA-92081
288     getCodeStyleSettings().setRightMargin(PythonLanguage.getInstance(), 30);
289     getCommonCodeStyleSettings().WRAP_LONG_LINES = true;
290     doTest();
291   }
292
293   public void testWrapAssignment() {  // PY-8572
294     getCodeStyleSettings().setRightMargin(PythonLanguage.getInstance(), 120);
295     getCommonCodeStyleSettings().WRAP_LONG_LINES = false;
296     doTest();
297   }
298
299   public void testIndentInSlice() {  // PY-8572
300     getCodeStyleSettings().setRightMargin(PythonLanguage.getInstance(), 120);
301     getCommonCodeStyleSettings().WRAP_LONG_LINES = false;
302     doTest();
303   }
304
305   public void testIndentInComprehensions() {  // PY-8516
306     getPythonCodeStyleSettings().ALIGN_COLLECTIONS_AND_COMPREHENSIONS = false;
307     doTest();
308   }
309
310   public void testAlignInGenerators() {  // PY-8822
311     doTest();
312   }
313
314   public void testAlignInCallExpression() {
315     doTest();
316   }
317
318   public void _testAlignInNestedCallInWith() { //PY-11337 TODO:
319     doTest();
320   }
321
322   public void testContinuationIndentForCallInStatementPart() {  // PY-8577
323     doTest();
324   }
325
326   public void testIfConditionContinuation() {  // PY-8195
327     doTest();
328   }
329
330   public void _testIndentInNestedCall() {  // PY-11919 TODO: required changes in formatter to be able to make indent relative to block or alignment
331     doTest();
332   }
333
334   public void testIndentAfterBackslash() {
335     doTest();
336   }
337
338   public void testSpaceBeforeBackslash() {
339     getPythonCodeStyleSettings().SPACE_BEFORE_BACKSLASH = false;
340     doTest();
341   }
342
343   public void testNewLineAfterColon() {
344     getPythonCodeStyleSettings().NEW_LINE_AFTER_COLON = true;
345     doTest();
346   }
347
348   public void testNewLineAfterColonMultiClause() {
349     doTest();
350   }
351
352   public void testLongWith() {  // PY-8743
353     PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON27);
354     try {
355       doTest();
356     }
357     finally {
358       PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null);
359     }
360   }
361
362   // PY-8961, PY-16050
363   public void testSpaceInAnnotations() {
364     doTestPy3();
365   }
366
367   // PY-15791
368   public void testForceSpacesAroundEqualSignInAnnotatedParameter() {
369     doTestPy3();
370   }
371
372   public void testWrapInBinaryExpression() {  // PY-9032
373     getCodeStyleSettings().setRightMargin(PythonLanguage.getInstance(), 80);
374     doTest(true);
375   }
376
377   public void testSpaceWithinDeclarationParentheses() {  // PY-8818
378     getCommonCodeStyleSettings().SPACE_WITHIN_METHOD_PARENTHESES = true;
379     doTest();
380   }
381
382   public void testWrapBeforeElse() {  // PY-10319
383     doTest(true);
384   }
385
386   public void testSpacesInImportParentheses() {  // PY-11359
387     doTest();
388   }
389
390   public void testWrapImports() {  // PY-9163
391     getCodeStyleSettings().setRightMargin(PythonLanguage.getInstance(), 80);
392     doTest();
393   }
394
395   public void testCommentAfterBlock() {  // PY-9542
396     doTest();
397   }
398
399   public void testWrapOnDot() {  // PY-6359
400     doTest();
401   }
402
403   public void testIndentParensInImport() { // PY-9075
404     doTest();
405   }
406
407   public void testAlignInParenthesizedExpression() {
408     doTest();
409   }
410
411   public void testAlignInParameterList() {
412     doTest();
413   }
414
415   public void testAlignListComprehensionInDict() { //PY-10076
416     doTest();
417   }
418
419   public void testParenthesisAroundGeneratorExpression() {
420     doTest();
421   }
422
423   private void doTest() {
424     doTest(false);
425   }
426
427   private void doTest(final boolean reformatText) {
428     myFixture.configureByFile("formatter/" + getTestName(true) + ".py");
429     WriteCommandAction.runWriteCommandAction(null, new Runnable() {
430       @Override
431       public void run() {
432         CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myFixture.getProject());
433         PsiFile file = myFixture.getFile();
434         if (reformatText) {
435           codeStyleManager.reformatText(file, 0, file.getTextLength());
436         }
437         else {
438           codeStyleManager.reformat(file);
439         }
440       }
441     });
442     myFixture.checkResultByFile("formatter/" + getTestName(true) + "_after.py");
443   }
444
445   // PY-12861
446   public void testSpacesInsideParenthesisAreStripped() {
447     doTest();
448   }
449
450   // PY-14838
451   public void testNoAlignmentAfterDictHangingIndentInFunctionCall() {
452     getCommonCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
453     doTest();
454   }
455
456   // PY-13955
457   public void testNoAlignmentAfterDictHangingIndentInFunctionCallOnTyping() {
458     getCommonCodeStyleSettings().ALIGN_MULTILINE_PARAMETERS_IN_CALLS = true;
459     final String testName = "formatter/" + getTestName(true);
460     myFixture.configureByFile(testName + ".py");
461     WriteCommandAction.runWriteCommandAction(null, new Runnable() {
462       @Override
463       public void run() {
464         myFixture.type("\n(");
465       }
466     });
467     myFixture.checkResultByFile(testName + "_after.py");
468   }
469
470   // PY-12145
471   public void testAlignmentOfClosingBraceInDictLiteralWhenNoHangingIndent() {
472     doTest();
473   }
474
475   // PY-13004
476   public void testAlignmentOfClosingParenthesisOfArgumentListWhenNoHangingIndent() {
477     doTest();
478   }
479
480   // PY-14408
481   public void testIndentsWithTabsInsideDictLiteral() {
482     getIndentOptions().USE_TAB_CHARACTER = true;
483     doTest();
484   }
485
486   // PY-12749
487   public void testContinuationIndentIsNotUsedForNestedFunctionCallsInWithStatement() {
488     doTest();
489   }
490
491   public void testAlignmentOfClosingParenthesisInNestedFunctionCallsWithSingleArgument() {
492     doTest();
493   }
494
495   // PY-12748
496   public void testIndentCommentariesInsideFromImportStatement() {
497     doTest();
498   }
499
500   public void testClosingParenthesisInFromImportStatementWithNoHangingIndent() {
501     doTest();
502   }
503
504   // PY-12932
505   public void testCommentedCodeFragmentIgnored() {
506     doTest();
507   }
508
509   // PY-12932
510   public void testTrailingComment() {
511     doTest();
512   }
513
514   // PY-12938
515   public void testDoubleHashCommentIgnored() {
516     doTest();
517   }
518
519   // PY-12938
520   public void testDocCommentIgnored() {
521     doTest();
522   }
523
524   // PY-12775
525   public void testShebangCommentIgnored() {
526     doTest();
527   }
528
529   // PY-13232
530   public void testWhitespaceInsertedAfterHashSignInMultilineComment() {
531     doTest();
532   }
533
534   /**
535    * This test merely checks that call to {@link com.intellij.psi.codeStyle.CodeStyleManager#reformat(com.intellij.psi.PsiElement)}
536    * is possible for Python sources.
537    */
538   public void testReformatOfSingleElementPossible() {
539     myFixture.configureByFile("formatter/" + getTestName(true) + ".py");
540     WriteCommandAction.runWriteCommandAction(myFixture.getProject(), new Runnable() {
541       @Override
542       public void run() {
543         final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getCaretOffset());
544         assertNotNull(elementAtCaret);
545         final PyStatement statement = PsiTreeUtil.getParentOfType(elementAtCaret, PyStatement.class, false);
546         assertNotNull(statement);
547         final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(myFixture.getProject());
548         codeStyleManager.reformat(statement);
549       }
550     });
551     myFixture.checkResultByFile("formatter/" + getTestName(true) + "_after.py");
552   }
553
554   // PY-11552
555   public void testExtraBlankLinesBetweenMethodsAndAtTheEnd() {
556     getCommonCodeStyleSettings().KEEP_BLANK_LINES_IN_DECLARATIONS = 1;
557     doTest();
558   }
559
560   // PY-11552
561   public void testTrailingBlankLinesWithBackslashesAtFileEnd() {
562     doTest();
563   }
564
565   // PY-11552
566   public void testTrailingBlankLinesWithBackslashesAtFunctionEnd() {
567     doTest();
568   }
569
570   // PY-11552
571   public void testTrailingBlankLinesWithBackslashesAtFunctionEndNoNewLine() {
572     doTest();
573   }
574
575   // PY-11552
576   public void testTrailingBlankLinesWithBackslashesMixed() {
577     doTest();
578   }
579
580   // PY-11552
581   public void testTrailingBlankLinesInEmptyFile() {
582     doTest();
583   }
584
585   // PY-14962
586   public void testAlignDictLiteralOnValue() {
587     getPythonCodeStyleSettings().DICT_ALIGNMENT = PyCodeStyleSettings.DICT_ALIGNMENT_ON_VALUE;
588     doTest();
589   }
590
591   // PY-14962
592   public void testAlignDictLiteralOnColon() {
593     getPythonCodeStyleSettings().DICT_ALIGNMENT = PyCodeStyleSettings.DICT_ALIGNMENT_ON_COLON;
594     doTest();
595   }
596
597   // PY-14962
598   public void testDictWrappingChopDownIfLong() {
599     getCodeStyleSettings().setRightMargin(PythonLanguage.getInstance(), 80);
600     getPythonCodeStyleSettings().DICT_WRAPPING = WrapType.CHOP_DOWN_IF_LONG.getLegacyRepresentation();
601     doTest();
602   }
603
604   // PY-14962
605   public void testForceNewLineAfterLeftBraceInDict() {
606     getPythonCodeStyleSettings().DICT_NEW_LINE_AFTER_LEFT_BRACE = true;
607     doTest();
608   }
609
610   // PY-14962
611   public void testForceNewLineBeforeRightBraceInDict() {
612     getPythonCodeStyleSettings().DICT_NEW_LINE_BEFORE_RIGHT_BRACE = true;
613     doTest();
614   }
615
616   // PY-16393
617   public void testHangingIndentDetectionIgnoresComments() {
618     doTest();
619   }
620   
621   // PY-15530
622   public void testAlignmentInArgumentListWhereFirstArgumentIsEmptyCall() {
623     doTest();
624   }
625
626   public void testAlignmentInListLiteralWhereFirstItemIsEmptyTuple() {
627     doTest();
628   }
629
630   public void testHangingIndentInNamedArgumentValue() {
631     doTest();
632   }
633
634   public void testHangingIndentInParameterDefaultValue() {
635     doTest();
636   }
637
638   // PY-15171
639   public void testHangingIndentInKeyValuePair() {
640     doTest();
641   }
642
643   public void testDoNotDestroyAlignment_OnPostponedFormatting() throws Exception {
644     getPythonCodeStyleSettings().DICT_ALIGNMENT = PyCodeStyleSettings.DICT_ALIGNMENT_ON_COLON;
645     doTest();
646   }
647
648   public void testAlignmentOfEmptyCollectionLiterals() {
649     doTest();
650   }
651 }