Home | History | Annotate | Download | only in layout
      1 /*
      2  * Copyright (C) 2010 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 
     17 package com.android.ide.common.layout;
     18 
     19 import static com.android.SdkConstants.ANDROID_URI;
     20 import static com.android.SdkConstants.ATTR_ID;
     21 
     22 import com.android.annotations.NonNull;
     23 import com.android.annotations.Nullable;
     24 import com.android.ide.common.api.DropFeedback;
     25 import com.android.ide.common.api.IClientRulesEngine;
     26 import com.android.ide.common.api.IDragElement;
     27 import com.android.ide.common.api.INode;
     28 import com.android.ide.common.api.IValidator;
     29 import com.android.ide.common.api.IViewMetadata;
     30 import com.android.ide.common.api.IViewRule;
     31 import com.android.ide.common.api.Margins;
     32 import com.android.ide.common.api.Point;
     33 import com.android.ide.common.api.Rect;
     34 import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository;
     35 
     36 import java.util.ArrayList;
     37 import java.util.Collection;
     38 import java.util.Collections;
     39 import java.util.List;
     40 import java.util.Map;
     41 
     42 import junit.framework.TestCase;
     43 
     44 /**
     45  * Common layout helpers from LayoutRule tests
     46  */
     47 @SuppressWarnings("javadoc")
     48 public class LayoutTestBase extends TestCase {
     49     /**
     50      * Helper function used by tests to drag a button into a canvas containing
     51      * the given children.
     52      *
     53      * @param rule The rule to test on
     54      * @param targetNode The target layout node to drag into
     55      * @param dragBounds The (original) bounds of the dragged item
     56      * @param dropPoint The drag point we should drag to and drop
     57      * @param secondDropPoint An optional second drag point to drag to before
     58      *            drawing graphics and dropping (or null if not applicable)
     59      * @param insertIndex The expected insert position we end up with after
     60      *            dropping at the dropPoint
     61      * @param currentIndex If the dragged widget is already in the canvas this
     62      *            should be its child index; if not, pass in -1
     63      * @param graphicsFragments This is a varargs array of String fragments
     64      *            we expect to see in the graphics output on the drag over
     65      *            event.
     66      * @return The inserted node
     67      */
     68     protected INode dragInto(IViewRule rule, INode targetNode, Rect dragBounds, Point dropPoint,
     69             Point secondDropPoint, int insertIndex, int currentIndex,
     70             String... graphicsFragments) {
     71 
     72         String draggedButtonId = (currentIndex == -1) ? "@+id/DraggedButton" : targetNode
     73                 .getChildren()[currentIndex].getStringAttr(ANDROID_URI, ATTR_ID);
     74 
     75         IDragElement[] elements = TestDragElement.create(TestDragElement.create(
     76                 "android.widget.Button", dragBounds).id(draggedButtonId));
     77 
     78         // Enter target
     79         DropFeedback feedback = rule.onDropEnter(targetNode, null/*targetView*/, elements);
     80         assertNotNull(feedback);
     81         assertFalse(feedback.invalidTarget);
     82         assertNotNull(feedback.painter);
     83 
     84         if (currentIndex != -1) {
     85             feedback.sameCanvas = true;
     86         }
     87 
     88         // Move near top left corner of the target
     89         feedback = rule.onDropMove(targetNode, elements, feedback, dropPoint);
     90         assertNotNull(feedback);
     91 
     92         if (secondDropPoint != null) {
     93             feedback = rule.onDropMove(targetNode, elements, feedback, secondDropPoint);
     94             assertNotNull(feedback);
     95         }
     96 
     97         if (insertIndex == -1) {
     98             assertTrue(feedback.invalidTarget);
     99         } else {
    100             assertFalse(feedback.invalidTarget);
    101         }
    102 
    103         // Paint feedback and make sure it's what we expect
    104         TestGraphics graphics = new TestGraphics();
    105         assertNotNull(feedback.painter);
    106         feedback.painter.paint(graphics, targetNode, feedback);
    107         String drawn = graphics.getDrawn().toString();
    108 
    109         // Check that each graphics fragment is drawn
    110         for (String fragment : graphicsFragments) {
    111             if (!drawn.contains(fragment)) {
    112                 // Get drawn-output since unit test truncates message in below
    113                 // contains-assertion
    114                 System.out.println("Could not find: " + fragment);
    115                 System.out.println("Full graphics output: " + drawn);
    116             }
    117             assertTrue(fragment + " not found; full=" + drawn, drawn.contains(fragment));
    118         }
    119 
    120         // Attempt a drop?
    121         if (insertIndex == -1) {
    122             // No, not expected to succeed (for example, when drop point is over an
    123             // invalid region in RelativeLayout) - just return.
    124             return null;
    125         }
    126         int childrenCountBefore = targetNode.getChildren().length;
    127         rule.onDropped(targetNode, elements, feedback, dropPoint);
    128 
    129         if (currentIndex == -1) {
    130             // Inserting new from outside
    131             assertEquals(childrenCountBefore+1, targetNode.getChildren().length);
    132         } else {
    133             // Moving from existing; must remove in old position first
    134             ((TestNode) targetNode).removeChild(currentIndex);
    135 
    136             assertEquals(childrenCountBefore, targetNode.getChildren().length);
    137         }
    138         // Ensure that it's inserted in the right place
    139         String actualId = targetNode.getChildren()[insertIndex].getStringAttr(
    140                 ANDROID_URI, ATTR_ID);
    141         if (!draggedButtonId.equals(actualId)) {
    142             // Using assertEquals instead of fail to get nice diff view on test
    143             // failure
    144             List<String> childrenIds = new ArrayList<String>();
    145             for (INode child : targetNode.getChildren()) {
    146                 childrenIds.add(child.getStringAttr(ANDROID_URI, ATTR_ID));
    147             }
    148             int index = childrenIds.indexOf(draggedButtonId);
    149             String message = "Button found at index " + index + " instead of " + insertIndex
    150                     + " among " + childrenIds;
    151             System.out.println(message);
    152             assertEquals(message, draggedButtonId, actualId);
    153         }
    154 
    155 
    156         return targetNode.getChildren()[insertIndex];
    157     }
    158 
    159     /**
    160      * Utility method for asserting that two collections contain exactly the
    161      * same elements (regardless of order)
    162      * @param expected expected collection
    163      * @param actual  actual collection
    164      */
    165     public static void assertContainsSame(Collection<String> expected, Collection<String> actual) {
    166         if (expected.size() != actual.size()) {
    167             fail("Collection sizes differ; expected " + expected.size() + " but was "
    168                     + actual.size());
    169         }
    170 
    171         // Sort prior to comparison to ensure we have the same elements
    172         // regardless of order
    173         List<String> expectedList = new ArrayList<String>(expected);
    174         Collections.sort(expectedList);
    175         List<String> actualList = new ArrayList<String>(actual);
    176         Collections.sort(actualList);
    177         // Instead of just assertEquals(expectedList, actualList);
    178         // we iterate one element at a time so we can show the first
    179         // -difference-.
    180         for (int i = 0; i < expectedList.size(); i++) {
    181             String expectedElement = expectedList.get(i);
    182             String actualElement = actualList.get(i);
    183             if (!expectedElement.equals(actualElement)) {
    184                 System.out.println("Expected items: " + expectedList);
    185                 System.out.println("Actual items  : " + actualList);
    186             }
    187             assertEquals("Collections differ; first difference:", expectedElement, actualElement);
    188         }
    189     }
    190 
    191     protected void initialize(IViewRule rule, String fqn) {
    192         rule.onInitialize(fqn, new TestRulesEngine(fqn));
    193     }
    194 
    195     public static class TestRulesEngine implements IClientRulesEngine {
    196         private final String mFqn;
    197 
    198         public TestRulesEngine(String fqn) {
    199             mFqn = fqn;
    200         }
    201 
    202         @Override
    203         public void debugPrintf(@NonNull String msg, Object... params) {
    204             fail("Not supported in tests yet");
    205         }
    206 
    207         @Override
    208         public void displayAlert(@NonNull String message) {
    209             fail("Not supported in tests yet");
    210         }
    211 
    212         @Override
    213         public String displayInput(@NonNull String message, @Nullable String value,
    214                 @Nullable IValidator filter) {
    215             fail("Not supported in tests yet");
    216             return null;
    217         }
    218 
    219         @Override
    220         public @NonNull String getFqcn() {
    221             return mFqn;
    222         }
    223 
    224         @Override
    225         public @NonNull IViewMetadata getMetadata(final @NonNull String fqcn) {
    226             return new IViewMetadata() {
    227                 @Override
    228                 public @NonNull String getDisplayName() {
    229                     // This also works when there is no "."
    230                     return fqcn.substring(fqcn.lastIndexOf('.') + 1);
    231                 }
    232 
    233                 @Override
    234                 public @NonNull FillPreference getFillPreference() {
    235                     return ViewMetadataRepository.get().getFillPreference(fqcn);
    236                 }
    237 
    238                 @Override
    239                 public @NonNull Margins getInsets() {
    240                     return null;
    241                 }
    242 
    243                 @Override
    244                 public @NonNull List<String> getTopAttributes() {
    245                     return ViewMetadataRepository.get().getTopAttributes(fqcn);
    246                 }
    247             };
    248         }
    249 
    250         @Override
    251         public int getMinApiLevel() {
    252             return 8;
    253         }
    254 
    255         @Override
    256         public IViewRule loadRule(@NonNull String fqcn) {
    257             fail("Not supported in tests yet");
    258             return null;
    259         }
    260 
    261         @Override
    262         public String displayReferenceInput(String currentValue) {
    263             fail("Not supported in tests yet");
    264             return null;
    265         }
    266 
    267         @Override
    268         public IValidator getResourceValidator(String resourceTypeName, boolean uniqueInProject,
    269                 boolean uniqueInLayout, boolean exists, String... allowed) {
    270             fail("Not supported in tests yet");
    271             return null;
    272         }
    273 
    274         @Override
    275         public String displayResourceInput(@NonNull String resourceTypeName,
    276                 @Nullable String currentValue) {
    277             fail("Not supported in tests yet");
    278             return null;
    279         }
    280 
    281         @Override
    282         public String[] displayMarginInput(@Nullable String all, @Nullable String left,
    283                 @Nullable String right, @Nullable String top, @Nullable String bottom) {
    284             fail("Not supported in tests yet");
    285             return null;
    286         }
    287 
    288         @Override
    289         public String displayIncludeSourceInput() {
    290             fail("Not supported in tests yet");
    291             return null;
    292         }
    293 
    294         @Override
    295         public void select(@NonNull Collection<INode> nodes) {
    296             fail("Not supported in tests yet");
    297         }
    298 
    299         @Override
    300         public String displayFragmentSourceInput() {
    301             fail("Not supported in tests yet");
    302             return null;
    303         }
    304 
    305         @Override
    306         public void layout() {
    307             fail("Not supported in tests yet");
    308         }
    309 
    310         @Override
    311         public void redraw() {
    312             fail("Not supported in tests yet");
    313         }
    314 
    315         @Override
    316         public Map<INode, Rect> measureChildren(@NonNull INode parent,
    317                 @Nullable AttributeFilter filter) {
    318             return null;
    319         }
    320 
    321         @Override
    322         public int pxToDp(int px) {
    323             // Arbitrary conversion
    324             return px / 3;
    325         }
    326 
    327         @Override
    328         public int dpToPx(int dp) {
    329             // Arbitrary conversion
    330             return 3 * dp;
    331         }
    332 
    333         @Override
    334         public @NonNull String getUniqueId(@NonNull String prefix) {
    335             fail("Not supported in tests yet");
    336             return null;
    337         }
    338 
    339         @Override
    340         public int screenToLayout(int pixels) {
    341             fail("Not supported in tests yet");
    342             return pixels;
    343         }
    344 
    345         @Override
    346         public @NonNull String getAppNameSpace() {
    347             fail("Not supported in tests yet");
    348             return null;
    349         }
    350 
    351         @Override
    352         public @Nullable Object getViewObject(@NonNull INode node) {
    353             fail("Not supported in tests yet");
    354             return null;
    355         }
    356 
    357         @Override
    358         public boolean rename(INode node) {
    359             fail("Not supported in tests yet");
    360             return false;
    361         }
    362 
    363         @Override
    364         @Nullable
    365         public String displayCustomViewClassInput() {
    366             fail("Not supported in tests yet");
    367             return null;
    368         }
    369     }
    370 
    371     public void testDummy() {
    372         // To avoid JUnit warning that this class contains no tests, even though
    373         // this is an abstract class and JUnit shouldn't try
    374     }
    375 }
    376