Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2012 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 package com.android.ide.eclipse.adt.internal.refactorings.core;
     17 
     18 import com.android.annotations.NonNull;
     19 import com.android.annotations.Nullable;
     20 import com.android.ide.eclipse.adt.AdtUtils;
     21 import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.AdtProjectTest;
     22 import com.google.common.base.Charsets;
     23 import com.google.common.base.Splitter;
     24 import com.google.common.io.ByteStreams;
     25 import com.google.common.io.Files;
     26 
     27 import org.eclipse.core.resources.IFile;
     28 import org.eclipse.core.resources.IProject;
     29 import org.eclipse.core.resources.IResource;
     30 import org.eclipse.core.runtime.NullProgressMonitor;
     31 import org.eclipse.jdt.internal.corext.refactoring.changes.RenameCompilationUnitChange;
     32 import org.eclipse.jdt.internal.corext.refactoring.changes.RenamePackageChange;
     33 import org.eclipse.jface.text.Document;
     34 import org.eclipse.jface.text.IDocument;
     35 import org.eclipse.ltk.core.refactoring.Change;
     36 import org.eclipse.ltk.core.refactoring.CompositeChange;
     37 import org.eclipse.ltk.core.refactoring.Refactoring;
     38 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
     39 import org.eclipse.ltk.core.refactoring.TextChange;
     40 import org.eclipse.ltk.core.refactoring.TextFileChange;
     41 import org.eclipse.ltk.core.refactoring.resource.MoveResourceChange;
     42 import org.eclipse.ltk.core.refactoring.resource.RenameResourceChange;
     43 import org.eclipse.text.edits.TextEdit;
     44 
     45 import java.io.File;
     46 import java.io.IOException;
     47 import java.util.Arrays;
     48 import java.util.Collections;
     49 import java.util.Comparator;
     50 import java.util.List;
     51 
     52 @SuppressWarnings({"javadoc","restriction"})
     53 public abstract class RefactoringTestBase extends AdtProjectTest {
     54     protected void checkRefactoring(Refactoring refactoring, String expected) throws Exception {
     55         checkRefactoring(refactoring, expected, null);
     56     }
     57 
     58     @Override
     59     protected void setUp() throws Exception {
     60         // Not calling super.setUp
     61     }
     62 
     63     protected void checkRefactoring(Refactoring refactoring, String expected,
     64             @Nullable String expectedWarnings) throws Exception {
     65         RefactoringStatus status = refactoring.checkAllConditions(new NullProgressMonitor());
     66         assertNotNull(status);
     67         if (expectedWarnings == null) {
     68             expectedWarnings = "<OK\n>";
     69         }
     70         if (status.toString().trim().startsWith(
     71             "<WARNING\n" +
     72             "\t\n" +
     73             "WARNING: Code modification may not be accurate as affected resource '")) {
     74             // Test instability, probably a timing issue with getting the new project
     75             // compiled (to recognize Android classpath entries)
     76             // Just continue to ensure that the refactoring list matches.
     77         } else {
     78             assertEquals(status.toString().trim(), expectedWarnings.trim());
     79         }
     80         if (!status.isOK()) {
     81             return;
     82         }
     83         assertTrue(status.toString(), status.isOK());
     84         Change change = refactoring.createChange(new NullProgressMonitor());
     85         assertNotNull(change);
     86         String explanation = "CHANGES:\n-------\n" + describe(change);
     87         if (!expected.trim().equals(explanation.trim())) { // allow trimming endlines in expected
     88             assertEquals(expected, explanation);
     89         }
     90     }
     91 
     92     private IProject mProject;
     93 
     94     @Override
     95     protected IProject getProject() {
     96         return mProject;
     97     }
     98 
     99     protected IProject createProject(Object[] testData) throws Exception {
    100         String name = getName();
    101         IProject project = createProject(name);
    102         mProject = project;
    103         File projectDir = AdtUtils.getAbsolutePath(project).toFile();
    104         assertNotNull(projectDir);
    105         assertTrue(projectDir.getPath(), projectDir.exists());
    106         createTestDataDir(projectDir, testData);
    107         project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
    108 
    109         for (int i = 0; i < testData.length; i+= 2) {
    110             assertTrue(testData[i].toString(), testData[i] instanceof String);
    111             String relative = (String) testData[i];
    112             IResource member = project.findMember(relative);
    113             assertNotNull(relative, member);
    114             assertTrue(member.getClass().getSimpleName(), member instanceof IFile);
    115         }
    116 
    117         return project;
    118     }
    119 
    120     public static String describe(Change change) throws Exception {
    121         StringBuilder sb = new StringBuilder(1000);
    122         describe(sb, change, 0);
    123 
    124         // Trim trailing space
    125         for (int i = sb.length() - 1; i >= 0; i--) {
    126             if (!Character.isWhitespace(sb.charAt(i))) {
    127                 sb.setLength(i + 1);
    128                 break;
    129             }
    130         }
    131 
    132         return sb.toString();
    133     }
    134 
    135     protected static void describe(StringBuilder sb, Change change, int indent) throws Exception {
    136         if (change instanceof CompositeChange
    137                 && ((CompositeChange) change).isSynthetic()) {
    138             // Don't display information about synthetic changes
    139         } else {
    140             String changeName = change.getName();
    141 
    142             if (changeName.contains("MoreUnit")) {
    143                 // If MoreUnit plugin is installed, don't include in unit test results
    144                 return;
    145             }
    146 
    147             // Describe this change
    148             indent(sb, indent);
    149             if (change.isEnabled()) {
    150                 sb.append("[x] ");
    151             } else {
    152                 sb.append("[ ] ");
    153             }
    154             sb.append(changeName);
    155 
    156             IFile file = getFile(change);
    157             if (file != null) {
    158                 sb.append(" - ");
    159                 sb.append(file.getFullPath());
    160                 sb.append('\n');
    161             } else {
    162                 sb.append('\n');
    163             }
    164 
    165             if (change instanceof TextFileChange) {
    166                 assertNotNull(file);
    167                 if (file != null) {
    168                     TextChange tc = (TextChange) change;
    169                     TextEdit edit = tc.getEdit();
    170                     byte[] bytes = ByteStreams.toByteArray(file.getContents());
    171                     String before = new String(bytes, Charsets.UTF_8);
    172                     IDocument document = new Document();
    173                     document.replace(0, 0, before);
    174                     // Make a copy: edits are sometimes destructive when run repeatedly!
    175                     edit.copy().apply(document);
    176                     String after = document.get();
    177 
    178                     String diff = getDiff(before, after);
    179                     for (String line : Splitter.on('\n').split(diff)) {
    180                         if (!line.trim().isEmpty()) {
    181                             indent(sb, indent + 1);
    182                             sb.append(line);
    183                         }
    184                         sb.append('\n');
    185                     }
    186                 }
    187             } else if (change instanceof RenameCompilationUnitChange) {
    188                 // Change name, appended above, is adequate
    189             } else if (change instanceof RenameResourceChange) {
    190                 // Change name, appended above, is adequate
    191             } else if (change instanceof RenamePackageChange) {
    192                 // Change name, appended above, is adequate
    193             } else if (change instanceof MoveResourceChange) {
    194                 // Change name, appended above, is adequate
    195             } else if (change instanceof CompositeChange) {
    196                 // Don't print details about children here; they'll be nested below
    197             } else {
    198                 indent(sb, indent);
    199                 sb.append("<UNKNOWN CHANGE TYPE " + change.getClass().getName() + ">");
    200             }
    201             sb.append('\n');
    202         }
    203 
    204         if (change instanceof CompositeChange) {
    205             CompositeChange composite = (CompositeChange) change;
    206             Change[] children = composite.getChildren();
    207             List<Change> sorted = Arrays.asList(children);
    208             // Process children in a fixed (output-alphabetical) order to ensure stable output
    209             Collections.sort(sorted, new Comparator<Change>() {
    210                 @Override
    211                 public int compare(Change change1, Change change2) {
    212                     try {
    213                         IFile file1 = getFile(change1);
    214                         IFile file2 = getFile(change2);
    215                         if (file1 != null && file2 != null) {
    216                             // Sort in decreasing order. This places the most interesting
    217                             // files first: res > src > gen
    218                             int fileDelta = file2.getFullPath().toOSString().compareToIgnoreCase(
    219                                     file1.getFullPath().toOSString());
    220                             if (fileDelta != 0) {
    221                                 return fileDelta;
    222                             }
    223                         }
    224 
    225                         int nameDelta = change2.getName().compareTo(change1.getName());
    226                         if (nameDelta != 0) {
    227                             return nameDelta;
    228                         }
    229 
    230                         // This is pretty inefficient but ensures stable output
    231                         return describe(change2).compareTo(describe(change1));
    232                     } catch (Exception e) {
    233                         fail(e.getLocalizedMessage());
    234                         return 0;
    235                     }
    236                 }
    237 
    238             });
    239             for (Change child : sorted) {
    240                 describe(sb, child, indent + (composite.isSynthetic() ? 0 : 1));
    241             }
    242         }
    243     }
    244 
    245     @Nullable
    246     private static IFile getFile(@NonNull Change change) {
    247         if (change instanceof TextFileChange) {
    248             TextFileChange tfc = (TextFileChange) change;
    249             return tfc.getFile();
    250         }
    251 
    252         return null;
    253     }
    254 
    255     protected static void indent(StringBuilder sb, int indent) {
    256         for (int i = 0; i < indent; i++) {
    257             sb.append("  ");
    258         }
    259     }
    260 
    261     protected void createTestDataDir(File dir, Object[] data) throws IOException {
    262         for (int i = 0, n = data.length; i < n; i += 2) {
    263             assertTrue("Must be a path: " + data[i], data[i] instanceof String);
    264             String relativePath = ((String) data[i]).replace('/', File.separatorChar);
    265             File to = new File(dir, relativePath);
    266             File parent = to.getParentFile();
    267             if (!parent.exists()) {
    268                 boolean mkdirs = parent.mkdirs();
    269                 assertTrue(to.getPath(), mkdirs);
    270             }
    271 
    272             Object o = data[i + 1];
    273             if (o instanceof String) {
    274                 String contents = (String) o;
    275                 Files.write(contents, to, Charsets.UTF_8);
    276             } else if (o instanceof byte[]) {
    277                 Files.write((byte[]) o, to);
    278             } else {
    279                 fail("Data must be a String or a byte[] for " + to);
    280             }
    281         }
    282     }
    283 
    284     // Test sources
    285 
    286     protected static final String SAMPLE_MANIFEST =
    287             "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
    288             "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
    289             "    package=\"com.example.refactoringtest\"\n" +
    290             "    android:versionCode=\"1\"\n" +
    291             "    android:versionName=\"1.0\" >\n" +
    292             "\n" +
    293             "    <uses-sdk\n" +
    294             "        android:minSdkVersion=\"8\"\n" +
    295             "        android:targetSdkVersion=\"17\" />\n" +
    296             "\n" +
    297             "    <application\n" +
    298             "        android:icon=\"@drawable/ic_launcher\"\n" +
    299             "        android:label=\"@string/app_name\"\n" +
    300             "        android:theme=\"@style/AppTheme\" >\n" +
    301             "        <activity\n" +
    302             "            android:name=\"com.example.refactoringtest.MainActivity\"\n" +
    303             "            android:label=\"@string/app_name\" >\n" +
    304             "            <intent-filter>\n" +
    305             "                <action android:name=\"android.intent.action.MAIN\" />\n" +
    306             "\n" +
    307             "                <category android:name=\"android.intent.category.LAUNCHER\" />\n" +
    308             "            </intent-filter>\n" +
    309             "        </activity>\n" +
    310             "        <activity\n" +
    311             "            android:name=\".MainActivity2\"\n" +
    312             "            android:label=\"@string/app_name2\" >\n" +
    313             "        </activity>\n" +
    314             "    </application>\n" +
    315             "\n" +
    316             "</manifest>";
    317 
    318     protected static final String SAMPLE_MAIN_ACTIVITY =
    319             "package com.example.refactoringtest;\n" +
    320             "\n" +
    321             "import android.os.Bundle;\n" +
    322             "import android.app.Activity;\n" +
    323             "import android.view.Menu;\n" +
    324             "import android.view.View;\n" +
    325             "\n" +
    326             "public class MainActivity extends Activity {\n" +
    327             "\n" +
    328             "    @Override\n" +
    329             "    protected void onCreate(Bundle savedInstanceState) {\n" +
    330             "        super.onCreate(savedInstanceState);\n" +
    331             "        setContentView(R.layout.activity_main);\n" +
    332             "        View view1 = findViewById(R.id.textView1);\n" +
    333             "    }\n" +
    334             "\n" +
    335             "    @Override\n" +
    336             "    public boolean onCreateOptionsMenu(Menu menu) {\n" +
    337             "        // Inflate the menu; this adds items to the action bar if it is present.\n" +
    338             "        getMenuInflater().inflate(R.menu.activity_main, menu);\n" +
    339             "        return true;\n" +
    340             "    }\n" +
    341             "\n" +
    342             "}\n";
    343 
    344     protected static final String SAMPLE_MAIN_ACTIVITY2 =
    345             "package com.example.refactoringtest;\n" +
    346             "\n" +
    347             "import android.os.Bundle;\n" +
    348             "import android.app.Activity;\n" +
    349             "import android.view.Menu;\n" +
    350             "import android.view.View;\n" +
    351             "\n" +
    352             "public class MainActivity2 extends Activity {\n" +
    353             "\n" +
    354             "    @Override\n" +
    355             "    protected void onCreate(Bundle savedInstanceState) {\n" +
    356             "        super.onCreate(savedInstanceState);\n" +
    357             "    }\n" +
    358             "\n" +
    359             "}\n";
    360 
    361     protected static final String MY_FRAGMENT =
    362             "package com.example.refactoringtest;\n" +
    363             "import android.support.v4.app.ListFragment;\n" +
    364             "\n" +
    365             "public class MyFragment extends ListFragment {\n" +
    366             "\n" +
    367             "}\n";
    368 
    369     protected static final String SAMPLE_LAYOUT =
    370             "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
    371             "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
    372             "    android:layout_width=\"match_parent\"\n" +
    373             "    android:layout_height=\"match_parent\"\n" +
    374             "    tools:context=\".MainActivity\" >\n" +
    375             "\n" +
    376             "    <TextView\n" +
    377             "        android:id=\"@+id/textView1\"\n" +
    378             "        android:layout_width=\"wrap_content\"\n" +
    379             "        android:layout_height=\"wrap_content\"\n" +
    380             "        android:layout_centerVertical=\"true\"\n" +
    381             "        android:layout_toRightOf=\"@+id/button2\"\n" +
    382             "        android:text=\"@string/hello_world\" />\n" +
    383             "\n" +
    384             "    <Button\n" +
    385             "        android:id=\"@+id/button1\"\n" +
    386             "        android:layout_width=\"wrap_content\"\n" +
    387             "        android:layout_height=\"wrap_content\"\n" +
    388             "        android:layout_alignLeft=\"@+id/textView1\"\n" +
    389             "        android:layout_below=\"@+id/textView1\"\n" +
    390             "        android:layout_marginLeft=\"22dp\"\n" +
    391             "        android:layout_marginTop=\"24dp\"\n" +
    392             "        android:text=\"Button\" />\n" +
    393             "\n" +
    394             "    <Button\n" +
    395             "        android:id=\"@+id/button2\"\n" +
    396             "        android:layout_width=\"wrap_content\"\n" +
    397             "        android:layout_height=\"wrap_content\"\n" +
    398             "        android:layout_alignParentLeft=\"true\"\n" +
    399             "        android:layout_alignParentTop=\"true\"\n" +
    400             "        android:text=\"Button\" />\n" +
    401             "\n" +
    402             "    <fragment android:name=\"com.example.refactoringtest.MyFragment\"/>" +
    403             "\n" +
    404             "</RelativeLayout>";
    405 
    406     protected static final String SAMPLE_LAYOUT_2 =
    407             "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
    408             "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
    409             "    android:layout_width=\"match_parent\"\n" +
    410             "    android:layout_height=\"match_parent\"\n" +
    411             "    tools:context=\".MainActivity\" >\n" +
    412             "\n" +
    413             "    <ListView\n" +
    414             "        android:layout_width=\"match_parent\"\n" +
    415             "        android:layout_height=\"wrap_content\"\n" +
    416             "        tools:listitem=\"@layout/preview\" >\n" +
    417             "    </ListView>\n" +
    418             "\n" +
    419             "    <fragment\n" +
    420             "        android:name=\"android.support.v4.app.ListFragment\"\n" +
    421             "        android:layout_width=\"wrap_content\"\n" +
    422             "        android:layout_height=\"wrap_content\"\n" +
    423             "        tools:layout=\"@layout/preview\" />\n" +
    424             "\n" +
    425             "\n" +
    426             "</RelativeLayout>";
    427 
    428 
    429     protected static final String SAMPLE_MENU =
    430             "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n" +
    431             "\n" +
    432             "    <item\n" +
    433             "        android:id=\"@+id/menu_settings\"\n" +
    434             "        android:orderInCategory=\"100\"\n" +
    435             "        android:showAsAction=\"never\"\n" +
    436             "        android:title=\"@string/menu_settings\"/>\n" +
    437             "\n" +
    438             "</menu>";
    439 
    440     protected static final String SAMPLE_STRINGS =
    441             "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
    442             "<resources>\n" +
    443             "\n" +
    444             "    <string name=\"app_name\">RefactoringTest</string>\n" +
    445             "    <string name=\"hello_world\">Hello world!</string>\n" +
    446             "    <string name=\"menu_settings\">Settings</string>\n" +
    447             "\n" +
    448             "</resources>";
    449 
    450     protected static final String SAMPLE_STYLES =
    451             "<resources>\n" +
    452             "\n" +
    453             "    <!--\n" +
    454             "        Base application theme, dependent on API level. This theme is replaced\n" +
    455             "        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.\n" +
    456             "    -->\n" +
    457             "    <style name=\"AppBaseTheme\" parent=\"android:Theme.Light\">\n" +
    458             "        <!--\n" +
    459             "            Theme customizations available in newer API levels can go in\n" +
    460             "            res/values-vXX/styles.xml, while customizations related to\n" +
    461             "            backward-compatibility can go here.\n" +
    462             "        -->\n" +
    463             "    </style>\n" +
    464             "\n" +
    465             "    <!-- Application theme. -->\n" +
    466             "    <style name=\"AppTheme\" parent=\"AppBaseTheme\">\n" +
    467             "        <!-- All customizations that are NOT specific to a particular API-level can go here. -->\n" +
    468             "    </style>\n" +
    469             "\n" +
    470             "</resources>";
    471 
    472     protected static final String SAMPLE_R =
    473             "/* AUTO-GENERATED FILE.  DO NOT MODIFY.\n" +
    474             " *\n" +
    475             " * This class was automatically generated by the\n" +
    476             " * aapt tool from the resource data it found.  It\n" +
    477             " * should not be modified by hand.\n" +
    478             " */\n" +
    479             "\n" +
    480             "package com.example.refactoringtest;\n" +
    481             "\n" +
    482             "public final class R {\n" +
    483             "    public static final class attr {\n" +
    484             "    }\n" +
    485             "    public static final class drawable {\n" +
    486             "        public static final int ic_launcher=0x7f020000;\n" +
    487             "    }\n" +
    488             "    public static final class id {\n" +
    489             "        public static final int button1=0x7f070002;\n" +
    490             "        public static final int button2=0x7f070001;\n" +
    491             "        public static final int menu_settings=0x7f070003;\n" +
    492             "        public static final int textView1=0x7f070000;\n" +
    493             "    }\n" +
    494             "    public static final class layout {\n" +
    495             "        public static final int activity_main=0x7f030000;\n" +
    496             "    }\n" +
    497             "    public static final class menu {\n" +
    498             "        public static final int activity_main=0x7f060000;\n" +
    499             "    }\n" +
    500             "    public static final class string {\n" +
    501             "        public static final int app_name=0x7f040000;\n" +
    502             "        public static final int hello_world=0x7f040001;\n" +
    503             "        public static final int menu_settings=0x7f040002;\n" +
    504             "    }\n" +
    505             "    public static final class style {\n" +
    506             "        /** \n" +
    507             "        Base application theme, dependent on API level. This theme is replaced\n" +
    508             "        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.\n" +
    509             "    \n" +
    510             "\n" +
    511             "            Theme customizations available in newer API levels can go in\n" +
    512             "            res/values-vXX/styles.xml, while customizations related to\n" +
    513             "            backward-compatibility can go here.\n" +
    514             "        \n" +
    515             "\n" +
    516             "        Base application theme for API 11+. This theme completely replaces\n" +
    517             "        AppBaseTheme from res/values/styles.xml on API 11+ devices.\n" +
    518             "    \n" +
    519             " API 11 theme customizations can go here. \n" +
    520             "\n" +
    521             "        Base application theme for API 14+. This theme completely replaces\n" +
    522             "        AppBaseTheme from BOTH res/values/styles.xml and\n" +
    523             "        res/values-v11/styles.xml on API 14+ devices.\n" +
    524             "    \n" +
    525             " API 14 theme customizations can go here. \n" +
    526             "         */\n" +
    527             "        public static final int AppBaseTheme=0x7f050000;\n" +
    528             "        /**  Application theme. \n" +
    529             " All customizations that are NOT specific to a particular API-level can go here. \n" +
    530             "         */\n" +
    531             "        public static final int AppTheme=0x7f050001;\n" +
    532             "    }\n" +
    533             "}\n";
    534 
    535     protected static final Object[] TEST_PROJECT = new Object[] {
    536         "AndroidManifest.xml",
    537         SAMPLE_MANIFEST,
    538 
    539         "src/com/example/refactoringtest/MainActivity.java",
    540         SAMPLE_MAIN_ACTIVITY,
    541 
    542         "src/com/example/refactoringtest/MainActivity2.java",
    543         SAMPLE_MAIN_ACTIVITY2,
    544 
    545         "gen/com/example/refactoringtest/R.java",
    546         SAMPLE_R,
    547 
    548         "res/drawable-xhdpi/ic_launcher.png",
    549         new byte[] { 0 },
    550         "res/drawable-hdpi/ic_launcher.png",
    551         new byte[] { 0 },
    552         "res/drawable-ldpi/ic_launcher.png",
    553         new byte[] { 0 },
    554         "res/drawable-mdpi/ic_launcher.png",
    555         new byte[] { 0 },
    556 
    557         "res/layout/activity_main.xml",
    558         SAMPLE_LAYOUT,
    559 
    560         "res/layout-land/activity_main.xml",
    561         SAMPLE_LAYOUT_2,
    562 
    563         "res/menu/activity_main.xml",
    564         SAMPLE_MENU,
    565 
    566         "res/values/strings.xml",   // file 3
    567         SAMPLE_STRINGS,
    568 
    569         "res/values/styles.xml",   // file 3
    570         SAMPLE_STYLES,
    571     };
    572 
    573     // More test data
    574 
    575     protected static final String CUSTOM_VIEW_1 =
    576             "package com.example.refactoringtest;\n" +
    577             "\n" +
    578             "import android.content.Context;\n" +
    579             "import android.widget.Button;\n" +
    580             "\n" +
    581             "public class CustomView1 extends Button {\n" +
    582             "    public CustomView1(Context context) {\n" +
    583             "        super(context);\n" +
    584             "    }\n" +
    585             "}\n";
    586 
    587     protected static final String CUSTOM_VIEW_1_STYLES =
    588             "<resources>\n" +
    589             "\n" +
    590             "    <!-- Aattributes for the custom view -->\n" +
    591             "    <declare-styleable name=\"CustomView1\">\n" +
    592             "        <attr name=\"exampleString\" format=\"string\" />\n" +
    593             "        <attr name=\"exampleDimension\" format=\"dimension\" />\n" +
    594             "        <attr name=\"exampleColor\" format=\"color\" />\n" +
    595             "        <attr name=\"exampleDrawable\" format=\"color|reference\" />\n" +
    596             "    </declare-styleable>\n" +
    597             "\n" +
    598             "</resources>";
    599 
    600     protected static final String CUSTOM_VIEW_2 =
    601             "package com.example.refactoringtest.subpackage;\n" +
    602             "\n" +
    603             "import android.content.Context;\n" +
    604             "import android.widget.Button;\n" +
    605             "\n" +
    606             "public class CustomView2 extends Button {\n" +
    607             "    public CustomView2(Context context) {\n" +
    608             "        super(context);\n" +
    609             "    }\n" +
    610             "}\n";
    611 
    612     protected static final String CUSTOM_VIEW_LAYOUT =
    613             "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
    614             "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
    615             "    xmlns:tools=\"http://schemas.android.com/tools\"\n" +
    616             "    android:layout_width=\"match_parent\"\n" +
    617             "    android:layout_height=\"match_parent\"\n" +
    618             "    android:orientation=\"vertical\"\n" +
    619             "    tools:ignore=\"HardcodedText\" >\n" +
    620             "\n" +
    621             "    <com.example.refactoringtest.CustomView1\n" +
    622             "        android:id=\"@+id/customView1\"\n" +
    623             "        android:layout_width=\"wrap_content\"\n" +
    624             "        android:layout_height=\"wrap_content\"\n" +
    625             "        android:text=\"CustomView1\" />\n" +
    626             "\n" +
    627             "    <com.example.refactoringtest.subpackage.CustomView2\n" +
    628             "        android:id=\"@+id/customView2\"\n" +
    629             "        android:layout_width=\"wrap_content\"\n" +
    630             "        android:layout_height=\"wrap_content\"\n" +
    631             "        android:text=\"CustomView2\" />\n" +
    632             "\n" +
    633             "</LinearLayout>";
    634 
    635     protected static final Object[] TEST_PROJECT2 = new Object[] {
    636         "AndroidManifest.xml",
    637         SAMPLE_MANIFEST,
    638 
    639         "src/com/example/refactoringtest/MainActivity.java",
    640         SAMPLE_MAIN_ACTIVITY,
    641 
    642         "src/com/example/refactoringtest/CustomView1.java",
    643         CUSTOM_VIEW_1,
    644 
    645         "res/values/attrs_custom_view.xml",
    646         CUSTOM_VIEW_1_STYLES,
    647 
    648         "src/com/example/refactoringtest/subpackage/CustomView2.java",
    649         CUSTOM_VIEW_2,
    650 
    651         "src/com/example/refactoringtest/MyFragment.java",
    652         MY_FRAGMENT,
    653 
    654         "gen/com/example/refactoringtest/R.java",
    655         SAMPLE_R,
    656 
    657         "res/drawable-xhdpi/ic_launcher.png",
    658         new byte[] { 0 },
    659         "res/drawable-hdpi/ic_launcher.png",
    660         new byte[] { 0 },
    661         "res/drawable-ldpi/ic_launcher.png",
    662         new byte[] { 0 },
    663         "res/drawable-mdpi/ic_launcher.png",
    664         new byte[] { 0 },
    665 
    666         "res/layout/activity_main.xml",
    667         SAMPLE_LAYOUT,
    668 
    669         "res/layout-land/activity_main.xml",
    670         SAMPLE_LAYOUT_2,
    671 
    672         "res/layout/customviews.xml",
    673         CUSTOM_VIEW_LAYOUT,
    674 
    675         "res/layout-land/customviews.xml",
    676         CUSTOM_VIEW_LAYOUT,
    677 
    678         "res/menu/activity_main.xml",
    679         SAMPLE_MENU,
    680 
    681         "res/values/strings.xml",   // file 3
    682         SAMPLE_STRINGS,
    683 
    684         "res/values/styles.xml",   // file 3
    685         SAMPLE_STYLES,
    686 
    687         // Just a gen file, should not be refactored
    688         "bin/AndroidManifest.xml",
    689         SAMPLE_MANIFEST,
    690 
    691     };
    692 
    693 
    694     protected static final String MANIFEST =
    695             "/* AUTO-GENERATED FILE.  DO NOT MODIFY.\n" +
    696             " *\n" +
    697             " * This class was automatically generated by the\n" +
    698             " * aapt tool from the resource data it found.  It\n" +
    699             " * should not be modified by hand.\n" +
    700             " */\n" +
    701             "\n" +
    702             "package com.example.refactoringtest;\n" +
    703             "\n" +
    704             "public final class Manifest {\n" +
    705             "    public static final class permission {\n" +
    706             "        public static final String WRITE_SCHEDULE=\"com.example.refactoringtest.permission.WRITE_SCHEDULE\";\n" +
    707             "    }\n" +
    708             "}";
    709 
    710     protected static final String BUILD_CONFIG =
    711             "/** Automatically generated file. DO NOT MODIFY */\n" +
    712             "package com.example.refactoringtest;\n" +
    713             "\n" +
    714             "public final class BuildConfig {\n" +
    715             "    public final static boolean DEBUG = true;\n" +
    716             "}";
    717 
    718     protected static final String MORE_CODE_JAVA =
    719             "package com.example.refactoringtest.subpkg;\n" +
    720             "\n" +
    721             "import android.os.Bundle;\n" +
    722             "import android.app.Activity;\n" +
    723             "import android.view.Menu;\n" +
    724             "import android.view.View;\n" +
    725             "import com.example.refactoringtest.BuildConfig;\n" +
    726             "import com.example.refactoringtest.Manifest;\n" +
    727             "import com.example.refactoringtest.R;\n" +
    728             "\n" +
    729             "public class MoreCode extends Activity {\n" +
    730             "\n" +
    731             "    protected void code() {\n" +
    732             "        if (BuildConfig.DEBUG) {\n" +
    733             "            System.out.println(Manifest.permission);\n" +
    734             "        }" +
    735             "        System.out.println(com.example.refactoringtest.BuildConfig.DEBUG);\n" +
    736             "    }\n" +
    737             "\n" +
    738             "}\n";
    739 
    740     /** Project which includes references to BuildConfig, Manifest, and R */
    741     protected static final Object[] TEST_PROJECT3;
    742     static {
    743         Object[] additional = new Object[] {
    744                 "src/com/example/refactoringtest/subpkg/MoreCode.java",
    745                 MORE_CODE_JAVA,
    746 
    747                 "gen/com/example/refactoringtest/BuildConfig.java",
    748                 BUILD_CONFIG,
    749 
    750                 "gen/com/example/refactoringtest/Manifest.java",
    751                 MANIFEST,
    752         };
    753         TEST_PROJECT3 = new Object[TEST_PROJECT2.length + additional.length];
    754         System.arraycopy(TEST_PROJECT2, 0, TEST_PROJECT3, 0, TEST_PROJECT2.length);
    755         System.arraycopy(additional, 0, TEST_PROJECT3, TEST_PROJECT2.length, additional.length);
    756     };
    757 }
    758