package com.mixpanel.android.viewcrawler;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.test.AndroidTestCase;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.RelativeLayout;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ViewVisitorTest extends AndroidTestCase {
public void setUp() throws Exception {
super.setUp();
final Paint paint = new Paint();
paint.setColor(Color.BLUE);
final Bitmap.Config conf = Bitmap.Config.ARGB_8888;
mBitmap1a = Bitmap.createBitmap(10, 10, conf); // this creates a MUTABLE bitmap
final Canvas canvas1 = new Canvas(mBitmap1a);
canvas1.drawCircle(3, 3, 4, paint);
mBitmap1b = Bitmap.createBitmap(mBitmap1a);
mBitmap2 = Bitmap.createBitmap(10, 10, conf);
final Canvas canvas2 = new Canvas(mBitmap2);
canvas2.drawCircle(6, 6, 4, paint);
mRootView = new TestView(getContext());
mButton2Path = new ArrayList<Pathfinder.PathElement>();
mButton2Path.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, "com.mixpanel.android.viewcrawler.TestView", 0, -1, null, null));
mButton2Path.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, "android.widget.LinearLayout", 0, -1, null, null));
mButton2Path.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, "android.widget.LinearLayout", 0, -1, null, null));
mButton2Path.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, "android.widget.Button", 1, -1, null, null));
mWorkingRootPath1 = new ArrayList<Pathfinder.PathElement>();
mWorkingRootPath1.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, "java.lang.Object", 0, -1, null, null));
mWorkingRootPath2 = new ArrayList<Pathfinder.PathElement>();
mWorkingRootPath2.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, -1, null, null));
mFailingRootPath1 = new ArrayList<Pathfinder.PathElement>();
mFailingRootPath1.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, "android.widget.Button", 0, -1, null, null));
mFailingRootPath2 = new ArrayList<Pathfinder.PathElement>();
mFailingRootPath2.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, "java.lang.Object", 1, -1, null, null));
mFailingRootPath3 = new ArrayList<Pathfinder.PathElement>();
mFailingRootPath3.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, "java.lang.Object", 0, 1234, null, null));
mFailingRootPath4 = new ArrayList<Pathfinder.PathElement>();
mFailingRootPath4.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, "java.lang.Object", 0, -1, null, "NO SUCH TAG"));
mRootWildcardPath = new ArrayList<Pathfinder.PathElement>();
mRootWildcardPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, -1, null, null));
mRootGoodTagIdPath = new ArrayList<Pathfinder.PathElement>();
mRootGoodTagIdPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, TestView.ROOT_ID, null, TestView.CRAZY_TAG));
mRootBadTagIdPath = new ArrayList<Pathfinder.PathElement>();
mRootBadTagIdPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, TestView.ROOT_ID, null, "NO DICE"));
mFindText2DescriptionPath = new ArrayList<Pathfinder.PathElement>();
mFindText2DescriptionPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, TestView.TEXT2_VIEW_ID, TestView.TEXT_2_CONTENT_DESCRIPTION, null));
mFailText2DescriptionPath = new ArrayList<Pathfinder.PathElement>();
mFailText2DescriptionPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, TestView.TEXT2_VIEW_ID, "DOESNT MATCH", null));
mThirdLayerViewId = new ArrayList<Pathfinder.PathElement>();
mThirdLayerViewId.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, -1, null, null));
mThirdLayerViewId.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, -1, null, null));
mThirdLayerViewId.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, TestView.TEXT_VIEW_ID, null, null));
mThirdLayerViewTag = new ArrayList<Pathfinder.PathElement>();
mThirdLayerViewTag.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, -1, null, null));
mThirdLayerViewTag.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, -1, null, null));
mThirdLayerViewTag.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, TestView.TEXT_VIEW_ID, null, TestView.CRAZY_TAG));
mThirdLayerWildcard = new ArrayList<Pathfinder.PathElement>();
mThirdLayerWildcard.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, -1, null, null));
mThirdLayerWildcard.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, -1, null, null));
mThirdLayerWildcard.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, -1, null, null));
mFindRootIdPath = new ArrayList<Pathfinder.PathElement>();
mFindRootIdPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, TestView.ROOT_ID, null, null));
mFindNonsenseIdPath = new ArrayList<Pathfinder.PathElement>();
mFindNonsenseIdPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, 8080808, null, null));
mFindTextViewIdPath = new ArrayList<Pathfinder.PathElement>();
mFindTextViewIdPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, TestView.TEXT_VIEW_ID, null, null));
mFailTextViewIdPath = new ArrayList<Pathfinder.PathElement>();
mFailTextViewIdPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, TestView.TEXT_VIEW_ID, null, "NO SUCH TAG"));
mFirstInButtonGroup = new ArrayList<Pathfinder.PathElement>();
mFirstInButtonGroup.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, TestView.BUTTON_GROUP_ID, null, null));
mFirstInButtonGroup.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, 0, -1, null, null));
mFindButtonGroupInRoot = new ArrayList<Pathfinder.PathElement>();
mFindButtonGroupInRoot.add(new Pathfinder.PathElement(Pathfinder.PathElement.ZERO_LENGTH_PREFIX, null, -1, TestView.ROOT_ID, null, null));
mFindButtonGroupInRoot.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, TestView.BUTTON_GROUP_ID, null, null));
mFindButton2 = new ArrayList<Pathfinder.PathElement>();
mFindButton2.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, mRootView.mAdHocButton2.getClass().getCanonicalName(), -1, -1, null, null));
mRelativeLayoutPath = new ArrayList<Pathfinder.PathElement>();
mRelativeLayoutPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, TestView.RELATIVE_LAYOUT_ID, null, null));
mRelativeLayoutButtonPath = new ArrayList<Pathfinder.PathElement>();
mRelativeLayoutButtonPath.add(new Pathfinder.PathElement(Pathfinder.PathElement.SHORTEST_PREFIX, null, -1, TestView.RELATIVE_LAYOUT_BUTTON1_ID, null, null));
mTrackListener = new CollectingEventListener();
mLayoutErrorListener = new TestView.MockOnLayoutErrorListener();
}
public void testPath() {
{
final CollectorEditor button2Editor = new CollectorEditor(mButton2Path);
button2Editor.visit(mRootView);
assertEquals(button2Editor.collected.size(), 1);
assertEquals(button2Editor.collected.get(0), mRootView.mAdHocButton2);
}
{
final CollectorEditor rootPathEditor = new CollectorEditor(mWorkingRootPath1);
rootPathEditor.visit(mRootView);
assertEquals(rootPathEditor.collected.size(), 1);
assertEquals(rootPathEditor.collected.get(0), mRootView);
}
{
final CollectorEditor rootPathEditor = new CollectorEditor(mWorkingRootPath2);
rootPathEditor.visit(mRootView);
assertEquals(rootPathEditor.collected.size(), 1);
assertEquals(rootPathEditor.collected.get(0), mRootView);
}
{
final CollectorEditor rootPathEditor = new CollectorEditor(mRootGoodTagIdPath);
rootPathEditor.visit(mRootView);
assertEquals(rootPathEditor.collected.size(), 1);
assertEquals(rootPathEditor.collected.get(0), mRootView);
}
{
final CollectorEditor rootPathFails1 = new CollectorEditor(mFailingRootPath1);
rootPathFails1.visit(mRootView);
assertEquals(rootPathFails1.collected.size(), 0);
}
{
final CollectorEditor rootPathFails3 = new CollectorEditor(mFailingRootPath3);
rootPathFails3.visit(mRootView);
assertEquals(rootPathFails3.collected.size(), 0);
}
{
final CollectorEditor rootPathFails4 = new CollectorEditor(mFailingRootPath4);
rootPathFails4.visit(mRootView);
assertEquals(rootPathFails4.collected.size(), 0);
}
{
final CollectorEditor rootPathFails5 = new CollectorEditor(mRootBadTagIdPath);
rootPathFails5.visit(mRootView);
assertEquals(rootPathFails5.collected.size(), 0);
}
{
final CollectorEditor collector = new CollectorEditor(mFindText2DescriptionPath);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 1);
assertEquals(collector.collected.get(0), mRootView.mTextView2);
}
{
final CollectorEditor collector = new CollectorEditor(mFailText2DescriptionPath);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 0);
}
{
final CollectorEditor collector = new CollectorEditor(mThirdLayerViewId);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 1);
assertEquals(collector.collected.get(0), mRootView.mTextView1);
}
{
final CollectorEditor collector = new CollectorEditor(mThirdLayerViewTag);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 1);
assertEquals(collector.collected.get(0), mRootView.mTextView1);
}
{
final CollectorEditor collector = new CollectorEditor(mThirdLayerWildcard);
collector.visit(mRootView);
assertEquals(collector.collected.size(), mRootView.mThirdLayer.size());
final Set<View> allFound = new HashSet<View>(collector.collected);
assertEquals(mRootView.mThirdLayer, allFound);
}
{
final CollectorEditor collector = new CollectorEditor(mFindRootIdPath);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 1);
assertEquals(mRootView, collector.collected.get(0));
}
{
final CollectorEditor collector = new CollectorEditor(mFindNonsenseIdPath);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 0);
}
{
final CollectorEditor collector = new CollectorEditor(mFindTextViewIdPath);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 1);
assertEquals(collector.collected.get(0), mRootView.mTextView1);
}
{
final CollectorEditor collector = new CollectorEditor(mFailTextViewIdPath);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 0);
}
{
final CollectorEditor collector = new CollectorEditor(mFirstInButtonGroup);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 1);
assertEquals(collector.collected.get(0), mRootView.mAdHocButton1);
}
{
final CollectorEditor collector = new CollectorEditor(mFindButtonGroupInRoot);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 1);
assertEquals(collector.collected.get(0), mRootView.mButtonGroup);
}
{
final CollectorEditor collector = new CollectorEditor(mFindButton2);
collector.visit(mRootView);
assertEquals(collector.collected.size(), 1);
assertEquals(collector.collected.get(0), mRootView.mAdHocButton2);
}
}
public void testClickTracking() {
final ViewVisitor.AddAccessibilityEventVisitor visitor = new ViewVisitor.AddAccessibilityEventVisitor(mButton2Path, AccessibilityEvent.TYPE_VIEW_CLICKED, "Visitor1", mTrackListener);
visitor.visit(mRootView);
assertTrue(mTrackListener.events.isEmpty());
mRootView.mAdHocButton1.performClick();
assertTrue(mTrackListener.events.isEmpty());
mRootView.mAdHocButton2.performClick();
assertEquals(mTrackListener.events.size(), 1);
assertEquals(mTrackListener.events.get(0), "Visitor1");
mRootView.mAdHocButton3.performClick();
assertEquals(mTrackListener.events.size(), 1);
assertEquals(mTrackListener.events.get(0), "Visitor1");
}
public void testMultipleEventsOnClick() {
if (Build.VERSION.SDK_INT <= 16) {
return; // We don't actually support multiple handlers on Jellybean.
}
final ViewVisitor.AddAccessibilityEventVisitor visitor1 =
new ViewVisitor.AddAccessibilityEventVisitor(mButton2Path, AccessibilityEvent.TYPE_VIEW_CLICKED, "Visitor1", mTrackListener);
visitor1.visit(mRootView);
assertTrue(mTrackListener.events.isEmpty());
mRootView.mAdHocButton2.performClick();
assertEquals(mTrackListener.events.size(), 1);
assertEquals(mTrackListener.events.get(0), "Visitor1");
mTrackListener.events.clear();
final ViewVisitor.AddAccessibilityEventVisitor visitor2 =
new ViewVisitor.AddAccessibilityEventVisitor(mButton2Path, AccessibilityEvent.TYPE_VIEW_CLICKED, "Visitor2", mTrackListener);
visitor2.visit(mRootView);
mRootView.mAdHocButton2.performClick();
assertEquals(mTrackListener.events.size(), 2);
assertTrue(mTrackListener.events.contains("Visitor1"));
assertTrue(mTrackListener.events.contains("Visitor2"));
visitor1.cleanup();
mTrackListener.events.clear();
mRootView.mAdHocButton2.performClick();
assertEquals(mTrackListener.events.size(), 1);
assertTrue(mTrackListener.events.contains("Visitor2"));
visitor2.cleanup();
mTrackListener.events.clear();
mRootView.mAdHocButton2.performClick();
assertEquals(mTrackListener.events.size(), 0);
}
public void testResetSameEventOnClick() {
final ViewVisitor.AddAccessibilityEventVisitor visitor1 =
new ViewVisitor.AddAccessibilityEventVisitor(mButton2Path, AccessibilityEvent.TYPE_VIEW_CLICKED, "Visitor1", mTrackListener);
visitor1.visit(mRootView);
visitor1.visit(mRootView);
mRootView.mAdHocButton2.performClick();
assertEquals(mTrackListener.events.size(), 1);
assertEquals(mTrackListener.events.get(0), "Visitor1");
mTrackListener.events.clear();
}
public void testDuplicateBitmapSet() throws NoSuchMethodException {
final Caller mutateBitmap1a = new Caller(TestView.AdHocButton2.class, "setCountingProperty", new Object[] { mBitmap1a }, Void.TYPE);
final Caller mutateBitmap1b = new Caller(TestView.AdHocButton2.class, "setCountingProperty", new Object[] { mBitmap1b }, Void.TYPE);
final Caller mutateBitmap2 = new Caller(TestView.AdHocButton2.class, "setCountingProperty", new Object[] { mBitmap2 }, Void.TYPE);
final Caller accessor = new Caller(TestView.AdHocButton2.class, "getCountingProperty", new Object[]{}, Object.class);
{
final ViewVisitor propertySetVisitor1_1 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateBitmap1a, accessor);
propertySetVisitor1_1.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, mBitmap1a);
propertySetVisitor1_1.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
}
{
final ViewVisitor propertySetVisitor1_2 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateBitmap1b, accessor);
propertySetVisitor1_2.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, mBitmap1a);
}
{
final ViewVisitor propertySetVisitor2 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateBitmap2, accessor);
propertySetVisitor2.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 2);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, mBitmap2);
}
}
public void testDuplicateDrawableSet() throws NoSuchMethodException {
final BitmapDrawable drawable1a_1 = new BitmapDrawable(Resources.getSystem(), mBitmap1a);
final BitmapDrawable drawable1a_2 = new BitmapDrawable(Resources.getSystem(), mBitmap1a);
final BitmapDrawable drawable2 = new BitmapDrawable(Resources.getSystem(), mBitmap2);
final Caller mutateDrawable1a_1 = new Caller(TestView.AdHocButton2.class, "setCountingProperty", new Object[] { drawable1a_1 }, Void.TYPE);
final Caller mutateDrawable1a_2 = new Caller(TestView.AdHocButton2.class, "setCountingProperty", new Object[] { drawable1a_2 }, Void.TYPE);
final Caller mutateDrawable2 = new Caller(TestView.AdHocButton2.class, "setCountingProperty", new Object[] { drawable2 }, Void.TYPE);
final Caller accessor = new Caller(TestView.AdHocButton2.class, "getCountingProperty", new Object[]{}, Object.class);
{
final ViewVisitor propertySetVisitor1_1 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateDrawable1a_1, accessor);
propertySetVisitor1_1.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, drawable1a_1);
propertySetVisitor1_1.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
}
{
final ViewVisitor propertySetVisitor1_2 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateDrawable1a_2, accessor);
propertySetVisitor1_2.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, drawable1a_1);
}
{
final ViewVisitor propertySetVisitor2 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateDrawable2, accessor);
propertySetVisitor2.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 2);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, drawable2);
}
}
public void testDuplicateTextSet() throws NoSuchMethodException {
final Caller mutateCountingProperty1a = new Caller(TestView.AdHocButton2.class, "setCountingProperty", new Object[]{"Set String1"}, Void.TYPE);
final Caller mutateCountingProperty1b = new Caller(TestView.AdHocButton2.class, "setCountingProperty", new Object[]{"Set String1"}, Void.TYPE);
final Caller mutateCountingProperty2 = new Caller(TestView.AdHocButton2.class, "setCountingProperty", new Object[]{"Set String2"}, Void.TYPE);
final Caller accessCountingProperty = new Caller(TestView.AdHocButton2.class, "getCountingProperty", new Object[]{}, Object.class);
{
final ViewVisitor propertySetVisitor1_1 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateCountingProperty1a, accessCountingProperty);
propertySetVisitor1_1.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, "Set String1");
propertySetVisitor1_1.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
}
{
final ViewVisitor propertySetVisitor1_2 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateCountingProperty1a, accessCountingProperty);
propertySetVisitor1_2.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, "Set String1");
}
{
final ViewVisitor propertySetVisitor1_3 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateCountingProperty1b, accessCountingProperty);
propertySetVisitor1_3.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 1);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, "Set String1");
}
{
final ViewVisitor propertySetVisitor2 =
new ViewVisitor.PropertySetVisitor(mButton2Path, mutateCountingProperty2, accessCountingProperty);
propertySetVisitor2.visit(mRootView);
assertEquals(mRootView.mAdHocButton2.countingPropertyCount, 2);
assertEquals(mRootView.mAdHocButton2.countingPropertyValue, "Set String2");
}
}
public void testLayoutBasicInteraction() {
ArrayList<ViewVisitor.LayoutRule> params = new ArrayList<ViewVisitor.LayoutRule>();
// add LAYOUT_ALIGNPARENTTOP
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE));
// add "LAYOUT_BELOW mRelativeLayoutButton2" to mRelativeLayoutButton1
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.BELOW, TestView.RELATIVE_LAYOUT_BUTTON2_ID));
// add LAYOUT_ALIGNPARENTBOTTOM to mRelativeLayoutButton1
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE));
// remove LAYOUT_ALIGNPARENTBOTTOM from mRelativeLayoutButton1
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.ALIGN_PARENT_BOTTOM, TestView.NO_ANCHOR));
final ViewVisitor layoutVisitor =
new ViewVisitor.LayoutUpdateVisitor(mRelativeLayoutPath, params, "test", mLayoutErrorListener);
layoutVisitor.visit(mRootView);
RelativeLayout.LayoutParams layoutParams =
(RelativeLayout.LayoutParams) mRootView.mRelativeLayoutButton1.getLayoutParams();
int[] rules = layoutParams.getRules();
assertEquals(RelativeLayout.TRUE, rules[RelativeLayout.ALIGN_PARENT_TOP]);
assertEquals(TestView.RELATIVE_LAYOUT_BUTTON2_ID, rules[RelativeLayout.BELOW]);
assertEquals(TestView.NO_ANCHOR, rules[RelativeLayout.ALIGN_PARENT_BOTTOM]);
assertEquals(true, mLayoutErrorListener.errorList.isEmpty());
}
public void testLayoutCircularDependency() {
{ // vertical layout circle
ArrayList<ViewVisitor.LayoutRule> params = new ArrayList<ViewVisitor.LayoutRule>();
// add ALIGN_PARENT_TOP
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE));
// add "BELOW mRelativeLayoutButton2" to mRelativeLayoutButton1, should success
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.BELOW, TestView.RELATIVE_LAYOUT_BUTTON2_ID));
// add "ALIGN_LEFT mRelativeLayoutButton1" to mRelativeLayoutButton2, should success
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON2_ID, RelativeLayout.ALIGN_LEFT, TestView.RELATIVE_LAYOUT_BUTTON1_ID));
// add "BELOW mRelativeLayoutButton1" to mRelativeLayoutButton2, should fail
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON2_ID, RelativeLayout.ABOVE, TestView.RELATIVE_LAYOUT_BUTTON1_ID));
final ViewVisitor layoutVisitor =
new ViewVisitor.LayoutUpdateVisitor(mRelativeLayoutPath, params, "test1", mLayoutErrorListener);
layoutVisitor.visit(mRootView);
RelativeLayout.LayoutParams layoutParamsButton1 =
(RelativeLayout.LayoutParams) mRootView.mRelativeLayoutButton1.getLayoutParams();
int[] rulesButton1 = layoutParamsButton1.getRules();
assertEquals(TestView.NO_ANCHOR, rulesButton1[RelativeLayout.ALIGN_PARENT_TOP]);
assertEquals(TestView.NO_ANCHOR, rulesButton1[RelativeLayout.BELOW]);
RelativeLayout.LayoutParams layoutParamsButton2 =
(RelativeLayout.LayoutParams) mRootView.mRelativeLayoutButton2.getLayoutParams();
int[] rulesButton2 = layoutParamsButton2.getRules();
assertEquals(TestView.NO_ANCHOR, rulesButton2[RelativeLayout.ALIGN_LEFT]);
assertEquals(TestView.NO_ANCHOR, rulesButton2[RelativeLayout.ABOVE]);
ViewVisitor.LayoutErrorMessage e = mLayoutErrorListener.errorList.get(0);
assertEquals("circular_dependency", e.getErrorType());
assertEquals("test1", e.getName());
mLayoutErrorListener.errorList.clear();
}
{ // horizontal layout circle
ArrayList<ViewVisitor.LayoutRule> params = new ArrayList<ViewVisitor.LayoutRule>();
// add ALIGN_PARENT_BOTTOM to mRelativeLayoutButton1, should success
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE));
// add "LEFT_OF mRelativeLayoutButton2" to mRelativeLayoutButton1, should success
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.LEFT_OF, TestView.RELATIVE_LAYOUT_BUTTON2_ID));
// add "ALIGN_BOTTOM mRelativeLayoutButton1" to mRelativeLayoutButton2, should success
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON2_ID, RelativeLayout.ALIGN_BOTTOM, TestView.RELATIVE_LAYOUT_BUTTON1_ID));
// add "ALIGN_RIGHT mRelativeLayoutButton1" to mRelativeLayoutButton2, should fail
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON2_ID, RelativeLayout.ALIGN_RIGHT, TestView.RELATIVE_LAYOUT_BUTTON1_ID));
final ViewVisitor layoutVisitor =
new ViewVisitor.LayoutUpdateVisitor(mRelativeLayoutPath, params, "test2", mLayoutErrorListener);
layoutVisitor.visit(mRootView);
RelativeLayout.LayoutParams layoutParamsButton1 =
(RelativeLayout.LayoutParams) mRootView.mRelativeLayoutButton1.getLayoutParams();
int[] rulesButton1 = layoutParamsButton1.getRules();
assertEquals(TestView.NO_ANCHOR, rulesButton1[RelativeLayout.ALIGN_PARENT_BOTTOM]);
assertEquals(TestView.NO_ANCHOR, rulesButton1[RelativeLayout.LEFT_OF]);
RelativeLayout.LayoutParams layoutParamsButton2 =
(RelativeLayout.LayoutParams) mRootView.mRelativeLayoutButton2.getLayoutParams();
int[] rulesButton2 = layoutParamsButton2.getRules();
assertEquals(TestView.NO_ANCHOR, rulesButton2[RelativeLayout.ALIGN_BOTTOM]);
assertEquals(TestView.NO_ANCHOR, rulesButton2[RelativeLayout.ALIGN_RIGHT]);
ViewVisitor.LayoutErrorMessage e = mLayoutErrorListener.errorList.get(0);
assertEquals("circular_dependency", e.getErrorType());
assertEquals("test2", e.getName());
mLayoutErrorListener.errorList.clear();
}
{ // mix of vertical and horizontal layouts, no circle
ArrayList<ViewVisitor.LayoutRule> params = new ArrayList<ViewVisitor.LayoutRule>();
// add ALIGN_PARENT_BOTTOM to mRelativeLayoutButton1, should success
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE));
// add "LEFT_OF mRelativeLayoutButton2" to mRelativeLayoutButton1, should success
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON1_ID, RelativeLayout.LEFT_OF, TestView.RELATIVE_LAYOUT_BUTTON2_ID));
// add "ALIGN_LEFT mRelativeLayoutButton1" to mRelativeLayoutButton2, should success
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON2_ID, RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE));
// add "BELOW mRelativeLayoutButton1" to mRelativeLayoutButton2, should success
params.add(new ViewVisitor.LayoutRule(TestView.RELATIVE_LAYOUT_BUTTON2_ID, RelativeLayout.BELOW, TestView.RELATIVE_LAYOUT_BUTTON1_ID));
final ViewVisitor layoutVisitor =
new ViewVisitor.LayoutUpdateVisitor(mRelativeLayoutPath, params, "test3", mLayoutErrorListener);
layoutVisitor.visit(mRootView);
RelativeLayout.LayoutParams layoutParamsButton1 =
(RelativeLayout.LayoutParams) mRootView.mRelativeLayoutButton1.getLayoutParams();
int[] rulesButton1 = layoutParamsButton1.getRules();
assertEquals(RelativeLayout.TRUE, rulesButton1[RelativeLayout.ALIGN_PARENT_BOTTOM]);
assertEquals(TestView.RELATIVE_LAYOUT_BUTTON2_ID, rulesButton1[RelativeLayout.LEFT_OF]);
RelativeLayout.LayoutParams layoutParamsButton2 =
(RelativeLayout.LayoutParams) mRootView.mRelativeLayoutButton2.getLayoutParams();
int[] rulesButton2 = layoutParamsButton2.getRules();
assertEquals(RelativeLayout.TRUE, rulesButton2[RelativeLayout.ALIGN_PARENT_TOP]);
assertEquals(TestView.RELATIVE_LAYOUT_BUTTON1_ID, rulesButton2[RelativeLayout.BELOW]);
assertEquals(true, mLayoutErrorListener.errorList.isEmpty());
}
}
private static class CollectorEditor extends ViewVisitor {
public CollectorEditor(List<Pathfinder.PathElement> path) {
super(path);
collected = new ArrayList<View>();
}
@Override
public void cleanup() {}
@Override
public void accumulate(View targetView) {
collected.add(targetView);
}
@Override
protected String name() {
return "CollectorEditor";
};
public List<View> collected;
}
private static class CollectingEventListener implements ViewVisitor.OnEventListener {
@Override
public void OnEvent(View v, String eventName, boolean debounce) {
events.add(eventName);
}
public final List<String> events = new ArrayList<String>();
}
private Bitmap mBitmap1a;
private Bitmap mBitmap1b;
private Bitmap mBitmap2;
private List<Pathfinder.PathElement> mButton2Path;
private List<Pathfinder.PathElement> mWorkingRootPath1;
private List<Pathfinder.PathElement> mWorkingRootPath2;
private List<Pathfinder.PathElement> mFailingRootPath1;
private List<Pathfinder.PathElement> mFailingRootPath2;
private List<Pathfinder.PathElement> mFailingRootPath3;
private List<Pathfinder.PathElement> mFailingRootPath4;
private List<Pathfinder.PathElement> mFindRootIdPath;
private List<Pathfinder.PathElement> mFindNonsenseIdPath;
private List<Pathfinder.PathElement> mFindText2DescriptionPath;
private List<Pathfinder.PathElement> mFailText2DescriptionPath;
private List<Pathfinder.PathElement> mFindTextViewIdPath;
private List<Pathfinder.PathElement> mFailTextViewIdPath;
private List<Pathfinder.PathElement> mFirstInButtonGroup;
private List<Pathfinder.PathElement> mFindButtonGroupInRoot;
private List<Pathfinder.PathElement> mFindButton2;
private List<Pathfinder.PathElement> mRelativeLayoutPath;
private List<Pathfinder.PathElement> mRelativeLayoutButtonPath;
private List<Pathfinder.PathElement> mRootWildcardPath;
private List<Pathfinder.PathElement> mRootGoodTagIdPath;
private List<Pathfinder.PathElement> mRootBadTagIdPath;
private List<Pathfinder.PathElement> mThirdLayerViewId;
private List<Pathfinder.PathElement> mThirdLayerViewTag;
private List<Pathfinder.PathElement> mThirdLayerWildcard;
private CollectingEventListener mTrackListener;
private TestView.MockOnLayoutErrorListener mLayoutErrorListener;
private TestView mRootView;
}