blob: 4b4bb814abd928dd31439abe1258fa0c2f80d0f6 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.ide.common.layout;
import static com.android.SdkConstants.ANDROID_URI;
import static com.android.SdkConstants.ATTR_ID;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.common.api.DropFeedback;
import com.android.ide.common.api.IClientRulesEngine;
import com.android.ide.common.api.IDragElement;
import com.android.ide.common.api.INode;
import com.android.ide.common.api.IValidator;
import com.android.ide.common.api.IViewMetadata;
import com.android.ide.common.api.IViewRule;
import com.android.ide.common.api.Margins;
import com.android.ide.common.api.Point;
import com.android.ide.common.api.Rect;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
/**
* Common layout helpers from LayoutRule tests
*/
@SuppressWarnings("javadoc")
public class LayoutTestBase extends TestCase {
/**
* Helper function used by tests to drag a button into a canvas containing
* the given children.
*
* @param rule The rule to test on
* @param targetNode The target layout node to drag into
* @param dragBounds The (original) bounds of the dragged item
* @param dropPoint The drag point we should drag to and drop
* @param secondDropPoint An optional second drag point to drag to before
* drawing graphics and dropping (or null if not applicable)
* @param insertIndex The expected insert position we end up with after
* dropping at the dropPoint
* @param currentIndex If the dragged widget is already in the canvas this
* should be its child index; if not, pass in -1
* @param graphicsFragments This is a varargs array of String fragments
* we expect to see in the graphics output on the drag over
* event.
* @return The inserted node
*/
protected INode dragInto(IViewRule rule, INode targetNode, Rect dragBounds, Point dropPoint,
Point secondDropPoint, int insertIndex, int currentIndex,
String... graphicsFragments) {
String draggedButtonId = (currentIndex == -1) ? "@+id/DraggedButton" : targetNode
.getChildren()[currentIndex].getStringAttr(ANDROID_URI, ATTR_ID);
IDragElement[] elements = TestDragElement.create(TestDragElement.create(
"android.widget.Button", dragBounds).id(draggedButtonId));
// Enter target
DropFeedback feedback = rule.onDropEnter(targetNode, null/*targetView*/, elements);
assertNotNull(feedback);
assertFalse(feedback.invalidTarget);
assertNotNull(feedback.painter);
if (currentIndex != -1) {
feedback.sameCanvas = true;
}
// Move near top left corner of the target
feedback = rule.onDropMove(targetNode, elements, feedback, dropPoint);
assertNotNull(feedback);
if (secondDropPoint != null) {
feedback = rule.onDropMove(targetNode, elements, feedback, secondDropPoint);
assertNotNull(feedback);
}
if (insertIndex == -1) {
assertTrue(feedback.invalidTarget);
} else {
assertFalse(feedback.invalidTarget);
}
// Paint feedback and make sure it's what we expect
TestGraphics graphics = new TestGraphics();
assertNotNull(feedback.painter);
feedback.painter.paint(graphics, targetNode, feedback);
String drawn = graphics.getDrawn().toString();
// Check that each graphics fragment is drawn
for (String fragment : graphicsFragments) {
if (!drawn.contains(fragment)) {
// Get drawn-output since unit test truncates message in below
// contains-assertion
System.out.println("Could not find: " + fragment);
System.out.println("Full graphics output: " + drawn);
}
assertTrue(fragment + " not found; full=" + drawn, drawn.contains(fragment));
}
// Attempt a drop?
if (insertIndex == -1) {
// No, not expected to succeed (for example, when drop point is over an
// invalid region in RelativeLayout) - just return.
return null;
}
int childrenCountBefore = targetNode.getChildren().length;
rule.onDropped(targetNode, elements, feedback, dropPoint);
if (currentIndex == -1) {
// Inserting new from outside
assertEquals(childrenCountBefore+1, targetNode.getChildren().length);
} else {
// Moving from existing; must remove in old position first
((TestNode) targetNode).removeChild(currentIndex);
assertEquals(childrenCountBefore, targetNode.getChildren().length);
}
// Ensure that it's inserted in the right place
String actualId = targetNode.getChildren()[insertIndex].getStringAttr(
ANDROID_URI, ATTR_ID);
if (!draggedButtonId.equals(actualId)) {
// Using assertEquals instead of fail to get nice diff view on test
// failure
List<String> childrenIds = new ArrayList<String>();
for (INode child : targetNode.getChildren()) {
childrenIds.add(child.getStringAttr(ANDROID_URI, ATTR_ID));
}
int index = childrenIds.indexOf(draggedButtonId);
String message = "Button found at index " + index + " instead of " + insertIndex
+ " among " + childrenIds;
System.out.println(message);
assertEquals(message, draggedButtonId, actualId);
}
return targetNode.getChildren()[insertIndex];
}
/**
* Utility method for asserting that two collections contain exactly the
* same elements (regardless of order)
* @param expected expected collection
* @param actual actual collection
*/
public static void assertContainsSame(Collection<String> expected, Collection<String> actual) {
if (expected.size() != actual.size()) {
fail("Collection sizes differ; expected " + expected.size() + " but was "
+ actual.size());
}
// Sort prior to comparison to ensure we have the same elements
// regardless of order
List<String> expectedList = new ArrayList<String>(expected);
Collections.sort(expectedList);
List<String> actualList = new ArrayList<String>(actual);
Collections.sort(actualList);
// Instead of just assertEquals(expectedList, actualList);
// we iterate one element at a time so we can show the first
// -difference-.
for (int i = 0; i < expectedList.size(); i++) {
String expectedElement = expectedList.get(i);
String actualElement = actualList.get(i);
if (!expectedElement.equals(actualElement)) {
System.out.println("Expected items: " + expectedList);
System.out.println("Actual items : " + actualList);
}
assertEquals("Collections differ; first difference:", expectedElement, actualElement);
}
}
protected void initialize(IViewRule rule, String fqn) {
rule.onInitialize(fqn, new TestRulesEngine(fqn));
}
public static class TestRulesEngine implements IClientRulesEngine {
private final String mFqn;
public TestRulesEngine(String fqn) {
mFqn = fqn;
}
@Override
public void debugPrintf(@NonNull String msg, Object... params) {
fail("Not supported in tests yet");
}
@Override
public void displayAlert(@NonNull String message) {
fail("Not supported in tests yet");
}
@Override
public String displayInput(@NonNull String message, @Nullable String value,
@Nullable IValidator filter) {
fail("Not supported in tests yet");
return null;
}
@Override
public @NonNull String getFqcn() {
return mFqn;
}
@Override
public @NonNull IViewMetadata getMetadata(final @NonNull String fqcn) {
return new IViewMetadata() {
@Override
public @NonNull String getDisplayName() {
// This also works when there is no "."
return fqcn.substring(fqcn.lastIndexOf('.') + 1);
}
@Override
public @NonNull FillPreference getFillPreference() {
return ViewMetadataRepository.get().getFillPreference(fqcn);
}
@Override
public @NonNull Margins getInsets() {
return null;
}
@Override
public @NonNull List<String> getTopAttributes() {
return ViewMetadataRepository.get().getTopAttributes(fqcn);
}
};
}
@Override
public int getMinApiLevel() {
return 8;
}
@Override
public IViewRule loadRule(@NonNull String fqcn) {
fail("Not supported in tests yet");
return null;
}
@Override
public String displayReferenceInput(String currentValue) {
fail("Not supported in tests yet");
return null;
}
@Override
public IValidator getResourceValidator(String resourceTypeName, boolean uniqueInProject,
boolean uniqueInLayout, boolean exists, String... allowed) {
fail("Not supported in tests yet");
return null;
}
@Override
public String displayResourceInput(@NonNull String resourceTypeName,
@Nullable String currentValue) {
fail("Not supported in tests yet");
return null;
}
@Override
public String[] displayMarginInput(@Nullable String all, @Nullable String left,
@Nullable String right, @Nullable String top, @Nullable String bottom) {
fail("Not supported in tests yet");
return null;
}
@Override
public String displayIncludeSourceInput() {
fail("Not supported in tests yet");
return null;
}
@Override
public void select(@NonNull Collection<INode> nodes) {
fail("Not supported in tests yet");
}
@Override
public String displayFragmentSourceInput() {
fail("Not supported in tests yet");
return null;
}
@Override
public void layout() {
fail("Not supported in tests yet");
}
@Override
public void redraw() {
fail("Not supported in tests yet");
}
@Override
public Map<INode, Rect> measureChildren(@NonNull INode parent,
@Nullable AttributeFilter filter) {
return null;
}
@Override
public int pxToDp(int px) {
// Arbitrary conversion
return px / 3;
}
@Override
public int dpToPx(int dp) {
// Arbitrary conversion
return 3 * dp;
}
@Override
public @NonNull String getUniqueId(@NonNull String prefix) {
fail("Not supported in tests yet");
return null;
}
@Override
public int screenToLayout(int pixels) {
fail("Not supported in tests yet");
return pixels;
}
@Override
public @NonNull String getAppNameSpace() {
fail("Not supported in tests yet");
return null;
}
@Override
public @Nullable Object getViewObject(@NonNull INode node) {
fail("Not supported in tests yet");
return null;
}
@Override
public boolean rename(INode node) {
fail("Not supported in tests yet");
return false;
}
@Override
@Nullable
public String displayCustomViewClassInput() {
fail("Not supported in tests yet");
return null;
}
}
public void testDummy() {
// To avoid JUnit warning that this class contains no tests, even though
// this is an abstract class and JUnit shouldn't try
}
}