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