| package com.jetbrains.python.refactoring.classes.pullUp; |
| |
| import com.google.common.collect.Collections2; |
| import com.intellij.util.containers.MultiMap; |
| import com.jetbrains.python.psi.LanguageLevel; |
| import com.jetbrains.python.psi.PyClass; |
| import com.jetbrains.python.psi.PyElement; |
| import com.jetbrains.python.refactoring.classes.NameTransformer; |
| import com.jetbrains.python.refactoring.classes.PyMemberInfoStorage; |
| import com.jetbrains.python.refactoring.classes.PyPresenterTestMemberEntry; |
| import com.jetbrains.python.refactoring.classes.PyRefactoringPresenterTestCase; |
| import com.jetbrains.python.refactoring.classes.membersManager.PyMemberInfo; |
| import org.easymock.Capture; |
| import org.easymock.EasyMock; |
| import org.hamcrest.Matcher; |
| import org.hamcrest.Matchers; |
| import org.jetbrains.annotations.NotNull; |
| import org.junit.Assert; |
| |
| import java.util.Collection; |
| |
| |
| /** |
| * Test presenter for pull-up refactoring |
| * |
| * @author Ilya.Kazakevich |
| */ |
| public class PyPullUpPresenterTest extends PyRefactoringPresenterTestCase<PyPullUpViewInitializationInfo, PyPullUpView> { |
| |
| |
| public PyPullUpPresenterTest() { |
| super(PyPullUpView.class, "pullup"); |
| } |
| |
| /** |
| * Checks that parents are returned in MRO order and no parents outside of source root are included |
| */ |
| public void testParentsOrder() throws Exception { |
| final PyPullUpPresenter sut = configureByClass("Child"); |
| configureParent(); |
| myMocksControl.replay(); |
| |
| sut.launch(); |
| Assert.assertTrue("Presenter did not show parents", myViewConfigCapture.hasCaptured()); |
| final Collection<PyClass> parents = myViewConfigCapture.getValue().getParents(); |
| Assert.assertThat("Wrong list of parents or parents are listed in wrong order", Collections2.transform(parents, CLASS_TO_NAME), |
| Matchers.contains("SubParent1", "SubParent2", "MainParent")); |
| } |
| |
| /** |
| * Checks that refactoring does not work for classes with out of allowed parents |
| */ |
| public void testNoParents() throws Exception { |
| ensureNoMembers("NoParentsAllowed"); |
| } |
| |
| /** |
| * Ensures that presenter displays conflicts if destination class already has that members |
| */ |
| public void testConflicts() throws Exception { |
| final PyPullUpPresenterImpl sut = configureByClass("ChildWithConflicts"); |
| configureParent(); |
| final Collection<PyMemberInfo<PyElement>> infos = getMemberInfos(sut); |
| |
| final Capture<MultiMap<PyClass, PyMemberInfo<?>>> conflictCapture = new Capture<MultiMap<PyClass, PyMemberInfo<?>>>(); |
| EasyMock.expect(myView.showConflictsDialog(EasyMock.capture(conflictCapture), EasyMock.<Collection<PyMemberInfo<?>>>anyObject())).andReturn(false).anyTimes(); |
| EasyMock.expect(myView.getSelectedMemberInfos()).andReturn(infos).anyTimes(); |
| final PyClass parent = getClassByName("ParentWithConflicts"); |
| EasyMock.expect(myView.getSelectedParent()).andReturn(parent).anyTimes(); |
| myMocksControl.replay(); |
| sut.okClicked(); |
| |
| final MultiMap<PyClass, PyMemberInfo<?>> conflictMap = conflictCapture.getValue(); |
| Assert.assertTrue("No conflicts found, while it should", conflictMap.containsKey(parent)); |
| final Collection<String> conflictedMemberNames = Collections2.transform(conflictMap.get(parent), NameTransformer.INSTANCE); |
| Assert.assertThat("Failed to find right conflicts", conflictedMemberNames, Matchers.containsInAnyOrder( |
| "extends Bar", |
| "CLASS_FIELD", |
| "self.instance_field", |
| "my_func(self)", |
| "__init__(self)" |
| )); |
| |
| |
| } |
| |
| /** |
| * Checks that refactoring does not work for classes with out of members |
| */ |
| public void testNoMembers() throws Exception { |
| ensureNoMembers("NoMembers"); |
| } |
| |
| /** |
| * Checks that refactoring does not work when C3 MRO can't be calculated |
| */ |
| public void testBadMro() throws Exception { |
| ensureNoMembers("BadMro"); |
| } |
| |
| /** |
| * Checks that parent can't be moved to itself |
| */ |
| public void testNoMoveParentToItSelf() throws Exception { |
| final Collection<PyPresenterTestMemberEntry> memberNamesAndStatus = launchAndGetMembers("Foo", "Bar"); |
| |
| compareMembers(memberNamesAndStatus, Matchers.containsInAnyOrder(new PyPresenterTestMemberEntry("__init__(self)", true, false, false), |
| new PyPresenterTestMemberEntry("self.foo", true, false, false), |
| new PyPresenterTestMemberEntry("extends Bar", false, false, false))); |
| } |
| |
| /** |
| * Checks that some members are not allowed (and may nto be abstract), while others are for Py2 |
| */ |
| public void testMembersPy2() throws Exception { |
| ensureCorrectMembersForHugeChild(false); |
| } |
| |
| /** |
| * Checks that some members are not allowed (and may nto be abstract), while others are for Py3 |
| */ |
| public void testMembersPy3() throws Exception { |
| setLanguageLevel(LanguageLevel.PYTHON30); |
| ensureCorrectMembersForHugeChild(true); |
| } |
| |
| /** |
| * Checks members for class HugeChild |
| * |
| * @param py3K if python 3 |
| */ |
| private void ensureCorrectMembersForHugeChild(final boolean py3K) { |
| final Collection<PyPresenterTestMemberEntry> memberNamesAndStatus = launchAndGetMembers("HugeChild", "SubParent1"); |
| |
| //Pair will return correct type |
| final Matcher<Iterable<? extends PyPresenterTestMemberEntry>> matcher = Matchers |
| .containsInAnyOrder(new PyPresenterTestMemberEntry("extends date", true, false, false), |
| new PyPresenterTestMemberEntry("CLASS_FIELD", true, true, false), |
| new PyPresenterTestMemberEntry("__init__(self)", true, false, false), |
| new PyPresenterTestMemberEntry("extends SubParent1", false, false, false), |
| new PyPresenterTestMemberEntry("foo(self)", true, false, true), |
| new PyPresenterTestMemberEntry("bar(self)", true, false, true), |
| new PyPresenterTestMemberEntry("static_1(cls)", true, true, py3K), |
| new PyPresenterTestMemberEntry("static_2()", true, true, py3K), |
| new PyPresenterTestMemberEntry("self.instance_field_1", true, false, false), |
| new PyPresenterTestMemberEntry("self.instance_field_2", true, false, false), |
| new PyPresenterTestMemberEntry("bad_method()", true, false, true), |
| new PyPresenterTestMemberEntry("name", true, false, false), |
| new PyPresenterTestMemberEntry("some_property", true, false, false)); |
| compareMembers(memberNamesAndStatus, matcher); |
| } |
| |
| |
| /** |
| * Launches presenter and returns members it displayed to user |
| * |
| * @param classUnderRefactoring class to refactor |
| * @param destinationClass where to move it |
| * @return members displayed to user |
| */ |
| @NotNull |
| private Collection<PyPresenterTestMemberEntry> launchAndGetMembers(@NotNull final String classUnderRefactoring, |
| @NotNull final String destinationClass) { |
| final PyPullUpPresenterImpl sut = configureByClass(classUnderRefactoring); |
| |
| EasyMock.expect(myView.getSelectedParent()).andReturn(getClassByName(destinationClass)).anyTimes(); |
| |
| myMocksControl.replay(); |
| sut.launch(); |
| |
| return getMembers(); |
| } |
| |
| /** |
| * Checks that refactoring does not work for classes with out of members |
| */ |
| private void ensureNoMembers(@NotNull final String className) throws Exception { |
| try { |
| final PyPullUpPresenter sut = configureByClass(className); |
| |
| myMocksControl.replay(); |
| sut.launch(); |
| } |
| catch (final IllegalArgumentException ignored) { |
| return; |
| } |
| Assert |
| .fail("Presenter should throw exception, but it returned list of parents instead: " + myViewConfigCapture.getValue().getParents()); |
| } |
| |
| /** |
| * Creates presenter (sut) by class |
| * |
| * @param name name of class |
| * @return presenter |
| */ |
| private PyPullUpPresenterImpl configureByClass(@NotNull final String name) { |
| final PyClass childClass = getClassByName(name); |
| final PyMemberInfoStorage storage = new PyMemberInfoStorage(childClass); |
| return new PyPullUpPresenterImpl(myView, storage, childClass); |
| } |
| |
| /** |
| * Makes view to return class "Parent" as selected parent |
| */ |
| private void configureParent() { |
| EasyMock.expect(myView.getSelectedParent()).andReturn(getClassByName("Parent")).anyTimes(); |
| } |
| } |