2 * Copyright 2000-2013 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.jetbrains.python.refactoring.changeSignature;
18 import com.intellij.openapi.project.Project;
19 import com.intellij.openapi.util.Disposer;
20 import com.intellij.refactoring.BaseRefactoringProcessor;
21 import com.intellij.testFramework.TestDataPath;
22 import com.intellij.util.Function;
23 import com.intellij.util.containers.ContainerUtil;
24 import com.jetbrains.python.PyBundle;
25 import com.jetbrains.python.PythonFileType;
26 import com.jetbrains.python.fixtures.PyTestCase;
27 import com.jetbrains.python.psi.LanguageLevel;
28 import com.jetbrains.python.psi.PyFunction;
29 import org.jetbrains.annotations.Nullable;
31 import java.util.Arrays;
32 import java.util.List;
37 @TestDataPath("$CONTENT_ROOT/../testData/")
38 public class PyChangeSignatureTest extends PyTestCase {
40 public void testChooseSuperMethod() {
41 doChangeSignatureTest("baz", null);
44 public void testChangeFunctionName() {
45 doChangeSignatureTest("bar", null);
48 public void testRemovePositionalParam() {
49 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "a", null, false)));
52 public void testRemoveFirstPositionalParam() {
53 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(1, "b", null, false)));
56 public void testRemoveKeyedParam() { //PY-9753
57 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "tries", null, false),
58 new PyParameterInfo(2, "delay", "3", true),
59 new PyParameterInfo(3, "backoff", "1", true),
60 new PyParameterInfo(4, "exceptions_to_check", "Exception", true),
61 new PyParameterInfo(5, "retry_for_lambda", "None", true)));
64 public void testSwitchPositionalParam() {
65 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(1, "b", null, false), new PyParameterInfo(0, "a", null, false)));
68 public void testAddPositionalParam() {
69 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "a", null, false), new PyParameterInfo(1, "b", null, false),
70 new PyParameterInfo(-1, "c", "3", false)));
73 public void testAddDefaultParam() {
74 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "a", null, false), new PyParameterInfo(1, "b", null, false),
75 new PyParameterInfo(-1, "c", "3", true)));
78 public void testRemoveDefaultFromParam() {
79 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "a", null, false), new PyParameterInfo(1, "b", "2", false)));
82 public void testAddDefaultParam1() {
83 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "a", null, false), new PyParameterInfo(-1, "d", "1", true),
84 new PyParameterInfo(1, "b", "None", true)));
87 public void testUpdateDocstring() {
88 final PyParameterInfo a = new PyParameterInfo(0, "a", null, false);
89 final PyParameterInfo d1 = new PyParameterInfo(1, "d", "1", true);
91 doChangeSignatureTest(null, Arrays.asList(a, d1));
94 public void testFixDocstringRemove() {
95 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "a", null, false)));
98 public void testClassMethod() {
99 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "self", null, false), new PyParameterInfo(1, "a", null, true),
100 new PyParameterInfo(-1, "b", "2", false)));
103 public void testKeywordParam() {
104 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "a", null, false),
105 new PyParameterInfo(-1, "b", "2", false)));
108 public void testParamAnnotation() {
109 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "b", null, false)), LanguageLevel.PYTHON32);
112 public void testKwArgs() {
113 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "param", null, false),
114 new PyParameterInfo(1, "**kwargs", null, false)), LanguageLevel.PYTHON32);
117 public void testKeywordOnlyParams() {
118 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "param", null, false),
119 new PyParameterInfo(-1, "*", null, false),
120 new PyParameterInfo(-1, "a", "2", false)), LanguageLevel.PYTHON32);
123 public void testKeywordOnlyParamRemoveDefaultValue() {
124 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "my", "None", false),
125 new PyParameterInfo(1, "*", null, false),
126 new PyParameterInfo(2, "param", null, false)), LanguageLevel.PYTHON32);
129 public void testKeywordOnlyParamRemoveDefaultValue1() {
130 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "my", "None", false),
131 new PyParameterInfo(1, "*", null, false),
132 new PyParameterInfo(2, "param", "1", true)), LanguageLevel.PYTHON32);
135 public void testKeywordOnlyParamRemoveDefaultValue2() {
136 doChangeSignatureTest(null, Arrays.asList(new PyParameterInfo(0, "my", "None", true),
137 new PyParameterInfo(1, "*", null, false),
138 new PyParameterInfo(2, "param", "1", false)), LanguageLevel.PYTHON32);
141 public void testRenameOverriding() {
142 doChangeSignatureTest("m1", Arrays.asList(new PyParameterInfo(0, "self", null, false)));
145 public void testDuplicateParam() {
146 doChangeSignatureTest("some_function_name", Arrays.asList(new PyParameterInfo(0, "argument_1", null, false),
147 new PyParameterInfo(2, "opt2", "None", true),
148 new PyParameterInfo(3, "**extra_info", null, false)));
150 public void testMoveParam() {
151 doChangeSignatureTest("f1", Arrays.asList(new PyParameterInfo(1, "b", "2", true),
152 new PyParameterInfo(0, "a", "1", true)));
155 public void testMoveRenameParam() {
156 final PyParameterInfo b = new PyParameterInfo(-1, "b", "1", false);
157 final PyParameterInfo a = new PyParameterInfo(0, "a", "2", true);
159 doChangeSignatureTest("foo", Arrays.asList(b,
163 public void testKeywordOnlyMove() {
164 doChangeSignatureTest("f", Arrays.asList(new PyParameterInfo(2, "param2", null, false),
165 new PyParameterInfo(0, "*", null, false),
166 new PyParameterInfo(1, "param1", null, false)), LanguageLevel.PYTHON32);
170 public void testRenameStarredParameters() {
171 final PyParameterInfo argsParam = new PyParameterInfo(1, "*args", null, false);
172 argsParam.setName("*foo");
173 final PyParameterInfo kwargsParam = new PyParameterInfo(2, "**kwargs", null, false);
174 kwargsParam.setName("**bar");
175 doChangeSignatureTest("func", Arrays.asList(new PyParameterInfo(0, "arg1", null, false), argsParam, kwargsParam), LanguageLevel.PYTHON32);
178 public void testRenameAndMoveParam() {
179 final PyParameterInfo p2 = new PyParameterInfo(1, "p2", null, false);
180 final PyParameterInfo p1 = new PyParameterInfo(0, "p1", null, false);
182 doChangeSignatureTest("f", Arrays.asList(p2,
186 public void testEmptyParameterName() {
187 doValidationTest(null, Arrays.asList(new PyParameterInfo(-1, "", "2", true)),
188 PyBundle.message("refactoring.change.signature.dialog.validation.parameter.name"));
191 public void testDecorator() {
192 doChangeSignatureTest("decorator", Arrays.asList(new PyParameterInfo(0, "arg1", null, false)));
195 public void testNonDefaultAfterDefault() {
196 doValidationTest(null, Arrays.asList(new PyParameterInfo(-1, "a", "2", false), new PyParameterInfo(1, "b", "2", false)), null);
199 public void testNonDefaultAfterDefault1() {
200 doValidationTest(null, Arrays.asList(new PyParameterInfo(1, "b", "1", true), new PyParameterInfo(-1, "a", "2", false)),
201 PyBundle.message("ANN.non.default.param.after.default"));
205 public void testAnnotationsForStarredParametersAreNotShownInDialog() throws Exception {
206 runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() {
208 myFixture.configureByText(PythonFileType.INSTANCE, "def func(a, b:int, *args: tuple, c:list, d:str='foo', ** kwargs:dict):\n" +
210 final PyFunction function = (PyFunction)new PyChangeSignatureHandler().findTargetMember(myFixture.getFile(), myFixture.getEditor());
211 assertNotNull(function);
212 final List<String> expected = Arrays.asList("a", "b", "*args", "c", "d", "**kwargs");
213 final List<PyParameterInfo> parameters = new PyMethodDescriptor(function).getParameters();
214 assertEquals(expected, ContainerUtil.map(parameters, new Function<PyParameterInfo, String>() {
216 public String fun(PyParameterInfo info) {
217 return info.getOldName();
224 public void testDuplicateNamesOfStarredParameters() throws Exception {
225 final PyParameterInfo firstParam = new PyParameterInfo(0, "*foo", null, false);
226 firstParam.setName("*bar");
227 doValidationTest(null, Arrays.asList(firstParam, new PyParameterInfo(1, "**bar", null, false)),
228 PyBundle.message("ANN.duplicate.param.name"));
231 public void testMultipleSingleStarredParameters() throws Exception {
232 final PyParameterInfo firstParam = new PyParameterInfo(0, "foo", null, false);
233 firstParam.setName("*foo");
234 doValidationTest(null, Arrays.asList(firstParam, new PyParameterInfo(1, "*bar", null, false)),
235 PyBundle.message("refactoring.change.signature.dialog.validation.multiple.star"));
238 public void testMultipleDoubleStarredParameters() throws Exception {
239 final PyParameterInfo firstParam = new PyParameterInfo(0, "foo", null, false);
240 firstParam.setName("**foo");
241 doValidationTest(null, Arrays.asList(firstParam, new PyParameterInfo(1, "**bar", null, false)),
242 PyBundle.message("refactoring.change.signature.dialog.validation.multiple.double.star"));
245 public void testParameterNameWithMoreThanTwoStars() throws Exception {
246 final PyParameterInfo firstParam = new PyParameterInfo(0, "**kwargs", null, false);
247 firstParam.setName("***kwargs");
248 doValidationTest(null, Arrays.asList(firstParam), PyBundle.message("refactoring.change.signature.dialog.validation.parameter.name"));
251 public void doChangeSignatureTest(@Nullable String newName, @Nullable List<PyParameterInfo> parameters) {
252 myFixture.configureByFile("refactoring/changeSignature/" + getTestName(true) + ".before.py");
253 changeSignature(newName, parameters);
254 myFixture.checkResultByFile("refactoring/changeSignature/" + getTestName(true) + ".after.py");
257 private void doChangeSignatureTest(@Nullable String newName, @Nullable List<PyParameterInfo> parameters, LanguageLevel level) {
258 setLanguageLevel(level);
260 doChangeSignatureTest(newName, parameters);
263 setLanguageLevel(null);
267 public void doValidationTest(@Nullable String newName, @Nullable List<PyParameterInfo> parameters, @Nullable String expected) {
268 myFixture.configureByFile("refactoring/changeSignature/" + getTestName(true) + ".py");
269 final PyChangeSignatureHandler changeSignatureHandler = new PyChangeSignatureHandler();
270 final PyFunction function = (PyFunction)changeSignatureHandler.findTargetMember(myFixture.getFile(), myFixture.getEditor());
271 assertNotNull(function);
273 final PyMethodDescriptor method = new PyMethodDescriptor(function);
274 final TestPyChangeSignatureDialog dialog = new TestPyChangeSignatureDialog(function.getProject(), method);
276 if (newName != null) {
277 dialog.setNewName(newName);
279 if (parameters != null) {
280 dialog.setParameterInfos(parameters);
283 final String validationError = dialog.validateAndCommitData();
284 assertEquals(expected, validationError);
287 Disposer.dispose(dialog.getDisposable());
291 private void changeSignature(@Nullable String newName, @Nullable List<PyParameterInfo> parameters) {
292 final PyChangeSignatureHandler changeSignatureHandler = new PyChangeSignatureHandler();
293 final PyFunction function = (PyFunction)changeSignatureHandler.findTargetMember(myFixture.getFile(), myFixture.getEditor());
294 assertNotNull(function);
295 final PyFunction newFunction = PyChangeSignatureHandler.getSuperMethod(function);
296 assertNotNull(newFunction);
297 final PyMethodDescriptor method = new PyMethodDescriptor(newFunction);
298 final TestPyChangeSignatureDialog dialog = new TestPyChangeSignatureDialog(newFunction.getProject(), method);
300 if (newName != null) {
301 dialog.setNewName(newName);
303 if (parameters != null) {
304 dialog.setParameterInfos(parameters);
307 final String validationError = dialog.validateAndCommitData();
308 assertTrue(validationError, validationError == null);
310 final BaseRefactoringProcessor baseRefactoringProcessor = dialog.createRefactoringProcessor();
311 assert baseRefactoringProcessor instanceof PyChangeSignatureProcessor;
313 final PyChangeSignatureProcessor processor = (PyChangeSignatureProcessor)baseRefactoringProcessor;
317 Disposer.dispose(dialog.getDisposable());
322 public static class TestPyChangeSignatureDialog extends PyChangeSignatureDialog {
324 public TestPyChangeSignatureDialog(Project project, PyMethodDescriptor method) {
325 super(project, method);
328 public void setNewName(String newName) {
329 myNameField.setText(newName);