• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
checkRefactoring(Refactoring refactoring, String expected)54     protected void checkRefactoring(Refactoring refactoring, String expected) throws Exception {
55         checkRefactoring(refactoring, expected, null);
56     }
57 
58     @Override
setUp()59     protected void setUp() throws Exception {
60         // Not calling super.setUp
61     }
62 
checkRefactoring(Refactoring refactoring, String expected, @Nullable String expectedWarnings)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
getProject()95     protected IProject getProject() {
96         return mProject;
97     }
98 
createProject(Object[] testData)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 
describe(Change change)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 
describe(StringBuilder sb, Change change, int indent)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
getFile(@onNull Change change)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 
indent(StringBuilder sb, int indent)255     protected static void indent(StringBuilder sb, int indent) {
256         for (int i = 0; i < indent; i++) {
257             sb.append("  ");
258         }
259     }
260 
createTestDataDir(File dir, Object[] data)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];
System.arraycopy(TEST_PROJECT2, 0, TEST_PROJECT3, 0, TEST_PROJECT2.length)754         System.arraycopy(TEST_PROJECT2, 0, TEST_PROJECT3, 0, TEST_PROJECT2.length);
System.arraycopy(additional, 0, TEST_PROJECT3, TEST_PROJECT2.length, additional.length)755         System.arraycopy(additional, 0, TEST_PROJECT3, TEST_PROJECT2.length, additional.length);
756     };
757 }
758