Home | History | Annotate | Download | only in refactoring
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
      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 
     17 package com.android.ide.eclipse.adt.internal.editors.layout.refactoring;
     18 
     19 import com.android.utils.Pair;
     20 
     21 import org.eclipse.core.resources.IFile;
     22 import org.eclipse.core.runtime.IPath;
     23 import org.eclipse.core.runtime.NullProgressMonitor;
     24 import org.eclipse.jface.text.ITextSelection;
     25 import org.eclipse.jface.text.TextSelection;
     26 import org.eclipse.ltk.core.refactoring.Change;
     27 import org.eclipse.ltk.core.refactoring.TextFileChange;
     28 import org.eclipse.ui.IWorkbench;
     29 import org.eclipse.ui.IWorkbenchPage;
     30 import org.eclipse.ui.IWorkbenchWindow;
     31 import org.eclipse.ui.PlatformUI;
     32 import org.eclipse.ui.ide.IDE;
     33 import org.w3c.dom.Attr;
     34 import org.w3c.dom.Element;
     35 
     36 import java.util.ArrayList;
     37 import java.util.Collections;
     38 import java.util.Comparator;
     39 import java.util.HashMap;
     40 import java.util.List;
     41 import java.util.Map;
     42 import java.util.Set;
     43 
     44 public class ExtractStyleRefactoringTest extends RefactoringTest {
     45     @Override
     46     protected boolean testCaseNeedsUniqueProject() {
     47         return true;
     48     }
     49 
     50     public void testExtract1() throws Exception {
     51         // Test extracting into a new style file
     52         checkRefactoring("extractstyle1.xml", "newstyles.xml", "newstyle",
     53                 false /* removeExtracted */, false /* applyStyle */, null, 1, "@+id/button2");
     54     }
     55 
     56     public void testExtract1b() throws Exception {
     57         // Extract and apply new style
     58         checkRefactoring("extractstyle1.xml", "newstyles2.xml", "newstyle",
     59                 false /* removeExtracted */, true /* applyStyle */, null, 2, "@+id/button2");
     60     }
     61 
     62     public void testExtract1c() throws Exception {
     63         // Extract and remove extracted
     64         checkRefactoring("extractstyle1.xml", "newstyles3.xml", "newstyle",
     65                 true /* removeExtracted */, false /* applyStyle */, null, 2, "@+id/button2");
     66     }
     67 
     68     public void testExtract1d() throws Exception {
     69         // Extract and apply style and remove extracted
     70         checkRefactoring("extractstyle1.xml", "newstyles4.xml", "newstyle",
     71                 true /* removeExtracted */, true /* applyStyle */, null, 2, "@+id/button2");
     72     }
     73 
     74     public void testExtract2() throws Exception {
     75         getTestDataFile(getProject(), "navigationstyles.xml", "res/values/navigationstyles.xml");
     76 
     77         // -Modify- the existing styles.xml file
     78         checkRefactoring("extractstyle1.xml", "navigationstyles.xml", "newstyle",
     79                 true /* removeExtracted */, true /* applyStyle */, null, 2, "@+id/button2");
     80     }
     81 
     82     public void testExtract3() throws Exception {
     83         // Select multiple elements - overlap in values.
     84         checkRefactoring("extractstyle1.xml", "newstyles4.xml", "newstyle",
     85                 true /* removeExtracted */, true /* applyStyle */, null, 2,
     86                 "@+id/button1", "@+id/button2");
     87     }
     88 
     89     // This test fails for some reason - not in the refactoring (checked manually)
     90     // but the DOM model returns null when run in a test context.
     91     public void testExtract4() throws Exception {
     92         // Test extracting on a single caret position over an attribute: Should extract
     93         // just that one attribute
     94         checkRefactoringByOffset("extractstyle1.xml", "newstyles5.xml", "newstyle",
     95                 true /* removeExtracted */, true /* applyStyle */, null, 2,
     96                 "android:text^Color=\"#FF00FF\"", "android:text^Color=\"#FF00FF\"");
     97     }
     98 
     99     public void testExtract5() throws Exception {
    100         // Test extracting on a range selection inside an element: should extract just
    101         // the attributes that overlap the selection
    102         checkRefactoringByOffset("extractstyle1.xml", "newstyles6.xml", "newstyle",
    103                 true /* removeExtracted */, true /* applyStyle */, null, 2,
    104                 "android:^textSize=\"20pt",
    105                 "android:id=\"@+id/button1\" android:layout_a^lignParentBottom");
    106     }
    107 
    108     public void testExtract6() throws Exception {
    109         // Test extracting on a single caret position which is not over any attributes:
    110         checkRefactoringByOffset("extractstyle1.xml", "newstyles7.xml", "newstyle",
    111                 true /* removeExtracted */, true /* applyStyle */, null, 0,
    112                 "<Bu^tton", "<Bu^tton");
    113     }
    114 
    115     public void testExtract7() throws Exception {
    116         // Verify that even with a different namespace prefix we end up with android:
    117         // in the extracted style
    118         checkRefactoring("extractstyle2.xml", "newstyles8.xml", "newstyle",
    119                 true /* removeExtracted */, true /* applyStyle */, null, 2,
    120                 "@+id/button1", "@+id/button2");
    121     }
    122 
    123     public void testExtract8() throws Exception {
    124         // Test setting parent style
    125         checkRefactoring("extractstyle1.xml", "newstyles3.xml", "newstyle",
    126                 true /* removeExtracted */, false /* applyStyle */, "android:Widget.Button",
    127                 2, "@+id/button2");
    128     }
    129 
    130     // Check extract style on a selection of elements
    131     private void checkRefactoring(String basename, String styleFileName, String newStyleName,
    132             boolean removeExtracted, boolean applyStyle, String parentStyle,
    133             int expectedModifiedFileCount, String... ids) throws Exception {
    134         assertTrue(ids.length > 0);
    135 
    136         IFile file = getLayoutFile(getProject(), basename);
    137         TestContext info = setupTestContext(file, basename);
    138         TestLayoutEditorDelegate layoutEditor = info.mLayoutEditorDelegate;
    139         List<Element> selectedElements = getElements(info.mElement, ids);
    140 
    141         // Open the file such that ModelManager.getExistingModelForRead() in DomUtilities
    142         // will succeed
    143         IWorkbench workbench = PlatformUI.getWorkbench();
    144         IWorkbenchWindow activeWorkbenchWindow = workbench.getActiveWorkbenchWindow();
    145         IWorkbenchPage page = activeWorkbenchWindow.getActivePage();
    146         IDE.openEditor(page, file);
    147 
    148         ExtractStyleRefactoring refactoring = new ExtractStyleRefactoring(selectedElements,
    149                 layoutEditor);
    150         checkRefactoring(basename, styleFileName, newStyleName, removeExtracted, applyStyle,
    151                 parentStyle, expectedModifiedFileCount, file, refactoring);
    152     }
    153 
    154     // Check extract style against a set of editor text locations
    155     private void checkRefactoringByOffset(String basename, String styleFileName,
    156             String newStyleName, boolean removeExtracted, boolean applyStyle,
    157             String parentStyle,
    158             int expectedModifiedFileCount, String beginCaretLocation, String endCaretLocation)
    159             throws Exception {
    160         IFile file = getLayoutFile(getProject(), basename);
    161         int beginOffset = getCaretOffset(file, beginCaretLocation);
    162         int endOffset = getCaretOffset(file, endCaretLocation);
    163 
    164         TestContext info = setupTestContext(file, basename);
    165         TestLayoutEditorDelegate layoutEditor = info.mLayoutEditorDelegate;
    166 
    167         // Open the file such that ModelManager.getExistingModelForRead() in DomUtilities
    168         // will succeed
    169         IWorkbench workbench = PlatformUI.getWorkbench();
    170         IWorkbenchWindow activeWorkbenchWindow = workbench.getActiveWorkbenchWindow();
    171         IWorkbenchPage page = activeWorkbenchWindow.getActivePage();
    172         IDE.openEditor(page, file);
    173 
    174         ITextSelection selection = new TextSelection(beginOffset, endOffset - beginOffset);
    175         ExtractStyleRefactoring refactoring = new ExtractStyleRefactoring(file,
    176                 layoutEditor, selection, null);
    177         checkRefactoring(basename, styleFileName, newStyleName, removeExtracted, applyStyle,
    178                 parentStyle, expectedModifiedFileCount, file, refactoring);
    179     }
    180 
    181     // Common test code used by the other two check methods
    182     private void checkRefactoring(String basename, String styleFileName, String newStyleName,
    183             boolean removeExtracted, boolean applyStyle, String parentStyle,
    184             int expectedModifiedFileCount, IFile file,
    185             ExtractStyleRefactoring refactoring) throws Exception {
    186         refactoring.setStyleName(newStyleName);
    187         refactoring.setApplyStyle(applyStyle);
    188         refactoring.setRemoveExtracted(removeExtracted);
    189         refactoring.setStyleFileName(styleFileName);
    190         refactoring.setParent(parentStyle);
    191 
    192         // Pick the attributes to extract -- for now everything (and where there are
    193         // conflicting values, pick the first one)
    194         Pair<Map<String, List<Attr>>, Set<Attr>> result = refactoring.getAvailableAttributes();
    195         Map<String, List<Attr>> availableAttributes = result.getFirst();
    196         Set<Attr> selected = result.getSecond();
    197         List<Attr> chosenAttributes = new ArrayList<Attr>();
    198         for (List<Attr> list : availableAttributes.values()) {
    199             Collections.sort(list, new Comparator<Attr>() {
    200                 @Override
    201                 public int compare(Attr a1, Attr a2) {
    202                     return a1.getValue().compareTo(a2.getValue());
    203                 }
    204             });
    205             Attr attr = list.get(0);
    206             if (selected.contains(attr)) {
    207                 chosenAttributes.add(attr);
    208             }
    209         }
    210         refactoring.setChosenAttributes(chosenAttributes);
    211 
    212         List<Change> changes = refactoring.computeChanges(new NullProgressMonitor());
    213         assertEquals(expectedModifiedFileCount, changes.size());
    214 
    215         Map<IPath,String> fileToGolden = new HashMap<IPath,String>();
    216         IPath sourcePath = file.getProjectRelativePath();
    217         fileToGolden.put(sourcePath, basename);
    218         IPath newPath = refactoring.getStyleFile(getProject()).getProjectRelativePath();
    219         fileToGolden.put(newPath, styleFileName);
    220 
    221         checkEdits(changes, fileToGolden, true);
    222 
    223         int modifiedFileCount = 0;
    224         for (Change change : changes) {
    225             if (change instanceof TextFileChange) {
    226                 modifiedFileCount++;
    227             }
    228         }
    229         assertEquals(expectedModifiedFileCount, modifiedFileCount);
    230     }
    231 
    232 }
    233