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