1package org.robolectric.shadows;
2
3import static android.os.Build.VERSION_CODES.LOLLIPOP;
4import static org.assertj.core.api.Assertions.assertThat;
5import static org.robolectric.Shadows.shadowOf;
6
7import android.graphics.Rect;
8import android.os.Bundle;
9import android.os.Parcel;
10import android.view.View;
11import android.view.accessibility.AccessibilityNodeInfo;
12import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
13import android.view.accessibility.AccessibilityWindowInfo;
14import org.junit.After;
15import org.junit.Before;
16import org.junit.Test;
17import org.junit.runner.RunWith;
18import org.robolectric.RobolectricTestRunner;
19import org.robolectric.RuntimeEnvironment;
20import org.robolectric.annotation.Config;
21
22@RunWith(RobolectricTestRunner.class)
23public class ShadowAccessibilityNodeInfoTest {
24
25  private AccessibilityNodeInfo node;
26
27  private ShadowAccessibilityNodeInfo shadow;
28
29  @Before
30  public void setUp() {
31    ShadowAccessibilityNodeInfo.resetObtainedInstances();
32    assertThat(ShadowAccessibilityNodeInfo.areThereUnrecycledNodes(true)).isEqualTo(false);
33    node = AccessibilityNodeInfo.obtain();
34  }
35
36  @Test
37  public void shouldHaveObtainedNode() {
38    assertThat(ShadowAccessibilityNodeInfo.areThereUnrecycledNodes(false)).isEqualTo(true);
39  }
40
41  @Test
42  public void shouldHaveZeroBounds() {
43    Rect outBounds = new Rect();
44    node.getBoundsInParent(outBounds);
45    assertThat(outBounds.left).isEqualTo(0);
46  }
47
48  @Test
49  public void shouldHaveClonedCorrectly() {
50    node.setAccessibilityFocused(true);
51    node.setBoundsInParent(new Rect(0, 0, 100, 100));
52    node.setContentDescription("test");
53    AccessibilityNodeInfo anotherNode = AccessibilityNodeInfo.obtain(node);
54    assertThat(anotherNode).isEqualTo(node);
55    assertThat(anotherNode.getContentDescription().toString()).isEqualTo("test");
56  }
57
58  @Test
59  public void shouldWriteAndReadFromParcelCorrectly() {
60    Parcel p = Parcel.obtain();
61    node.setContentDescription("test");
62    node.writeToParcel(p, 0);
63    p.setDataPosition(0);
64    AccessibilityNodeInfo anotherNode = AccessibilityNodeInfo.CREATOR.createFromParcel(p);
65    assertThat(node).isEqualTo(anotherNode);
66    node.setContentDescription(null);
67  }
68
69  @Test
70  public void shouldNotHaveInfiniteLoopWithSameLoopedChildren() {
71    node = AccessibilityNodeInfo.obtain();
72    AccessibilityNodeInfo child = AccessibilityNodeInfo.obtain();
73    shadowOf(node).addChild(child);
74    shadowOf(child).addChild(node);
75    AccessibilityNodeInfo anotherNode = AccessibilityNodeInfo.obtain(node);
76    assertThat(node).isEqualTo(anotherNode);
77  }
78
79  @Test
80  public void shouldNotHaveInfiniteLoopWithDifferentLoopedChildren() {
81    node = AccessibilityNodeInfo.obtain();
82    shadow = shadowOf(node);
83    AccessibilityNodeInfo child1 = AccessibilityNodeInfo.obtain();
84    shadow.addChild(child1);
85    ShadowAccessibilityNodeInfo child1Shadow = shadowOf(child1);
86    child1Shadow.addChild(node);
87    AccessibilityNodeInfo anotherNode = ShadowAccessibilityNodeInfo.obtain();
88    AccessibilityNodeInfo child2 = ShadowAccessibilityNodeInfo.obtain();
89    child2.setText("test");
90    ShadowAccessibilityNodeInfo child2Shadow = shadowOf(child2);
91    ShadowAccessibilityNodeInfo anotherNodeShadow = shadowOf(anotherNode);
92    anotherNodeShadow.addChild(child2);
93    child2Shadow.addChild(anotherNode);
94    assertThat(node).isNotEqualTo(anotherNode);
95  }
96
97  @Test
98  @Config(minSdk = LOLLIPOP)
99  public void shouldRecordFlagsProperly() {
100    node = AccessibilityNodeInfo.obtain();
101    node.setClickable(false);
102    shadow = shadowOf(node);
103    shadow.setPasteable(false);
104    assertThat(shadow.isClickable()).isEqualTo(false);
105    assertThat(shadow.isPasteable()).isEqualTo(false);
106    node.setText("Test");
107    shadow.setTextSelectionSetable(true);
108    shadow.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
109    node.setTextSelection(0, 1);
110    assertThat(shadow.getActions()).isEqualTo(AccessibilityNodeInfo.ACTION_SET_SELECTION);
111    assertThat(shadow.getTextSelectionStart()).isEqualTo(0);
112    assertThat(shadow.getTextSelectionEnd()).isEqualTo(1);
113    AccessibilityWindowInfo window = ShadowAccessibilityWindowInfo.obtain();
114    shadow.setAccessibilityWindowInfo(window);
115    assertThat(node.getWindow()).isEqualTo(window);
116    shadow.setAccessibilityWindowInfo(null);
117    // Remove action was added in API 21
118    node.removeAction(AccessibilityAction.ACTION_SET_SELECTION);
119    shadow.setPasteable(true);
120    shadow.setTextSelectionSetable(false);
121    node.addAction(AccessibilityNodeInfo.ACTION_PASTE);
122    assertThat(shadow.getActions()).isEqualTo(AccessibilityNodeInfo.ACTION_PASTE);
123    node.setClickable(true);
124    assertThat(shadow.isClickable()).isEqualTo(true);
125    node.setClickable(false);
126    shadow.setPasteable(false);
127    node.removeAction(AccessibilityNodeInfo.ACTION_PASTE);
128    node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
129    assertThat(shadow.getActions()).isEqualTo(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
130    node.removeAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
131  }
132
133  @Test
134  public void shouldRecordActionsPerformed() {
135    node.setClickable(true);
136    node.addAction(AccessibilityNodeInfo.ACTION_CLICK);
137    shadow = shadowOf(node);
138    shadow.setOnPerformActionListener(new ShadowAccessibilityNodeInfo.OnPerformActionListener() {
139      @Override
140      public boolean onPerformAccessibilityAction(int action, Bundle arguments) {
141        if (action == AccessibilityNodeInfo.ACTION_CLICK) {
142          return true;
143        } else {
144          return false;
145        }
146      }
147    });
148
149    boolean clickResult = node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
150    assertThat(clickResult).isEqualTo(true);
151    assertThat(shadow.getPerformedActions().isEmpty()).isEqualTo(false);
152    assertThat(shadow.getPerformedActions().get(0)).isEqualTo(AccessibilityNodeInfo.ACTION_CLICK);
153    boolean longClickResult = node.performAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
154    assertThat(longClickResult).isEqualTo(false);
155    assertThat(shadow.getPerformedActions().size()).isEqualTo(2);
156    assertThat(shadow.getPerformedActions().get(1))
157        .isEqualTo(AccessibilityNodeInfo.ACTION_LONG_CLICK);
158  }
159
160  @Test
161  public void equalsTest_unrelatedNodesAreUnequal() {
162    AccessibilityNodeInfo nodeA = AccessibilityNodeInfo.obtain();
163    AccessibilityNodeInfo nodeB = AccessibilityNodeInfo.obtain();
164    shadowOf(nodeA).setText("test");
165    shadowOf(nodeB).setText("test");
166
167    assertThat(nodeA).isNotEqualTo(nodeB);
168  }
169
170  @Test
171  public void equalsTest_nodesFromTheSameViewAreEqual() {
172    View view = new View(RuntimeEnvironment.application);
173    AccessibilityNodeInfo nodeA = AccessibilityNodeInfo.obtain(view);
174    AccessibilityNodeInfo nodeB = AccessibilityNodeInfo.obtain(view);
175    shadowOf(nodeA).setText("tomato");
176    shadowOf(nodeB).setText("tomatoe");
177
178    assertThat(nodeA).isEqualTo(nodeB);
179  }
180
181  @Test
182  public void equalsTest_nodesFromDifferentViewsAreNotEqual() {
183    View viewA = new View(RuntimeEnvironment.application);
184    View viewB = new View(RuntimeEnvironment.application);
185    AccessibilityNodeInfo nodeA = AccessibilityNodeInfo.obtain(viewA);
186    AccessibilityNodeInfo nodeB = AccessibilityNodeInfo.obtain(viewB);
187    shadowOf(nodeA).setText("test");
188    shadowOf(nodeB).setText("test");
189
190    assertThat(nodeA).isNotEqualTo(nodeB);
191  }
192
193  @Test
194  public void equalsTest_nodeIsEqualToItsClone_evenWhenModified() {
195    node = AccessibilityNodeInfo.obtain();
196    AccessibilityNodeInfo clone = AccessibilityNodeInfo.obtain(node);
197    shadowOf(clone).setText("test");
198
199    assertThat(node).isEqualTo(clone);
200  }
201
202  @After
203  public void tearDown() {
204    ShadowAccessibilityNodeInfo.resetObtainedInstances();
205    assertThat(ShadowAccessibilityNodeInfo.areThereUnrecycledNodes(true)).isEqualTo(false);
206  }
207}
208