1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.ide.eclipse.adt.internal.editors.layout.refactoring; 17 18 import static com.android.AndroidConstants.FD_RES_LAYOUT; 19 import static com.android.AndroidConstants.FD_RES_VALUES; 20 import static com.android.sdklib.SdkConstants.FD_RES; 21 22 import com.android.ide.eclipse.adt.AdtPlugin; 23 import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor; 24 import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; 25 import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; 26 import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate; 27 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; 28 import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; 29 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode; 30 import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; 31 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectCreator; 32 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState; 33 import com.android.ide.eclipse.adt.internal.wizards.newproject.NewProjectWizardState.Mode; 34 import com.android.ide.eclipse.tests.SdkTestCase; 35 import com.android.sdklib.IAndroidTarget; 36 import com.android.sdklib.SdkConstants; 37 38 import org.eclipse.core.resources.IContainer; 39 import org.eclipse.core.resources.IFile; 40 import org.eclipse.core.resources.IFolder; 41 import org.eclipse.core.resources.IProject; 42 import org.eclipse.core.resources.ResourcesPlugin; 43 import org.eclipse.core.runtime.NullProgressMonitor; 44 import org.eclipse.core.runtime.Path; 45 import org.eclipse.jface.operation.IRunnableContext; 46 import org.eclipse.jface.operation.IRunnableWithProgress; 47 import org.eclipse.jface.text.source.ISourceViewer; 48 import org.eclipse.swt.graphics.Point; 49 import org.eclipse.wst.sse.core.StructuredModelManager; 50 import org.eclipse.wst.sse.core.internal.provisional.IModelManager; 51 import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; 52 import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; 53 54 import java.io.BufferedReader; 55 import java.io.ByteArrayInputStream; 56 import java.io.File; 57 import java.io.InputStream; 58 import java.io.InputStreamReader; 59 import java.lang.reflect.InvocationTargetException; 60 import java.util.Calendar; 61 import java.util.HashMap; 62 import java.util.Map; 63 64 @SuppressWarnings({"restriction", "javadoc"}) 65 public class AdtProjectTest extends SdkTestCase { 66 private static final int TARGET_API_LEVEL = 12; 67 public static final String TEST_PROJECT_PACKAGE = "com.android.eclipse.tests"; //$NON-NLS-1$ 68 69 /** Update golden files if different from the actual results */ 70 private static final boolean UPDATE_DIFFERENT_FILES = false; 71 /** Create golden files if missing */ 72 private static final boolean UPDATE_MISSING_FILES = true; 73 private static final String TEST_DATA_REL_PATH = 74 "eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/" 75 + "internal/editors/layout/refactoring/testdata"; 76 private static final String PROJECTNAME_PREFIX = "testproject-"; 77 private static final long TESTS_START_TIME = System.currentTimeMillis(); 78 private static File sTempDir = null; 79 80 /** 81 * We don't stash the project used by each test case as a field such that test cases 82 * can share a single project instance (which is typically much faster). 83 * However, see {@link #getProjectName()} for exceptions to this sharing scheme. 84 */ 85 private static Map<String, IProject> sProjectMap = new HashMap<String, IProject>(); 86 87 @Override setUp()88 protected void setUp() throws Exception { 89 super.setUp(); 90 91 // Prevent preview icon computation during plugin test to make test faster 92 if (AdtPlugin.getDefault() == null) { 93 fail("This test must be run as an Eclipse plugin test, not a plain JUnit test!"); 94 } 95 AdtPrefs.getPrefs().setPaletteModes("ICON_TEXT"); //$NON-NLS-1$ 96 97 getProject(); 98 } 99 100 /** Set to true if the subclass test case should use a per-instance project rather 101 * than a shared project. This is needed by projects which modify the project in such 102 * a way that it affects what other tests see (for example, the quickfix resource creation 103 * tests will add in new resources, which the code completion tests will then list as 104 * possible matches if the code completion test is run after the quickfix test.) 105 * @return true to create a per-instance project instead of the default shared project 106 */ testCaseNeedsUniqueProject()107 protected boolean testCaseNeedsUniqueProject() { 108 return false; 109 } 110 testNeedsUniqueProject()111 protected boolean testNeedsUniqueProject() { 112 return false; 113 } 114 115 @Override validateSdk(IAndroidTarget target)116 protected boolean validateSdk(IAndroidTarget target) { 117 // Not quite working yet. When enabled will make tests run faster. 118 //if (target.getVersion().getApiLevel() < TARGET_API_LEVEL) { 119 // return false; 120 //} 121 122 return true; 123 } 124 125 /** Returns a name to use for the project used in this test. Subclasses do not need to 126 * override this if they can share a project with others - which is the case if they do 127 * not modify the project in a way that does not affect other tests. For example 128 * the resource quickfix test will create new resources which affect what shows up 129 * in the code completion results, so the quickfix tests will override this method 130 * to produce a unique project for its own tests. 131 */ getProjectName()132 private String getProjectName() { 133 if (testNeedsUniqueProject()) { 134 return PROJECTNAME_PREFIX + getClass().getSimpleName() + "-" + getName(); 135 } else if (testCaseNeedsUniqueProject()) { 136 return PROJECTNAME_PREFIX + getClass().getSimpleName(); 137 } else { 138 return PROJECTNAME_PREFIX + TESTS_START_TIME; 139 } 140 } 141 getProject()142 protected IProject getProject() { 143 String projectName = getProjectName(); 144 IProject project = sProjectMap.get(projectName); 145 if (project == null) { 146 project = createProject(projectName); 147 assertNotNull(project); 148 sProjectMap.put(projectName, project); 149 } 150 151 return project; 152 } 153 getTestDataFile(IProject project, String name)154 protected IFile getTestDataFile(IProject project, String name) throws Exception { 155 return getTestDataFile(project, name, name); 156 } 157 getLayoutFile(IProject project, String name)158 protected IFile getLayoutFile(IProject project, String name) throws Exception { 159 return getTestDataFile(project, name, FD_RES + "/" + FD_RES_LAYOUT + "/" + name); 160 } 161 getValueFile(IProject project, String name)162 protected IFile getValueFile(IProject project, String name) throws Exception { 163 return getTestDataFile(project, name, FD_RES + "/" + FD_RES_VALUES + "/" + name); 164 } 165 getTestDataFile(IProject project, String sourceName, String destPath)166 protected IFile getTestDataFile(IProject project, String sourceName, 167 String destPath) throws Exception { 168 return getTestDataFile(project, sourceName, destPath, false); 169 } 170 getTestDataFile(IProject project, String sourceName, String destPath, boolean overwrite)171 protected IFile getTestDataFile(IProject project, String sourceName, 172 String destPath, boolean overwrite) throws Exception { 173 String[] split = destPath.split("/"); //$NON-NLS-1$ 174 IContainer parent; 175 String name; 176 if (split.length == 1) { 177 parent = project; 178 name = destPath; 179 } else { 180 IFolder folder = project.getFolder(split[0]); 181 NullProgressMonitor monitor = new NullProgressMonitor(); 182 if (!folder.exists()) { 183 folder.create(true /* force */, true /* local */, monitor); 184 } 185 for (int i = 1, n = split.length; i < n -1; i++) { 186 IFolder subFolder = folder.getFolder(split[i]); 187 if (!subFolder.exists()) { 188 subFolder.create(true /* force */, true /* local */, monitor); 189 } 190 folder = subFolder; 191 } 192 name = split[split.length - 1]; 193 parent = folder; 194 } 195 IFile file = parent.getFile(new Path(name)); 196 if (overwrite && file.exists()) { 197 String currentContents = AdtPlugin.readFile(file); 198 String newContents = readTestFile(sourceName, true); 199 if (currentContents == null || !currentContents.equals(newContents)) { 200 file.delete(true, new NullProgressMonitor()); 201 } else { 202 return file; 203 } 204 } 205 if (!file.exists()) { 206 String xml = readTestFile(sourceName, true); 207 InputStream bstream = new ByteArrayInputStream(xml.getBytes("UTF-8")); //$NON-NLS-1$ 208 NullProgressMonitor monitor = new NullProgressMonitor(); 209 file.create(bstream, false /* force */, monitor); 210 } 211 212 return file; 213 } 214 createProject(String name)215 protected IProject createProject(String name) { 216 IAndroidTarget target = null; 217 218 IAndroidTarget[] targets = getSdk().getTargets(); 219 for (IAndroidTarget t : targets) { 220 if (t.getVersion().getApiLevel() >= TARGET_API_LEVEL) { 221 target = t; 222 break; 223 } 224 } 225 assertNotNull(target); 226 227 228 IRunnableContext context = new IRunnableContext() { 229 @Override 230 public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) 231 throws InvocationTargetException, InterruptedException { 232 runnable.run(new NullProgressMonitor()); 233 } 234 }; 235 NewProjectWizardState state = new NewProjectWizardState(Mode.ANY); 236 state.projectName = name; 237 state.target = target; 238 state.packageName = TEST_PROJECT_PACKAGE; 239 state.activityName = name; 240 state.applicationName = name; 241 state.createActivity = false; 242 state.useDefaultLocation = true; 243 244 NewProjectCreator creator = new NewProjectCreator(state, context); 245 creator.createAndroidProjects(); 246 return validateProjectExists(name); 247 } 248 createTestProject()249 public void createTestProject() { 250 IAndroidTarget target = null; 251 252 IAndroidTarget[] targets = getSdk().getTargets(); 253 for (IAndroidTarget t : targets) { 254 if (t.getVersion().getApiLevel() >= TARGET_API_LEVEL) { 255 target = t; 256 break; 257 } 258 } 259 assertNotNull(target); 260 } 261 validateProjectExists(String name)262 private static IProject validateProjectExists(String name) { 263 IProject iproject = getProject(name); 264 assertTrue(String.format("%s project not created", name), iproject.exists()); 265 assertTrue(String.format("%s project not opened", name), iproject.isOpen()); 266 return iproject; 267 } 268 getProject(String name)269 private static IProject getProject(String name) { 270 IProject iproject = ResourcesPlugin.getWorkspace().getRoot() 271 .getProject(name); 272 return iproject; 273 } 274 getCaretOffset(IFile file, String caretLocation)275 protected int getCaretOffset(IFile file, String caretLocation) { 276 assertTrue(caretLocation, caretLocation.contains("^")); 277 278 String fileContent = AdtPlugin.readFile(file); 279 return getCaretOffset(fileContent, caretLocation); 280 } 281 getCaretOffset(String fileContent, String caretLocation)282 protected int getCaretOffset(String fileContent, String caretLocation) { 283 assertTrue(caretLocation, caretLocation.contains("^")); //$NON-NLS-1$ 284 285 int caretDelta = caretLocation.indexOf("^"); //$NON-NLS-1$ 286 assertTrue(caretLocation, caretDelta != -1); 287 288 // String around caret/range without the range and caret marker characters 289 String caretContext; 290 if (caretLocation.contains("[^")) { //$NON-NLS-1$ 291 caretDelta--; 292 assertTrue(caretLocation, caretLocation.startsWith("[^", caretDelta)); //$NON-NLS-1$ 293 int caretRangeEnd = caretLocation.indexOf(']', caretDelta + 2); 294 assertTrue(caretLocation, caretRangeEnd != -1); 295 caretContext = caretLocation.substring(0, caretDelta) 296 + caretLocation.substring(caretDelta + 2, caretRangeEnd) 297 + caretLocation.substring(caretRangeEnd + 1); 298 } else { 299 caretContext = caretLocation.substring(0, caretDelta) 300 + caretLocation.substring(caretDelta + 1); // +1: skip "^" 301 } 302 303 int caretContextIndex = fileContent.indexOf(caretContext); 304 assertTrue("Caret content " + caretContext + " not found in file", 305 caretContextIndex != -1); 306 return caretContextIndex + caretDelta; 307 } 308 309 /** 310 * If the given caret location string contains a selection range, select that range in 311 * the given viewer 312 * 313 * @param viewer the viewer to contain the selection 314 * @param caretLocation the location string 315 */ updateCaret(ISourceViewer viewer, String caretLocation)316 protected int updateCaret(ISourceViewer viewer, String caretLocation) { 317 assertTrue(caretLocation, caretLocation.contains("^")); //$NON-NLS-1$ 318 319 int caretDelta = caretLocation.indexOf("^"); //$NON-NLS-1$ 320 assertTrue(caretLocation, caretDelta != -1); 321 String text = viewer.getTextWidget().getText(); 322 323 int length = 0; 324 325 // String around caret/range without the range and caret marker characters 326 String caretContext; 327 328 if (caretLocation.contains("[^")) { //$NON-NLS-1$ 329 caretDelta--; 330 assertTrue(caretLocation, caretLocation.startsWith("[^", caretDelta)); //$NON-NLS-1$ 331 332 int caretRangeEnd = caretLocation.indexOf(']', caretDelta + 2); 333 assertTrue(caretLocation, caretRangeEnd != -1); 334 length = caretRangeEnd - caretDelta - 2; 335 assertTrue(length > 0); 336 caretContext = caretLocation.substring(0, caretDelta) 337 + caretLocation.substring(caretDelta + 2, caretRangeEnd) 338 + caretLocation.substring(caretRangeEnd + 1); 339 } else { 340 caretContext = caretLocation.substring(0, caretDelta) 341 + caretLocation.substring(caretDelta + 1); // +1: skip "^" 342 } 343 344 int caretContextIndex = text.indexOf(caretContext); 345 346 assertTrue("Caret content " + caretContext + " not found in file", 347 caretContextIndex != -1); 348 349 int offset = caretContextIndex + caretDelta; 350 viewer.setSelectedRange(offset, length); 351 352 return offset; 353 } 354 addSelection(String newFileContents, Point selectedRange)355 protected String addSelection(String newFileContents, Point selectedRange) { 356 int selectionBegin = selectedRange.x; 357 int selectionEnd = selectionBegin + selectedRange.y; 358 return addSelection(newFileContents, selectionBegin, selectionEnd); 359 } 360 addSelection(String newFileContents, int selectionBegin, int selectionEnd)361 protected String addSelection(String newFileContents, int selectionBegin, int selectionEnd) { 362 // Insert selection markers -- [ ] for the selection range, ^ for the caret 363 String newFileWithCaret; 364 if (selectionBegin < selectionEnd) { 365 newFileWithCaret = newFileContents.substring(0, selectionBegin) + "[^" 366 + newFileContents.substring(selectionBegin, selectionEnd) + "]" 367 + newFileContents.substring(selectionEnd); 368 } else { 369 // Selected range 370 newFileWithCaret = newFileContents.substring(0, selectionBegin) + "^" 371 + newFileContents.substring(selectionBegin); 372 } 373 374 return newFileWithCaret; 375 } 376 getCaretContext(String file, int offset)377 protected String getCaretContext(String file, int offset) { 378 int windowSize = 20; 379 int begin = Math.max(0, offset - windowSize / 2); 380 int end = Math.min(file.length(), offset + windowSize / 2); 381 382 return "..." + file.substring(begin, offset) + "^" + file.substring(offset, end) + "..."; 383 } 384 385 /** 386 * Very primitive line differ, intended for files where there are very minor changes 387 * (such as code completion apply-tests) 388 */ getDiff(String before, String after)389 protected String getDiff(String before, String after) { 390 // Do line by line analysis 391 String[] beforeLines = before.split("\n"); 392 String[] afterLines = after.split("\n"); 393 394 int firstDelta = 0; 395 for (; firstDelta < Math.min(beforeLines.length, afterLines.length); firstDelta++) { 396 if (!beforeLines[firstDelta].equals(afterLines[firstDelta])) { 397 break; 398 } 399 } 400 401 if (firstDelta == beforeLines.length && firstDelta == afterLines.length) { 402 return ""; 403 } 404 405 // Counts from the end of both arrays 406 int lastDelta = 0; 407 for (; lastDelta < Math.min(beforeLines.length, afterLines.length); lastDelta++) { 408 if (!beforeLines[beforeLines.length - 1 - lastDelta].equals( 409 afterLines[afterLines.length - 1 - lastDelta])) { 410 break; 411 } 412 } 413 414 415 boolean showBeforeWindow = firstDelta >= beforeLines.length - lastDelta; 416 boolean showAfterWindow = firstDelta >= afterLines.length - lastDelta; 417 418 StringBuilder sb = new StringBuilder(); 419 if (showAfterWindow && firstDelta > 0) { 420 sb.append(" "); 421 sb.append(afterLines[firstDelta - 1]); 422 sb.append('\n'); 423 } 424 for (int i = firstDelta; i < beforeLines.length - lastDelta; i++) { 425 sb.append("<"); 426 if (beforeLines[i].length() > 0) { 427 sb.append(" "); 428 } 429 sb.append(beforeLines[i]); 430 sb.append('\n'); 431 } 432 if (showAfterWindow && lastDelta < afterLines.length - 1) { 433 sb.append(" "); 434 sb.append(afterLines[afterLines.length - (lastDelta -1)]); 435 sb.append('\n'); 436 } 437 438 sb.append("---\n"); 439 440 if (showBeforeWindow && firstDelta > 0) { 441 sb.append(" "); 442 sb.append(beforeLines[firstDelta - 1]); 443 sb.append('\n'); 444 } 445 for (int i = firstDelta; i < afterLines.length - lastDelta; i++) { 446 sb.append(">"); 447 if (afterLines[i].length() > 0) { 448 sb.append(" "); 449 } 450 sb.append(afterLines[i]); 451 sb.append('\n'); 452 } 453 if (showBeforeWindow && lastDelta < beforeLines.length - 1) { 454 sb.append(" "); 455 sb.append(beforeLines[beforeLines.length - (lastDelta -1)]); 456 sb.append('\n'); 457 } 458 459 return sb.toString(); 460 } 461 removeSessionData(String data)462 protected String removeSessionData(String data) { 463 if (getProject() != null) { 464 data = data.replace(getProject().getName(), "PROJECTNAME"); 465 } 466 467 return data; 468 } 469 createDesc(String name, String fqn, boolean hasChildren)470 public static ViewElementDescriptor createDesc(String name, String fqn, boolean hasChildren) { 471 if (hasChildren) { 472 return new ViewElementDescriptor(name, name, fqn, "", "", new AttributeDescriptor[0], 473 new AttributeDescriptor[0], new ElementDescriptor[1], false); 474 } else { 475 return new ViewElementDescriptor(name, fqn); 476 } 477 } 478 createNode(UiViewElementNode parent, String fqn, boolean hasChildren)479 public static UiViewElementNode createNode(UiViewElementNode parent, String fqn, 480 boolean hasChildren) { 481 String name = fqn.substring(fqn.lastIndexOf('.') + 1); 482 ViewElementDescriptor descriptor = createDesc(name, fqn, hasChildren); 483 if (parent == null) { 484 // All node hierarchies should be wrapped inside a document node at the root 485 parent = new UiViewElementNode(createDesc("doc", "doc", true)); 486 } 487 return (UiViewElementNode) parent.appendNewUiChild(descriptor); 488 } 489 createNode(String fqn, boolean hasChildren)490 public static UiViewElementNode createNode(String fqn, boolean hasChildren) { 491 return createNode(null, fqn, hasChildren); 492 } 493 readTestFile(String relativePath, boolean expectExists)494 protected String readTestFile(String relativePath, boolean expectExists) { 495 String path = "testdata" + File.separator + relativePath; //$NON-NLS-1$ 496 InputStream stream = 497 AdtProjectTest.class.getResourceAsStream(path); 498 if (!expectExists && stream == null) { 499 return null; 500 } 501 502 assertNotNull(relativePath + " does not exist", stream); 503 504 BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); 505 String xml = AdtPlugin.readFile(reader); 506 assertNotNull(xml); 507 assertTrue(xml.length() > 0); 508 509 // Remove any references to the project name such that we are isolated from 510 // that in golden file. 511 // Appears in strings.xml etc. 512 xml = removeSessionData(xml); 513 514 return xml; 515 } 516 assertEqualsGolden(String basename, String actual)517 protected void assertEqualsGolden(String basename, String actual) { 518 assertEqualsGolden(basename, actual, basename.substring(basename.lastIndexOf('.') + 1)); 519 } 520 assertEqualsGolden(String basename, String actual, String newExtension)521 protected void assertEqualsGolden(String basename, String actual, String newExtension) { 522 String testName = getName(); 523 if (testName.startsWith("test")) { 524 testName = testName.substring(4); 525 if (Character.isUpperCase(testName.charAt(0))) { 526 testName = Character.toLowerCase(testName.charAt(0)) + testName.substring(1); 527 } 528 } 529 String expectedName; 530 String extension = basename.substring(basename.lastIndexOf('.') + 1); 531 if (newExtension == null) { 532 newExtension = extension; 533 } 534 expectedName = basename.substring(0, basename.indexOf('.')) 535 + "-expected-" + testName + '.' + newExtension; 536 String expected = readTestFile(expectedName, false); 537 if (expected == null) { 538 File expectedPath = new File( 539 UPDATE_MISSING_FILES ? getTargetDir() : getTempDir(), expectedName); 540 AdtPlugin.writeFile(expectedPath, actual); 541 System.out.println("Expected - written to " + expectedPath + ":\n"); 542 System.out.println(actual); 543 fail("Did not find golden file (" + expectedName + "): Wrote contents as " 544 + expectedPath); 545 } else { 546 if (!expected.replaceAll("\r\n", "\n").equals(actual.replaceAll("\r\n", "\n"))) { 547 File expectedPath = new File(getTempDir(), expectedName); 548 File actualPath = new File(getTempDir(), 549 expectedName.replace("expected", "actual")); 550 AdtPlugin.writeFile(expectedPath, expected); 551 AdtPlugin.writeFile(actualPath, actual); 552 // Also update data dir with the current value 553 if (UPDATE_DIFFERENT_FILES) { 554 AdtPlugin.writeFile( new File(getTargetDir(), expectedName), actual); 555 } 556 System.out.println("The files differ: diff " + expectedPath + " " 557 + actualPath); 558 assertEquals("The files differ - see " + expectedPath + " versus " + actualPath, 559 expected, actual); 560 } 561 } 562 } 563 564 /** Get the location to write missing golden files to */ getTargetDir()565 protected File getTargetDir() { 566 // Set $ADT_SDK_SOURCE_PATH to point to your git "sdk" directory; if done, then 567 // if you run a unit test which refers to a golden file which does not exist, it 568 // will be created directly into the test data directory and you can rerun the 569 // test 570 // and it should pass (after you verify that the golden file contains the correct 571 // result of course). 572 String sdk = System.getenv("ADT_SDK_SOURCE_PATH"); 573 if (sdk != null) { 574 File sdkPath = new File(sdk); 575 if (sdkPath.exists()) { 576 File testData = new File(sdkPath, TEST_DATA_REL_PATH.replace('/', 577 File.separatorChar)); 578 if (testData.exists()) { 579 return testData; 580 } 581 } 582 } 583 return getTempDir(); 584 } 585 getTempDir()586 protected File getTempDir() { 587 if (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_DARWIN) { 588 return new File("/tmp"); //$NON-NLS-1$ 589 } 590 591 if (sTempDir == null) { 592 // On Windows, we don't want to pollute the temp folder (which is generally 593 // already incredibly busy). So let's create a temp folder for the results. 594 595 File base = new File(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$ 596 597 Calendar c = Calendar.getInstance(); 598 String name = String.format("adtTests_%1$tF_%1$tT", c).replace(':', '-'); //$NON-NLS-1$ 599 File tmpDir = new File(base, name); 600 if (!tmpDir.exists() && tmpDir.mkdir()) { 601 sTempDir = tmpDir; 602 } else { 603 sTempDir = base; 604 } 605 } 606 607 return sTempDir; 608 } 609 610 /** Special editor context set on the model to be rendered */ 611 protected static class TestLayoutEditorDelegate extends LayoutEditorDelegate { 612 TestLayoutEditorDelegate( IFile file, IStructuredDocument structuredDocument, UiDocumentNode uiRootNode)613 public TestLayoutEditorDelegate( 614 IFile file, 615 IStructuredDocument structuredDocument, 616 UiDocumentNode uiRootNode) { 617 super(new TestAndroidXmlCommonEditor(file, structuredDocument, uiRootNode)); 618 } 619 620 static class TestAndroidXmlCommonEditor extends CommonXmlEditor { 621 622 private final IFile mFile; 623 private final IStructuredDocument mStructuredDocument; 624 private UiDocumentNode mUiRootNode; 625 TestAndroidXmlCommonEditor( IFile file, IStructuredDocument structuredDocument, UiDocumentNode uiRootNode)626 TestAndroidXmlCommonEditor( 627 IFile file, 628 IStructuredDocument structuredDocument, 629 UiDocumentNode uiRootNode) { 630 mFile = file; 631 mStructuredDocument = structuredDocument; 632 mUiRootNode = uiRootNode; 633 } 634 635 @Override getInputFile()636 public IFile getInputFile() { 637 return mFile; 638 } 639 640 @Override getProject()641 public IProject getProject() { 642 return mFile.getProject(); 643 } 644 645 @Override getStructuredDocument()646 public IStructuredDocument getStructuredDocument() { 647 return mStructuredDocument; 648 } 649 650 @Override getUiRootNode()651 public UiDocumentNode getUiRootNode() { 652 return mUiRootNode; 653 } 654 655 @Override editorDirtyStateChanged()656 public void editorDirtyStateChanged() { 657 } 658 659 @Override getModelForRead()660 public IStructuredModel getModelForRead() { 661 IModelManager mm = StructuredModelManager.getModelManager(); 662 if (mm != null) { 663 try { 664 return mm.getModelForRead(mFile); 665 } catch (Exception e) { 666 fail(e.toString()); 667 } 668 } 669 670 return null; 671 } 672 } 673 } 674 testDummy()675 public void testDummy() { 676 // This class contains shared test functionality for testcase subclasses, 677 // but without an actual test in the class JUnit complains (even if we make 678 // it abstract) 679 } 680 } 681