package org.robolectric.android;
import android.graphics.Rect;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.google.android.apps.common.testing.accessibility.framework.integrations.AccessibilityViewCheckException;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.AccessibilityChecks;
import org.robolectric.annotation.AccessibilityChecks.ForRobolectricVersion;
import org.robolectric.util.TestRunnerWithManifest;
import static org.mockito.Mockito.mock;
import static org.robolectric.Shadows.shadowOf;
/**
* Tests for accessibility checking. The checking relies on the Accessibility Test Framework for
* Android, which has support-v4 as a dependency, so these tests are included where the presence
* of that library is guaranteed.
*/
@RunWith(TestRunnerWithManifest.class)
public class AccessibilityUtilTest {
private static final String DUPLICATE_STRING = "Duplicate";
private TextView textViewWithClickableSpan;
private LinearLayout parentLayout;
private View labeledView;
private View unlabeledView;
@Before
public void setUp() throws Exception {
Rect validViewBounds = new Rect(100, 100, 200, 200);
// Set the statics back to their default values
AccessibilityUtil.setRunChecksForRobolectricVersion(null);
AccessibilityUtil.setSuppressingResultMatcher(null);
AccessibilityUtil.setRunChecksFromRootView(false);
AccessibilityUtil.setThrowExceptionForErrors(true);
labeledView = new View(RuntimeEnvironment.application);
labeledView.setContentDescription("Something");
labeledView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
labeledView.setClickable(true);
// Force the views on the screen so they'll be seen as visible even though they aren't
// part of a valid view hierarchy
shadowOf(labeledView).setGlobalVisibleRect(validViewBounds);
unlabeledView = new View(RuntimeEnvironment.application);
unlabeledView.setContentDescription(null);
unlabeledView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
unlabeledView.setClickable(true);
shadowOf(unlabeledView).setGlobalVisibleRect(validViewBounds);
parentLayout = new LinearLayout(RuntimeEnvironment.application);
parentLayout.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
parentLayout.addView(labeledView);
shadowOf(parentLayout).setGlobalVisibleRect(validViewBounds);
textViewWithClickableSpan = new TextView(RuntimeEnvironment.application);
SpannableString spannableString = new SpannableString("Some text");
ClickableSpan mockClickableSpan = mock(ClickableSpan.class);
spannableString.setSpan(mockClickableSpan, 0, 1, Spanned.SPAN_COMPOSING);
textViewWithClickableSpan.setText(spannableString);
shadowOf(textViewWithClickableSpan).setGlobalVisibleRect(validViewBounds);
}
@Test(expected = AccessibilityViewCheckException.class)
public void checkUnlabeledView_shouldThrow() throws Exception {
AccessibilityUtil.checkView(unlabeledView);
}
@Test
public void checkOKView_shouldNotThrow() throws Exception {
AccessibilityUtil.checkView(labeledView);
}
@Test
public void default_viewWithSiblingIssue_shouldNotThrow() throws Exception {
parentLayout.addView(unlabeledView);
AccessibilityUtil.checkView(labeledView);
}
@Test(expected = AccessibilityViewCheckException.class)
public void whenCheckingFromRoot_viewWithSiblingIssue_shouldThrow() throws Exception {
parentLayout.addView(unlabeledView);
AccessibilityUtil.setRunChecksFromRootView(true);
AccessibilityUtil.checkView(labeledView);
}
@Test(expected = AccessibilityViewCheckException.class)
@AccessibilityChecks
public void whenAnnotationPresent_conditionalCheckRun() {
AccessibilityUtil.checkViewIfCheckingEnabled(unlabeledView);
}
@Test
public void whenAnnotationNotPresent_conditionalCheckNotRun() {
AccessibilityUtil.checkViewIfCheckingEnabled(unlabeledView);
}
@Test(expected = AccessibilityViewCheckException.class)
public void framework2pt0Error_byDefault_shouldThrow() throws Exception {
AccessibilityUtil.checkView(textViewWithClickableSpan);
}
@Test
public void framework2pt0Error_whenCheckingForRL3pt0_shouldNotThrow() throws Exception {
AccessibilityUtil.setRunChecksForRobolectricVersion(ForRobolectricVersion.VERSION_3_0);
AccessibilityUtil.checkView(textViewWithClickableSpan);
}
@Test
@AccessibilityChecks(forRobolectricVersion = ForRobolectricVersion.VERSION_3_0)
public void framework2pt0Error_annotationForRL3pt0_shouldNotThrow() throws Exception {
AccessibilityUtil.checkView(textViewWithClickableSpan);
}
@Test(expected = AccessibilityViewCheckException.class)
@AccessibilityChecks(forRobolectricVersion = ForRobolectricVersion.VERSION_3_0)
public void framework2pt0Error_codeForcesRL3pt1_shouldThrow() throws Exception {
AccessibilityUtil.setRunChecksForRobolectricVersion(ForRobolectricVersion.VERSION_3_1);
AccessibilityUtil.checkView(textViewWithClickableSpan);
}
@Test
public void whenSuppressingResults_shouldNotThrow() throws Exception {
AccessibilityUtil.setSuppressingResultMatcher(Matchers.anything());
AccessibilityUtil.checkView(unlabeledView);
}
@Test
public void whenOnlyPrintingResults_shouldNotThrow() throws Exception {
AccessibilityUtil.setThrowExceptionForErrors(false);
AccessibilityUtil.checkView(unlabeledView);
}
@Test
public void warningIssue_shouldNotThrow() throws Exception {
labeledView.setContentDescription(DUPLICATE_STRING);
parentLayout.setContentDescription(DUPLICATE_STRING);
parentLayout.setClickable(true);
AccessibilityUtil.checkView(parentLayout);
}
}