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 */ 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 */ 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 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 196 protected TestRulesEngine(String fqn) { 197 mFqn = fqn; 198 } 199 200 @Override 201 public void debugPrintf(String msg, Object... params) { 202 fail("Not supported in tests yet"); 203 } 204 205 @Override 206 public void displayAlert(String message) { 207 fail("Not supported in tests yet"); 208 } 209 210 @Override 211 public String displayInput(String message, String value, IValidator filter) { 212 fail("Not supported in tests yet"); 213 return null; 214 } 215 216 @Override 217 public String getFqcn() { 218 return mFqn; 219 } 220 221 @Override 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 248 public int getMinApiLevel() { 249 return 8; 250 } 251 252 @Override 253 public IViewRule loadRule(String fqcn) { 254 fail("Not supported in tests yet"); 255 return null; 256 } 257 258 @Override 259 public String displayReferenceInput(String currentValue) { 260 fail("Not supported in tests yet"); 261 return null; 262 } 263 264 @Override 265 public IValidator getResourceValidator() { 266 fail("Not supported in tests yet"); 267 return null; 268 } 269 270 @Override 271 public String displayResourceInput(String resourceTypeName, String currentValue) { 272 fail("Not supported in tests yet"); 273 return null; 274 } 275 276 @Override 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 284 public String displayIncludeSourceInput() { 285 fail("Not supported in tests yet"); 286 return null; 287 } 288 289 @Override 290 public void select(Collection<INode> nodes) { 291 fail("Not supported in tests yet"); 292 } 293 294 @Override 295 public String displayFragmentSourceInput() { 296 fail("Not supported in tests yet"); 297 return null; 298 } 299 300 @Override 301 public void layout() { 302 fail("Not supported in tests yet"); 303 } 304 305 @Override 306 public void redraw() { 307 fail("Not supported in tests yet"); 308 } 309 310 @Override 311 public Map<INode, Rect> measureChildren(INode parent, AttributeFilter filter) { 312 return null; 313 } 314 315 @Override 316 public int pxToDp(int px) { 317 fail("Not supported in tests yet"); 318 return px; 319 } 320 321 @Override 322 public String getUniqueId(String prefix) { 323 fail("Not supported in tests yet"); 324 return null; 325 } 326 327 @Override 328 public int screenToLayout(int pixels) { 329 fail("Not supported in tests yet"); 330 return 0; 331 } 332 333 @Override 334 public int dpToPx(int dp) { 335 fail("Not supported in tests yet"); 336 return 0; 337 } 338 339 @Override 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