1 /* 2 * Copyright (C) 2018 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.settings.core; 18 19 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_APPEND; 20 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; 21 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEYWORDS; 22 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE; 23 import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_UNAVAILABLE_SLICE_SUBTITLE; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import android.content.Context; 28 import android.content.res.XmlResourceParser; 29 import android.os.Bundle; 30 import android.text.TextUtils; 31 import android.util.AttributeSet; 32 import android.util.Xml; 33 34 import com.android.settings.R; 35 import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag; 36 37 import org.junit.Before; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 import org.robolectric.RobolectricTestRunner; 41 import org.robolectric.RuntimeEnvironment; 42 import org.robolectric.annotation.Config; 43 import org.xmlpull.v1.XmlPullParser; 44 import org.xmlpull.v1.XmlPullParserException; 45 46 import java.io.IOException; 47 import java.util.List; 48 import java.util.Objects; 49 50 /** 51 * These tests use a series of preferences that have specific attributes which are sometimes 52 * uncommon (such as summaryOn). 53 * 54 * If changing a preference file breaks a test in this test file, please replace its reference 55 * with another preference with a matchin replacement attribute. 56 */ 57 @RunWith(RobolectricTestRunner.class) 58 public class PreferenceXmlParserUtilsTest { 59 60 private Context mContext; 61 62 @Before setUp()63 public void setUp() { 64 mContext = RuntimeEnvironment.application; 65 } 66 67 @Test testDataTitleValid_ReturnsPreferenceTitle()68 public void testDataTitleValid_ReturnsPreferenceTitle() { 69 XmlResourceParser parser = getChildByType(R.xml.display_settings, 70 "com.android.settings.display.TimeoutListPreference"); 71 final AttributeSet attrs = Xml.asAttributeSet(parser); 72 String title = PreferenceXmlParserUtils.getDataTitle(mContext, attrs); 73 String expTitle = mContext.getString(R.string.screen_timeout); 74 assertThat(title).isEqualTo(expTitle); 75 } 76 77 @Test testDataKeywordsValid_ReturnsPreferenceKeywords()78 public void testDataKeywordsValid_ReturnsPreferenceKeywords() { 79 XmlResourceParser parser = getParentPrimedParser(R.xml.display_settings); 80 final AttributeSet attrs = Xml.asAttributeSet(parser); 81 String keywords = PreferenceXmlParserUtils.getDataKeywords(mContext, attrs); 82 String expKeywords = mContext.getString(R.string.keywords_display); 83 assertThat(keywords).isEqualTo(expKeywords); 84 } 85 86 @Test testDataKeyValid_ReturnsPreferenceKey()87 public void testDataKeyValid_ReturnsPreferenceKey() { 88 XmlResourceParser parser = getChildByType(R.xml.display_settings, 89 "com.android.settings.display.TimeoutListPreference"); 90 final AttributeSet attrs = Xml.asAttributeSet(parser); 91 String key = PreferenceXmlParserUtils.getDataKey(mContext, attrs); 92 String expKey = "screen_timeout"; 93 assertThat(key).isEqualTo(expKey); 94 } 95 96 @Test testDataSummaryValid_ReturnsPreferenceSummary()97 public void testDataSummaryValid_ReturnsPreferenceSummary() { 98 XmlResourceParser parser = getChildByType(R.xml.display_settings, 99 "com.android.settings.display.TimeoutListPreference"); 100 final AttributeSet attrs = Xml.asAttributeSet(parser); 101 String summary = PreferenceXmlParserUtils.getDataSummary(mContext, attrs); 102 String expSummary = mContext.getString(R.string.summary_placeholder); 103 assertThat(summary).isEqualTo(expSummary); 104 } 105 106 @Test 107 @Config(qualifiers = "mcc999") testDataSummaryOnOffValid_ReturnsPreferenceSummaryOnOff()108 public void testDataSummaryOnOffValid_ReturnsPreferenceSummaryOnOff() { 109 XmlResourceParser parser = getChildByType(R.xml.display_settings, "CheckBoxPreference"); 110 final AttributeSet attrs = Xml.asAttributeSet(parser); 111 112 assertThat(PreferenceXmlParserUtils.getDataSummaryOn(mContext, attrs)) 113 .isEqualTo("summary_on"); 114 assertThat(PreferenceXmlParserUtils.getDataSummaryOff(mContext, attrs)) 115 .isEqualTo("summary_off"); 116 } 117 118 @Test 119 @Config(qualifiers = "mcc999") testDataEntriesValid_ReturnsPreferenceEntries()120 public void testDataEntriesValid_ReturnsPreferenceEntries() { 121 XmlResourceParser parser = getChildByType(R.xml.display_settings, "ListPreference"); 122 final AttributeSet attrs = Xml.asAttributeSet(parser); 123 String entries = PreferenceXmlParserUtils.getDataEntries(mContext, attrs); 124 String[] expEntries = mContext.getResources() 125 .getStringArray(R.array.app_install_location_entries); 126 for (String expEntry : expEntries) { 127 assertThat(entries).contains(expEntry); 128 } 129 } 130 131 // Null checks 132 @Test 133 @Config(qualifiers = "mcc999") testDataKeyInvalid_ReturnsNull()134 public void testDataKeyInvalid_ReturnsNull() { 135 XmlResourceParser parser = getParentPrimedParser(R.xml.display_settings); 136 final AttributeSet attrs = Xml.asAttributeSet(parser); 137 String key = PreferenceXmlParserUtils.getDataKey(mContext, attrs); 138 assertThat(key).isNull(); 139 } 140 141 @Test 142 @Config(qualifiers = "mcc999") testControllerAttribute_returnsValidData()143 public void testControllerAttribute_returnsValidData() { 144 XmlResourceParser parser = getChildByType(R.xml.about_legal, "Preference"); 145 final AttributeSet attrs = Xml.asAttributeSet(parser); 146 147 String controller = PreferenceXmlParserUtils.getController(mContext, attrs); 148 assertThat(controller).isEqualTo("mind_flayer"); 149 } 150 151 @Test testDataSummaryInvalid_ReturnsNull()152 public void testDataSummaryInvalid_ReturnsNull() { 153 XmlResourceParser parser = getParentPrimedParser(R.xml.display_settings); 154 final AttributeSet attrs = Xml.asAttributeSet(parser); 155 String summary = PreferenceXmlParserUtils.getDataSummary(mContext, attrs); 156 assertThat(summary).isNull(); 157 } 158 159 @Test testDataSummaryOffInvalid_ReturnsNull()160 public void testDataSummaryOffInvalid_ReturnsNull() { 161 XmlResourceParser parser = getParentPrimedParser(R.xml.display_settings); 162 final AttributeSet attrs = Xml.asAttributeSet(parser); 163 String summaryOff = PreferenceXmlParserUtils.getDataSummaryOff(mContext, attrs); 164 assertThat(summaryOff).isNull(); 165 } 166 167 @Test testDataEntriesInvalid_ReturnsNull()168 public void testDataEntriesInvalid_ReturnsNull() { 169 XmlResourceParser parser = getParentPrimedParser(R.xml.display_settings); 170 final AttributeSet attrs = Xml.asAttributeSet(parser); 171 String entries = PreferenceXmlParserUtils.getDataEntries(mContext, attrs); 172 assertThat(entries).isNull(); 173 } 174 175 @Test 176 @Config(qualifiers = "mcc999") extractMetadata_shouldContainKeyAndControllerName()177 public void extractMetadata_shouldContainKeyAndControllerName() 178 throws IOException, XmlPullParserException { 179 List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 180 R.xml.location_settings, 181 MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_NEED_PREF_CONTROLLER); 182 183 assertThat(metadata).isNotEmpty(); 184 for (Bundle bundle : metadata) { 185 assertThat(bundle.getString(PreferenceXmlParserUtils.METADATA_KEY)).isNotNull(); 186 assertThat(bundle.getString(PreferenceXmlParserUtils.METADATA_CONTROLLER)).isNotNull(); 187 } 188 } 189 190 @Test 191 @Config(qualifiers = "mcc999") extractMetadata_requestTitle_shouldContainTitle()192 public void extractMetadata_requestTitle_shouldContainTitle() 193 throws IOException, XmlPullParserException { 194 List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 195 R.xml.location_settings, MetadataFlag.FLAG_NEED_PREF_TITLE); 196 for (Bundle bundle : metadata) { 197 assertThat(bundle.getString(PreferenceXmlParserUtils.METADATA_TITLE)).isNotNull(); 198 } 199 } 200 201 @Test 202 @Config(qualifiers = "mcc999") extractMetadata_requestSummary_shouldContainSummary()203 public void extractMetadata_requestSummary_shouldContainSummary() 204 throws IOException, XmlPullParserException { 205 List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 206 R.xml.location_settings, MetadataFlag.FLAG_NEED_PREF_SUMMARY); 207 for (Bundle bundle : metadata) { 208 assertThat(bundle.getString(PreferenceXmlParserUtils.METADATA_SUMMARY)).isNotNull(); 209 } 210 } 211 212 @Test 213 @Config(qualifiers = "mcc999") extractMetadata_requestIcon_shouldContainIcon()214 public void extractMetadata_requestIcon_shouldContainIcon() 215 throws IOException, XmlPullParserException { 216 List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 217 R.xml.location_settings, MetadataFlag.FLAG_NEED_PREF_ICON); 218 for (Bundle bundle : metadata) { 219 assertThat(bundle.getInt(PreferenceXmlParserUtils.METADATA_ICON)).isNotEqualTo(0); 220 } 221 } 222 223 @Test 224 @Config(qualifiers = "mcc999") extractMetadata_requestPrefType_shouldContainPrefType()225 public void extractMetadata_requestPrefType_shouldContainPrefType() 226 throws IOException, XmlPullParserException { 227 List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 228 R.xml.location_settings, MetadataFlag.FLAG_NEED_PREF_TYPE); 229 for (Bundle bundle : metadata) { 230 assertThat(bundle.getString(PreferenceXmlParserUtils.METADATA_PREF_TYPE)).isNotNull(); 231 } 232 } 233 234 @Test 235 @Config(qualifiers = "mcc999") extractMetadata_requestIncludeScreen_shouldContainScreen()236 public void extractMetadata_requestIncludeScreen_shouldContainScreen() 237 throws IOException, XmlPullParserException { 238 List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 239 R.xml.location_settings, 240 MetadataFlag.FLAG_NEED_PREF_TYPE | MetadataFlag.FLAG_INCLUDE_PREF_SCREEN); 241 242 boolean hasPreferenceScreen = false; 243 for (Bundle bundle : metadata) { 244 if (TextUtils.equals(bundle.getString(PreferenceXmlParserUtils.METADATA_PREF_TYPE), 245 PreferenceXmlParserUtils.PREF_SCREEN_TAG)) { 246 hasPreferenceScreen = true; 247 break; 248 } 249 } 250 251 assertThat(hasPreferenceScreen).isTrue(); 252 } 253 254 @Test 255 @Config(qualifiers = "mcc999") extractMetadata_requestIncludesKeywords_shouldContainKeywords()256 public void extractMetadata_requestIncludesKeywords_shouldContainKeywords() throws Exception { 257 final String expectedKeywords = "a, b, c"; 258 final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 259 R.xml.location_settings, 260 MetadataFlag.FLAG_NEED_PREF_TYPE | MetadataFlag.FLAG_NEED_KEYWORDS); 261 final Bundle bundle = metadata.get(0); 262 263 final String keywords = bundle.getString(METADATA_KEYWORDS); 264 265 assertThat(keywords).isEqualTo(expectedKeywords); 266 } 267 268 @Test 269 @Config(qualifiers = "mcc998") extractMetadata_requestSearchable_shouldDefaultToTrue()270 public void extractMetadata_requestSearchable_shouldDefaultToTrue() throws Exception { 271 final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 272 R.xml.location_settings, MetadataFlag.FLAG_NEED_SEARCHABLE); 273 for (Bundle bundle : metadata) { 274 assertThat(bundle.getBoolean(METADATA_SEARCHABLE)).isTrue(); 275 } 276 } 277 278 @Test 279 @Config(qualifiers = "mcc999") extractMetadata_requestSearchable_shouldReturnAttributeValue()280 public void extractMetadata_requestSearchable_shouldReturnAttributeValue() throws Exception { 281 final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 282 R.xml.display_settings, 283 MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_NEED_SEARCHABLE); 284 boolean foundKey = false; 285 for (Bundle bundle : metadata) { 286 if (TextUtils.equals(bundle.getString(METADATA_KEY), "pref_key_5")) { 287 assertThat(bundle.getBoolean(METADATA_SEARCHABLE)).isFalse(); 288 foundKey = true; 289 break; 290 } 291 } 292 assertThat(foundKey).isTrue(); 293 } 294 295 @Test 296 @Config(qualifiers = "mcc999") extractMetadata_requestAppendProperty_shouldDefaultToFalse()297 public void extractMetadata_requestAppendProperty_shouldDefaultToFalse() 298 throws Exception { 299 final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 300 R.xml.display_settings, 301 MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND); 302 303 for (Bundle bundle : metadata) { 304 assertThat(bundle.getBoolean(METADATA_APPEND)).isFalse(); 305 } 306 } 307 308 @Test 309 @Config(qualifiers = "mcc999") extractMetadata_requestAppendProperty_shouldReturnCorrectValue()310 public void extractMetadata_requestAppendProperty_shouldReturnCorrectValue() 311 throws Exception { 312 final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 313 R.xml.battery_saver_schedule_settings, 314 MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND); 315 316 for (Bundle bundle : metadata) { 317 assertThat(bundle.getBoolean(METADATA_APPEND)).isTrue(); 318 } 319 } 320 321 @Test 322 @Config(qualifiers = "mcc999") extractMetadata_requestUnavailableSliceSubtitle_shouldDefaultNull()323 public void extractMetadata_requestUnavailableSliceSubtitle_shouldDefaultNull() 324 throws Exception { 325 final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 326 R.xml.night_display_settings, 327 MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE); 328 329 boolean bundleWithKey1Found = false; 330 for (Bundle bundle : metadata) { 331 if (bundle.getString(METADATA_KEY).equals("key1")) { 332 assertThat(bundle.getString(METADATA_UNAVAILABLE_SLICE_SUBTITLE)).isNull(); 333 bundleWithKey1Found = true; 334 break; 335 } 336 } 337 assertThat(bundleWithKey1Found).isTrue(); 338 } 339 340 @Test 341 @Config(qualifiers = "mcc999") extractMetadata_requestUnavailableSliceSubtitle_shouldReturnAttributeValue()342 public void extractMetadata_requestUnavailableSliceSubtitle_shouldReturnAttributeValue() 343 throws Exception { 344 final String expectedSubtitle = "subtitleOfUnavailable"; 345 final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, 346 R.xml.night_display_settings, 347 MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE); 348 349 boolean bundleWithKey2Found = false; 350 for (Bundle bundle : metadata) { 351 if (bundle.getString(METADATA_KEY).equals("key2")) { 352 assertThat(bundle.getString(METADATA_UNAVAILABLE_SLICE_SUBTITLE)).isEqualTo( 353 expectedSubtitle); 354 bundleWithKey2Found = true; 355 break; 356 } 357 } 358 assertThat(bundleWithKey2Found).isTrue(); 359 } 360 361 /** 362 * @param resId the ID for the XML preference 363 * @return an XML resource parser that points to the start tag 364 */ getParentPrimedParser(int resId)365 private XmlResourceParser getParentPrimedParser(int resId) { 366 XmlResourceParser parser = null; 367 try { 368 parser = mContext.getResources().getXml(resId); 369 370 int type; 371 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 372 && type != XmlPullParser.START_TAG) { 373 } 374 } catch (Exception e) { 375 376 } 377 return parser; 378 } 379 getChildByType(int resId, String xmlType)380 private XmlResourceParser getChildByType(int resId, String xmlType) { 381 XmlResourceParser parser = null; 382 try { 383 parser = mContext.getResources().getXml(resId); 384 385 int type; 386 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 387 && type != XmlPullParser.START_TAG) { 388 } 389 while (true) { 390 if (Objects.equals(parser.getName(), xmlType)) { 391 break; 392 } 393 final int nextEvent = parser.next(); 394 if (nextEvent == XmlPullParser.END_DOCUMENT) { 395 break; 396 } 397 } 398 } catch (Exception e) { 399 400 } 401 return parser; 402 } 403 } 404