blob: e49b0eaee6c8c90d2351ef57eba820884e254713 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.testFramework.TestDataFile;
import com.intellij.testFramework.TestDataPath;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
import com.jetbrains.python.documentation.DocStringFormat;
import com.jetbrains.python.documentation.PyDocumentationSettings;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.inspections.*;
import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection;
import com.jetbrains.python.psi.LanguageLevel;
import org.jetbrains.annotations.NonNls;
/**
* @author dcheryasov
*/
@TestDataPath("$CONTENT_ROOT/../testData/inspections/")
public class PyQuickFixTest extends PyTestCase {
public void testAddImport() {
doInspectionTest(new String[] { "AddImport.py", "ImportTarget.py" }, PyUnresolvedReferencesInspection.class, "Import 'ImportTarget'", true, true);
}
public void testAddImportDoc() {
doInspectionTest(new String[] { "AddImportDoc.py", "ImportTarget.py" }, PyUnresolvedReferencesInspection.class, "Import 'ImportTarget'", true, true);
}
public void testAddImportDocComment() { // PY-728
doInspectionTest(new String[] { "AddImportDocComment.py", "ImportTarget.py" }, PyUnresolvedReferencesInspection.class, "Import 'ImportTarget'", true, true);
}
public void testImportFromModule() {
doInspectionTest(new String[] { "importFromModule/foo/bar.py", "importFromModule/foo/baz.py", "importFromModule/foo/__init__.py" },
PyUnresolvedReferencesInspection.class, "Import 'importFromModule.foo.baz'", true, true);
}
public void testImportFromModuleStar() { // PY-6302
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
myFixture.copyDirectoryToProject("importFromModuleStar", "");
myFixture.configureFromTempProjectFile("source.py");
myFixture.checkHighlighting(true, false, false);
final IntentionAction intentionAction = myFixture.findSingleIntention("Import 'target.xyzzy()'");
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile("importFromModuleStar/source_after.py");
}
public void testQualifyByImport() {
final PyCodeInsightSettings settings = PyCodeInsightSettings.getInstance();
boolean oldPreferFrom = settings.PREFER_FROM_IMPORT;
boolean oldHighlightUnused = settings.HIGHLIGHT_UNUSED_IMPORTS;
settings.PREFER_FROM_IMPORT = false;
settings.HIGHLIGHT_UNUSED_IMPORTS = false;
try {
doInspectionTest(new String[]{"QualifyByImport.py", "QualifyByImportFoo.py"}, PyUnresolvedReferencesInspection.class, PyBundle.message("ACT.qualify.with.module"), true, true);
}
finally {
settings.PREFER_FROM_IMPORT = oldPreferFrom;
settings.HIGHLIGHT_UNUSED_IMPORTS = oldHighlightUnused;
}
}
public void testAddToImportFromList() {
final PyCodeInsightSettings settings = PyCodeInsightSettings.getInstance();
boolean oldHighlightUnused = settings.HIGHLIGHT_UNUSED_IMPORTS;
settings.HIGHLIGHT_UNUSED_IMPORTS = false;
try {
doInspectionTest(new String[]{"AddToImportFromList.py", "AddToImportFromFoo.py"}, PyUnresolvedReferencesInspection.class, "Import 'foo(a) from AddToImportFromFoo'", true, true);
}
finally {
settings.HIGHLIGHT_UNUSED_IMPORTS = oldHighlightUnused;
}
}
// TODO: add a test for multiple variants of above
// TODO: add tests for stub indexes-based autoimport of unimported somehow.
public void testAddSelf() {
doInspectionTest("AddSelf.py", PyMethodParametersInspection.class, PyBundle.message("QFIX.add.parameter.self", "self"), true, true);
}
public void testReplacePrint() {
doInspectionTest("ReplacePrint.py", PyCompatibilityInspection.class, PyBundle.message("QFIX.statement.effect"), true, true);
}
public void testAddSelfFunction() { //PY-4556
doInspectionTest("AddSelfFunction.py",
PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference", "get_a", "self"), true, true);
}
public void testAddSelfToClassmethod() { //PY-9721
doInspectionTest("AddSelfToClassmethod.py",
PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference", "foo", "cls"), true, true);
}
public void testAddCls() {
doInspectionTest("AddCls.py", PyMethodParametersInspection.class, PyBundle.message("QFIX.add.parameter.self", "cls"), true, true);
}
public void testRenameToSelf() {
doInspectionTest("RenameToSelf.py", PyMethodParametersInspection.class, PyBundle.message("QFIX.rename.parameter.to.$0", "self"), true,
true);
}
public void testRemoveTrailingSemicolon() {
doInspectionTest("RemoveTrailingSemicolon.py", PyTrailingSemicolonInspection.class, PyBundle.message("QFIX.remove.trailing.semicolon"),
true, true);
}
public void testDictCreation() {
doInspectionTest("DictCreation.py", PyDictCreationInspection.class, PyBundle.message("QFIX.dict.creation"), true, true);
}
public void testDictCreationTuple() { //PY-6283
doInspectionTest("DictCreationTuple.py", PyDictCreationInspection.class, PyBundle.message("QFIX.dict.creation"), true, true);
}
public void testDictCreationDuplicate() { //PY-7318
doInspectionTest("DictCreationDuplicate.py", PyDictCreationInspection.class, PyBundle.message("QFIX.dict.creation"), true, true);
}
public void testTransformClassicClass() {
doInspectionTest("TransformClassicClass.py", PyClassicStyleClassInspection.class,
PyBundle.message("QFIX.classic.class.transform"), true, true);
}
public void testAddGlobalQuickFix() {
doInspectionTest("AddGlobalStatement.py", PyUnboundLocalVariableInspection.class,
PyBundle.message("QFIX.add.global"), true, true);
}
public void testAddGlobalExistingQuickFix() {
doInspectionTest("AddGlobalExistingStatement.py", PyUnboundLocalVariableInspection.class,
PyBundle.message("QFIX.add.global"), true, true);
}
public void testSimplifyBooleanCheckQuickFix() {
doInspectionTest("SimplifyBooleanCheck.py", PySimplifyBooleanCheckInspection.class,
PyBundle.message("QFIX.simplify.$0", "b"), true, true);
}
public void testFromFutureImportQuickFix() {
doInspectionTest("MoveFromFutureImport.py", PyFromFutureImportInspection.class,
PyBundle.message("QFIX.move.from.future.import"), true, true);
}
public void testFromFutureImportQuickFixDocString() { // PY-10080
doInspectionTest("MoveFromFutureImportDocString.py", PyFromFutureImportInspection.class,
PyBundle.message("QFIX.move.from.future.import"), true, true);
}
public void testComparisonWithNoneQuickFix() {
doInspectionTest("ComparisonWithNone.py", PyComparisonWithNoneInspection.class,
PyBundle.message("QFIX.replace.equality"), true, true);
}
public void testAddClassFix() {
doInspectionTest("AddClass.py", PyUnresolvedReferencesInspection.class, "Create class 'Xyzzy'", true, true);
}
public void testAddFunctionToModule() { // PY-1602
doInspectionTest(
"AddFunctionToModule.py",
PyUnresolvedReferencesInspection.class,
PyBundle.message("QFIX.NAME.add.function.$0.to.module.$1", "frob", "AddFunctionToModule.py"),
true, true
);
}
public void testRedundantParentheses() { // PY-1470
String[] testFiles = new String[]{"RedundantParentheses.py"};
myFixture.enableInspections(PyRedundantParenthesesInspection.class);
myFixture.configureByFiles(testFiles);
myFixture.checkHighlighting(true, false, true);
final IntentionAction intentionAction = myFixture.findSingleIntention(PyBundle.message("QFIX.redundant.parentheses"));
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after"));
}
public void testRedundantParenthesesBoolean() { // PY-3095
doInspectionTest("RedundantParenthesesBoolean.py", PyRedundantParenthesesInspection.class,
PyBundle.message("QFIX.redundant.parentheses"), true, true);
}
public void testRedundantParenthesesMore() { // PY-3239
doInspectionTest("RedundantParenthesesMore.py", PyRedundantParenthesesInspection.class,
PyBundle.message("QFIX.redundant.parentheses"), true, true);
}
public void testRedundantParenthesesParenthesizedExpression() { // PY-12679
doInspectionTest("RedundantParenthesesParenthesizedExpression.py", PyRedundantParenthesesInspection.class,
PyBundle.message("QFIX.redundant.parentheses"), true, true);
}
public void testChainedComparisons() { // PY-1020
doInspectionTest("ChainedComparisons.py", PyChainedComparisonsInspection.class,
PyBundle.message("QFIX.chained.comparison"), true, true);
}
public void testChainedComparison1() { // PY-3126
doInspectionTest("ChainedComparison1.py", PyChainedComparisonsInspection.class,
PyBundle.message("QFIX.chained.comparison"), true, true);
}
public void testChainedComparison2() { // PY-3126
doInspectionTest("ChainedComparison2.py", PyChainedComparisonsInspection.class,
PyBundle.message("QFIX.chained.comparison"), true, true);
}
public void testChainedComparison3() { // PY-3126
doInspectionTest("ChainedComparison3.py", PyChainedComparisonsInspection.class,
PyBundle.message("QFIX.chained.comparison"), true, true);
}
public void testChainedComparison4() { // PY-5623
doInspectionTest("ChainedComparison4.py", PyChainedComparisonsInspection.class,
PyBundle.message("QFIX.chained.comparison"), true, true);
}
public void testChainedComparison5() { // PY-6467
doInspectionTest("ChainedComparison5.py", PyChainedComparisonsInspection.class,
PyBundle.message("QFIX.chained.comparison"), true, true);
}
public void testStatementEffect() { // PY-1362, PY-2585
doInspectionTest("StatementEffect.py", PyStatementEffectInspection.class,
PyBundle.message("QFIX.statement.effect"), true, true);
}
public void testStatementEffectIntroduceVariable() { // PY-1265
doInspectionTest("StatementEffectIntroduceVariable.py", PyStatementEffectInspection.class,
PyBundle.message("QFIX.statement.effect.introduce.variable"), true, true);
}
public void testReplacePrintEnd() {
runWithLanguageLevel(LanguageLevel.PYTHON34, new Runnable() {
@Override
public void run() {
doInspectionTest("ReplacePrintEnd.py", PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true, true);
}});
}
public void testReplacePrintComment() {
runWithLanguageLevel(LanguageLevel.PYTHON34, new Runnable() {
@Override
public void run() {
doInspectionTest("ReplacePrintComment.py", PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true,
true);
}});
}
public void testUnresolvedWith() { // PY-2083
setLanguageLevel(LanguageLevel.PYTHON25);
doInspectionTest("UnresolvedWith.py", PyUnresolvedReferencesInspection.class,
PyBundle.message("QFIX.unresolved.reference.add.future"), true, true);
}
public void testUnresolvedRefCreateFunction() { // PY-2092
doInspectionTest("UnresolvedRefCreateFunction.py", PyUnresolvedReferencesInspection.class,
PyBundle.message("QFIX.unresolved.reference.create.function.$0", "ref"), true, true);
}
public void testUnresolvedRefNoCreateFunction() {
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);
myFixture.configureByFile("UnresolvedRefNoCreateFunction.py");
myFixture.checkHighlighting(true, false, false);
final IntentionAction intentionAction = myFixture.getAvailableIntention(
PyBundle.message("QFIX.unresolved.reference.create.function.$0", "ref"));
assertNull(intentionAction);
}
public void testReplaceNotEqOperator() {
doInspectionTest("ReplaceNotEqOperator.py", PyCompatibilityInspection.class,
PyBundle.message("INTN.replace.noteq.operator"), true, true);
}
public void testListCreation() {
doInspectionTest("ListCreation.py", PyListCreationInspection.class,
PyBundle.message("QFIX.list.creation"), true, true);
}
public void testConvertSingleQuotedDocstring() { //PY-1445
doInspectionTest("ConvertSingleQuotedDocstring.py", PySingleQuotedDocstringInspection.class,
PyBundle.message("QFIX.convert.single.quoted.docstring"), true, true);
}
public void testConvertSingleQuotedDocstringEscape() { //PY-8926
doInspectionTest("ConvertSingleQuotedDocstringEscape.py", PySingleQuotedDocstringInspection.class,
PyBundle.message("QFIX.convert.single.quoted.docstring"), true, true);
}
public void testDefaultArgument() { //PY-3127
doInspectionTest("DefaultArgument.py", PyDefaultArgumentInspection.class,
PyBundle.message("QFIX.default.argument"), true, true);
}
public void testDefaultArgumentEmptyList() {
doInspectionTest("DefaultArgumentEmptyList.py", PyDefaultArgumentInspection.class,
PyBundle.message("QFIX.default.argument"), true, true);
}
public void testPyArgumentEqualDefault() { //PY-3125
doInspectionTest("ArgumentEqualDefault.py", PyArgumentEqualDefaultInspection.class,
PyBundle.message("QFIX.remove.argument.equal.default"), true, true);
}
public void testAddCallSuper() { //PY-3315
doInspectionTest("AddCallSuper.py", PyMissingConstructorInspection.class,
PyBundle.message("QFIX.add.super"), true, true);
}
public void testAddCallSuper1() { //PY-4017
doInspectionTest("AddCallSuper1.py", PyMissingConstructorInspection.class,
PyBundle.message("QFIX.add.super"), true, true);
}
public void testAddCallSuperAnnotations() {
runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() {
@Override
public void run() {
doInspectionTest("AddCallSuperAnnotations.py",
PyMissingConstructorInspection.class,
PyBundle.message("QFIX.add.super"), true, true);
}
});
}
public void testAddCallSuperPass() { //PY-8654
doInspectionTest("AddCallSuperPass.py", PyMissingConstructorInspection.class,
PyBundle.message("QFIX.add.super"), true, true);
}
public void testAddEncoding() { //PY-491
doInspectionTest("AddEncoding.py", PyMandatoryEncodingInspection.class,
PyBundle.message("QFIX.add.encoding"), true, true);
}
public void testRemoveDecorator() { //PY-3348
doInspectionTest("RemoveDecorator.py", PyDecoratorInspection.class,
PyBundle.message("QFIX.remove.decorator"), true, true);
}
public void testAddParameter() {
doInspectionTest("AddParameter.py", PyUnresolvedReferencesInspection.class,
PyBundle.message("QFIX.unresolved.reference.add.param.$0", "test"), true, true);
}
public void testRenameUnresolvedReference() { //PY-6595
doInspectionTest("RenameUnresolvedReference.py", PyUnresolvedReferencesInspection.class,
PyBundle.message("QFIX.rename.unresolved.reference"), true, true);
}
public void testSetFunctionToLiteral() { //PY-3120
setLanguageLevel(LanguageLevel.PYTHON27);
doInspectionTest("SetFunctionToLiteral.py", PySetFunctionToLiteralInspection.class,
PyBundle.message("QFIX.replace.function.set.with.literal"), true, true);
}
public void testDictComprehensionToCall() {
doInspectionTest("DictComprehensionToCall.py", PyCompatibilityInspection.class,
PyBundle.message("INTN.convert.dict.comp.to"), true, true);
}
public void testDocstringParams() { //PY-3394
PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule());
documentationSettings.setFormat(DocStringFormat.EPYTEXT);
try {
doInspectionTest("DocstringParams.py", PyDocstringInspection.class,
PyBundle.message("QFIX.docstring.add.$0", "b"), true, true);
}
finally {
documentationSettings.setFormat(DocStringFormat.PLAIN);
}
}
public void testDocstringParams1() {
PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule());
documentationSettings.setFormat(DocStringFormat.EPYTEXT);
try {
doInspectionTest("DocstringParams1.py", PyDocstringInspection.class,
PyBundle.message("QFIX.docstring.remove.$0", "c"), true, true);
}
finally {
documentationSettings.setFormat(DocStringFormat.PLAIN);
}
}
public void testDocstringParams2() { //PY-4964
PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule());
documentationSettings.setFormat(DocStringFormat.EPYTEXT);
try {
doInspectionTest("DocstringParams2.py", PyDocstringInspection.class,
PyBundle.message("QFIX.docstring.add.$0", "ham"), true, true);
}
finally {
documentationSettings.setFormat(DocStringFormat.PLAIN);
}
}
public void testUnnecessaryBackslash() {
String[] testFiles = new String[]{"UnnecessaryBackslash.py"};
myFixture.enableInspections(PyUnnecessaryBackslashInspection.class);
myFixture.configureByFiles(testFiles);
myFixture.checkHighlighting(true, false, true);
IntentionAction intentionAction = myFixture.getAvailableIntention(PyBundle.message("QFIX.remove.unnecessary.backslash"));
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after"));
}
public void testUnresolvedRefTrueFalse() { //PY-3051
doInspectionTest("UnresolvedRefTrueFalse.py", PyUnresolvedReferencesInspection.class,
PyBundle.message("QFIX.unresolved.reference.replace.$0", "True"), true, true);
}
public void testUnnecessaryBackslashInArgumentList() {
String[] testFiles = new String[]{"UnnecessaryBackslashInArguments.py"};
myFixture.enableInspections(PyUnnecessaryBackslashInspection.class);
myFixture.configureByFiles(testFiles);
myFixture.checkHighlighting(true, false, true);
IntentionAction intentionAction = myFixture.getAvailableIntention(PyBundle.message("QFIX.remove.unnecessary.backslash"));
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after"));
}
// PY-8788
public void testRenameShadowingBuiltins() {
final String fileName = "RenameShadowingBuiltins.py";
myFixture.configureByFile(fileName);
myFixture.enableInspections(PyShadowingBuiltinsInspection.class);
myFixture.checkHighlighting(true, false, true);
final IntentionAction intentionAction = myFixture.getAvailableIntention("Rename element");
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile(graftBeforeExt(fileName, "_after"));
}
// PY-8788
public void testRenameFunctionShadowingBuiltins() {
final String fileName = "RenameFunctionShadowingBuiltins.py";
myFixture.configureByFile(fileName);
myFixture.enableInspections(PyShadowingBuiltinsInspection.class);
myFixture.checkHighlighting(true, false, true);
final IntentionAction intentionAction = myFixture.getAvailableIntention("Rename element");
assertNotNull(intentionAction);
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile(graftBeforeExt(fileName, "_after"));
}
@Override
@NonNls
protected String getTestDataPath() {
return PythonTestUtil.getTestDataPath() + "/inspections/";
}
protected void doInspectionTest(@TestDataFile @NonNls String testFileName,
final Class inspectionClass,
@NonNls String quickFixName,
boolean applyFix,
boolean available) {
doInspectionTest(new String[]{testFileName}, inspectionClass, quickFixName, applyFix, available);
}
/**
* Runs daemon passes and looks for given fix within infos.
*
* @param testFiles names of files to participate; first is used for inspection and then for check by "_after".
* @param inspectionClass what inspection to run
* @param quickFixName how the resulting fix should be named (the human-readable name users see)
* @param applyFix true if the fix needs to be applied
* @param available true if the fix should be available, false if it should be explicitly not available.
* @throws Exception
*/
protected void doInspectionTest(@NonNls String[] testFiles,
final Class inspectionClass,
@NonNls String quickFixName,
boolean applyFix,
boolean available) {
myFixture.enableInspections(inspectionClass);
myFixture.configureByFiles(testFiles);
myFixture.checkHighlighting(true, false, false);
final IntentionAction intentionAction = myFixture.findSingleIntention(quickFixName);
if (available) {
assertNotNull(intentionAction);
if (applyFix) {
myFixture.launchAction(intentionAction);
myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after"));
}
}
else {
assertNull(intentionAction);
}
}
// Turns "name.ext" to "name_insertion.ext"
@NonNls
private static String graftBeforeExt(String name, String insertion) {
int dotpos = name.indexOf('.');
if (dotpos < 0) dotpos = name.length();
return name.substring(0, dotpos) + insertion + name.substring(dotpos, name.length());
}
}