1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.idea.validator; 18 19 import com.android.ide.common.rendering.api.SessionParams; 20 import com.android.layoutlib.bridge.intensive.RenderTestBase; 21 import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator; 22 import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback; 23 import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser; 24 import com.android.tools.idea.validator.ValidatorData.Issue; 25 import com.android.tools.idea.validator.ValidatorData.Level; 26 import com.android.tools.idea.validator.ValidatorData.Type; 27 28 import org.junit.Test; 29 30 import android.view.View; 31 32 import java.util.EnumSet; 33 import java.util.Set; 34 import java.util.stream.Collectors; 35 36 import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckPreset; 37 import com.google.android.apps.common.testing.accessibility.framework.AccessibilityHierarchyCheck; 38 39 import static org.junit.Assert.assertEquals; 40 import static org.junit.Assert.assertTrue; 41 42 public class LayoutValidatorTests extends RenderTestBase { 43 44 @Test testRenderAndVerify()45 public void testRenderAndVerify() throws Exception { 46 LayoutPullParser parser = createParserFromPath("a11y_test1.xml"); 47 LayoutLibTestCallback layoutLibCallback = 48 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 49 layoutLibCallback.initResources(); 50 SessionParams params = getSessionParamsBuilder() 51 .setParser(parser) 52 .setConfigGenerator(ConfigGenerator.NEXUS_5) 53 .setCallback(layoutLibCallback) 54 .disableDecoration() 55 .enableLayoutValidation() 56 .build(); 57 58 renderAndVerify(params, "a11y_test1.png"); 59 } 60 61 @Test testValidation()62 public void testValidation() throws Exception { 63 render(sBridge, generateParams(), -1, session -> { 64 ValidatorResult result = LayoutValidator 65 .validate(((View) session.getRootViews().get(0).getViewObject()), null); 66 assertEquals(3, result.getIssues().size()); 67 for (Issue issue : result.getIssues()) { 68 assertEquals(Type.ACCESSIBILITY, issue.mType); 69 assertEquals(Level.ERROR, issue.mLevel); 70 } 71 72 Issue first = result.getIssues().get(0); 73 assertEquals("This item may not have a label readable by screen readers.", 74 first.mMsg); 75 assertEquals("https://support.google.com/accessibility/android/answer/7158690", 76 first.mHelpfulUrl); 77 assertEquals("SpeakableTextPresentCheck", first.mSourceClass); 78 79 Issue second = result.getIssues().get(1); 80 assertEquals("This item's size is 10dp x 10dp. Consider making this touch target " + 81 "48dp wide and 48dp high or larger.", 82 second.mMsg); 83 assertEquals("https://support.google.com/accessibility/android/answer/7101858", 84 second.mHelpfulUrl); 85 assertEquals("TouchTargetSizeCheck", second.mSourceClass); 86 87 Issue third = result.getIssues().get(2); 88 assertEquals("The item's text contrast ratio is 1.00. This ratio is based on a text color " + 89 "of #000000 and background color of #000000. Consider increasing this item's" + 90 " text contrast ratio to 4.50 or greater.", 91 third.mMsg); 92 assertEquals("https://support.google.com/accessibility/android/answer/7158390", 93 third.mHelpfulUrl); 94 assertEquals("TextContrastCheck", third.mSourceClass); 95 }); 96 } 97 98 @Test testValidationPolicyType()99 public void testValidationPolicyType() throws Exception { 100 try { 101 ValidatorData.Policy newPolicy = new ValidatorData.Policy( 102 EnumSet.of(Type.RENDER), 103 EnumSet.of(Level.ERROR, Level.WARNING)); 104 LayoutValidator.updatePolicy(newPolicy); 105 106 render(sBridge, generateParams(), -1, session -> { 107 ValidatorResult result = LayoutValidator.validate( 108 ((View) session.getRootViews().get(0).getViewObject()), null); 109 assertTrue(result.getIssues().isEmpty()); 110 }); 111 } finally { 112 LayoutValidator.updatePolicy(LayoutValidator.DEFAULT_POLICY); 113 } 114 } 115 116 @Test testValidationPolicyLevel()117 public void testValidationPolicyLevel() throws Exception { 118 try { 119 ValidatorData.Policy newPolicy = new ValidatorData.Policy( 120 EnumSet.of(Type.ACCESSIBILITY, Type.RENDER), 121 EnumSet.of(Level.VERBOSE)); 122 LayoutValidator.updatePolicy(newPolicy); 123 124 render(sBridge, generateParams(), -1, session -> { 125 ValidatorResult result = LayoutValidator.validate( 126 ((View) session.getRootViews().get(0).getViewObject()), null); 127 assertEquals(27, result.getIssues().size()); 128 result.getIssues().forEach(issue ->assertEquals(Level.VERBOSE, issue.mLevel)); 129 }); 130 } finally { 131 LayoutValidator.updatePolicy(LayoutValidator.DEFAULT_POLICY); 132 } 133 } 134 135 @Test testValidationPolicyChecks()136 public void testValidationPolicyChecks() throws Exception { 137 Set<AccessibilityHierarchyCheck> allChecks = 138 AccessibilityCheckPreset.getAccessibilityHierarchyChecksForPreset( 139 AccessibilityCheckPreset.LATEST); 140 Set<AccessibilityHierarchyCheck> filtered =allChecks 141 .stream() 142 .filter(it -> it.getClass().getSimpleName().equals("TextContrastCheck")) 143 .collect(Collectors.toSet()); 144 try { 145 ValidatorData.Policy newPolicy = new ValidatorData.Policy( 146 EnumSet.of(Type.ACCESSIBILITY, Type.RENDER), 147 EnumSet.of(Level.ERROR)); 148 newPolicy.mChecks.addAll(filtered); 149 LayoutValidator.updatePolicy(newPolicy); 150 151 render(sBridge, generateParams(), -1, session -> { 152 ValidatorResult result = LayoutValidator.validate( 153 ((View) session.getRootViews().get(0).getViewObject()), null); 154 assertEquals(1, result.getIssues().size()); 155 Issue textCheck = result.getIssues().get(0); 156 assertEquals("The item's text contrast ratio is 1.00. This ratio is based on a text color " + 157 "of #000000 and background color of #000000. Consider increasing this item's" + 158 " text contrast ratio to 4.50 or greater.", 159 textCheck.mMsg); 160 assertEquals("https://support.google.com/accessibility/android/answer/7158390", 161 textCheck.mHelpfulUrl); 162 assertEquals("TextContrastCheck", textCheck.mSourceClass); 163 }); 164 } finally { 165 LayoutValidator.updatePolicy(LayoutValidator.DEFAULT_POLICY); 166 } 167 } 168 generateParams()169 private SessionParams generateParams() throws Exception { 170 LayoutPullParser parser = createParserFromPath("a11y_test1.xml"); 171 LayoutLibTestCallback layoutLibCallback = 172 new LayoutLibTestCallback(getLogger(), mDefaultClassLoader); 173 layoutLibCallback.initResources(); 174 return getSessionParamsBuilder() 175 .setParser(parser) 176 .setConfigGenerator(ConfigGenerator.NEXUS_5) 177 .setCallback(layoutLibCallback) 178 .disableDecoration() 179 .enableLayoutValidation() 180 .build(); 181 } 182 } 183