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