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