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