1 package org.robolectric.android;
2 
3 import static org.mockito.Mockito.mock;
4 import static org.robolectric.Shadows.shadowOf;
5 
6 import android.graphics.Rect;
7 import android.text.SpannableString;
8 import android.text.Spanned;
9 import android.text.style.ClickableSpan;
10 import android.view.View;
11 import android.widget.LinearLayout;
12 import android.widget.TextView;
13 import com.google.android.apps.common.testing.accessibility.framework.integrations.AccessibilityViewCheckException;
14 import org.hamcrest.Matchers;
15 import org.junit.Before;
16 import org.junit.Test;
17 import org.junit.runner.RunWith;
18 import org.robolectric.RuntimeEnvironment;
19 import org.robolectric.annotation.AccessibilityChecks;
20 import org.robolectric.annotation.AccessibilityChecks.ForRobolectricVersion;
21 import org.robolectric.util.TestRunnerWithManifest;
22 
23 /**
24  * Tests for accessibility checking. The checking relies on the Accessibility Test Framework for
25  * Android, which has support-v4 as a dependency, so these tests are included where the presence
26  * of that library is guaranteed.
27  */
28 @RunWith(TestRunnerWithManifest.class)
29 public class AccessibilityUtilTest {
30   private static final String DUPLICATE_STRING = "Duplicate";
31   private TextView textViewWithClickableSpan;
32   private LinearLayout parentLayout;
33   private View labeledView;
34   private View unlabeledView;
35 
36   @Before
setUp()37   public void setUp() throws Exception {
38     Rect validViewBounds = new Rect(100, 100, 200, 200);
39 
40     // Set the statics back to their default values
41     AccessibilityUtil.setRunChecksForRobolectricVersion(null);
42     AccessibilityUtil.setSuppressingResultMatcher(null);
43     AccessibilityUtil.setRunChecksFromRootView(false);
44     AccessibilityUtil.setThrowExceptionForErrors(true);
45 
46     labeledView = new View(RuntimeEnvironment.application);
47     labeledView.setContentDescription("Something");
48     labeledView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
49     labeledView.setClickable(true);
50     // Force the views on the screen so they'll be seen as visible even though they aren't
51     // part of a valid view hierarchy
52     shadowOf(labeledView).setGlobalVisibleRect(validViewBounds);
53 
54     unlabeledView = new View(RuntimeEnvironment.application);
55     unlabeledView.setContentDescription(null);
56     unlabeledView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
57     unlabeledView.setClickable(true);
58     shadowOf(unlabeledView).setGlobalVisibleRect(validViewBounds);
59 
60     parentLayout = new LinearLayout(RuntimeEnvironment.application);
61     parentLayout.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
62     parentLayout.addView(labeledView);
63     shadowOf(parentLayout).setGlobalVisibleRect(validViewBounds);
64 
65     textViewWithClickableSpan = new TextView(RuntimeEnvironment.application);
66     SpannableString spannableString = new SpannableString("Some text");
67     ClickableSpan mockClickableSpan = mock(ClickableSpan.class);
68     spannableString.setSpan(mockClickableSpan, 0, 1, Spanned.SPAN_COMPOSING);
69     textViewWithClickableSpan.setText(spannableString);
70     shadowOf(textViewWithClickableSpan).setGlobalVisibleRect(validViewBounds);
71   }
72 
73   @Test(expected = AccessibilityViewCheckException.class)
checkUnlabeledView_shouldThrow()74   public void checkUnlabeledView_shouldThrow() throws Exception {
75     AccessibilityUtil.checkView(unlabeledView);
76   }
77 
78   @Test
checkOKView_shouldNotThrow()79   public void checkOKView_shouldNotThrow() throws Exception {
80     AccessibilityUtil.checkView(labeledView);
81   }
82 
83   @Test
default_viewWithSiblingIssue_shouldNotThrow()84   public void default_viewWithSiblingIssue_shouldNotThrow() throws Exception {
85     parentLayout.addView(unlabeledView);
86     AccessibilityUtil.checkView(labeledView);
87   }
88 
89   @Test(expected = AccessibilityViewCheckException.class)
whenCheckingFromRoot_viewWithSiblingIssue_shouldThrow()90   public void whenCheckingFromRoot_viewWithSiblingIssue_shouldThrow() throws Exception {
91     parentLayout.addView(unlabeledView);
92     AccessibilityUtil.setRunChecksFromRootView(true);
93     AccessibilityUtil.checkView(labeledView);
94   }
95 
96   @Test(expected = AccessibilityViewCheckException.class)
97   @AccessibilityChecks
whenAnnotationPresent_conditionalCheckRun()98   public void whenAnnotationPresent_conditionalCheckRun() {
99     AccessibilityUtil.checkViewIfCheckingEnabled(unlabeledView);
100   }
101 
102   @Test
whenAnnotationNotPresent_conditionalCheckNotRun()103   public void whenAnnotationNotPresent_conditionalCheckNotRun() {
104     AccessibilityUtil.checkViewIfCheckingEnabled(unlabeledView);
105   }
106 
107   @Test(expected = AccessibilityViewCheckException.class)
framework2pt0Error_byDefault_shouldThrow()108   public void framework2pt0Error_byDefault_shouldThrow() throws Exception {
109     AccessibilityUtil.checkView(textViewWithClickableSpan);
110   }
111 
112   @Test
framework2pt0Error_whenCheckingForRL3pt0_shouldNotThrow()113   public void framework2pt0Error_whenCheckingForRL3pt0_shouldNotThrow() throws Exception {
114     AccessibilityUtil.setRunChecksForRobolectricVersion(ForRobolectricVersion.VERSION_3_0);
115     AccessibilityUtil.checkView(textViewWithClickableSpan);
116   }
117 
118   @Test
119   @AccessibilityChecks(forRobolectricVersion = ForRobolectricVersion.VERSION_3_0)
framework2pt0Error_annotationForRL3pt0_shouldNotThrow()120   public void framework2pt0Error_annotationForRL3pt0_shouldNotThrow() throws Exception {
121     AccessibilityUtil.checkView(textViewWithClickableSpan);
122   }
123 
124   @Test(expected = AccessibilityViewCheckException.class)
125   @AccessibilityChecks(forRobolectricVersion = ForRobolectricVersion.VERSION_3_0)
framework2pt0Error_codeForcesRL3pt1_shouldThrow()126   public void framework2pt0Error_codeForcesRL3pt1_shouldThrow() throws Exception {
127     AccessibilityUtil.setRunChecksForRobolectricVersion(ForRobolectricVersion.VERSION_3_1);
128     AccessibilityUtil.checkView(textViewWithClickableSpan);
129   }
130 
131   @Test
whenSuppressingResults_shouldNotThrow()132   public void whenSuppressingResults_shouldNotThrow() throws Exception {
133     AccessibilityUtil.setSuppressingResultMatcher(Matchers.anything());
134     AccessibilityUtil.checkView(unlabeledView);
135   }
136 
137   @Test
whenOnlyPrintingResults_shouldNotThrow()138   public void whenOnlyPrintingResults_shouldNotThrow() throws Exception {
139     AccessibilityUtil.setThrowExceptionForErrors(false);
140     AccessibilityUtil.checkView(unlabeledView);
141   }
142 
143   @Test
warningIssue_shouldNotThrow()144   public void warningIssue_shouldNotThrow() throws Exception {
145     labeledView.setContentDescription(DUPLICATE_STRING);
146     parentLayout.setContentDescription(DUPLICATE_STRING);
147     parentLayout.setClickable(true);
148     AccessibilityUtil.checkView(parentLayout);
149   }
150 
151 }
152 
153